-
Notifications
You must be signed in to change notification settings - Fork 0
mixerlabs/widgets
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A WORD OF CAUTION This is currently just a code drop of our widget publication system. It will need some work (mostly reshuffling of imports) to be installable as an independent Django app. If you have any interest in this, please send us a message (through GitHub), and we'll be glad to help! INTRODUCTION Widgets provide componentized editing of pages, taking care of most things for you, so you are free to write your components without much care of state, history, page placement, interference with other widgets, etc. Widgets have their state automatically handled by pickling and unpickling their python object instances. Widgets are kept in a tree, and updates trickle up to the root so that it always contains the latest references. Every state ever "frozen" is kept, and can thus be reached from page histories, reverted, diff'd against, etc. API Widgets are responsible for rendering themselves to HTML. The parent page places this correctly within the page, and can dynamically update it through AJAX requests. Widgets also need to be able to render an *editor*, which modifies state on the widget. To help with inline editing, a number of utilities are provided to ease AJAX interaction, both in the (Python) views & as django template helpers to make the call from the client side. The heading widget views are defined fully as follows (a serendipitous example as it contains exactly the set of required implementations): from .widget import Widget from .router import view, ajax, render_template_with_namespace class Heading(Widget): """The heading widget providers headers""" css_container = 'header' css_hover = 'header-over' def __init__(self): super(Heading, self).__init__() self.contents = 'Untitled' def render(self): return '<h2>%s</h2>' % self.contents @render_template_with_namespace def render_edit(self): return 'widgets/_edit_heading.html', {'widget': self} @ajax('edit') def edit(self): return self.render_edit() @ajax('save') def save(self, contents): self.contents = contents self.freeze() return self.render() ``render'' simply returns the HTML necessary to render the widget in situ whereas ``render_edit'' returns the HTML necessary to render the heading editor. The ajax callbacks are: ``edit'': Called by the page whenever the user wishes to edit the widget contents. Returns the HTML necessary to render the editor. ``save'': Called by the page when the user wishes to save the edits made. Returns the HTML necessary to render the widget in situ. The decorator ``render_template_with_namespace'' provides template namespacing for the widget. In the template, any '__' strings are substituted by a string unique to *that particular instance* of the widget. Similarly, '___' strings are substituted by one unique for that instance *and* the template, thus these are analogous to "protected" and "private" namespaces for widget-templates. Namespaces are also to comply with the client-side page API. Here is the template code for rendering: {% load widgets %} <input id="__input" type="text" value="{{ widget.contents }}"></input> <script type="text/javascript"> function __save(cb) { {% call widget "save" %} { contents: $("#__input").val() } {% callback data %} __html(data) cb() {% endcall %} }; </script> Pretty self-explanatory. The page API *provides* ``__html'' (which is actually namespaced by the aforementioned method), and each widget editor has to *define* ``__save''. The page calls into ``__save'' whenever the user hits the save button. Here the template calls into the widget (using the ``call'' template tag to generate the necessary AJAX code), providing a callback (``cb'') to be called whenever the widget is finished saving. The heading widget calls ``__html'' with the new rendered widget (returned from the AJAX call) before telling the page its save is complete. DELEGATES & PAGES Toplevel widgets (ie. pages) sit at the roots of widget trees. These avail themselves of a *delegate* -- a convention of callbacks that provide certain hosted functionality. For example, the toplevel ``reverse()'' calls into its delegate to reverse the path that precedes the widget hierarchy.
About
mixerlabs' widgets publishing system
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published