Source code for ferris.core.views

import template
import json_util
from protorpc import protojson
from protorpc.message_types import VoidMessage
from ferris.core.events import ViewEvents

_views = {}


def factory(name):
    """
    Creates a view instance by name
    """
    global _views
    return _views.get(name.lower(), _views.get((name + 'View').lower()))


class ViewContext(dict):
    def get_dotted(self, name, default=None):
        data = self
        path = name.split('.')
        for chunk in path[:-1]:
            data = data.setdefault(chunk, {})
        return data.setdefault(path[-1], default)

    def set_dotted(self, name, value):
        path = name.split('.')
        container = self.get_dotted('.'.join(path[:-1]), {})
        container[path[-1]] = value

    def set(self, **kwargs):
        self.update(**kwargs)


[docs]class View(object): class __metaclass__(type): def __new__(meta, name, bases, dict): global _views cls = type.__new__(meta, name, bases, dict) if name != 'View': _views[name.lower()] = cls return cls def __init__(self, controller, context=None): self.controller = controller self.auto_render = True if not context: context = ViewContext() if isinstance(context, dict) and not isinstance(context, ViewContext): context = ViewContext(**context) self.context = context self.events = ViewEvents(prefix='view') def render(self, *args, **kwargs): raise NotImplementedError("Base view can't render anything")
[docs]class TemplateView(View): def __init__(self, controller, context=None): super(TemplateView, self).__init__(controller, context) self.template_name = None self.template_ext = 'html' self.theme = None self.setup_template_variables() def setup_template_variables(self): self.context.get_dotted('this', {}).update({ 'route': self.controller.route, 'name': self.controller.name, 'uri': self.controller.uri, 'uri_exists': self.controller.uri_exists, 'on_uri': self.controller.on_uri, 'request': self.controller.request, 'self': self.controller, 'encode_key': self.controller.util.encode_key, 'decode_key': self.controller.util.decode_key, 'user': self.controller.user, 'events': self.events }) self.context.update({ 'route': self.controller.route, 'uri': self.controller.uri, 'uri_exists': self.controller.uri_exists, 'on_uri': self.controller.on_uri, 'request': self.controller.request, 'user': self.controller.user }) self.controller.events.setup_template_variables(controller=self.controller) def render(self, *args, **kwargs): self.controller.events.before_render(controller=self.controller) result = template.render_template(self.get_template_names(), self.context, theme=self.theme) self.controller.response.content_type = 'text/html' self.controller.response.charset = 'utf-8' self.controller.response.unicode_body = result self.controller.events.after_render(controller=self.controller, result=result) return self.controller.response def get_template_names(self): """ Generates a list of template names. The template engine will try each template in the list until it finds one. For non-prefixed actions, the return value is simply: ``[ "[controller]/[action].[ext]" ]``. For prefixed actions, another entry is added to the list : ``[ "[controller]/[prefix_][action].[ext]" ]``. This means that actions that are prefixed can fallback to using the non-prefixed template. For example, the action ``Posts.json_list`` would try these templates:: posts/json_list.html posts/list.html """ if self.template_name: return self.template_name templates = [] template_path = "%s/" % self.controller.name action_name = "%s.%s" % (self.controller.route.action, self.template_ext) templates.append("%s%s" % (template_path, action_name)) if self.controller.route.prefix: templates.insert(0, "%s%s_%s" % (template_path, self.controller.route.prefix, action_name)) self.controller.events.template_names(controller=self.controller, templates=templates) return templates
[docs]class JsonView(View): def __init__(self, controller, context=None): super(JsonView, self).__init__(controller, context) self.variable_name = ('data',) def _get_data(self, default=None): self.variable_name = self.variable_name if isinstance(self.variable_name, (list, tuple)) else (self.variable_name,) if hasattr(self.controller, 'scaffold'): self.variable_name += (self.controller.scaffold.singular, self.controller.scaffold.plural) for v in self.variable_name: data = self.context.get(v, None) if data: return data return default def render(self, *args, **kwargs): self.controller.events.before_render(controller=self.controller) result = unicode(json_util.stringify(self._get_data())) self.controller.response.content_type = 'application/json' self.controller.response.charset = 'utf-8' self.controller.response.unicode_body = result self.controller.events.after_render(controller=self.controller, result=result) return self.controller.response
[docs]class MessageView(JsonView): def render(self, *args, **kwargs): self.controller.events.before_render(controller=self.controller) data = self._get_data(default=VoidMessage()) result = unicode(protojson.encode_message(data)) self.controller.response.content_type = 'application/json' self.controller.response.charset = 'utf-8' self.controller.response.unicode_body = result self.controller.events.after_render(controller=self.controller, result=result) return self.controller.response