form wizard with calculator

master
fefa4ka 10 years ago
parent 60c3cbbc88
commit 85d6cd590a
  1. 7
      app/settings.py
  2. 13
      djangocms_forms/cms_plugins.py
  3. 20
      djangocms_forms/migrations/0004_auto_20150914_0835.py
  4. 23
      djangocms_forms/templates/djangocms_forms/form_template/default.html
  5. 1
      requirements.txt
  6. 0
      smartsnippets/__init__.py
  7. 281
      smartsnippets/admin.py
  8. 225
      smartsnippets/cms_plugins.py
  9. 5
      smartsnippets/exceptions.py
  10. 94
      smartsnippets/migrations/0001_initial.py
  11. 20
      smartsnippets/migrations/0002_change_smartsnippetvariable_description.py
  12. 20
      smartsnippets/migrations/0003_change_smartsnippetvariable_description.py
  13. 0
      smartsnippets/migrations/__init__.py
  14. 283
      smartsnippets/models.py
  15. 68
      smartsnippets/resources_processor.py
  16. 33
      smartsnippets/settings.py
  17. 95
      smartsnippets/south_migrations/0001_initial.py
  18. 74
      smartsnippets/south_migrations/0002_auto.py
  19. 70
      smartsnippets/south_migrations/0003_auto__add_field_smartsnippet_template_path.py
  20. 70
      smartsnippets/south_migrations/0004_auto__chg_field_smartsnippet_template_path.py
  21. 123
      smartsnippets/south_migrations/0005_auto__add_dropdownvariable__add_smartsnippetvariable__add_unique_smart.py
  22. 118
      smartsnippets/south_migrations/0006_populate_variables_and_relations.py
  23. 94
      smartsnippets/south_migrations/0007_auto__del_field_variable_name__chg_field_variable_snippet_variable__ad.py
  24. 94
      smartsnippets/south_migrations/0008_auto__add_field_smartsnippet_description__add_field_smartsnippet_docum.py
  25. 84
      smartsnippets/south_migrations/0009_auto__chg_field_variable_value.py
  26. 84
      smartsnippets/south_migrations/0010_auto__chg_field_variable_value.py
  27. 87
      smartsnippets/south_migrations/0011_auto__add_field_smartsnippetvariable_resources.py
  28. 0
      smartsnippets/south_migrations/__init__.py
  29. 249
      smartsnippets/static/admin/css/codemirror.css
  30. 173
      smartsnippets/static/admin/css/custom.css
  31. 11
      smartsnippets/static/admin/css/smartsnippets-extra.css
  32. 18
      smartsnippets/static/admin/css/snippet_plugin_default.css
  33. 41
      smartsnippets/static/admin/js/CMInstance.js
  34. 105
      smartsnippets/static/admin/js/SmartSnippetLib.js
  35. 29
      smartsnippets/static/admin/js/SmartSnippets.PredefinedWidgets.js
  36. 421
      smartsnippets/static/admin/js/SmartSnippets.Variables.js
  37. 5637
      smartsnippets/static/admin/js/codemirror/codemirror.js
  38. 606
      smartsnippets/static/admin/js/codemirror/css.js
  39. 104
      smartsnippets/static/admin/js/codemirror/htmlmixed.js
  40. 471
      smartsnippets/static/admin/js/codemirror/javascript.js
  41. 330
      smartsnippets/static/admin/js/codemirror/xml.js
  42. 3
      smartsnippets/static/admin/js/custom.js
  43. 1
      smartsnippets/static/admin/js/default.jQuery.init.js
  44. 5
      smartsnippets/static/admin/js/snippet_plugin_default.js
  45. 113
      smartsnippets/static/css/tipTip.css
  46. BIN
      smartsnippets/static/images/drag.gif
  47. BIN
      smartsnippets/static/images/help.png
  48. BIN
      smartsnippets/static/images/snippet.png
  49. 21
      smartsnippets/static/js/jquery.tipTip.minified.js
  50. 2
      smartsnippets/static/libs/ace/css/ace.min.css
  51. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_alerts.scssc
  52. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_background-variant.scssc
  53. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_border-radius.scssc
  54. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_buttons.scssc
  55. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_center-block.scssc
  56. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_clearfix.scssc
  57. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_forms.scssc
  58. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_gradients.scssc
  59. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_grid-framework.scssc
  60. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_grid.scssc
  61. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_hide-text.scssc
  62. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_image.scssc
  63. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_labels.scssc
  64. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_list-group.scssc
  65. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_nav-divider.scssc
  66. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_nav-vertical-align.scssc
  67. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_opacity.scssc
  68. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_pagination.scssc
  69. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_panels.scssc
  70. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_progress-bar.scssc
  71. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_reset-filter.scssc
  72. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_resize.scssc
  73. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_responsive-visibility.scssc
  74. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_size.scssc
  75. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_tab-focus.scssc
  76. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_table-row.scssc
  77. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_text-emphasis.scssc
  78. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_text-overflow.scssc
  79. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/86c1908123397cf1005de81f48cf5488379aee2b/_vendor-prefixes.scssc
  80. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/a3fc55010a1edcf08f2f14e264cea00e2e5d53de/bootstrap.scssc
  81. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/a3fc55010a1edcf08f2f14e264cea00e2e5d53de/bootstrapV320.scssc
  82. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_alerts.scssc
  83. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_badges.scssc
  84. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_breadcrumbs.scssc
  85. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_button-groups.scssc
  86. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_buttons.scssc
  87. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_carousel.scssc
  88. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_close.scssc
  89. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_code.scssc
  90. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_component-animations.scssc
  91. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_dropdowns.scssc
  92. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_forms.scssc
  93. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_glyphicons.scssc
  94. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_grid.scssc
  95. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_input-groups.scssc
  96. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_jumbotron.scssc
  97. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_labels.scssc
  98. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_list-group.scssc
  99. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_media.scssc
  100. BIN
      smartsnippets/static/libs/bootstrap/.sass-cache/f36248dd960f1a9339c30cc05a0df413bcc543e4/_mixins.scssc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -244,9 +244,9 @@ INSTALLED_APPS = (
'blog',
'aldryn_bootstrap3',
'djangocms_forms'
# 'debug_toolbar',
'debug_toolbar',
'djangocms_forms',
'smartsnippets',
)
SOUTH_MIGRATION_MODULES = {
@ -321,6 +321,7 @@ CMS_TEMPLATES = (
DJANGOCMS_FORMS_TEMPLATES = (
('djangocms_forms/form_template/default.html', 'Default'),
('form_template/consultation.html', 'Consultation'),
('form_template/product_class.html', 'Trademark Product Class'),
)

@ -104,13 +104,24 @@ class FormPlugin(CMSPluginBase):
context = super(FormPlugin, self).render(context, instance, placeholder)
request = context['request']
form_slug = "form-%d" % instance.plugin_reference.id
submission_instance = instance
if request.session.get(form_slug, False):
try:
submission_instance = FormSubmission.objects.get(id=request.session.get(form_slug, False))
except:
pass
form = FormBuilder(
initial={'referrer': request.path_info}, form_definition=instance,
label_suffix='', auto_id='%s')
context.update({
'form': form
'form': form,
'results': submission_instance
})
return context

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('djangocms_forms', '0003_add_referrer_field'),
]
operations = [
migrations.AlterField(
model_name='formdefinition',
name='form_template',
field=models.CharField(default=b'djangocms_forms/form_template/default.html', max_length=150, verbose_name='Form Template', blank=True, choices=[(b'djangocms_forms/form_template/default.html', b'Default'), (b'form_template/consultation.html', b'Consultation'), (b'form_template/product_class.html', b'Trademark Product Class')]),
preserve_default=True,
),
]

@ -1,4 +1,27 @@
{% load cms_tags djangocms_forms_tags i18n sekizai_tags staticfiles %}
<script type="application/javascript">
var form = {
{% for item in results.form_data %}
{% if item.label %}
'{{ item.label }}'
{% else %}
'{{ item.name }}'
{% endif %}
: {
'size':
{% if item.value == True %}
1
{% elif item.value == False %}
0
{% else %}
{{ item.value|length }}
{% endif %}
,
'values': '{{ item.value }}'
},
{% endfor %}
};
</script>
<div class="forms" id="{{ instance.form_id }}">
{% if instance.title %}
<h3 class="title">{{ instance.title }}</h3>

@ -33,3 +33,4 @@ django-admin-enhancer
aldryn-apphooks-config
#export C_INCLUDE_PATH=/usr/local/Cellar/libxml2/2.9.2/include/libxml2:$C_INCLUDE_PATH
git+https://github.com/MagicSolutions/django-cmsplugin-tabs.git#egg=django-cmsplugin-tabs
django-cms-smartsnippets

@ -0,0 +1,281 @@
import re
from collections import Counter
from django.contrib import admin
from django.db.models import Q
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.sites.models import Site
from django.core.exceptions import ValidationError
from django.forms import ModelForm, ModelMultipleChoiceField
from django.forms.models import BaseInlineFormSet
from django.template import Template, TemplateSyntaxError, \
TemplateDoesNotExist, loader
from django.template.loader import render_to_string
from django.forms.widgets import Select
from django.contrib.admin.templatetags.admin_static import static
from admin_extend.extend import registered_form, extend_registered, \
add_bidirectional_m2m
from models import SmartSnippet, SmartSnippetVariable, DropDownVariable, clean_variable_name
from settings import (
shared_sites, include_orphan, restrict_user, handle_permissions_checks,
custom_widgets_resources, USE_BOOTSTRAP_ACE)
from widgets_pool import widget_pool
class SnippetForm(ModelForm):
include_orphan = include_orphan
use_ace_theme = USE_BOOTSTRAP_ACE
class Meta:
model = SmartSnippet
exclude = ()
def __init__(self, *args, **kwargs):
if 'sites' in self.base_fields:
# disallow django to validate if empty since it is done
# in the clean sites method
self.base_fields['sites'].required = False
super(SnippetForm, self).__init__(*args, **kwargs)
def clean_sites(self):
empty_sites = Site.objects.none()
self.cleaned_data['sites'] = self.cleaned_data.get(
'sites', empty_sites) or empty_sites
def ids_list(queryset):
return list(queryset.values_list('id', flat=True))
all_in_form = self.base_fields['sites'].queryset
assigned_in_form = ids_list(self.cleaned_data['sites'])
unassigned_in_form = ids_list(
all_in_form.exclude(id__in=assigned_in_form))
if self.instance.pk:
assigned_and_unchanged = ids_list(
self.instance.sites.exclude(id__in=unassigned_in_form))
all_assigned = assigned_in_form + assigned_and_unchanged
else:
all_assigned = assigned_in_form
self.cleaned_data['sites'] = Site.objects.filter(id__in=all_assigned)
if not self.include_orphan and not self.cleaned_data['sites']:
raise ValidationError('This field is required.')
return self.cleaned_data['sites']
def clean_template_code(self):
code = self.cleaned_data.get('template_code', None)
if not code:
return code
try:
Template(code)
except TemplateSyntaxError, e:
raise ValidationError(e)
return code
def clean_template_path(self):
path = self.cleaned_data.get('template_path', None)
if not path:
return path
try:
loader.get_template(path)
except TemplateDoesNotExist, e:
raise ValidationError(e)
return path
def clean(self):
clean_result = super(SnippetForm, self).clean()
self.validate_unique_variable_names()
return clean_result
def validate_unique_variable_names(self):
""" Validates name uniqueness over all variable inlines. """
all_variable_names = [clean_variable_name(value)
for key, value in self.data.dict().iteritems()
if re.match(r"variables[0-9-]*name", key)]
duplicate_variable_names = [var_name for var_name, count
in Counter(all_variable_names).iteritems()
if count > 1]
if duplicate_variable_names:
if len(duplicate_variable_names) == 1:
raise ValidationError(
'The variable name "{}" is used multiple times.'.format(duplicate_variable_names.pop()))
raise ValidationError('The variable names "{}" are used multiple times.'.format(
', '.join(duplicate_variable_names)))
class SnippetVariablesFormSet(BaseInlineFormSet):
def get_queryset(self):
if not hasattr(self, '_queryset'):
available_widgets = [widget.__name__ for widget in widget_pool.get_all_widgets()]
qs = super(SnippetVariablesFormSet, self).get_queryset().filter(widget__in=available_widgets)
self._queryset = qs
return self._queryset
class SnippetVariablesAdmin(admin.StackedInline):
model = SmartSnippetVariable
extra = 0
readonly_fields = ['predefined_widgets']
def predefined_widgets(self, ssvar):
return render_to_string(
'smartsnippets/predefined_widgets.html',
{'widgets': custom_widgets_resources,
'snippet_var': ssvar})
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'widget':
kwargs['widget'] = Select(choices=tuple([(x.__name__, x.name) for x in widget_pool.get_all_widgets()]))
return super(SnippetVariablesAdmin,self).formfield_for_dbfield(db_field, **kwargs)
@staticmethod
def _fieldsets(required):
return (
(None, {
'fields': (required, )
}),
('Advanced', {
'fields': (('resources', 'predefined_widgets'), ),
'classes': ('collapse', )
}),
)
class RegularSnippetVariablesAdmin(SnippetVariablesAdmin):
formset = SnippetVariablesFormSet
fieldsets = SnippetVariablesAdmin._fieldsets(('name', 'widget'))
class DropDownVariableAdmin(SnippetVariablesAdmin):
model = DropDownVariable
exclude = ('widget',)
fieldsets = SnippetVariablesAdmin._fieldsets(('name', 'choices'))
class SnippetAdmin(admin.ModelAdmin):
inlines = [RegularSnippetVariablesAdmin, DropDownVariableAdmin]
shared_sites = shared_sites
include_orphan = include_orphan
restrict_user = restrict_user
list_filter = ('sites__name', )
list_display = ('name', 'site_list')
search_fields = ['name']
form = SnippetForm
change_form_template = 'smartsnippets/change_form.html'
filter_horizontal = ('sites', )
class Media:
js = ("admin/js/SmartSnippets.Variables.js",
"admin/js/SmartSnippets.PredefinedWidgets.js",)
@property
def media(self):
media_obj = super(SnippetAdmin, self).media
if not USE_BOOTSTRAP_ACE:
media_obj.add_css({
'all': (
static('admin/css/forms.css'),
static('admin/css/smartsnippets-extra.css'),)
})
return media_obj
def site_list(self, template):
return ", ".join([site.name for site in template.sites.all()])
site_list.short_description = 'sites'
def get_readonly_fields(self, request, obj=None):
if not handle_permissions_checks:
return super(SnippetAdmin, self)\
.get_readonly_fields(request, obj=obj)
ro = self.form.base_fields.keys()
if request.user.is_superuser or obj is None:
return []
if self.restrict_user and self.shared_sites:
if obj.sites.filter(name__in=self.shared_sites):
return ro
return []
def has_delete_permission(self, request, obj=None):
if not handle_permissions_checks:
return super(SnippetAdmin, self)\
.has_delete_permission(request, obj=obj)
if request.user.is_superuser or obj is None:
return True
if self.restrict_user and self.shared_sites:
return not bool(obj.sites.filter(name__in=self.shared_sites))
return True
def formfield_for_manytomany(self, db_field, request, **kwargs):
if not handle_permissions_checks:
return super(SnippetAdmin, self)\
.formfield_for_manytomany(db_field, request, **kwargs)
if db_field.name == "sites":
f = Q()
if not request.user.is_superuser:
if self.restrict_user:
f |= Q(globalpagepermission__user=request.user)
f |= Q(globalpagepermission__group__user=request.user)
kwargs["queryset"] = Site.objects.filter(f).distinct()
return (super(SnippetAdmin, self)
.formfield_for_manytomany(db_field, request, **kwargs))
def get_queryset(self, request):
q = super(SnippetAdmin, self).get_queryset(request)
if not handle_permissions_checks:
return q
f = Q()
if not request.user.is_superuser:
if self.restrict_user:
f |= Q(sites__globalpagepermission__user=request.user)
f |= Q(sites__globalpagepermission__group__user=request.user)
if self.shared_sites:
f |= Q(sites__name__in=self.shared_sites)
if self.include_orphan:
f |= Q(sites__isnull=True)
return q.filter(f).distinct()
admin.site.register(SmartSnippet, SnippetAdmin)
@extend_registered
class ExtendedSiteAdminForm(add_bidirectional_m2m(registered_form(Site))):
snippets = ModelMultipleChoiceField(
queryset=SmartSnippet.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Snippets',
is_stacked=False
)
)
def _get_bidirectional_m2m_fields(self):
return super(ExtendedSiteAdminForm, self).\
_get_bidirectional_m2m_fields() + [('snippets', 'smartsnippet_set')]
def clean_snippets(self):
assigned_snippets = self.cleaned_data['snippets']
if self.instance.pk is None or include_orphan:
return assigned_snippets
pks = [s.pk for s in assigned_snippets]
# snippets that were previously assigned to this site, but got unassigned
unassigned_snippets = self.instance.smartsnippet_set.exclude(pk__in=pks)
snippets_with_no_sites = []
for snippet in unassigned_snippets:
if snippet.sites.count() == 1:
snippets_with_no_sites.append(snippet)
if snippets_with_no_sites:
raise ValidationError(
"Following snippets will remain with no sites assigned: %s" %
", ".join(s.name for s in snippets_with_no_sites))
return assigned_snippets

