import inspect\r
\r
class DecoratableObject(object):\r
+ MODE_OVERRIDE = 0\r
+ MODE_PARAMS = 1\r
+ MODE_RESULT = 2\r
+\r
def __init__(self, fn):\r
+ a = inspect.getargspec(fn)\r
self._callable = fn\r
+ self._params_decoration = None\r
+ self._result_decoration = None\r
\r
- def _decorate(self, fn, needs_origin):\r
+ def _decorate(self, fn, needs_origin, method=False):\r
origin = self._callable\r
\r
if needs_origin:\r
- self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)\r
+ if method:\r
+ self._callable = lambda inst, *args, **kwargs: fn(inst, origin, *args, **kwargs)\r
+ else:\r
+ self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)\r
else:\r
- self._callable = lambda *args, **kwargs: fn(*args, **kwargs)\r
+ self._callable = fn\r
\r
- def _decorate_method(self, fn, needs_origin):\r
- origin = self._callable\r
+ def _decorate_params(self, fn):\r
+ if not self._params_decoration:\r
+ self._params_decoration = []\r
\r
- if needs_origin:\r
- self._callable = lambda inst, *args, **kwargs: fn(inst, origin, *args, **kwargs)\r
- else:\r
- self._callable = lambda inst, *args, **kwargs: fn(inst, *args, **kwargs)\r
+ self._params_decoration.append(fn)\r
\r
+ def _decorate_result(self, fn):\r
+ if not self._result_decoration:\r
+ self._result_decoration = []\r
+\r
+ self._result_decoration.append(fn)\r
\r
def __call__(self, *args, **kwargs):\r
- return self._callable(*args, **kwargs)\r
+ if self._params_decoration:\r
+ for dec in self._params_decoration:\r
+ args, kwargs = dec(*args, **kwargs)\r
+\r
+ res = self._callable(*args, **kwargs)\r
+\r
+ if self._result_decoration:\r
+ for dec in self._result_decoration:\r
+ res = dec(res)\r
\r
+ return res\r
+\r
+\r
+def _create_decorator(origin, needs_origin, mode, method=False):\r
+ def decorator(fn):\r
+ if mode == DecoratableObject.MODE_OVERRIDE:\r
+ origin._decorate(fn, needs_origin, method=method)\r
+ elif mode == DecoratableObject.MODE_PARAMS:\r
+ origin._decorate_params(fn)\r
+ elif mode == DecoratableObject.MODE_RESULT:\r
+ origin._decorate_result(fn)\r
+\r
+ return fn\r
+\r
+ return decorator\r
\r
-def _decorate_method(origin, needs_origin):\r
+\r
+def _decorate_method(origin, needs_origin, mode):\r
if not hasattr(origin, '_decoratable_obj'):\r
name = origin.__name__\r
cls = origin.im_class\r
else:\r
decoratable = origin._decoratable_obj\r
\r
- def decorator(fn):\r
- decoratable._decorate_method(fn, needs_origin)\r
-\r
- return decorator\r
+ return _create_decorator(decoratable, needs_origin, mode, method=True)\r
\r
-def _decorate_function(origin, needs_origin):\r
+def _decorate_function(origin, needs_origin, mode):\r
if not isinstance(origin, DecoratableObject):\r
mod = inspect.getmodule(origin)\r
\r
name = origin.__name__\r
origin = DecoratableObject(origin)\r
- setattr(mod, name, DecoratableObject(origin))\r
+ setattr(mod, name, origin)\r
+\r
+ return _create_decorator(origin, needs_origin, mode)\r
+\r
+\r
+def decorate(origin, needs_origin=True, mode=DecoratableObject.MODE_OVERRIDE):\r
+ if inspect.ismethod(origin):\r
+ return _decorate_method(origin, needs_origin, mode)\r
+\r
+ if inspect.isfunction(origin) or isinstance(origin, DecoratableObject):\r
+ return _decorate_function(origin, needs_origin, mode)\r
\r
def decorator(fn):\r
- origin._decorate(fn, needs_origin)\r
+ return fn\r
\r
- return decorator\r
\r
+def _decorate_params(origin):\r
+ return decorate(origin, mode=DecoratableObject.MODE_PARAMS)\r
\r
-def decorate(origin, needs_origin=True):\r
- if inspect.ismethod(origin):\r
- return _decorate_method(origin, needs_origin)\r
+decorate.params = _decorate_params\r
+\r
+def _decorate_result(origin):\r
+ return decorate(origin, mode=DecoratableObject.MODE_RESULT)\r
\r
- if inspect.isfunction(origin):\r
- return _decorate_function(origin, needs_origin)
\ No newline at end of file
+decorate.result = _decorate_result\r
--- /dev/null
+
+
+class Registry(list):
+ def add(self, register):
+ for i, r in enumerate(self):
+ if r.weight > register.weight:
+ self.insert(i, register)
+ return
+
+ self.append(register)
+
+"""Links next in the very top of the page"""
+HEADER_LINKS = 'HEADER_LINKS'
+
+"""The tabs next to the top of the page"""
+PAGE_TOP_TABS = 'PAGE_TOP_TABS'
+
+
+__CONTAINER = {
+ HEADER_LINKS: Registry(),
+ PAGE_TOP_TABS: Registry()
+}
+
+
+def register(registry, ui_object):
+ if not registry in __CONTAINER:
+ raise('unknown registry')
+
+ __CONTAINER[registry].add(ui_object)
+
+def register_multi(registry, *ui_objects):
+ for ui_object in ui_objects:
+ register(registry, ui_object)
+
+
+def get_registry_by_name(name):
+ name = name.upper()
+
+ if not name in __CONTAINER:
+ raise('unknown registry')
+
+ return __CONTAINER[name]
+
+
+
+from ui_objects import *
+
--- /dev/null
+from django.core.urlresolvers import reverse
+from forum.utils import html
+
+class UiObjectUserLevelBase(object):
+ def show_to(self, user):
+ return True
+
+class SuperuserUiObject(UiObjectUserLevelBase):
+ def show_to(self, user):
+ return user.is_superuser
+
+class StaffUiObject(UiObjectUserLevelBase):
+ def show_to(self, user):
+ return user.is_staff or user.is_superuser
+
+class ReputedUserUiObject(UiObjectUserLevelBase):
+ def __init__(self, min_rep):
+ self.min_rep = min_rep
+
+ def show_to(self, user):
+ return user.is_authenticated() and user.reputation >= int(self.min_rep)
+
+class LoggedInUserUiObject(UiObjectUserLevelBase):
+ def show_to(self, user):
+ return user.is_authenticated()
+
+class PublicUiObject(UiObjectUserLevelBase):
+ pass
+
+
+
+class UiObjectArgument(object):
+ def __init__(self, argument):
+ self.argument = argument
+
+ def __call__(self, context):
+ if callable(self.argument):
+ return self.argument(context)
+ else:
+ return self.argument
+
+
+class UiObjectBase(object):
+ def __init__(self, user_level=None, weight=500):
+ self.user_level = user_level or PublicUiObject()
+ self.weight = weight
+
+ def can_render(self, context):
+ return self.user_level.show_to(context['request'].user)
+
+ def render(self, context):
+ return ''
+
+class UiLoopObjectBase(UiObjectBase):
+ def update_context(self, context):
+ pass
+
+
+
+class UiLinkObject(UiObjectBase):
+ def __init__(self, text, url, attrs=None, pre_code='', post_code='', user_level=None, weight=500):
+ super(UiLinkObject, self).__init__(user_level, weight)
+ self.text = UiObjectArgument(text)
+ self.url = UiObjectArgument(url)
+ self.attrs = UiObjectArgument(attrs or {})
+ self.pre_code = UiObjectArgument(pre_code)
+ self.post_code = UiObjectArgument(post_code)
+
+ def render(self, context):
+ return "%s %s %s" % (self.pre_code(context),
+ html.hyperlink(self.url(context), self.text(context), **self.attrs(context)),
+ self.post_code(context))
+
+
+class UiLoopContextObject(UiLoopObjectBase):
+ def __init__(self, loop_context, user_level=None, weight=500):
+ super(UiLoopContextObject, self).__init__(user_level, weight)
+ self.loop_context = UiObjectArgument(loop_context)
+
+ def update_context(self, context):
+ context.update(self.loop_context(context))
+
+
+class UiTopPageTabObject(UiLoopObjectBase):
+ def __init__(self, tab_name, tab_title, url_pattern, weight):
+ super(UiTopPageTabObject, self).__init__(weight=weight)
+ self.tab_name = tab_name
+ self.tab_title = tab_title
+ self.url_pattern = url_pattern
+
+ def update_context(self, context):
+ context.update(dict(
+ tab_name=self.tab_name,
+ tab_title=self.tab_title,
+ tab_url=reverse(self.url_pattern)
+ ))
use_skin = ''
return None
return use_skin + '/' + url
+
+
+
<!-- template header.html -->
-{% load extra_tags %}
-{% load i18n %}
+{% load extra_tags ui_registry i18n %}
+
<div id="roof">
<div id="navBar">
<div id="top">
- {% if request.user.is_authenticated %}
- {% if request.user.is_superuser %}
- <a href="{% url admin_index %}">{% trans "administration" %}</a>
- {% endif %}
- <a href="{{ request.user.get_profile_url }}">{{ request.user.username }}</a> {% get_score_badge request.user %}
- <a href="{% url logout %}">{% trans "logout" %}</a>
- {% else %}
- <a href="{% url auth_signin %}">{% trans "login" %}</a>
- {% endif %}
- <a href="{% url about %}">{% trans "about" %}</a>
- <a href="{% url faq %}">{% trans "faq" %}</a>
+ {% loadregistry header_links %}
</div>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
</td>
<td width="77%" valign="bottom">
<div class="nav">
- <a id="nav_questions"{% ifequal tab "questions" %} class="on"{% endifequal %} href="{% url questions %}" >{% trans "questions" %}</a>
- <a id="nav_tags"{% ifequal tab "tags" %} class="on"{% endifequal %} href="{% url tags %}">{% trans "tags" %}</a>
- <a id="nav_users"{% ifequal tab "users" %} class="on"{% endifequal %} href="{% url users %}">{% trans "users" %}</a>
- <a id="nav_badges"{% ifequal tab "badges" %} class="on"{% endifequal %} href="{% url badges %}">{% trans "badges" %}</a>
- <a id="nav_unanswered"{% ifequal tab "unanswered" %} class="on"{% endifequal %} href="{% url unanswered %}">{% trans "unanswered questions" %}</a>
+ {% loopregistry page_top_tabs %}{% spaceless %}
+ <a id="nav_{{ tab_name }}"{% ifequal tab tab_name %} class="on"{% endifequal %} href="{{ tab_url }}" >{{ tab_title }}</a>
+ {% endspaceless %}{% endloopregistry %}
<div class="focus">
<a id="nav_ask" href="{% url ask %}" class="special">{% trans "ask a question" %}</a>
</div>
import os
sys.path.append(os.path.join(os.path.dirname(__file__),'markdownext'))
-import forum.views
+
+from forum.modules import get_modules_script, ui
+
+get_modules_script('settings')
+get_modules_script('startup')
+
import forum.badges
import forum.subscriptions
-from forum.modules import get_modules_script
-get_modules_script('settings')
-get_modules_script('startup')
\ No newline at end of file
+from django.utils.translation import ugettext as _
+from django.core.urlresolvers import reverse
+from forum.templatetags.extra_tags import get_score_badge
+
+
+ui.register_multi(ui.HEADER_LINKS,
+ ui.UiLinkObject(_('faq'), 'faq', weight=400),
+ ui.UiLinkObject(_('about'), 'about', weight=300),
+
+ ui.UiLinkObject(
+ text=lambda c: c['request'].user.is_authenticated() and _('logout') or _('login'),
+ url=lambda c: c['request'].user.is_authenticated() and reverse('logout') or reverse('auth_signin'),
+ weight=200),
+
+ ui.UiLinkObject(
+ user_level=ui.LoggedInUserUiObject(),
+ text=lambda c: c['request'].user.username,
+ url=lambda c: c['request'].user.get_profile_url(),
+ post_code=lambda c: get_score_badge(c['request'].user),
+ weight=100),
+
+ ui.UiLinkObject(
+ user_level=ui.SuperuserUiObject(),
+ text=_('administration'),
+ url=lambda c: reverse('admin_index'),
+ weight=0)
+
+)
+
+
+ui.register_multi(ui.PAGE_TOP_TABS,
+ ui.UiTopPageTabObject('questions', _('questions'), 'questions', weight=0),
+ ui.UiTopPageTabObject('tags', _('tags'), 'tags', weight=100),
+ ui.UiTopPageTabObject('users', _('users'), 'users', weight=200),
+ ui.UiTopPageTabObject('badges', _('badges'), 'badges', weight=300),
+ ui.UiTopPageTabObject('unanswered', _('unanswered questions'), 'unanswered', weight=400),
+)
+
+#register.header_link(lambda c: (_('faq'), reverse('faq')))
+
+
+
--- /dev/null
+from django import template
+from forum.modules import ui
+
+register = template.Library()
+
+
+class LoadRegistryNode(template.Node):
+ def __init__(self, registry):
+ self.registry = registry
+
+ def render(self, context):
+ result = ''
+
+ for ui_object in self.registry:
+ if ui_object.can_render(context):
+ result += ui_object.render(context)
+
+ return result
+
+
+@register.tag
+def loadregistry(parser, token):
+ try:
+ tag_name, registry = token.split_contents()
+ except ValueError:
+ raise template.TemplateSyntaxError, "%r tag requires exactly one argument" % token.contents.split()[0]
+
+ registry = ui.get_registry_by_name(registry)
+ return LoadRegistryNode(registry)
+
+
+class LoopRegistryNode(template.Node):
+ def __init__(self, registry, nodelist):
+ self.registry = registry
+ self.nodelist = nodelist
+
+ def render(self, context):
+ result = ''
+
+ for ui_object in self.registry:
+ if ui_object.can_render(context):
+ ui_object.update_context(context)
+ result += self.nodelist.render(context)
+
+ return result
+
+@register.tag
+def loopregistry(parser, token):
+ try:
+ tag_name, registry = token.split_contents()
+ except ValueError:
+ raise template.TemplateSyntaxError, "%r tag requires exactly one argument" % token.contents.split()[0]
+
+ registry = ui.get_registry_by_name(registry)
+ nodelist = parser.parse(('endloopregistry',))
+ parser.delete_first_token()
+
+ return LoopRegistryNode(registry, nodelist)
\ No newline at end of file
return mark_safe(parser.result)
def buildtag(name, content, **attrs):
- return mark_safe('<%s %s>%s</a>' % (name, " ".join('%s="%s"' % i for i in attrs.items()), content))
+ return mark_safe('<%s %s>%s</a>' % (name, " ".join('%s="%s"' % i for i in attrs.items()), str(content)))
def hyperlink(url, title, **attrs):
return mark_safe('<a href="%s" %s>%s</a>' % (url, " ".join('%s="%s"' % i for i in attrs.items()), title))