From d2410575d72f68d7777c4344600b1af75f2515c1 Mon Sep 17 00:00:00 2001 From: hernani Date: Sat, 19 Jun 2010 02:04:14 +0000 Subject: [PATCH] Starts preparing the app for module based html injection. git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@438 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- forum/modules/decorators.py | 93 ++++++++++++++++------ forum/modules/ui.py | 47 +++++++++++ forum/modules/ui_objects.py | 96 +++++++++++++++++++++++ forum/skins/__init__.py | 3 + forum/skins/default/templates/header.html | 24 ++---- forum/startup.py | 52 +++++++++++- forum/templatetags/ui_registry.py | 58 ++++++++++++++ forum/utils/html.py | 2 +- 8 files changed, 328 insertions(+), 47 deletions(-) create mode 100644 forum/modules/ui.py create mode 100644 forum/modules/ui_objects.py create mode 100644 forum/templatetags/ui_registry.py diff --git a/forum/modules/decorators.py b/forum/modules/decorators.py index 90109a9..8fbee7e 100644 --- a/forum/modules/decorators.py +++ b/forum/modules/decorators.py @@ -1,31 +1,68 @@ import inspect class DecoratableObject(object): + MODE_OVERRIDE = 0 + MODE_PARAMS = 1 + MODE_RESULT = 2 + def __init__(self, fn): + a = inspect.getargspec(fn) self._callable = fn + self._params_decoration = None + self._result_decoration = None - def _decorate(self, fn, needs_origin): + def _decorate(self, fn, needs_origin, method=False): origin = self._callable if needs_origin: - self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs) + if method: + self._callable = lambda inst, *args, **kwargs: fn(inst, origin, *args, **kwargs) + else: + self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs) else: - self._callable = lambda *args, **kwargs: fn(*args, **kwargs) + self._callable = fn - def _decorate_method(self, fn, needs_origin): - origin = self._callable + def _decorate_params(self, fn): + if not self._params_decoration: + self._params_decoration = [] - if needs_origin: - self._callable = lambda inst, *args, **kwargs: fn(inst, origin, *args, **kwargs) - else: - self._callable = lambda inst, *args, **kwargs: fn(inst, *args, **kwargs) + self._params_decoration.append(fn) + def _decorate_result(self, fn): + if not self._result_decoration: + self._result_decoration = [] + + self._result_decoration.append(fn) def __call__(self, *args, **kwargs): - return self._callable(*args, **kwargs) + if self._params_decoration: + for dec in self._params_decoration: + args, kwargs = dec(*args, **kwargs) + + res = self._callable(*args, **kwargs) + + if self._result_decoration: + for dec in self._result_decoration: + res = dec(res) + return res + + +def _create_decorator(origin, needs_origin, mode, method=False): + def decorator(fn): + if mode == DecoratableObject.MODE_OVERRIDE: + origin._decorate(fn, needs_origin, method=method) + elif mode == DecoratableObject.MODE_PARAMS: + origin._decorate_params(fn) + elif mode == DecoratableObject.MODE_RESULT: + origin._decorate_result(fn) + + return fn + + return decorator -def _decorate_method(origin, needs_origin): + +def _decorate_method(origin, needs_origin, mode): if not hasattr(origin, '_decoratable_obj'): name = origin.__name__ cls = origin.im_class @@ -40,28 +77,36 @@ def _decorate_method(origin, needs_origin): else: decoratable = origin._decoratable_obj - def decorator(fn): - decoratable._decorate_method(fn, needs_origin) - - return decorator + return _create_decorator(decoratable, needs_origin, mode, method=True) -def _decorate_function(origin, needs_origin): +def _decorate_function(origin, needs_origin, mode): if not isinstance(origin, DecoratableObject): mod = inspect.getmodule(origin) name = origin.__name__ origin = DecoratableObject(origin) - setattr(mod, name, DecoratableObject(origin)) + setattr(mod, name, origin) + + return _create_decorator(origin, needs_origin, mode) + + +def decorate(origin, needs_origin=True, mode=DecoratableObject.MODE_OVERRIDE): + if inspect.ismethod(origin): + return _decorate_method(origin, needs_origin, mode) + + if inspect.isfunction(origin) or isinstance(origin, DecoratableObject): + return _decorate_function(origin, needs_origin, mode) def decorator(fn): - origin._decorate(fn, needs_origin) + return fn - return decorator +def _decorate_params(origin): + return decorate(origin, mode=DecoratableObject.MODE_PARAMS) -def decorate(origin, needs_origin=True): - if inspect.ismethod(origin): - return _decorate_method(origin, needs_origin) +decorate.params = _decorate_params + +def _decorate_result(origin): + return decorate(origin, mode=DecoratableObject.MODE_RESULT) - if inspect.isfunction(origin): - return _decorate_function(origin, needs_origin) \ No newline at end of file +decorate.result = _decorate_result diff --git a/forum/modules/ui.py b/forum/modules/ui.py new file mode 100644 index 0000000..5cfcac4 --- /dev/null +++ b/forum/modules/ui.py @@ -0,0 +1,47 @@ + + +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 * + diff --git a/forum/modules/ui_objects.py b/forum/modules/ui_objects.py new file mode 100644 index 0000000..01a61d3 --- /dev/null +++ b/forum/modules/ui_objects.py @@ -0,0 +1,96 @@ +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) + )) diff --git a/forum/skins/__init__.py b/forum/skins/__init__.py index be6bd4f..7a7e0cd 100644 --- a/forum/skins/__init__.py +++ b/forum/skins/__init__.py @@ -55,3 +55,6 @@ def find_media_source(url): use_skin = '' return None return use_skin + '/' + url + + + diff --git a/forum/skins/default/templates/header.html b/forum/skins/default/templates/header.html index 64056b6..12a684a 100644 --- a/forum/skins/default/templates/header.html +++ b/forum/skins/default/templates/header.html @@ -1,20 +1,10 @@ -{% load extra_tags %} -{% load i18n %} +{% load extra_tags ui_registry i18n %} +