@ -0,0 +1,225 @@
from django.db.models import Q
from django.forms.widgets import Media as WidgetsMedia
from django.contrib.sites.models import Site
from django.contrib.admin.templatetags.admin_static import static
from django.core.urlresolvers import reverse
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from .models import SmartSnippetPointer, SmartSnippet, Variable
from .settings import (
shared_sites, include_orphan, restrict_user, USE_BOOTSTRAP_ACE)
from django.conf import settings
import itertools
def variables_media(media, variables=None):
variables = variables or []
media.add_js([static('admin/js/SmartSnippetLib.js')])
media.add_js(
itertools.chain(*[var.js for var in variables])
)
media.add_css(
{'all': itertools.chain(*[var.css for var in variables])})
def add_variables_media(context):
if not context:
return
formMedia = context.get('media')
if not formMedia:
return
variables = context.get('variables')
variables_media(formMedia, variables)
class SmartSnippetPlugin(CMSPluginBase):
shared_sites = shared_sites
include_orphan = include_orphan
restrict_user = restrict_user
change_form_template = 'smartsnippets/snippet_change_form.html'
model = SmartSnippetPointer
name = 'Smart Snippet'
render_template = 'smartsnippets/plugin.html'
text_enabled = True
@property
def media(self):
if not USE_BOOTSTRAP_ACE:
media_obj = super(SmartSnippetPlugin, self).media
else:
media_obj = WidgetsMedia(
js=((
static('admin/js/core.js'),
static('admin/js/admin/RelatedObjectLookups.js'),
static('libs/jquery-2.1.1.min.js'),
static('libs/bootstrap/js/bootstrap.min.js'),
static('admin/js/custom.js'), )
),
css={
'all': (
'//fonts.googleapis.com/css?family=Open+Sans:400,300',
static('libs/bootstrap/css/bootstrap.css'),
static('libs/ace/css/ace.min.css'),
static('admin/css/custom.css'), )
}
)
media_obj.add_js(
(reverse('admin:jsi18n'),
static('admin/js/SmartSnippetLib.js'),
static('admin/js/jquery.init.js'),
static('admin/js/default.jQuery.init.js')))
if not USE_BOOTSTRAP_ACE:
media_obj.add_css({
'all': (
static('admin/css/forms.css'),
static('admin/css/base.css'),
static('css/tipTip.css'),
static('admin/css/snippet_plugin_default.css'), )
})
media_obj.add_js((
static('js/jquery.tipTip.minified.js'),
static('admin/js/snippet_plugin_default.js'), )
)
return media_obj
def response_add(self, request, obj, **kwargs):
response = super(SmartSnippetPlugin, self)\
.response_add(request, obj, **kwargs)
if hasattr(response, 'context_data'):
response.context_data['plugin'] = obj
return response
def add_view(self, request, form_url='', extra_context=None):
extra_context = extra_context or {}
try:
snippet = SmartSnippet.objects.get(
id=int(request.GET.get('snippet', '')))
except (ValueError, SmartSnippet.DoesNotExist):
snippet = None
else:
empty_plugin_vars = self._make_vars_for_rendering(snippet)
extra_context.update({'variables': empty_plugin_vars})
response = super(SmartSnippetPlugin, self).add_view(
request, form_url, extra_context)
if snippet and hasattr(response, 'context_data'):
self._change_snippet_plugin_for_preview(
response.context_data, snippet)
add_variables_media(response.context_data)
return response
def _make_vars_for_rendering(self, snippet, plugin=None):
"""
Create plugin varibles instances prepared for template rendering.
"""
plugin = plugin or SmartSnippetPointer(snippet=snippet)
selected_snippet_vars = snippet.variables.all()
existing_plugin_vars = plugin.variables.filter(
snippet_variable__in=selected_snippet_vars)
existing_snippet_var_ids = set([
plugin_var.snippet_variable.id
for plugin_var in existing_plugin_vars])
# add empty model instances; these are not saved in the db and are
# created just for rendering purpose
empty_plugin_vars = [
Variable(snippet=plugin, snippet_variable=snippet_var)
for snippet_var in selected_snippet_vars
if snippet_var.id not in existing_snippet_var_ids]
return sorted(
list(existing_plugin_vars) + empty_plugin_vars,
key=lambda v: v.snippet_variable.name)
def _change_snippet_plugin_for_preview(self, context, snippet):
"""
The plugin instance rendered in the context needs to correspond to
the new selected snippet in order for it to render its template code.
If this is not changed for the context, the plugin that is saved
in the db will get rendered in the preview box(which is not what
we want if the snippet gets changed).
"""
empty_plugin = SmartSnippetPointer(snippet=snippet)
# copy all attributes from the cms plugin to the plugin instance
# in order for cms to render it as if it exists
empty_plugin.__dict__.update(context['plugin'].__dict__)
empty_plugin.pk = empty_plugin.id
context['plugin'] = empty_plugin
context['original'] = context['plugin']
def change_view(self, request, object_id, *args, **kwargs):
extra_context = kwargs.get('extra_context', None) or {}
try:
selected_snippet = SmartSnippet.objects.get(
id=int(request.GET.get('snippet', '')))
except (ValueError, SmartSnippet.DoesNotExist):
selected_snippet = None
plugin = SmartSnippetPointer.objects.get(pk=object_id)
snippet_changed = (selected_snippet and
selected_snippet.id != plugin.snippet.id)
if snippet_changed:
variables = self._make_vars_for_rendering(
selected_snippet, plugin)
else:
snippet_vars = plugin.snippet.variables.all()
variables = plugin.variables.filter(
snippet_variable__in=snippet_vars
).order_by('snippet_variable__name')
extra_context.update({'variables': variables})
kwargs['extra_context'] = extra_context
response = super(SmartSnippetPlugin, self).change_view(
request, object_id, *args, **kwargs)
context = getattr(response, 'context_data', None)
add_variables_media(context)
if snippet_changed and context:
adminform = response.context_data.get('adminform')
if not adminform:
return response
adminform.form.initial['snippet'] = selected_snippet.id
self._change_snippet_plugin_for_preview(
response.context_data, selected_snippet)
return response
def render(self, context, instance, placeholder):
context.update({'content': instance.render(context)})
return context
def save_model(self, request, obj, form, change):
super(SmartSnippetPlugin, self).save_model(request, obj, form, change)
vars = obj.snippet.variables.all()
for var in vars:
v, _ = Variable.objects.get_or_create(snippet=obj, snippet_variable=var)
v.value = request.REQUEST.get('_'+var.name+'_', '')
v.save()
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "snippet":
f = Q(sites=Site.objects.get_current())
if self.shared_sites:
f |= Q(sites__name__in=self.shared_sites)
kwargs["queryset"] = SmartSnippet.objects.filter(f).distinct()
return (super(SmartSnippetPlugin, self)
.formfield_for_foreignkey(db_field, request, **kwargs))
def icon_src(self, instance):
return settings.STATIC_URL + u"images/snippet.png"
def icon_alt(self, instance):
if instance.snippet:
return instance.snippet.name
return ""
plugin_pool.register_plugin(SmartSnippetPlugin)

@ -0,0 +1,5 @@
class WidgetAlreadyRegistered(Exception):
pass
class WidgetNotRegistered(Exception):
pass

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('cms', '0001_initial'),
('sites', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SmartSnippet',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(unique=True, max_length=255)),
('template_code', models.TextField(verbose_name='Template code', blank=True)),
('template_path', models.CharField(help_text='Enter a template (i.e. "snippets/plugin_xy.html") which will be rendered.', max_length=100, verbose_name='Template path', blank=True)),
('description', models.TextField(verbose_name='Description', blank=True)),
('documentation_link', models.CharField(help_text='Enter URL (i.e. "http://snippets/docs/plugin_xy.html") to the extended documentation.', max_length=100, verbose_name='Documentation link', blank=True)),
('sites', models.ManyToManyField(help_text='Select on which sites the snippet will be available.', to='sites.Site', verbose_name=b'sites', blank=True)),
],
options={
'ordering': ['name'],
'verbose_name': 'Smart Snippet',
'verbose_name_plural': 'Smart Snippets',
},
bases=(models.Model,),
),
migrations.CreateModel(
name='SmartSnippetPointer',
fields=[
('cmsplugin_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('snippet', models.ForeignKey(to='smartsnippets.SmartSnippet')),
],
options={
'db_table': 'cmsplugin_smartsnippetpointer',
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='SmartSnippetVariable',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(help_text='Enter the name of the variable defined in the smart snippet template.', max_length=50)),
('widget', models.CharField(help_text='Select the type of the variable defined in the smart snippet template.', max_length=50)),
('resources', models.TextField(null=True, verbose_name='Admin resources', blank=True)),
],
options={
'ordering': ['name'],
'verbose_name': 'Standard variable',
},
bases=(models.Model,),
),
migrations.CreateModel(
name='DropDownVariable',
fields=[
('smartsnippetvariable_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='smartsnippets.SmartSnippetVariable')),
('choices', models.CharField(help_text='Enter a comma separated list of choices that will be available in the dropdown variable when adding and configuring the smart snippet on a page.', max_length=512)),
],
options={
},
bases=('smartsnippets.smartsnippetvariable',),
),
migrations.CreateModel(
name='Variable',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('value', models.TextField()),
('snippet', models.ForeignKey(related_name='variables', to='smartsnippets.SmartSnippetPointer')),
('snippet_variable', models.ForeignKey(related_name='variables', to='smartsnippets.SmartSnippetVariable')),
],
options={
},
bases=(models.Model,),
),
migrations.AlterUniqueTogether(
name='variable',
unique_together=set([('snippet_variable', 'snippet')]),
),
migrations.AddField(
model_name='smartsnippetvariable',
name='snippet',
field=models.ForeignKey(related_name='variables', to='smartsnippets.SmartSnippet'),
preserve_default=True,
),
migrations.AlterUniqueTogether(
name='smartsnippetvariable',
unique_together=set([('snippet', 'name')]),
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('smartsnippets', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='smartsnippetvariable',
name='name',
field=models.CharField(help_text='Enter the name of the variable defined in the smart snippet template. Unallowed charactes will be removed when the form is saved.', max_length=50),
preserve_default=True,
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('smartsnippets', '0002_change_smartsnippetvariable_description'),
]
operations = [
migrations.AlterField(
model_name='smartsnippetvariable',
name='name',
field=models.CharField(help_text='Enter the name of the variable defined in the smart snippet template. Unallowed characters will be removed when the form is saved.', max_length=50),
preserve_default=True,
),
]

@ -0,0 +1,283 @@
import re
from django.core.cache import cache
from django.db import models
from django.core.exceptions import ValidationError
from django.template import Template, TemplateSyntaxError, \
TemplateDoesNotExist, loader
from django.db.models import signals
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _
from cms.models import CMSPlugin
from sekizai.helpers import (
Watcher as sekizai_context_watcher,
get_varname as sekizai_cache_key,
)
from .resources_processor import get_resources
from .settings import (
snippet_caching_time, caching_enabled, allow_inheritance,
inherit_variable_pattern)
class SmartSnippet(models.Model):
name = models.CharField(unique=True, max_length=255)
template_code = models.TextField(_("Template code"), blank=True)
template_path = models.CharField(
_("Template path"),
max_length=100, blank=True,
help_text=_(
'Enter a template (i.e. "snippets/plugin_xy.html")'
' which will be rendered.'))
sites = models.ManyToManyField(
Site, null=False, blank=True,
help_text=_('Select on which sites the snippet will be available.'),
verbose_name='sites')
description = models.TextField(_("Description"), blank=True)
documentation_link = models.CharField(
_("Documentation link"),
max_length=100, blank=True,
help_text=_('Enter URL (i.e. "http://snippets/docs/plugin_xy.html")'
' to the extended documentation.'))
class Meta:
ordering = ['name']
verbose_name = 'Smart Snippet'
verbose_name_plural = 'Smart Snippets'
def __init__(self, *args, **kwargs):
#hack due to
# https://code.djangoproject.com/ticket/16433#no1
for rel_obj in self._meta.get_all_related_objects():
rel_obj.help_text = ""
super(SmartSnippet, self).__init__(*args, **kwargs)
def get_template(self):
if self.template_path:
return loader.get_template(self.template_path)
else:
return Template(self.template_code)
def clean_template_code(self):
try:
self.get_template()
except (TemplateSyntaxError, TemplateDoesNotExist), e:
raise ValidationError(str(e))
def get_cache_key(self):
return 'smartsnippet-%s' % self.pk
def render(self, context):
return self.get_template().render(context)
def __unicode__(self):
return self.name
class SmartSnippetVariable(models.Model):
name = models.CharField(
max_length=50,
help_text=_('Enter the name of the variable defined in the smart snippet '
'template. Unallowed characters will be removed when the form is saved.'))
widget = models.CharField(
max_length=50,
help_text=_('Select the type of the variable defined '
'in the smart snippet template.'))
snippet = models.ForeignKey(SmartSnippet, related_name="variables")
resources = models.TextField(_('Admin resources'), null=True, blank=True)
def __init__(self, *args, **kwargs):
super(SmartSnippetVariable, self).__init__(*args, **kwargs)
self._resource_dict = None
@property
def resources_dict(self):
if self._resource_dict is None:
self._resource_dict = get_resources(self.resources)
return self._resource_dict
class Meta:
unique_together = (('snippet', 'name'))
ordering = ['name']
verbose_name = "Standard variable"
def save(self, *args, **kwargs):
self.name = clean_variable_name(self.name)
super(SmartSnippetVariable, self).save(*args, **kwargs)
# auto-generate missing variables for all snippet plugins
plugin_ids = SmartSnippetPointer.objects \
.filter(snippet=self.snippet) \
.exclude(variables__snippet_variable=self) \
.values_list('id', flat=True)
# in order to improve performance do a bulk create
Variable.objects.bulk_create([
Variable(snippet_id=plugin_id, snippet_variable=self)
for plugin_id in plugin_ids
])
if not caching_enabled:
return
# invalidate cache for changed plugins
cache_keys = [
SmartSnippetPointer.cache_key_format.format(primary_key=plugin_id)
for plugin_id in plugin_ids
]
cache.delete_many(cache_keys)
def __unicode__(self):
return self.name
class SmartSnippetPointer(CMSPlugin):
snippet = models.ForeignKey(SmartSnippet)
cache_key_format = 'smartsnippet-pointer-{primary_key}'
class Meta:
db_table = 'cmsplugin_smartsnippetpointer'
def get_cache_key(self):
return self.cache_key_format.format(primary_key=self.pk)
def _do_restore_sekizai_context(self, context, changes):
"""Sekizai tags involve magic with the context object.
When need to restore the sekizai content to the context"""
cache_key = sekizai_cache_key()
sekizai_container = context.get(cache_key)
for key, values in changes.items():
sekizai_namespace = sekizai_container[key]
for value in values:
sekizai_namespace.append(value)
def fetch_cached(self, context):
cache_key = self.get_cache_key()
user = context['request'].user
if not user.is_staff and caching_enabled and cache.has_key(cache_key):
cached_value = cache.get(cache_key)
rendered_content = cached_value.get('content')
sekizai = cached_value.get('sekizai')
self._do_restore_sekizai_context(context, sekizai)
return rendered_content
def set_and_get_cache(self, user, sekizai_diff, content):
if not user.is_staff and caching_enabled:
value = {'content': content, 'sekizai': sekizai_diff}
key = self.get_cache_key()
cache.set(key, value, snippet_caching_time)
return content
def render_pointer(self, context):
vars_qs = self.variables.select_related('snippet_variable').all()
def var_for_context(var):
default, overwrite = var.formatted_value, None
if allow_inheritance:
overwrite = context.get(
inherit_variable_pattern.format(identifier=var.pk))
name = var.snippet_variable.name
value = overwrite if overwrite is not None else default
return (name, value)
variables = dict(var_for_context(var) for var in vars_qs)
context.update(variables)
sekizai_differ = sekizai_context_watcher(context)
content = self.snippet.render(context)
sekizai_diff = sekizai_differ.get_changes()
user = context.get('request').user
return self.set_and_get_cache(user, sekizai_diff, content)
def render(self, context):
return self.fetch_cached(context) or self.render_pointer(context)
def copy_relations(self, old_instance):
for variable in old_instance.variables.all():
variable.pk = None
variable.snippet = self
variable.save()
def __unicode__(self):
return unicode(self.snippet)
class Variable(models.Model):
snippet_variable = models.ForeignKey(SmartSnippetVariable,
related_name='variables')
value = models.TextField()
snippet = models.ForeignKey(SmartSnippetPointer, related_name='variables')
class Meta:
unique_together = (('snippet_variable', 'snippet'))
@property
def formatted_value(self):
from widgets_pool import widget_pool
widget_instance = widget_pool.get_widget(self.widget)(self)
return widget_instance.formatted_value
@property
def name(self):
return self.snippet_variable.name
@property
def widget(self):
return self.snippet_variable.widget
@property
def templates(self):
return self.snippet_variable.resources_dict.get('html', set())
@property
def js(self):
return self.snippet_variable.resources_dict.get('js', set())
@property
def css(self):
return self.snippet_variable.resources_dict.get('css', set())
class DropDownVariable(SmartSnippetVariable):
choices = models.CharField(
max_length=512,
help_text=_(
'Enter a comma separated list of choices that will be '
'available in the dropdown variable when adding and '
'configuring the smart snippet on a page.'))
@property
def choices_list(self):
return ([choice.strip() for choice in self.choices.split(',') if choice.strip()]
if self.choices else [])
def save(self, *args, **kwargs):
self.widget = 'DropDownField'
super(DropDownVariable, self).save(*args, **kwargs)
def remove_cached_pointers(instance, **kwargs):
if not caching_enabled:
return
pointer_pks = SmartSnippetPointer.objects.filter(
snippet=instance
).values_list('pk', flat=True)
cache_keys = [
SmartSnippetPointer.cache_key_format.format(primary_key=pk)
for pk in pointer_pks
]
cache.delete_many(cache_keys)
def remove_cached_variables(instance, **kwargs):
if not caching_enabled:
return
key = instance.snippet.get_cache_key()
if key in cache:
cache.delete(key)
def clean_variable_name(variable_name):
""" Convert the variable name to a name that can be used as a template variable. """
return re.sub(r"[^a-zA-Z0-9_]", '', variable_name.replace(' ', '_'))
signals.post_save.connect(remove_cached_pointers, sender=SmartSnippet)
signals.post_save.connect(remove_cached_variables, sender=Variable)

@ -0,0 +1,68 @@
from collections import defaultdict
from django.contrib.admin.templatetags.admin_static import static
from django.conf import settings
import os
def get_filer_url(link):
if 'filertags' in settings.INSTALLED_APPS:
from filertags.templatetags.filertags import filerfile
return filerfile(link)
return link
def get_static_url(link):
return static(link)
PROCESSORS = {
'static': get_static_url,
'filer': get_filer_url,
}
def _process(resource):
# split processor name from resource link
link = resource.strip().split(':', 1)
processor_type = link[0].strip()
if processor_type in PROCESSORS:
processor_type, link = link
else:
processor_type = None
link = link[0]
res_type = os.path.splitext(link)[1].strip('.')
if not res_type:
return None
if not processor_type:
return (res_type, link)
return (res_type, PROCESSORS[processor_type](link))
def get_resources(resources_data):
"""
Parses resources_data to get all resources defined with
the following format:
snippet-field/custom.html, static: admin/style.css,
http://somesite/absolute-url.js
and returns a dictionary with resources extensions and the links defined.
"""
if not resources_data:
return {}
resources_data = resources_data or ''
resources = defaultdict(list)
for resource in resources_data.split(','):
processed_link = _process(resource)
if not processed_link:
continue
links = resources[processed_link[0]]
res_link = processed_link[1]
# check if already added. Note: using list and not set just to
# make sure the ordering is kept
if res_link not in links:
links.append(processed_link[1])
return resources

@ -0,0 +1,33 @@
from django.conf import settings
shared_sites = getattr(settings, 'SMARTSNIPPETS_SHARED_SITES', [])
include_orphan = getattr(settings, 'SMARTSNIPPETS_INCLUDE_ORPHAN', True)
restrict_user = getattr(settings, 'SMARTSNIPPETS_RESTRICT_USER', False)
handle_permissions_checks = getattr(settings, 'SMARTSNIPPETS_HANDLE_PERMISSIONS_CHECKS', True)
snippet_caching_time = getattr(settings, 'SMARTSNIPPETS_CACHING_TIME', 300)
caching_enabled = snippet_caching_time != 0
def _has_data_defined(widget_data):
return (
widget_data.get('widget', None) or
widget_data.get('resources', None)
)
custom_widgets_resources = {
widget_type: widget_data
for widget_type, widget_data in getattr(
settings, 'SMARTSNIPPETS_PREDEFINED_WIDGETS', {}).items()
if _has_data_defined(widget_data)
}
allow_inheritance = getattr(
settings, 'SMARTSNIPPETS_ALLOW_INHERITANCE',
'smartsnippets_inherit' in settings.INSTALLED_APPS)
inherit_variable_pattern = getattr(
settings, 'SMARTSNIPPETS_INHERIT_VAR_PATTERN',
'_snippet_inherit_{identifier}')
USE_BOOTSTRAP_ACE = getattr(
settings, 'SMARTSNIPPETS_USE_BOOTSTRAP_ACE', False)

@ -0,0 +1,95 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'SmartSnippet'
db.create_table('smartsnippets_smartsnippet', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
('template_code', self.gf('django.db.models.fields.TextField')()),
))
db.send_create_signal('smartsnippets', ['SmartSnippet'])
# Adding model 'SmartSnippetPointer'
db.create_table('cmsplugin_smartsnippetpointer', (
('cmsplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['cms.CMSPlugin'], unique=True, primary_key=True)),
('snippet', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['smartsnippets.SmartSnippet'])),
))
db.send_create_signal('smartsnippets', ['SmartSnippetPointer'])
# Adding model 'Variable'
db.create_table('smartsnippets_variable', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
('value', self.gf('django.db.models.fields.CharField')(max_length=255)),
('snippet', self.gf('django.db.models.fields.related.ForeignKey')(related_name='variables', to=orm['smartsnippets.SmartSnippetPointer'])),
))
db.send_create_signal('smartsnippets', ['Variable'])
# Adding unique constraint on 'Variable', fields ['name', 'snippet']
db.create_unique('smartsnippets_variable', ['name', 'snippet_id'])
def backwards(self, orm):
# Removing unique constraint on 'Variable', fields ['name', 'snippet']
db.delete_unique('smartsnippets_variable', ['name', 'snippet_id'])
# Deleting model 'SmartSnippet'
db.delete_table('smartsnippets_smartsnippet')
# Deleting model 'SmartSnippetPointer'
db.delete_table('cmsplugin_smartsnippetpointer')
# Deleting model 'Variable'
db.delete_table('smartsnippets_variable')
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'template_code': ('django.db.models.fields.TextField', [], {})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('name', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,74 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding M2M table for field sites on 'SmartSnippet'
db.create_table('smartsnippets_smartsnippet_sites', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('smartsnippet', models.ForeignKey(orm['smartsnippets.smartsnippet'], null=False)),
('site', models.ForeignKey(orm['sites.site'], null=False))
))
db.create_unique('smartsnippets_smartsnippet_sites', ['smartsnippet_id', 'site_id'])
def backwards(self, orm):
# Removing M2M table for field sites on 'SmartSnippet'
db.delete_table('smartsnippets_smartsnippet_sites')
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False'}),
'template_code': ('django.db.models.fields.TextField', [], {})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('name', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,70 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'SmartSnippet.template_path'
db.add_column('smartsnippets_smartsnippet', 'template_path', self.gf('django.db.models.fields.CharField')(default='', max_length=50, blank=True), keep_default=False)
def backwards(self, orm):
# Deleting field 'SmartSnippet.template_path'
db.delete_column('smartsnippets_smartsnippet', 'template_path')
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('name', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,70 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'SmartSnippet.template_path'
db.alter_column('smartsnippets_smartsnippet', 'template_path', self.gf('django.db.models.fields.CharField')(max_length=100))
def backwards(self, orm):
# Changing field 'SmartSnippet.template_path'
db.alter_column('smartsnippets_smartsnippet', 'template_path', self.gf('django.db.models.fields.CharField')(max_length=50))
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('name', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,123 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'Variable', fields ['snippet', 'name']
db.delete_unique('smartsnippets_variable', ['snippet_id', 'name'])
# Adding model 'DropDownVariable'
db.create_table('smartsnippets_dropdownvariable', (
('smartsnippetvariable_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['smartsnippets.SmartSnippetVariable'], unique=True, primary_key=True)),
('choices', self.gf('django.db.models.fields.CharField')(max_length=512)),
))
db.send_create_signal('smartsnippets', ['DropDownVariable'])
# Adding model 'SmartSnippetVariable'
db.create_table('smartsnippets_smartsnippetvariable', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=50)),
('widget', self.gf('django.db.models.fields.CharField')(max_length=50)),
('snippet', self.gf('django.db.models.fields.related.ForeignKey')(related_name='variables', to=orm['smartsnippets.SmartSnippet'])),
))
db.send_create_signal('smartsnippets', ['SmartSnippetVariable'])
# Adding unique constraint on 'SmartSnippetVariable', fields ['snippet', 'name']
db.create_unique('smartsnippets_smartsnippetvariable', ['snippet_id', 'name'])
# Adding field 'Variable.snippet_variable'
db.add_column('smartsnippets_variable', 'snippet_variable', self.gf('django.db.models.fields.related.ForeignKey')(related_name='variables', null=True, to=orm['smartsnippets.SmartSnippetVariable']), keep_default=False)
# Changing field 'Variable.value'
db.alter_column('smartsnippets_variable', 'value', self.gf('django.db.models.fields.CharField')(max_length=1024))
def backwards(self, orm):
# Removing unique constraint on 'SmartSnippetVariable', fields ['snippet', 'name']
db.delete_unique('smartsnippets_smartsnippetvariable', ['snippet_id', 'name'])
# Deleting model 'DropDownVariable'
db.delete_table('smartsnippets_dropdownvariable')
# Deleting model 'SmartSnippetVariable'
db.delete_table('smartsnippets_smartsnippetvariable')
# Deleting field 'Variable.snippet_variable'
db.delete_column('smartsnippets_variable', 'snippet_variable_id')
# Changing field 'Variable.value'
db.alter_column('smartsnippets_variable', 'value', self.gf('django.db.models.fields.CharField')(max_length=255))
# Adding unique constraint on 'Variable', fields ['snippet', 'name']
db.create_unique('smartsnippets_variable', ['snippet_id', 'name'])
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.dropdownvariable': {
'Meta': {'ordering': "['name']", 'object_name': 'DropDownVariable', '_ormbases': ['smartsnippets.SmartSnippetVariable']},
'choices': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'smartsnippetvariable_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['smartsnippets.SmartSnippetVariable']", 'unique': 'True', 'primary_key': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.smartsnippetvariable': {
'Meta': {'ordering': "['name']", 'unique_together': "(('snippet', 'name'),)", 'object_name': 'SmartSnippetVariable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippet']"}),
'widget': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.variable': {
'Meta': {'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'snippet_variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'null': 'True', 'to': "orm['smartsnippets.SmartSnippetVariable']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,118 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
from django.template import Template, VariableNode, loader
class Migration(DataMigration):
def forwards(self, orm):
# create variables for all templates using the old auto-detection method
for snippet in orm.SmartSnippet.objects.all():
for var_name in self.get_variables_list(snippet):
snippet.variables.create(name=var_name, widget='TextField')
# relate snippet instance variable by id instead of name
for snippet_ptr in orm.SmartSnippetPointer.objects.all():
for snippet_ptr_var in snippet_ptr.variables.all():
try:
snippet_var = orm.SmartSnippetVariable.objects.get(snippet=snippet_ptr.snippet,
name=snippet_ptr_var.name)
snippet_ptr_var.snippet_variable = snippet_var
snippet_ptr_var.save()
except orm.SmartSnippetVariable.DoesNotExist:
pass # ignore unused snippet variable values and then drop them
orm.Variable.objects.filter(snippet_variable=None).delete()
def backwards(self, orm):
# repopulate variable names from relation
for variable in orm.Variable.objects.all():
variable.name = variable.snippet_variable.name
variable.save()
# delete variable definitions
orm.Variable.objects.all().update(snippet_variable=None)
orm.SmartSnippetVariable.objects.all().delete()
def get_template(self, snippet):
if snippet.template_path:
return None
else:
return Template(snippet.template_code)
def get_variables_list(self, snippet):
t = self.get_template(snippet)
result = set()
if t is None:
return result
for node in t.nodelist.get_nodes_by_type(VariableNode):
v = getattr(node.filter_expression.var, 'var', None)
if v and not v.endswith('_'):
result.add(v)
return result
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.dropdownvariable': {
'Meta': {'ordering': "['name']", 'object_name': 'DropDownVariable', '_ormbases': ['smartsnippets.SmartSnippetVariable']},
'choices': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'smartsnippetvariable_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['smartsnippets.SmartSnippetVariable']", 'unique': 'True', 'primary_key': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.smartsnippetvariable': {
'Meta': {'ordering': "['name']", 'unique_together': "(('snippet', 'name'),)", 'object_name': 'SmartSnippetVariable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippet']"}),
'widget': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.variable': {
'Meta': {'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'snippet_variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'null': 'True', 'to': "orm['smartsnippets.SmartSnippetVariable']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,94 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting field 'Variable.name'
db.delete_column('smartsnippets_variable', 'name')
# Changing field 'Variable.snippet_variable'
db.alter_column('smartsnippets_variable', 'snippet_variable_id', self.gf('django.db.models.fields.related.ForeignKey')(default=0, to=orm['smartsnippets.SmartSnippetVariable']))
# Adding unique constraint on 'Variable', fields ['snippet', 'snippet_variable']
db.create_unique('smartsnippets_variable', ['snippet_id', 'snippet_variable_id'])
def backwards(self, orm):
# Removing unique constraint on 'Variable', fields ['snippet', 'snippet_variable']
db.delete_unique('smartsnippets_variable', ['snippet_id', 'snippet_variable_id'])
# Adding field 'Variable.name'
db.add_column('smartsnippets_variable', 'name', self.gf('django.db.models.fields.CharField')(default='', max_length=255), keep_default=False)
# Changing field 'Variable.snippet_variable'
db.alter_column('smartsnippets_variable', 'snippet_variable_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['smartsnippets.SmartSnippetVariable']))
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.dropdownvariable': {
'Meta': {'ordering': "['name']", 'object_name': 'DropDownVariable', '_ormbases': ['smartsnippets.SmartSnippetVariable']},
'choices': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'smartsnippetvariable_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['smartsnippets.SmartSnippetVariable']", 'unique': 'True', 'primary_key': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.smartsnippetvariable': {
'Meta': {'ordering': "['name']", 'unique_together': "(('snippet', 'name'),)", 'object_name': 'SmartSnippetVariable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippet']"}),
'widget': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('snippet_variable', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'snippet_variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetVariable']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'SmartSnippet.description'
db.add_column('smartsnippets_smartsnippet', 'description',
self.gf('django.db.models.fields.TextField')(default='', blank=True),
keep_default=False)
# Adding field 'SmartSnippet.documentation_link'
db.add_column('smartsnippets_smartsnippet', 'documentation_link',
self.gf('django.db.models.fields.CharField')(default='', max_length=100, blank=True),
keep_default=False)
def backwards(self, orm):
# Deleting field 'SmartSnippet.description'
db.delete_column('smartsnippets_smartsnippet', 'description')
# Deleting field 'SmartSnippet.documentation_link'
db.delete_column('smartsnippets_smartsnippet', 'documentation_link')
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'changed_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.dropdownvariable': {
'Meta': {'ordering': "['name']", 'object_name': 'DropDownVariable', '_ormbases': ['smartsnippets.SmartSnippetVariable']},
'choices': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'smartsnippetvariable_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['smartsnippets.SmartSnippetVariable']", 'unique': 'True', 'primary_key': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'documentation_link': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.smartsnippetvariable': {
'Meta': {'ordering': "['name']", 'unique_together': "(('snippet', 'name'),)", 'object_name': 'SmartSnippetVariable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippet']"}),
'widget': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('snippet_variable', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'snippet_variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetVariable']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Variable.value'
db.alter_column('smartsnippets_variable', 'value', self.gf('django.db.models.fields.CharField')(max_length=2048))
def backwards(self, orm):
# Changing field 'Variable.value'
db.alter_column('smartsnippets_variable', 'value', self.gf('django.db.models.fields.CharField')(max_length=1024))
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'changed_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 6, 3, 0, 0)'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.dropdownvariable': {
'Meta': {'ordering': "['name']", 'object_name': 'DropDownVariable', '_ormbases': ['smartsnippets.SmartSnippetVariable']},
'choices': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'smartsnippetvariable_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['smartsnippets.SmartSnippetVariable']", 'unique': 'True', 'primary_key': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'documentation_link': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.smartsnippetvariable': {
'Meta': {'ordering': "['name']", 'unique_together': "(('snippet', 'name'),)", 'object_name': 'SmartSnippetVariable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippet']"}),
'widget': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('snippet_variable', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'snippet_variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetVariable']"}),
'value': ('django.db.models.fields.CharField', [], {'max_length': '2048'})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Variable.value'
db.alter_column('smartsnippets_variable', 'value', self.gf('django.db.models.fields.TextField')())
def backwards(self, orm):
# Changing field 'Variable.value'
db.alter_column('smartsnippets_variable', 'value', self.gf('django.db.models.fields.CharField')(max_length=2048))
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'changed_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 11, 25, 0, 0)'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.dropdownvariable': {
'Meta': {'ordering': "['name']", 'object_name': 'DropDownVariable', '_ormbases': ['smartsnippets.SmartSnippetVariable']},
'choices': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'smartsnippetvariable_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['smartsnippets.SmartSnippetVariable']", 'unique': 'True', 'primary_key': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'documentation_link': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.smartsnippetvariable': {
'Meta': {'ordering': "['name']", 'unique_together': "(('snippet', 'name'),)", 'object_name': 'SmartSnippetVariable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippet']"}),
'widget': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('snippet_variable', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'snippet_variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetVariable']"}),
'value': ('django.db.models.fields.TextField', [], {})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'SmartSnippetVariable.resources'
db.add_column('smartsnippets_smartsnippetvariable', 'resources',
self.gf('django.db.models.fields.TextField')(null=True, blank=True),
keep_default=False)
def backwards(self, orm):
# Deleting field 'SmartSnippetVariable.resources'
db.delete_column('smartsnippets_smartsnippetvariable', 'resources')
models = {
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'changed_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2014, 11, 18, 0, 0)'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.CMSPlugin']", 'null': 'True', 'blank': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.dropdownvariable': {
'Meta': {'ordering': "['name']", 'object_name': 'DropDownVariable', '_ormbases': ['smartsnippets.SmartSnippetVariable']},
'choices': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
'smartsnippetvariable_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['smartsnippets.SmartSnippetVariable']", 'unique': 'True', 'primary_key': 'True'})
},
'smartsnippets.smartsnippet': {
'Meta': {'ordering': "['name']", 'object_name': 'SmartSnippet'},
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'documentation_link': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False', 'blank': 'True'}),
'template_code': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'template_path': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'})
},
'smartsnippets.smartsnippetpointer': {
'Meta': {'object_name': 'SmartSnippetPointer', 'db_table': "'cmsplugin_smartsnippetpointer'", '_ormbases': ['cms.CMSPlugin']},
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['cms.CMSPlugin']", 'unique': 'True', 'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['smartsnippets.SmartSnippet']"})
},
'smartsnippets.smartsnippetvariable': {
'Meta': {'ordering': "['name']", 'unique_together': "(('snippet', 'name'),)", 'object_name': 'SmartSnippetVariable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'resources': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippet']"}),
'widget': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'smartsnippets.variable': {
'Meta': {'unique_together': "(('snippet_variable', 'snippet'),)", 'object_name': 'Variable'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'snippet': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetPointer']"}),
'snippet_variable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variables'", 'to': "orm['smartsnippets.SmartSnippetVariable']"}),
'value': ('django.db.models.fields.TextField', [], {})
}
}
complete_apps = ['smartsnippets']

@ -0,0 +1,249 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
overflow: auto;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
}
/* CURSOR */
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black;
z-index: 3;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
z-index: 1;
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
.cm-tab { display: inline-block; }
/* DEFAULT THEME */
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
line-height: 1;
position: relative;
overflow: hidden;
background: white;
color: black;
}
.CodeMirror-scroll {
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px; padding-right: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
}
.CodeMirror-sizer {
position: relative;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
padding-bottom: 30px;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
padding-bottom: 30px;
margin-bottom: -32px;
display: inline-block;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-lines {
cursor: text;
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {
display: inline-block;
}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror-measure {
position: absolute;
width: 100%; height: 0px;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
visibility: hidden;
border-right: none;
width: 0;
}
.CodeMirror-focused div.CodeMirror-cursor {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
.CodeMirror span { *vertical-align: text-bottom; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursor {
visibility: hidden;
}
}

@ -0,0 +1,173 @@
body {
background: white;
}
.text-left {
text-align: left !important;
}
.smartsnippet-title {
color: #abbac3;
font-weight: 300;
font-size: 32px;
}
.smartsnippet-description {
font-size: 14px;
}
.smartsnippet-description p {
white-space: pre-wrap;
}
input[type=color], input[type=date], input[type=datetime-local], input[type=datetime],
input[type=email], input[type=month], input[type=number], input[type=password],
input[type=search], input[type=tel], input[type=text], input[type=time],
input[type=url], input[type=week], textarea, select {
color: #393939;
width: 55%;
}
.btn.btn-info[disabled] {
color: white !important;
}
.popover-content, .popover {
min-width: 330px;
}
.popover-content span {
display: block;
margin-bottom: 15px;
}
.popover-content img {
margin-top: 5px;
display: block;
}
.popover {
border-radius: 0;
padding: 0;
border-color: #ccc;
border-width: 1px;
color: #000;
font-weight: 300;
font-size: 12px;
box-shadow: none;
}
.widget-drag {
height: 38px;
width: 15px;
background: url(../../images/drag.gif) no-repeat 2px 4px;
display: inline-block;
float: left;
cursor: move;
margin-right: 12px;
}
.widget-box {
border: none;
margin-bottom: 20px;
}
.widget-body > table {
border: 1px solid #CCC !important;
border-top: none !important;
}
.deletelink {
color: white !important;
margin-right: 20px;
padding: 8px 18px;
border: none;
}
.form-horizontal .widget-body .field-snippet .row {
margin: 0;
}
.form-horizontal .widget-body .field-snippet {
margin-bottom: 0;
margin-top: 15px;
}
.form-horizontal .widget-body .field-snippet .col-sm-2 {
width: 25%;
}
.form-horizontal .widget-body .field-snippet .col-sm-9 {
padding-left: 15px !important;
}
.form-horizontal .widget-body .field-snippet .control-label {
text-align: right !important;
}
.collapsed .glyphicon-chevron-up:before {
content: "\e114";
}
.collapse-item {
height: 0;
position: relative;
overflow: hidden;
-webkit-transition: all .3s;
-o-transition: all .3s;
transition: all .3s;
}
.collapse-item.on {
height: auto;
}
.submit-button {
float: right;
position: relative;
}
td.filer-input-wrapper .help-button {
position: absolute;
top: 0;
right: -30px;
}
.help-button {
margin: 3px 0 0 10px;
}
.form-actions {
background: white;
}
.widget-header {
background: #fff;
padding: 0;
border: 1px solid #DDD;
}
.widget-header > .widget-title {
line-height: 36px;
font-size: 18px;
font-weight: 300;
text-transform: none;
padding: 0;
margin: 0;
display: inline;
color: #666;
}
.limiterBox {
border: none;
background: none;
padding: 3px 6px;
font-size: 12px;
color: #737373;
text-align: right;
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: 300;
margin-top: 3px;
margin-left: 15px;
}
.limiterBox:after {
display: none;
}
.limiterBox:before {
display: none;
}
.ui-dialog, .ui-jqdialog {
border: none;
display: inline-block !important;
}
.ui-dialog .ui-dialog-titlebar, .ui-jqdialog .ui-dialog-titlebar, .ui-dialog .ui-jqdialog-titlebar, .ui-jqdialog .ui-jqdialog-titlebar {
color: #fff;
background-color: #669fc7;
padding: 5px 10px;
}
.ui-dialog .ui-dialog-titlebar-close, .ui-jqdialog .ui-dialog-titlebar-close, .ui-dialog .ui-jqdialog-titlebar-close, .ui-jqdialog .ui-jqdialog-titlebar-close {
display: none;
}
#dialog-confirm {
padding: 10px 10px 0;
}
.ui-dialog .ui-dialog-buttonpane, .ui-jqdialog .ui-dialog-buttonpane, .ui-dialog .ui-jqdialog-buttonpane, .ui-jqdialog .ui-jqdialog-buttonpane {
padding: 0 10px 20px;
text-align: center;
background: none;
border-top: none;
}
.ui-dialog .ui-dialog-buttonpane button, .ui-jqdialog .ui-dialog-buttonpane button, .ui-dialog .ui-jqdialog-buttonpane button, .ui-jqdialog .ui-jqdialog-buttonpane button {
margin: 0 5px;
}

@ -0,0 +1,11 @@
.inline-related {
border: solid 1px #999;
}
.predefined-widgets li{
list-style-type: none;
padding: 3px;
border: 1px solid #7CA0C7;
cursor:pointer;
border-left: none;
border-right: none;
}

@ -0,0 +1,18 @@
span.plugin-help-tooltip{
cursor: help;
}
.plugin-help-tooltip{
float: left;
margin-right: 5px;
}
.plugin-help-tooltip img{
border: 0;
width: 20px;
height: 20px;
}
#layout_help_popup{
position: absolute;
top:0;
margin:0 auto;
}

@ -0,0 +1,41 @@
function CMInstance(elem, options, events){
if(!elem){
return null;
}
var codemirrorObj = null;
var defaults = {
continuousScanning: 500,
mode: 'htmlmixed',
height: "40.2em",
tabMode: "shift",
indentUnit: 4,
lineNumbers: true,
lineWrapping: true,
readOnly: true
};
//overwrite defaults if neccesary
if(options){
for(var j in options){
if(options.hasOwnProperty(j)){
defaults[j] = options[j];
}
}
}
//create CodeMirror instance
codemirrorObj = CodeMirror.fromTextArea(elem, defaults);
//attach events
if(events instanceof Array ){
for(var i=0; i<events.length; i++){
if(typeof events[i]['handler'] === 'function'){
codemirrorObj.on(events[i]['name'], events[i]['handler']);
}
}
}
return this;
}

@ -0,0 +1,105 @@
var SnippetWidgetRegistry = (function ($) {
var _self = {
'widgets': {},
'variables': {},
'events': {}
};
function SnippetWidgetError(message){
this.level = "Error";
this.htmlMessage = "Error detected." + message;
this.message = message;
this.name = 'SnippetWidgetError';
this.toString = function(){
return this.name + ": " + this.message;
}
}
return {
_call_event: function(event_name){
$.each(_self['events'], function (widget_type, event_data){
(event_data[event_name] || function(){})();
});
},
initializeVariables: function(variables_ids){
var vars = _self['variables'];
if(variables_ids){
vars = {};
$.each(variables_ids.filter(function(el){ return el in _self['variables']; }), function(i, var_name){
vars[var_name] = _self['variables'][var_name];
});
}
this._call_event('preInit');
$.each(vars, function (var_name, var_cls) {
var_cls.init(var_name);
});
this._call_event('postInit');
},
allValid: function(variables_ids){
var vars = _self['variables'];
if(variables_ids){
vars = {};
$.each(variables_ids.filter(function(el){ return el in _self['variables']; }), function(i, var_name){
vars[var_name] = _self['variables'][var_name];
});
}
this._call_event('preValidate');
var isValid = true;
$.each(vars, function (var_name, var_cls) {
isValid = (var_cls.validate(var_name) && isValid);
});
this._call_event('postValidate');
return isValid;
},
registerWidget: function (widget_type, widget_class, events) {
if (widget_class['init'] && widget_class['validate']){
_self['widgets'][widget_type] = _self['widgets'][widget_type] || (
_self['widgets'][widget_type] = widget_class)
// register events
if (widget_class['events'] && !_self['events'][widget_type]){
_self['events'][widget_type] = $.extend({}, widget_class['events']);
}
} else {
throw new SnippetWidgetError("init and validate attrs required.")
}
},
registerVariable: function(widget_type, variable_id) {
if (!_self['widgets'][widget_type]){
throw new SnippetWidgetError("Widget type " + widget_type + " is not registered.")
}
if (_self['variables'][variable_id]){
throw new SnippetWidgetError("Variable with id " + variable_id + " was already registered.")
}
_self['variables'][variable_id] = _self['widgets'][widget_type]
},
deregisterVariable: function(variable_id){
delete _self['variables'][variable_id]
},
deregisterAllVariables: function(){
_self['variables'] = {}
},
get_widget_class: function(widget_type){
var widget_class = _self['widgets'][widget_type];
if (!widget_class){
throw new SnippetWidgetError("Widget type " + widget_type + " is not registered.")
}
return widget_class;
},
get_variables: function(widget_type){
vars_ids = []
if (!widget_type){
return vars_ids;
}
$.each(_self['variables'], function (var_name, var_cls) {
if(_self['widgets'][widget_type] === var_cls){
vars_ids.push(""+ var_name);
}
});
return vars_ids;
}
};
})(jQuery || django.jQuery);

@ -0,0 +1,29 @@
(function($) {
$(document).ready(function(){
$('.field-box.field-predefined_widgets').each(function(){
if ($(this).find('ul.predefined-widgets li').length === 0){
$(this).hide();
}
});
});
}(django.jQuery));
function populateWidgetResources(predefined_widget_el){
(function($) {
var inline = $(predefined_widget_el).parents('.inline-related').first();
var widget_type = $(predefined_widget_el).attr('data-widget');
var widget_resources = $(predefined_widget_el).attr('data-resources');
var widget_select = inline.find('.field-widget').find('select').first();
var resources = inline.find('.field-resources').find('textarea').first();
if (widget_select.length > 0 && widget_type.length > 0){
widget_select.val(widget_type);
}
if (resources.length > 0 && widget_resources.length > 0){
resources.val(widget_resources);
}
}(django.jQuery));
}

@ -0,0 +1,421 @@
(function ($) {
/**
* This object provides helper functions for parsing a pasted smart snippet's code and auto populating the variable
* fields needed by that smart snippet.
* @type {Object}
*/
var LayoutParser = {
/**
* Clear all added variables from a container
* @param jQuery container
*/
emptyContainer:function (container) {
container.children('.inline-related ').each(function (i, item) {
if (!$(item).hasClass('empty-form'))
$(item).remove();
});
},
/**
* Gets the standard variables container or the drop down one
* @param String variablesHolderType
* @return {*\jQuery}
*/
getContainer:function (variablesHolderType) {
var cx = null;
$('.inline-group').each(function (i, item) {
if (variablesHolderType == 'standard') {
var header = $(item).children('h2').get(0);
if ($(header).text().toLowerCase() == 'standard variables') {
cx = $(item);
return;
}
} else if (variablesHolderType == 'select') {
var header = $(item).children('h2').get(0);
if ($(header).text().toLowerCase() == 'drop down variables') {
cx = $(item);
return;
}
}
});
return cx;
},
getExistingStandardVariables:function (container) {
var fieldRows = container.children('.dynamic-variables');
var existingVars = new Array();
fieldRows.each(function (i, row) {
var textField = $(row).find('.vTextField');
var typeField = $(row).find('select');
var name = textField.val();
var type = typeField.val();
var typeDocId = typeField.attr('id');
var obj = {name:name, type:type, typeDocId:typeDocId};
existingVars.push(obj);
});
return existingVars;
},
getExistingSelectVariables:function (container) {
var fieldRows = container.children('.dynamic-variables-2');
var existingVars = new Array();
fieldRows.each(function (i, row) {
var name = $(row).find('.field-name').find('.vTextField').val();
var nameDocId = $(row).find('.field-name').find('.vTextField').attr('id');
var values = $(row).find('.field-choices').find('.vTextField').val();
var valuesDocId = $(row).find('.field-choices').find('.vTextField').attr('id');
var obj = {name:name, values:values, valuesDocId:valuesDocId};
existingVars.push(obj);
});
return existingVars;
},
groupExistingVars:function (existingVars, newVars, variablesType) {
var similarVars = [];
var updateVars = [];
var toBeDeletedVars = [];
var similarFieldToCheck = (variablesType && variablesType.toLowerCase() == 'select' ? 'values' : 'type');
for (var i = 0; i < existingVars.length; i++) {
var toBeUpdated = false;
var updatedFieldValue = undefined;
var isSimilar = false;
for (var j = 0; j < newVars.length; j++) {
if (existingVars[i].name == newVars[j].varname && existingVars[i][similarFieldToCheck] == newVars[j][similarFieldToCheck]) {
isSimilar = true;
break;
} else if (existingVars[i].name == newVars[j].varname && existingVars[i][similarFieldToCheck] != newVars[j][similarFieldToCheck]) {
toBeUpdated = true;
updatedFieldValue = newVars[j][similarFieldToCheck];
break;
}
}
if (toBeUpdated) {
existingVars[i].updateWithValue = updatedFieldValue;
updateVars.push(existingVars[i]);
} else if (isSimilar) {
similarVars.push(existingVars[i]);
} else if (!toBeUpdated && !isSimilar) {
toBeDeletedVars.push(existingVars[i]);
}
}
return {
similarVars:similarVars,
toUpdateVars:updateVars,
deleteVars:toBeDeletedVars
};
},
findByVarName:function (arr, vName) {
var found = false;
$.each(arr, function (i, item) {
if (item.name == vName) {
found = item;
return;
}
});
return found;
},
markForDeletion:function (container, deletedVars) {
var rows = container.children('.inline-related');
var self = this;
$.each(rows, function (i, row) {
var varName = $(row).find('.field-name').find('.vTextField').val();
var isFoundVar = self.findByVarName(deletedVars, varName);
if (isFoundVar) {
var deleteBtn = $(row).find('a.inline-deletelink');
if(deleteBtn.get(0)) {
//most likely variable was added from a previous paste or by the user so trigger the deletion here
deleteBtn.trigger('click');
} else {
var deleteCheckbox = $(row).find('.delete').find('input[type=checkbox]');
deleteCheckbox.attr('checked', 'checked');
}
}
});
},
updateVars:function (container, updatedVars, varsType) {
var rows = container.children('.inline-related');
var objFieldToUpdate = (varsType.toLowerCase() == 'select' ? 'valuesDocId' : 'typeDocId');
var self = this;
$.each(rows, function (i, row) {
var varName = $(row).find('.field-name').find('.vTextField').val();
var isFoundVar = self.findByVarName(updatedVars, varName);
if (isFoundVar) {
$('#'+ isFoundVar[objFieldToUpdate]).val(isFoundVar.updateWithValue)
}
});
},
/**
* Find the "Add another Standard Variable" button and trigger a click event on it. Returns the div container
* holding form fields
* @param container
* @return {*|jQuery}
*/
clickAddNewFieldStd:function (container) {
//count the number of already inserted vars here
//subtract 1 for the empty one present by default
var presentFieldsCount = container.children('.inline-related').length - 1;
var addNewFieldBtn = $(container).children('div.add-row').find('a');
addNewFieldBtn.trigger('click');
var addedField = $(container).children('.inline-related').last().prev();
addedField.attr('id', 'variables-' + presentFieldsCount);
var textField = addedField.find('input.vTextField');
$(textField).attr('id', 'id_variables-' + presentFieldsCount + '-name');
$(textField).attr('name', 'variables-' + presentFieldsCount + '-name');
var textLabel = addedField.find('div.field-name').find('label');
$(textLabel).attr('for', 'id_variables-' + presentFieldsCount + '-name');
var select = addedField.find('div.field-widget').find('select');
$(select).attr('id', 'id_variables-' + presentFieldsCount + '-widget');
$(select).attr('name', 'variables-' + presentFieldsCount + '-widget');
var selectLabel = addedField.find('div.field-widget').find('label');
$(selectLabel).attr('for', 'id_variables-' + presentFieldsCount + '-widget')
return addedField;
},
/**
* Find the "Add another Drop Down Variable" button and trigger a click event on it. Returns the div container
* holding form fields. There is really no difference at the moment between this and the clickAddNewFieldStd.
* The only reason for them to be separate is for expressiveness and future extensions.
* @param container
* @return {*|jQuery}
*/
clickAddNewFieldSelect:function (container) {
var addNewFieldBtn = $(container).children('div.add-row').find('a');
addNewFieldBtn.trigger('click');
var addedField = $(container).children('.inline-related').last().prev();
var inputFields = addedField.children('.vTextField');
var presentFieldsCount = container.children('.inline-related').length;
$(inputFields[0]).attr('id', 'id_variables-2-' + presentFieldsCount + '-name');
$(inputFields[0]).attr('name', 'variables-2-' + presentFieldsCount + '-name');
$(inputFields[1]).attr('id', 'id_variables-2-' + presentFieldsCount + '-choices');
$(inputFields[1]).attr('name', 'variables-2-' + presentFieldsCount + '-choices');
return addedField;
},
/**
* Add a new standard variable in the container
* varNameObj = {varname: 'name', type: 'type'}
* @param varNameObj
* @param container
*/
addStdVar:function (varNameObj, container) {
var fieldCx = this.clickAddNewFieldStd(container);
$(fieldCx).find('input.vTextField').val(varNameObj.varname);
$(fieldCx).find('select').val(varNameObj.type);
},
/**
* Add a new drop down variable in the container
* varNameObj = {varname: 'name', type: 'type', values: 'value1,value2,value3'}
* @param varNameObj
* @param container
*/
addSelectVar:function (varNameObj, container) {
var fieldCx = this.clickAddNewFieldSelect(container);
$(fieldCx).find('div.field-name').find('input.vTextField').val(varNameObj.varname);
$(fieldCx).find('div.field-choices').find('input.vTextField').val(varNameObj.values);
},
/**
* The following code will try to match everything that's within an html comment tag. It should look like this
*
* <!-- SmartSnippets Variables
* varname=type
* -->
*
* Where type could be anything from TextField, TextAreaField, MerlinField or ImageField
* Each variable is declared on a new line.
*/
extractVarnames:function (text) {
var regex = /<!-- SmartSnippets Variables([^>]*)-->/gi;
var variablesSnippet = regex.exec(text);
var varNames = []; //hold the var names here
if (variablesSnippet) {
var lines = variablesSnippet[1].split('\n'); //split the input in multiple lines
$.each(lines, function (index, line) {
if ($.trim(line).length > 0) {
var vObj = {};
var vDeclarationArr = line.split('=');
vObj.varname = $.trim(vDeclarationArr[0]);
var type = $.trim(vDeclarationArr[1]);
if (type.toLowerCase().indexOf('select') != -1) {
var tmp = type.split('|');
vObj.type = $.trim(tmp[0]);
vObj.values = vDeclarationArr[2] ? $.trim(vDeclarationArr[2]) : '';
} else {
vObj.type = $.trim(vDeclarationArr[1]);
}
varNames.push(vObj);
}
});
}
return varNames;
},
groupNewVars:function (varsArr) {
var returnObj = {};
returnObj.standard = new Array();
returnObj.select = new Array();
$.each(varsArr, function (i, variable) {
if (variable.type.toLowerCase() == 'select') {
returnObj.select.push(variable);
} else {
returnObj.standard.push(variable);
}
});
return returnObj;
},
getOnlyToAddVars: function(groupedVars, newVars) {
var onlyToAdd = new Array();
for (var i = 0; i < newVars.length; i++) {
var notInUpdates = true;
var notInSimilar = true;
for(var j = 0; j < groupedVars.similarVars.length; j++) {
if(newVars[i].varname == groupedVars.similarVars[j].name) {
notInSimilar = false;
}
}
for(var k = 0; k < groupedVars.toUpdateVars.length; k++) {
if(newVars[i].varname == groupedVars.toUpdateVars[k].name) {
notInUpdates = false;
}
}
if(notInSimilar && notInUpdates) {
onlyToAdd.push(newVars[i]);
}
}
return onlyToAdd;
},
/**
* Given an array of objects with the following structure {varname: 'name', type: 'type', values: 'value1,
* value2,value3'} or varNameObj = {varname: 'name', type: 'type'} this function fill parse the array.
*
* @param varNamesArr
*/
populate:function (varNamesArr) {
var self = this;
if (varNamesArr.length > 0) { //don't do any mumbo jumbo if we have no varnames
var groupedNewVars = self.groupNewVars(varNamesArr);
var stdContainer = self.getContainer('standard');
var selectContainer = self.getContainer('select');
var existingStdVars = self.getExistingStandardVariables(stdContainer);
var existingSelectVars = self.getExistingSelectVariables(selectContainer);
var groupedExistingStdVars = self.groupExistingVars(existingStdVars, groupedNewVars.standard, 'standard');
if (existingStdVars.length > 0) {
self.markForDeletion(stdContainer, groupedExistingStdVars.deleteVars);
self.updateVars(stdContainer, groupedExistingStdVars.toUpdateVars, 'standard');
}
var groupedExistingSelectVars = self.groupExistingVars(existingSelectVars, groupedNewVars.select, 'select');
if(existingSelectVars.length > 0) {
self.markForDeletion(selectContainer, groupedExistingSelectVars.deleteVars);
self.updateVars(selectContainer, groupedExistingSelectVars.toUpdateVars, 'select');
}
var onlyToAddStdVars = self.getOnlyToAddVars(groupedExistingStdVars, groupedNewVars.standard);
var onlyToAddSelectVars = self.getOnlyToAddVars(groupedExistingSelectVars, groupedNewVars.select);
$.each(onlyToAddStdVars, function(i, vObj) {
self.addStdVar(vObj, stdContainer);
});
$.each(onlyToAddSelectVars, function(i, vObj) {
self.addSelectVar(vObj, selectContainer);
});
}
}
};
$.updateSnippetVars = function(el){
//use a setTimeout to capture pasted text
setTimeout(function () {
var checkboxes = django.jQuery('.delete input[type=checkbox]');
django.jQuery.each(checkboxes, function(i, box) {
django.jQuery(this).attr('checked', false);
});
var text = django.jQuery(el).val();
var varNames = LayoutParser.extractVarnames(text);
LayoutParser.populate(varNames);
}, 100);
};
$(document).ready(function () {
var textArea = $('#id_template_code');
textArea.bind('paste', function (e) {
var el = $(this);
// if ($.trim($(el).val()).length == 0) {//only when the area is empty
//use a setTimeout to capture pasted text
$.updateSnippetVars(el);
// }
});
});
})(django.jQuery);

File diff suppressed because it is too large Load Diff

@ -0,0 +1,606 @@
CodeMirror.defineMode("css", function(config) {
return CodeMirror.getMode(config, "text/css");
});
CodeMirror.defineMode("css-base", function(config, parserConfig) {
"use strict";
var indentUnit = config.indentUnit,
hooks = parserConfig.hooks || {},
atMediaTypes = parserConfig.atMediaTypes || {},
atMediaFeatures = parserConfig.atMediaFeatures || {},
propertyKeywords = parserConfig.propertyKeywords || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
allowNested = !!parserConfig.allowNested,
type = null;
function ret(style, tp) { type = tp; return style; }
function tokenBase(stream, state) {
var ch = stream.next();
if (hooks[ch]) {
// result[0] is style and result[1] is type
var result = hooks[ch](stream, state);
if (result !== false) return result;
}
if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
else if (ch == "=") ret(null, "compare");
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
}
else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
}
else if (/\d/.test(ch)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
}
else if (ch === "-") {
if (/\d/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^[^-]+-/)) {
return ret("meta", "meta");
}
}
else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
}
else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
}
else if (ch == ":") {
return ret("operator", ch);
}
else if (/[;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
}
else if (ch == "u" && stream.match("rl(")) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
return ret("property", "variable");
}
else {
stream.eatWhile(/[\w\\\-]/);
return ret("property", "variable");
}
}
function tokenString(quote, nonInclusive) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped)
break;
escaped = !escaped && ch == "\\";
}
if (!escaped) {
if (nonInclusive) stream.backUp(1);
state.tokenize = tokenBase;
}
return ret("string", "string");
};
}
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\']/, false))
state.tokenize = tokenString(")", true);
else
state.tokenize = tokenBase;
return ret(null, "(");
}
return {
startState: function(base) {
return {tokenize: tokenBase,
baseIndent: base || 0,
stack: []};
},
token: function(stream, state) {
// Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
//
// rule** or **ruleset:
// A selector + braces combo, or an at-rule.
//
// declaration block:
// A sequence of declarations.
//
// declaration:
// A property + colon + value combo.
//
// property value:
// The entire value of a property.
//
// component value:
// A single piece of a property value. Like the 5px in
// text-shadow: 0 0 5px blue;. Can also refer to things that are
// multiple terms, like the 1-4 terms that make up the background-size
// portion of the background shorthand.
//
// term:
// The basic unit of author-facing CSS, like a single number (5),
// dimension (5px), string ("foo"), or function. Officially defined
// by the CSS 2.1 grammar (look for the 'term' production)
//
//
// simple selector:
// A single atomic selector, like a type selector, an attr selector, a
// class selector, etc.
//
// compound selector:
// One or more simple selectors without a combinator. div.example is
// compound, div > .example is not.
//
// complex selector:
// One or more compound selectors chained with combinators.
//
// combinator:
// The parts of selectors that express relationships. There are four
// currently - the space (descendant combinator), the greater-than
// bracket (child combinator), the plus sign (next sibling combinator),
// and the tilda (following sibling combinator).
//
// sequence of selectors:
// One or more of the named type of selector chained with commas.
state.tokenize = state.tokenize || tokenBase;
if (state.tokenize == tokenBase && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (style && typeof style != "string") style = ret(style[0], style[1]);
// Changing style returned based on context
var context = state.stack[state.stack.length-1];
if (style == "variable") {
if (type == "variable-definition") state.stack.push("propertyValue");
return "variable-2";
} else if (style == "property") {
var word = stream.current().toLowerCase();
if (context == "propertyValue") {
if (valueKeywords.hasOwnProperty(word)) {
style = "string-2";
} else if (colorKeywords.hasOwnProperty(word)) {
style = "keyword";
} else {
style = "variable-2";
}
} else if (context == "rule") {
if (!propertyKeywords.hasOwnProperty(word)) {
style += " error";
}
} else if (context == "block") {
// if a value is present in both property, value, or color, the order
// of preference is property -> color -> value
if (propertyKeywords.hasOwnProperty(word)) {
style = "property";
} else if (colorKeywords.hasOwnProperty(word)) {
style = "keyword";
} else if (valueKeywords.hasOwnProperty(word)) {
style = "string-2";
} else {
style = "tag";
}
} else if (!context || context == "@media{") {
style = "tag";
} else if (context == "@media") {
if (atMediaTypes[stream.current()]) {
style = "attribute"; // Known attribute
} else if (/^(only|not)$/.test(word)) {
style = "keyword";
} else if (word == "and") {
style = "error"; // "and" is only allowed in @mediaType
} else if (atMediaFeatures.hasOwnProperty(word)) {
style = "error"; // Known property, should be in @mediaType(
} else {
// Unknown, expecting keyword or attribute, assuming attribute
style = "attribute error";
}
} else if (context == "@mediaType") {
if (atMediaTypes.hasOwnProperty(word)) {
style = "attribute";
} else if (word == "and") {
style = "operator";
} else if (/^(only|not)$/.test(word)) {
style = "error"; // Only allowed in @media
} else {
// Unknown attribute or property, but expecting property (preceded
// by "and"). Should be in parentheses
style = "error";
}
} else if (context == "@mediaType(") {
if (propertyKeywords.hasOwnProperty(word)) {
// do nothing, remains "property"
} else if (atMediaTypes.hasOwnProperty(word)) {
style = "error"; // Known property, should be in parentheses
} else if (word == "and") {
style = "operator";
} else if (/^(only|not)$/.test(word)) {
style = "error"; // Only allowed in @media
} else {
style += " error";
}
} else if (context == "@import") {
style = "tag";
} else {
style = "error";
}
} else if (style == "atom") {
if(!context || context == "@media{" || context == "block") {
style = "builtin";
} else if (context == "propertyValue") {
if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
style += " error";
}
} else {
style = "error";
}
} else if (context == "@media" && type == "{") {
style = "error";
}
// Push/pop context stack
if (type == "{") {
if (context == "@media" || context == "@mediaType") {
state.stack.pop();
state.stack[state.stack.length-1] = "@media{";
}
else {
var newContext = allowNested ? "block" : "rule";
state.stack.push(newContext);
}
}
else if (type == "}") {
var lastState = state.stack[state.stack.length - 1];
if (lastState == "interpolation") style = "operator";
state.stack.pop();
if (context == "propertyValue") state.stack.pop();
}
else if (type == "interpolation") state.stack.push("interpolation");
else if (type == "@media") state.stack.push("@media");
else if (type == "@import") state.stack.push("@import");
else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
state.stack.push("@mediaType");
else if (context == "@mediaType" && stream.current() == ",") state.stack.pop();
else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType(");
else if (context == "@mediaType(" && type == ")") state.stack.pop();
else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue");
else if (context == "propertyValue" && type == ";") state.stack.pop();
else if (context == "@import" && type == ";") state.stack.pop();
return style;
},
indent: function(state, textAfter) {
var n = state.stack.length;
if (/^\}/.test(textAfter))
n -= state.stack[state.stack.length-1] == "propertyValue" ? 2 : 1;
return state.baseIndent + n * indentUnit;
},
electricChars: "}",
blockCommentStart: "/*",
blockCommentEnd: "*/"
};
});
(function() {
function keySet(array) {
var keys = {};
for (var i = 0; i < array.length; ++i) {
keys[array[i]] = true;
}
return keys;
}
var atMediaTypes = keySet([
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
]);
var atMediaFeatures = keySet([
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid"
]);
var propertyKeywords = keySet([
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-iteration-count",
"animation-name", "animation-play-state", "animation-timing-function",
"appearance", "azimuth", "backface-visibility", "background",
"background-attachment", "background-clip", "background-color",
"background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color",
"border-bottom-left-radius", "border-bottom-right-radius",
"border-bottom-style", "border-bottom-width", "border-collapse",
"border-color", "border-image", "border-image-outset",
"border-image-repeat", "border-image-slice", "border-image-source",
"border-image-width", "border-left", "border-left-color",
"border-left-style", "border-left-width", "border-radius", "border-right",
"border-right-color", "border-right-style", "border-right-width",
"border-spacing", "border-style", "border-top", "border-top-color",
"border-top-left-radius", "border-top-right-radius", "border-top-style",
"border-top-width", "border-width", "bottom", "box-decoration-break",
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
"caption-side", "clear", "clip", "color", "color-profile", "column-count",
"column-fill", "column-gap", "column-rule", "column-rule-color",
"column-rule-style", "column-rule-width", "column-span", "column-width",
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
"cue-after", "cue-before", "cursor", "direction", "display",
"dominant-baseline", "drop-initial-after-adjust",
"drop-initial-after-align", "drop-initial-before-adjust",
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
"float", "float-offset", "font", "font-feature-settings", "font-family",
"font-kerning", "font-language-override", "font-size", "font-size-adjust",
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid-cell", "grid-column", "grid-column-align",
"grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow",
"grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span",
"grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
"line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marker-offset", "marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
"page", "page-break-after", "page-break-before", "page-break-inside",
"page-policy", "pause", "pause-after", "pause-before", "perspective",
"perspective-origin", "pitch", "pitch-range", "play-during", "position",
"presentation-level", "punctuation-trim", "quotes", "rendering-intent",
"resize", "rest", "rest-after", "rest-before", "richness", "right",
"rotation", "rotation-point", "ruby-align", "ruby-overhang",
"ruby-position", "ruby-span", "size", "speak", "speak-as", "speak-header",
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
"tab-size", "table-layout", "target", "target-name", "target-new",
"target-position", "text-align", "text-align-last", "text-decoration",
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
"text-decoration-style", "text-emphasis", "text-emphasis-color",
"text-emphasis-position", "text-emphasis-style", "text-height",
"text-indent", "text-justify", "text-outline", "text-shadow",
"text-space-collapse", "text-transform", "text-underline-position",
"text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi",
"vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "word-break",
"word-spacing", "word-wrap", "z-index",
// SVG-specific
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
"color-interpolation", "color-interpolation-filters", "color-profile",
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
"glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
]);
var colorKeywords = keySet([
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
"cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
"darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
"darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
"deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
"floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
"gold", "goldenrod", "gray", "green", "greenyellow", "honeydew",
"hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
"lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
"lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
"maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
"purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon",
"sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
"whitesmoke", "yellow", "yellowgreen"
]);
var valueKeywords = keySet([
"above", "absolute", "activeborder", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
"arabic-indic", "armenian", "asterisks", "auto", "avoid", "background",
"backwards", "baseline", "below", "bidi-override", "binary", "bengali",
"blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
"both", "bottom", "break-all", "break-word", "button", "button-bevel",
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
"col-resize", "collapse", "compact", "condensed", "contain", "content",
"content-box", "context-menu", "continuous", "copy", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari",
"disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
"double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
"element", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
"ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
"italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer",
"landscape", "lao", "large", "larger", "left", "level", "lighter",
"line-through", "linear", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "malayalam", "match",
"media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button",
"media-seek-back-button", "media-seek-forward-button", "media-slider",
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
"outside", "overlay", "overline", "padding", "padding-box", "painted",
"paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait",
"pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
"radio", "read-only", "read-write", "read-write-plaintext-only", "relative",
"repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
"ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
"s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"single", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke",
"sub", "subpixel-antialiased", "super", "sw-resize", "table",
"table-caption", "table-cell", "table-column", "table-column-group",
"table-footer-group", "table-header-group", "table-row", "table-row-group",
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
"xx-large", "xx-small"
]);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = null;
break;
}
maybeEnd = (ch == "*");
}
return ["comment", "comment"];
}
CodeMirror.defineMIME("text/css", {
atMediaTypes: atMediaTypes,
atMediaFeatures: atMediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
hooks: {
"<": function(stream, state) {
function tokenSGMLComment(stream, state) {
var dashes = 0, ch;
while ((ch = stream.next()) != null) {
if (dashes >= 2 && ch == ">") {
state.tokenize = null;
break;
}
dashes = (ch == "-") ? dashes + 1 : 0;
}
return ["comment", "comment"];
}
if (stream.eat("!")) {
state.tokenize = tokenSGMLComment;
return tokenSGMLComment(stream, state);
}
},
"/": function(stream, state) {
if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
return false;
}
},
name: "css-base"
});
CodeMirror.defineMIME("text/x-scss", {
atMediaTypes: atMediaTypes,
atMediaFeatures: atMediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
allowNested: true,
hooks: {
"$": function(stream) {
stream.match(/^[\w-]+/);
if (stream.peek() == ":") {
return ["variable", "variable-definition"];
}
return ["variable", "variable"];
},
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
"#": function(stream) {
if (stream.eat("{")) {
return ["operator", "interpolation"];
} else {
stream.eatWhile(/[\w\\\-]/);
return ["atom", "hash"];
}
}
},
name: "css-base"
});
})();

