parent
60c3cbbc88
commit
85d6cd590a
226 changed files with 30199 additions and 17 deletions
@ -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, |
||||
), |
||||
] |
||||
@ -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); |
||||
} |
||||
} |
||||
|
After Width: | Height: | Size: 200 B |
|
After Width: | Height: | Size: 4.4 KiB |
|
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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue