Commits

Simon Meers  committed c7ddca7

Working prototype for multi-configuration.

  • Participants
  • Parent commits 0a4001d
  • Branches multiconfig

Comments (0)

Files changed (12)

File markitup/fields.py

-from django.conf import settings
 from django.db import models
 from django.utils.safestring import mark_safe, SafeData
-from django.utils.functional import curry
 from django.core.exceptions import ImproperlyConfigured
-from markitup import widgets
+from . import settings
+from . import widgets
 
 _rendered_field_name = lambda name: '_%s_rendered' % name
 
-def _get_render_func(dotted_path, **kwargs):
-    (module, func) = dotted_path.rsplit('.', 1)
-    func = getattr(__import__(module, {}, {}, [func]), func)
-    return curry(func, **kwargs)
-
-try:
-    render_func = _get_render_func(settings.MARKITUP_FILTER[0],
-                                   **settings.MARKITUP_FILTER[1])
-except ImportError, e:
-    raise ImproperlyConfigured("Could not import MARKITUP_FILTER %s: %s" %
-                               (settings.MARKITUP_FILTER, e))
-except AttributeError, e:
-    raise ImproperlyConfigured("MARKITUP_FILTER setting is required")
-
 class Markup(SafeData):
     def __init__(self, instance, field_name, rendered_field_name):
         # instead of storing actual values store a reference to the instance
         # _rendered field itself is frozen as well. See introspection
         # rules below.
         self.add_rendered_field = not kwargs.pop('no_rendered_field', False)
+        self.config_key = kwargs.pop('config_key', 'default')
+        if not self.config_key in settings.MARKITUP_CONFIG:
+            raise RuntimeError(
+                u'Invalid MarkupField.config_key (%s); options are: %s' % (
+                    self.config_key, u', '.join(
+                        settings.MARKITUP_CONFIG.keys())))
         super(MarkupField, self).__init__(*args, **kwargs)
 
     def contribute_to_class(self, cls, name):
 
     def pre_save(self, model_instance, add):
         value = super(MarkupField, self).pre_save(model_instance, add)
-        rendered = render_func(value.raw)
+        rendered = settings.get_filter_function(self.config_key)(value.raw)
         setattr(model_instance, _rendered_field_name(self.attname), rendered)
         return value.raw
 
         defaults.update(kwargs)
         field = super(MarkupField, self).formfield(**defaults)
         field.hidden_widget = widgets.MarkupHiddenWidget
+        if hasattr(field.widget, 'set_config'):
+            field.widget.set_config(self.config_key)
         return field
 
 # register MarkupField to use the custom widget in the Admin

File markitup/markup.py

-"""
-markup filters for django-markitup
-
-Time-stamp: <2009-03-18 11:44:57 carljm markup.py>
-
-This module provides a ``filter_func`` module-level markup filter
-function based on the MARKITUP_PREVIEW_FILTER setting.
-
-MARKITUP_PREVIEW_FILTER should be a two-tuple, where the first element
-is a dotted-path string to a markup filter function, and the second
-element is a dictionary of kwargs to be passed to the filter function
-along with the markup to parse.
-
-For instance, if MARKITUP_PREVIEW_FILTER is set to::
-
-    ('markdown.markdown', {'safe_mode': True})
-
-then calling ``filter_func(text)`` is equivalent to::
-
-    from markdown import markdown
-    markdown(text, safe_mode=True)
-
-Though the implementation differs, the format of the
-MARKITUP_PREVIEW_FILTER setting is inspired by James Bennett's
-django-template-utils_.
-
-.. _django-template-utils: http://code.google.com/p/django-template-utils/
-
-"""
-from django.utils.functional import curry, wraps
-
-from markitup.settings import MARKITUP_PREVIEW_FILTER
-
-if MARKITUP_PREVIEW_FILTER is None:
-    filter_func = lambda text: text
-else:
-    filter_path, filter_kwargs = MARKITUP_PREVIEW_FILTER
-    module, funcname = filter_path.rsplit('.', 1)
-    func = getattr(__import__(module, {}, {}, [funcname]), funcname)
-    filter_func = wraps(func)(curry(func, **filter_kwargs))

File markitup/settings.py

 from django.conf import settings
+from django.utils.functional import curry, wraps
 
-MARKITUP_PREVIEW_FILTER = getattr(settings, 'MARKITUP_PREVIEW_FILTER',
-                                  getattr(settings, 'MARKITUP_FILTER', None))
+def fallback_function(text):
+    return text
+
+def resolve_function(dotted_path, **params):
+    if dotted_path is None:
+        return fallback_function
+    (module, func) = dotted_path.rsplit('.', 1)
+    func = getattr(__import__(module, {}, {}, [func]), func)
+    return wraps(func)(curry(func, **params))
+
+def inject_callables(config):
+    for key in ('filter', 'preview_filter'):
+        if config[key]:
+            dotted_path, params = config[key]
+        else:
+            dotted_path, params = None, {}
+        config['%s_function' % key] = resolve_function(dotted_path, **params)
+
+# deprecated/backward-compatible settings
+MARKITUP_FILTER = getattr(settings, 'MARKITUP_FILTER', None)
+MARKITUP_PREVIEW_FILTER = getattr(
+    settings, 'MARKITUP_PREVIEW_FILTER', MARKITUP_FILTER)
 MARKITUP_AUTO_PREVIEW = getattr(settings, 'MARKITUP_AUTO_PREVIEW', False)
 MARKITUP_SET = getattr(settings, 'MARKITUP_SET', 'markitup/sets/default')
 MARKITUP_SKIN = getattr(settings, 'MARKITUP_SKIN', 'markitup/skins/simple')
+
+DEFAULT_CONFIG = {
+    'filter': MARKITUP_FILTER,
+    'preview_filter': MARKITUP_PREVIEW_FILTER,
+    'auto_preview': MARKITUP_AUTO_PREVIEW,
+    'set': MARKITUP_SET,
+    'skin': MARKITUP_SKIN,
+    }
+
+DEFAULT_CONFIG_KEY = 'default'
+
+configurations = getattr(
+    settings, 'MARKITUP_CONFIG', (DEFAULT_CONFIG_KEY, DEFAULT_CONFIG))
+
+MARKITUP_CONFIG = {}
+for name, params in configurations:
+    MARKITUP_CONFIG[name] = dict(DEFAULT_CONFIG, **params)
+    # TODO: handle this more elegantly:
+    if MARKITUP_CONFIG[name]['preview_filter'] is None:
+        MARKITUP_CONFIG[name]['preview_filter'] = \
+            MARKITUP_CONFIG[name]['filter']
+    inject_callables(MARKITUP_CONFIG[name])
+
+if not DEFAULT_CONFIG_KEY in MARKITUP_CONFIG:
+    # inject copy of first configuration as under default key if not present
+    MARKITUP_CONFIG[DEFAULT_CONFIG_KEY] = MARKITUP_CONFIG[configurations[0][0]]
+
+def get_filter_function(config_key, preview=False, fail_silently=True):
+    try:
+        function_key = \
+            'preview_filter_function' if preview else 'filter_function'
+        return MARKITUP_CONFIG[config_key][function_key]
+    except KeyError:
+        if fail_silently:
+            return fallback_function
+        else:
+            raise
+
 JQUERY_URL = getattr(
     settings, 'JQUERY_URL',
     'http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js')

File markitup/static/markitup/sets/default/set.js

 // ----------------------------------------------------------------------------
 // Basic set. Feel free to add more tags
 // ----------------------------------------------------------------------------
-mySettings = {	
+if(typeof mySettings === 'undefined'){
+    var mySettings = {};
+}
+mySettings['default'] = {
 	onShiftEnter:  	{keepDefault:false, replaceWith:'<br />\n'},
 	onCtrlEnter:  	{keepDefault:false, openWith:'\n<p>', closeWith:'</p>'},
 	onTab:    		{keepDefault:false, replaceWith:'    '},

File markitup/static/markitup/sets/markdown/set.js

 // -------------------------------------------------------------------
 // Feel free to add more tags
 // -------------------------------------------------------------------
-mySettings = {
+if(typeof mySettings === 'undefined'){
+    var mySettings = {};
+}
+mySettings['markdown'] = {
 	onShiftEnter:		{keepDefault:false, openWith:'\n\n'},
 	markupSet: [
 		{name:'First Level Heading', key:'1', placeHolder:'Your title here...', closeWith:function(markItUp) { return miu.markdownTitle(markItUp, '=') } },

File markitup/static/markitup/sets/restructuredtext/set.js

 // Jannis Leidel <jannis@leidel.info>
 // http://enn.io
 // -------------------------------------------------------------------
-mySettings = {
+if(typeof mySettings === 'undefined'){
+    var mySettings = {};
+}
+mySettings['ReST'] = {
 	nameSpace: 'ReST',
 	onShiftEnter: {keepDefault:false, openWith:'\n\n'},
 	onTab: {keepDefault:false, replaceWith:'    '},

File markitup/static/markitup/sets/textile/set.js

 // -------------------------------------------------------------------
 // Feel free to add more tags
 // -------------------------------------------------------------------
-mySettings = {
+if(typeof mySettings === 'undefined'){
+    var mySettings = {};
+}
+mySettings['textile'] = {
 	onShiftEnter:		{keepDefault:false, replaceWith:'\n\n'},
 	markupSet: [
 		{name:'Heading 1', key:'1', openWith:'h1(!(([![Class]!]))!). ', placeHolder:'Your title here...' },

File markitup/templatetags/markitup_tags.py

 from django import template
 from django.core.urlresolvers import reverse, NoReverseMatch
-from markitup import settings
-from markitup.util import absolute_url
-from markitup.fields import render_func
+from . import settings
+from .util import absolute_url
 
 register = template.Library()
 
+@register.filter
+def render_markup(content, config_key='default'):
+    return settings.get_filter_function(config_key)(content)
 
-@register.filter
-def render_markup(content):
-    return render_func(content)
-
-
+# TODO: update the rest of this to use the new settings configuration
 
 # we do some funny stuff here for testability (the tests need to be
 # able to force a recalculation of this context)

File markitup/urls.py

-from django.conf.urls.defaults import *
-
-from markitup.views import apply_filter
+from django.conf.urls.defaults import patterns, url
+from .views import apply_filter
 
 urlpatterns = patterns(
     '',
-    url(r'preview/$', apply_filter, name='markitup_preview')
+    url(r'preview/$', apply_filter, name='markitup_preview'),
+    url(r'preview/(?P<config_key>[\w\-]+)/$', apply_filter,
+        name='markitup_preview')
     )

File markitup/util.py

 import posixpath
 from django.conf import settings as django_settings
-from markitup import settings
+from . import settings
 
 def absolute_url(path, prefix=None):
     if prefix is None:
         prefix = django_settings.STATIC_URL
-    if path.startswith(u'http://') or path.startswith(u'https://') or path.startswith(u'/'):
+    if path.startswith(u'http://') or path.startswith(u'https://') or \
+            path.startswith(u'/'):
         return path
     return posixpath.join(prefix, path)
+
+

File markitup/views.py

 from django.shortcuts import render_to_response
 from django.template import RequestContext
+from . import settings
 
-from markitup import settings
-from markitup.markup import filter_func
-
-def apply_filter(request):
-    markup = filter_func(request.POST.get('data', ''))
-    return render_to_response( 'markitup/preview.html',
-                              {'preview': markup},
-                              context_instance=RequestContext(request))
+def apply_filter(request, config_key='default'):
+    markup = settings.get_filter_function(config_key, preview=True)(
+        request.POST.get('data', ''))
+    context = RequestContext(request)
+    return render_to_response('markitup/preview.html', {'preview': markup})

File markitup/widgets.py

 from django.contrib.admin.widgets import AdminTextareaWidget
 from django.core.urlresolvers import reverse, NoReverseMatch
 
-from markitup import settings
-from markitup.util import absolute_url
+from . import settings
+from .util import absolute_url
 import posixpath
 
 class MarkupInput(forms.Widget):
     def __init__(self, attrs=None,
                  markitup_set=None,
                  markitup_skin=None,
-                 auto_preview=None):
+                 auto_preview=None,
+                 config_key=None):
+        self.init_args = { # workaround inflexibility in models.Field.formfield
+            'set': markitup_set,
+            'skin': markitup_skin,
+            'auto_preview': auto_preview}
         self.miu_set = absolute_url(markitup_set or settings.MARKITUP_SET)
-        self.miu_skin = absolute_url(markitup_skin or settings.MARKITUP_SKIN)
+        self.miu_skin = absolute_url(
+            markitup_skin or settings.MARKITUP_SKIN)
         if auto_preview is None:
             auto_preview = settings.MARKITUP_AUTO_PREVIEW
         self.auto_preview = auto_preview
         super(MarkItUpWidget, self).__init__(attrs)
 
+    def set_config(self, config_key):
+        self.config_key = config_key
+        config = settings.MARKITUP_CONFIG[self.config_key]
+        if self.init_args['set'] is None: # avoid clobbering overrides
+            self.miu_set = absolute_url(config['set'])
+        if self.init_args['skin'] is None:
+            self.miu_skin = absolute_url(config['skin'])
+        if self.init_args['auto_preview'] is None:
+            self.auto_preview = config['auto_preview']
+
     def _media(self):
         js_media = [absolute_url(settings.JQUERY_URL)] if settings.JQUERY_URL is not None else []
         js_media = js_media + [absolute_url('markitup/ajax_csrf.js'),
         else: auto_preview = ''
 
         try:
+            args = (self.config_key,) if self.config_key else ()
             preview_url = (
-                'mySettings["previewParserPath"] = "%s";'
-                % reverse('markitup_preview'))
+                'localSettings["previewParserPath"] = "%s";'
+                % reverse('markitup_preview', args=args))
         except NoReverseMatch:
-           preview_url = "";
+            preview_url = ""
 
         html += """
         <script type="text/javascript">
         (function($) {
           $(document).ready(function() {
             var element = $("#%(id)s");
+            var localSettings = $.extend(
+                true, {}, mySettings['%(config_key)s']);
             if(!element.hasClass("markItUpEditor")) {
               %(preview_url)s
-              element.markItUp(mySettings);
+              element.markItUp(localSettings);
             }
             %(auto_preview)s
           });
           })(jQuery);
         </script>
         """ % {'id': final_attrs['id'], 'auto_preview': auto_preview,
-               'preview_url': preview_url}
+               'preview_url': preview_url,
+               'config_key': self.config_key or settings.DEFAULT_CONFIG_KEY}
 
         return mark_safe(html)