@ -0,0 +1,104 @@
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
var cssMode = CodeMirror.getMode(config, "css");
var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
mode: CodeMirror.getMode(config, "javascript")});
if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
var conf = scriptTypesConf[i];
scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
}
scriptTypes.push({matches: /./,
mode: CodeMirror.getMode(config, "text/plain")});
function html(stream, state) {
var tagName = state.htmlState.tagName;
var style = htmlMode.token(stream, state.htmlState);
if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
// Script block: mode to change to depends on type attribute
var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
scriptType = scriptType ? scriptType[1] : "";
if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
for (var i = 0; i < scriptTypes.length; ++i) {
var tp = scriptTypes[i];
if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
if (tp.mode) {
state.token = script;
state.localMode = tp.mode;
state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
}
break;
}
}
} else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
state.token = css;
state.localMode = cssMode;
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
}
return style;
}
function maybeBackup(stream, pat, style) {
var cur = stream.current();
var close = cur.search(pat), m;
if (close > -1) stream.backUp(cur.length - close);
else if (m = cur.match(/<\/?$/)) {
stream.backUp(cur.length);
if (!stream.match(pat, false)) stream.match(cur[0]);
}
return style;
}
function script(stream, state) {
if (stream.match(/^<\/\s*script\s*>/i, false)) {
state.token = html;
state.localState = state.localMode = null;
return html(stream, state);
}
return maybeBackup(stream, /<\/\s*script\s*>/,
state.localMode.token(stream, state.localState));
}
function css(stream, state) {
if (stream.match(/^<\/\s*style\s*>/i, false)) {
state.token = html;
state.localState = state.localMode = null;
return html(stream, state);
}
return maybeBackup(stream, /<\/\s*style\s*>/,
cssMode.token(stream, state.localState));
}
return {
startState: function() {
var state = htmlMode.startState();
return {token: html, localMode: null, localState: null, htmlState: state};
},
copyState: function(state) {
if (state.localState)
var local = CodeMirror.copyState(state.localMode, state.localState);
return {token: state.token, localMode: state.localMode, localState: local,
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
},
token: function(stream, state) {
return state.token(stream, state);
},
indent: function(state, textAfter) {
if (!state.localMode || /^\s*<\//.test(textAfter))
return htmlMode.indent(state.htmlState, textAfter);
else if (state.localMode.indent)
return state.localMode.indent(state.localState, textAfter);
else
return CodeMirror.Pass;
},
electricChars: "/{}:",
innerMode: function(state) {
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
}
};
}, "xml", "javascript", "css");
CodeMirror.defineMIME("text/html", "htmlmixed");

@ -0,0 +1,471 @@
// TODO actually recognize syntax of TypeScript constructs
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var jsonMode = parserConfig.json;
var isTS = parserConfig.typescript;
// Tokenizer
var keywords = function(){
function kw(type) {return {type: type, style: "keyword"};}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
"this": kw("this")
};
// Extend the 'normal' keywords with the TypeScript language extensions
if (isTS) {
var type = {type: "variable", style: "variable-3"};
var tsKeywords = {
// object-like things
"interface": kw("interface"),
"class": kw("class"),
"extends": kw("extends"),
"constructor": kw("constructor"),
// scope modifiers
"public": kw("public"),
"private": kw("private"),
"protected": kw("protected"),
"static": kw("static"),
"super": kw("super"),
// types
"string": type, "number": type, "bool": type, "any": type
};
for (var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}();
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
function chain(stream, state, f) {
state.tokenize = f;
return f(stream, state);
}
function nextUntilUnescaped(stream, end) {
var escaped = false, next;
while ((next = stream.next()) != null) {
if (next == end && !escaped)
return false;
escaped = !escaped && next == "\\";
}
return escaped;
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp; content = cont;
return style;
}
function jsTokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'")
return chain(stream, state, jsTokenString(ch));
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
return ret(ch);
else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
}
else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
}
else if (ch == "/") {
if (stream.eat("*")) {
return chain(stream, state, jsTokenComment);
}
else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
}
else if (state.lastType == "operator" || state.lastType == "keyword c" ||
/^[\[{}\(,;:]$/.test(state.lastType)) {
nextUntilUnescaped(stream, "/");
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
return ret("regexp", "string-2");
}
else {
stream.eatWhile(isOperatorChar);
return ret("operator", null, stream.current());
}
}
else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
}
else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return ret("operator", null, stream.current());
}
else {
stream.eatWhile(/[\w\$_]/);
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
ret("variable", "variable", word);
}
}
function jsTokenString(quote) {
return function(stream, state) {
if (!nextUntilUnescaped(stream, quote))
state.tokenize = jsTokenBase;
return ret("string", "string");
};
}
function jsTokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = jsTokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "comment");
}
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true};
function JSLexical(indented, column, type, align, prev, info) {
this.indented = indented;
this.column = column;
this.type = type;
this.prev = prev;
this.info = info;
if (align != null) this.align = align;
}
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
}
function parseJS(state, style, type, content, stream) {
var cc = state.cc;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
while(true) {
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
if (combinator(type, content)) {
while(cc.length && cc[cc.length - 1].lex)
cc.pop()();
if (cx.marked) return cx.marked;
if (type == "variable" && inScope(state, content)) return "variable-2";
return style;
}
}
}
// Combinator utils
var cx = {state: null, column: null, marked: null, cc: null};
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function register(varname) {
function inList(list) {
for (var v = list; v; v = v.next)
if (v.name == varname) return true;
return false;
}
var state = cx.state;
if (state.context) {
cx.marked = "def";
if (inList(state.localVars)) return;
state.localVars = {name: varname, next: state.localVars};
} else {
if (inList(state.globalVars)) return;
state.globalVars = {name: varname, next: state.globalVars};
}
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
function pushcontext() {
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
cx.state.localVars = defaultVars;
}
function popcontext() {
cx.state.localVars = cx.state.context.vars;
cx.state.context = cx.state.context.prev;
}
function pushlex(type, info) {
var result = function() {
var state = cx.state;
state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
};
result.lex = true;
return result;
}
function poplex() {
var state = cx.state;
if (state.lexical.prev) {
if (state.lexical.type == ")")
state.indented = state.lexical.indented;
state.lexical = state.lexical.prev;
}
}
poplex.lex = true;
function expect(wanted) {
return function(type) {
if (type == wanted) return cont();
else if (wanted == ";") return pass();
else return cont(arguments.callee);
};
}
function statement(type) {
if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse(cx.state.indented));
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
poplex, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
block, poplex, poplex);
if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
return expressionInner(type, maybeoperatorComma);
}
function expressionNoComma(type) {
return expressionInner(type, maybeoperatorNoComma);
}
function expressionInner(type, maybeop) {
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef);
if (type == "keyword c") return cont(maybeexpression);
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
if (type == "operator") return cont(expression);
if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop);
if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop);
return cont();
}
function maybeexpression(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expression);
}
function maybeoperatorComma(type, value) {
if (type == ",") return pass();
return maybeoperatorNoComma(type, value, maybeoperatorComma);
}
function maybeoperatorNoComma(type, value, me) {
if (!me) me = maybeoperatorNoComma;
if (type == "operator") {
if (/\+\+|--/.test(value)) return cont(me);
if (value == "?") return cont(expression, expect(":"), expression);
return cont(expression);
}
if (type == ";") return;
if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me);
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, me);
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperatorComma, expect(";"), poplex);
}
function property(type) {
if (type == "variable") {cx.marked = "property"; return cont();}
}
function objprop(type, value) {
if (type == "variable") {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
} else if (type == "number" || type == "string") {
cx.marked = type + " property";
}
if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expressionNoComma);
}
function getterSetter(type) {
if (type == ":") return cont(expression);
if (type != "variable") return cont(expect(":"), expression);
cx.marked = "property";
return cont(functiondef);
}
function commasep(what, end) {
function proceed(type) {
if (type == ",") {
var lex = cx.state.lexical;
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
return cont(what, proceed);
}
if (type == end) return cont();
return cont(expect(end));
}
return function(type) {
if (type == end) return cont();
else return pass(what, proceed);
};
}
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function maybetype(type) {
if (type == ":") return cont(typedef);
return pass();
}
function typedef(type) {
if (type == "variable"){cx.marked = "variable-3"; return cont();}
return pass();
}
function vardef1(type, value) {
if (type == "variable") {
register(value);
return isTS ? cont(maybetype, vardef2) : cont(vardef2);
}
return pass();
}
function vardef2(type, value) {
if (value == "=") return cont(expressionNoComma, vardef2);
if (type == ",") return cont(vardef1);
}
function maybeelse(indent) {
return function(type, value) {
if (type == "keyword b" && value == "else") {
cx.state.lexical = new JSLexical(indent, 0, "form", null, cx.state.lexical);
return cont(statement, poplex);
}
return pass();
};
}
function forspec1(type) {
if (type == "var") return cont(vardef1, expect(";"), forspec2);
if (type == ";") return cont(forspec2);
if (type == "variable") return cont(formaybein);
return pass(expression, expect(";"), forspec2);
}
function formaybein(_type, value) {
if (value == "in") return cont(expression);
return cont(maybeoperatorComma, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
if (value == "in") return cont(expression);
return pass(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
if (type == "variable") {register(value); return cont(functiondef);}
if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
}
function funarg(type, value) {
if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: jsTokenBase,
lastType: null,
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars,
globalVars: parserConfig.globalVars,
context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: 0
};
},
token: function(stream, state) {
if (stream.sol()) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
}
if (state.tokenize != jsTokenComment && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
return parseJS(state, style, type, content, stream);
},
indent: function(state, textAfter) {
if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
if (state.tokenize != jsTokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
if (parserConfig.statementIndent != null) {
if (type == ")" && lexical.prev && lexical.prev.type == "stat") lexical = lexical.prev;
if (lexical.type == "stat") return lexical.indented + parserConfig.statementIndent;
}
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "form") return lexical.indented + indentUnit;
else if (type == "stat")
return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? indentUnit : 0);
else if (lexical.info == "switch" && !closing)
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
electricChars: ":{}",
blockCommentStart: jsonMode ? null : "/*",
blockCommentEnd: jsonMode ? null : "*/",
lineComment: jsonMode ? null : "//",
jsonMode: jsonMode
};
});
CodeMirror.defineMIME("text/javascript", "javascript");
CodeMirror.defineMIME("text/ecmascript", "javascript");
CodeMirror.defineMIME("application/javascript", "javascript");
CodeMirror.defineMIME("application/ecmascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });

@ -0,0 +1,330 @@
CodeMirror.defineMode("xml", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
var Kludges = parserConfig.htmlMode ? {
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
'track': true, 'wbr': true},
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
'th': true, 'tr': true},
contextGrabbers: {
'dd': {'dd': true, 'dt': true},
'dt': {'dd': true, 'dt': true},
'li': {'li': true},
'option': {'option': true, 'optgroup': true},
'optgroup': {'optgroup': true},
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
'rp': {'rp': true, 'rt': true},
'rt': {'rp': true, 'rt': true},
'tbody': {'tbody': true, 'tfoot': true},
'td': {'td': true, 'th': true},
'tfoot': {'tbody': true},
'th': {'td': true, 'th': true},
'thead': {'tbody': true, 'tfoot': true},
'tr': {'tr': true}
},
doNotIndent: {"pre": true},
allowUnquoted: true,
allowMissing: true
} : {
autoSelfClosers: {},
implicitlyClosed: {},
contextGrabbers: {},
doNotIndent: {},
allowUnquoted: false,
allowMissing: false
};
var alignCDATA = parserConfig.alignCDATA;
// Return variables for tokenizers
var tagName, type;
function inText(stream, state) {
function chain(parser) {
state.tokenize = parser;
return parser(stream, state);
}
var ch = stream.next();
if (ch == "<") {
if (stream.eat("!")) {
if (stream.eat("[")) {
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
else return null;
}
else if (stream.match("--")) return chain(inBlock("comment", "-->"));
else if (stream.match("DOCTYPE", true, true)) {
stream.eatWhile(/[\w\._\-]/);
return chain(doctype(1));
}
else return null;
}
else if (stream.eat("?")) {
stream.eatWhile(/[\w\._\-]/);
state.tokenize = inBlock("meta", "?>");
return "meta";
}
else {
var isClose = stream.eat("/");
tagName = "";
var c;
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
if (!tagName) return "error";
type = isClose ? "closeTag" : "openTag";
state.tokenize = inTag;
return "tag";
}
}
else if (ch == "&") {
var ok;
if (stream.eat("#")) {
if (stream.eat("x")) {
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
} else {
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
}
} else {
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
}
return ok ? "atom" : "error";
}
else {
stream.eatWhile(/[^&<]/);
return null;
}
}
function inTag(stream, state) {
var ch = stream.next();
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "tag";
}
else if (ch == "=") {
type = "equals";
return null;
}
else if (/[\'\"]/.test(ch)) {
state.tokenize = inAttribute(ch);
return state.tokenize(stream, state);
}
else {
stream.eatWhile(/[^\s\u00a0=<>\"\']/);
return "word";
}
}
function inAttribute(quote) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inTag;
break;
}
}
return "string";
};
}
function inBlock(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator)) {
state.tokenize = inText;
break;
}
stream.next();
}
return style;
};
}
function doctype(depth) {
return function(stream, state) {
var ch;
while ((ch = stream.next()) != null) {
if (ch == "<") {
state.tokenize = doctype(depth + 1);
return state.tokenize(stream, state);
} else if (ch == ">") {
if (depth == 1) {
state.tokenize = inText;
break;
} else {
state.tokenize = doctype(depth - 1);
return state.tokenize(stream, state);
}
}
}
return "meta";
};
}
var curState, curStream, setStyle;
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function pushContext(tagName, startOfLine) {
var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
curState.context = {
prev: curState.context,
tagName: tagName,
indent: curState.indented,
startOfLine: startOfLine,
noIndent: noIndent
};
}
function popContext() {
if (curState.context) curState.context = curState.context.prev;
}
function element(type) {
if (type == "openTag") {
curState.tagName = tagName;
curState.tagStart = curStream.column();
return cont(attributes, endtag(curState.startOfLine));
} else if (type == "closeTag") {
var err = false;
if (curState.context) {
if (curState.context.tagName != tagName) {
if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
popContext();
}
err = !curState.context || curState.context.tagName != tagName;
}
} else {
err = true;
}
if (err) setStyle = "error";
return cont(endclosetag(err));
}
return cont();
}
function endtag(startOfLine) {
return function(type) {
var tagName = curState.tagName;
curState.tagName = curState.tagStart = null;
if (type == "selfcloseTag" ||
(type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
maybePopContext(tagName.toLowerCase());
return cont();
}
if (type == "endTag") {
maybePopContext(tagName.toLowerCase());
pushContext(tagName, startOfLine);
return cont();
}
return cont();
};
}
function endclosetag(err) {
return function(type) {
if (err) setStyle = "error";
if (type == "endTag") { popContext(); return cont(); }
setStyle = "error";
return cont(arguments.callee);
};
}
function maybePopContext(nextTagName) {
var parentTagName;
while (true) {
if (!curState.context) {
return;
}
parentTagName = curState.context.tagName.toLowerCase();
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
return;
}
popContext();
}
}
function attributes(type) {
if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
if (type == "endTag" || type == "selfcloseTag") return pass();
setStyle = "error";
return cont(attributes);
}
function attribute(type) {
if (type == "equals") return cont(attvalue, attributes);
if (!Kludges.allowMissing) setStyle = "error";
else if (type == "word") setStyle = "attribute";
return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
}
function attvalue(type) {
if (type == "string") return cont(attvaluemaybe);
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
setStyle = "error";
return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
}
function attvaluemaybe(type) {
if (type == "string") return cont(attvaluemaybe);
else return pass();
}
return {
startState: function() {
return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null};
},
token: function(stream, state) {
if (!state.tagName && stream.sol()) {
state.startOfLine = true;
state.indented = stream.indentation();
}
if (stream.eatSpace()) return null;
setStyle = type = tagName = null;
var style = state.tokenize(stream, state);
state.type = type;
if ((style || type) && style != "comment") {
curState = state; curStream = stream;
while (true) {
var comb = state.cc.pop() || element;
if (comb(type || style)) break;
}
}
state.startOfLine = false;
return setStyle || style;
},
indent: function(state, textAfter, fullLine) {
var context = state.context;
if ((state.tokenize != inTag && state.tokenize != inText) ||
context && context.noIndent)
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
if (state.tagName) return state.tagStart + indentUnit * multilineTagIndentFactor;
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
if (context && /^<\//.test(textAfter))
context = context.prev;
while (context && !context.startOfLine)
context = context.prev;
if (context) return context.indent + indentUnit;
else return 0;
},
electricChars: "/",
blockCommentStart: "<!--",
blockCommentEnd: "-->",
configuration: parserConfig.htmlMode ? "html" : "xml"
};
});
CodeMirror.defineMIME("text/xml", "xml");
CodeMirror.defineMIME("application/xml", "xml");
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});

@ -0,0 +1,3 @@
(function($) {
window.hasAceTheme = true;
})(jQuery || django.jQuery);

@ -0,0 +1 @@
jQuery = jQuery || django.jQuery;

@ -0,0 +1,5 @@
(function($) {
$(document).ready(function(){
$(".plugin-help-tooltip").tipTip({maxWidth: "250px", delay: 100});
});
})(jQuery || django.jQuery);

@ -0,0 +1,113 @@
/* TipTip CSS - Version 1.2 */
#tiptip_holder {
display: none;
position: absolute;
top: 0;
left: 0;
z-index: 99999;
}
#tiptip_holder.tip_top {
padding-bottom: 5px;
}
#tiptip_holder.tip_bottom {
padding-top: 5px;
}
#tiptip_holder.tip_right {
padding-left: 5px;
}
#tiptip_holder.tip_left {
padding-right: 5px;
}
#tiptip_content {
font-size: 11px;
color: #fff;
text-shadow: 0 0 2px #000;
padding: 4px 8px;
border: 1px solid rgba(255,255,255,0.25);
background-color: rgb(25,25,25);
background-color: rgba(25,25,25,0.92);
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(transparent), to(#000));
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
box-shadow: 0 0 3px #555;
-webkit-box-shadow: 0 0 3px #555;
-moz-box-shadow: 0 0 3px #555;
}
#tiptip_arrow, #tiptip_arrow_inner {
position: absolute;
border-color: transparent;
border-style: solid;
border-width: 6px;
height: 0;
width: 0;
}
#tiptip_holder.tip_top #tiptip_arrow {
border-top-color: #fff;
border-top-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_bottom #tiptip_arrow {
border-bottom-color: #fff;
border-bottom-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_right #tiptip_arrow {
border-right-color: #fff;
border-right-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_left #tiptip_arrow {
border-left-color: #fff;
border-left-color: rgba(255,255,255,0.35);
}
#tiptip_holder.tip_top #tiptip_arrow_inner {
margin-top: -7px;
margin-left: -6px;
border-top-color: rgb(25,25,25);
border-top-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
margin-top: -5px;
margin-left: -6px;
border-bottom-color: rgb(25,25,25);
border-bottom-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_right #tiptip_arrow_inner {
margin-top: -6px;
margin-left: -5px;
border-right-color: rgb(25,25,25);
border-right-color: rgba(25,25,25,0.92);
}
#tiptip_holder.tip_left #tiptip_arrow_inner {
margin-top: -6px;
margin-left: -7px;
border-left-color: rgb(25,25,25);
border-left-color: rgba(25,25,25,0.92);
}
/* Webkit Hacks */
@media screen and (-webkit-min-device-pixel-ratio:0) {
#tiptip_content {
padding: 4px 8px 5px 8px;
background-color: rgba(45,45,45,0.88);
}
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
border-bottom-color: rgba(45,45,45,0.88);
}
#tiptip_holder.tip_top #tiptip_arrow_inner {
border-top-color: rgba(20,20,20,0.92);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

@ -0,0 +1,21 @@
/*
* TipTip
* Copyright 2010 Drew Wilson
* www.drewwilson.com
* code.drewwilson.com/entry/tiptip-jquery-plugin
*
* Version 1.3 - Updated: Mar. 23, 2010
*
* This Plug-In will create a custom tooltip to replace the default
* browser tooltip. It is extremely lightweight and very smart in
* that it detects the edges of the browser window and will make sure
* the tooltip stays within the current window size. As a result the
* tooltip will adjust itself to be displayed above, below, to the left
* or to the right depending on what is necessary to stay within the
* browser window. It is completely customizable as well via CSS.
*
* This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
(function($){$.fn.tipTip=function(options){var defaults={activation:"hover",keepAlive:false,maxWidth:"200px",edgeOffset:3,defaultPosition:"bottom",delay:400,fadeIn:200,fadeOut:200,attribute:"title",content:false,enter:function(){},exit:function(){}};var opts=$.extend(defaults,options);if($("#tiptip_holder").length<=0){var tiptip_holder=$('<div id="tiptip_holder" style="max-width:'+opts.maxWidth+';"></div>');var tiptip_content=$('<div id="tiptip_content"></div>');var tiptip_arrow=$('<div id="tiptip_arrow"></div>');$("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>')))}else{var tiptip_holder=$("#tiptip_holder");var tiptip_content=$("#tiptip_content");var tiptip_arrow=$("#tiptip_arrow")}return this.each(function(){var org_elem=$(this);if(opts.content){var org_title=opts.content}else{var org_title=org_elem.attr(opts.attribute)}if(org_title!=""){if(!opts.content){org_elem.removeAttr(opts.attribute)}var timeout=false;if(opts.activation=="hover"){org_elem.hover(function(){active_tiptip()},function(){if(!opts.keepAlive){deactive_tiptip()}});if(opts.keepAlive){tiptip_holder.hover(function(){},function(){deactive_tiptip()})}}else if(opts.activation=="focus"){org_elem.focus(function(){active_tiptip()}).blur(function(){deactive_tiptip()})}else if(opts.activation=="click"){org_elem.click(function(){active_tiptip();return false}).hover(function(){},function(){if(!opts.keepAlive){deactive_tiptip()}});if(opts.keepAlive){tiptip_holder.hover(function(){},function(){deactive_tiptip()})}}function active_tiptip(){opts.enter.call(this);tiptip_content.html(org_title);tiptip_holder.hide().removeAttr("class").css("margin","0");tiptip_arrow.removeAttr("style");var top=parseInt(org_elem.offset()['top']);var left=parseInt(org_elem.offset()['left']);var org_width=parseInt(org_elem.outerWidth());var org_height=parseInt(org_elem.outerHeight());var tip_w=tiptip_holder.outerWidth();var tip_h=tiptip_holder.outerHeight();var w_compare=Math.round((org_width-tip_w)/2);var h_compare=Math.round((org_height-tip_h)/2);var marg_left=Math.round(left+w_compare);var marg_top=Math.round(top+org_height+opts.edgeOffset);var t_class="";var arrow_top="";var arrow_left=Math.round(tip_w-12)/2;if(opts.defaultPosition=="bottom"){t_class="_bottom"}else if(opts.defaultPosition=="top"){t_class="_top"}else if(opts.defaultPosition=="left"){t_class="_left"}else if(opts.defaultPosition=="right"){t_class="_right"}var right_compare=(w_compare+left)<parseInt($(window).scrollLeft());var left_compare=(tip_w+left)>parseInt($(window).width());if((right_compare&&w_compare<0)||(t_class=="_right"&&!left_compare)||(t_class=="_left"&&left<(tip_w+opts.edgeOffset+5))){t_class="_right";arrow_top=Math.round(tip_h-13)/2;arrow_left=-12;marg_left=Math.round(left+org_width+opts.edgeOffset);marg_top=Math.round(top+h_compare)}else if((left_compare&&w_compare<0)||(t_class=="_left"&&!right_compare)){t_class="_left";arrow_top=Math.round(tip_h-13)/2;arrow_left=Math.round(tip_w);marg_left=Math.round(left-(tip_w+opts.edgeOffset+5));marg_top=Math.round(top+h_compare)}var top_compare=(top+org_height+opts.edgeOffset+tip_h+8)>parseInt($(window).height()+$(window).scrollTop());var bottom_compare=((top+org_height)-(opts.edgeOffset+tip_h+8))<0;if(top_compare||(t_class=="_bottom"&&top_compare)||(t_class=="_top"&&!bottom_compare)){if(t_class=="_top"||t_class=="_bottom"){t_class="_top"}else{t_class=t_class+"_top"}arrow_top=tip_h;marg_top=Math.round(top-(tip_h+5+opts.edgeOffset))}else if(bottom_compare|(t_class=="_top"&&bottom_compare)||(t_class=="_bottom"&&!top_compare)){if(t_class=="_top"||t_class=="_bottom"){t_class="_bottom"}else{t_class=t_class+"_bottom"}arrow_top=-12;marg_top=Math.round(top+org_height+opts.edgeOffset)}if(t_class=="_right_top"||t_class=="_left_top"){marg_top=marg_top+5}else if(t_class=="_right_bottom"||t_class=="_left_bottom"){marg_top=marg_top-5}if(t_class=="_left_top"||t_class=="_left_bottom"){marg_left=marg_left+5}tiptip_arrow.css({"margin-left":arrow_left+"px","margin-top":arrow_top+"px"});tiptip_holder.css({"margin-left":marg_left+"px","margin-top":marg_top+"px"}).attr("class","tip"+t_class);if(timeout){clearTimeout(timeout)}timeout=setTimeout(function(){tiptip_holder.stop(true,true).fadeIn(opts.fadeIn)},opts.delay)}function deactive_tiptip(){opts.exit.call(this);if(timeout){clearTimeout(timeout)}tiptip_holder.fadeOut(opts.fadeOut)}}})}})(jQuery);

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save