class ChoiceParameterView(_ParameterViewMixin, Element): """ View definition for L{Parameter} instances with type of C{CHOICE_INPUT}. """ implements(IParameterView) patternName = 'choice' def multiple(self, request, tag): """ Render a I{multiple} attribute on the given tag if the wrapped L{ChoiceParameter} instance allows multiple selection. """ if self.parameter.multiple: tag(multiple='multiple') return tag renderer(multiple) def options(self, request, tag): """ Render each of the options of the wrapped L{ChoiceParameter} instance. """ option = tag.patternGenerator('option') return tag[[ OptionView(index, o, option()) for (index, o) in enumerate(self.parameter.choices) ]] renderer(options)
class OptionView(Element): """ View definition for a single choice of a L{ChoiceParameter}. @type option: L{Option} """ def __init__(self, index, option, tag): self._index = index self.option = option self.docFactory = stan(tag) def __eq__(self, other): """ Define equality such other L{OptionView} instances which wrap the same L{Option} are considered equal to this one. """ if isinstance(other, OptionView): return self.option is other.option return False def __ne__(self, other): """ Define inequality as the negation of equality. """ return not self.__eq__(other) def description(self, request, tag): """ Render the description of the wrapped L{Option} instance. """ return tag[self.option.description] renderer(description) def value(self, request, tag): """ Render the value of the wrapped L{Option} instance. """ return tag[self.option.value] renderer(value) def index(self, request, tag): """ Render the index specified to C{__init__}. """ return tag[self._index] renderer(index) def selected(self, request, tag): """ Render a selected attribute on the given tag if the wrapped L{Option} instance is selected. """ if self.option.selected: tag(selected='selected') return tag renderer(selected)
class AddBlogPostDialogFragment(AddBlogPostFragment): """ L{AddBlogPostFragment} subclass for making comments of type L{FLAVOR.BLOG_POST} """ jsClass = u'Hyperbola.AddBlogPostDialog' fragmentName = 'add-comment/' + FLAVOR.BLOG_POST + '-dialog' def postTitle(self, req, tag): """ Determine a preset value for the title of the comment, by looking at the C{title} argument in the request. """ return req.args['title'][0] page.renderer(postTitle) def body(self, req, tag): """ Determine a preset value for the body of the comment, by looking at the C{body} argument in the request, and inserting a link to the url specified in the C{url} argument. """ body = req.args['body'][0] url = req.args['url'][0] link = tags.a(href=url)[self.postTitle(req, tag)] return flatten((link, tags.br, body)) page.renderer(body)
class ListChangeParameterView(_ParameterViewMixin, athena.LiveElement): """ L{IParameterView} adapter for L{ListChangeParameter}. @ivar parameter: the parameter being viewed. @type parameter: L{ListChangeParameter} """ jsClass = u'Mantissa.LiveForm.RepeatableForm' patternName = 'repeatable-form' def __init__(self, parameter): self.parameter = parameter athena.LiveElement.__init__(self) def getInitialArguments(self): """ Pass the name of our parameter to the client. """ return (self.parameter.name, ) def forms(self, req, tag): """ Make and return some forms, using L{self.parameter.getInitialLiveForms}. @return: some subforms. @rtype: C{list} of L{LiveForm} """ liveForms = self.parameter.getInitialLiveForms() for liveForm in liveForms: liveForm.setFragmentParent(self) return liveForms page.renderer(forms) def repeatForm(self): """ Make and return a form, using L{self.parameter.asLiveForm}. @return: a subform. @rtype: L{LiveForm} """ liveForm = self.parameter.asLiveForm() liveForm.setFragmentParent(self) return liveForm athena.expose(repeatForm) def repeater(self, req, tag): """ Render some UI for repeating our form. """ repeater = inevow.IQ(self.docFactory).onePattern('repeater') return repeater.fillSlots('object-description', self.parameter.modelObjectDescription) page.renderer(repeater)
class RepeatedLiveFormWrapper(athena.LiveElement): """ A wrapper around a L{LiveForm} which has been repeated via L{ListChangeParameter.asLiveForm}. @ivar liveForm: The repeated liveform. @type liveForm: L{LiveForm} @ivar identifier: An integer identifying this repetition. @type identifier: C{int} @ivar removable: Whether this repetition can be unrepeated/removed. @type removable: C{bool} """ fragmentName = 'repeated-liveform' jsClass = u'Mantissa.LiveForm.RepeatedLiveFormWrapper' def __init__(self, liveForm, identifier, removable=True): athena.LiveElement.__init__(self) self.liveForm = liveForm self.identifier = identifier self.removable = removable def getInitialArguments(self): """ Include the name of the form we're wrapping, and our original values. """ return (self.liveForm.subFormName.decode('utf-8'), self.identifier) def realForm(self, req, tag): """ Render L{liveForm}. """ self.liveForm.setFragmentParent(self) return self.liveForm page.renderer(realForm) def removeLink(self, req, tag): """ Render C{tag} if L{removable} is C{True}, otherwise return the empty string. """ if self.removable: return tag return '' page.renderer(removeLink)
class NestedElement(Nested, Element): def foo(self, request, tag): if self.count: return span[NestedFragment(self.count - 1)] return tag["Hello"] renderer(foo)
class SearchAggregatorFragment(webtheme.ThemedElement): implements(ixmantissa.INavigableFragment) jsClass = u'Mantissa.Search.Search' fragmentName = 'search' def __init__(self, searchResults, store): super(SearchAggregatorFragment, self).__init__() self.searchResults = searchResults self.store = store def head(self): return None def search(self, ctx, data): if self.searchResults: f = scrolltable.SearchResultScrollingFragment( self.store, self.searchResults, (scrolltable.UnsortableColumn(exmess.Message.senderDisplay), scrolltable.UnsortableColumn(exmess.Message.subject), scrolltable.UnsortableColumnWrapper( scrolltable.TimestampAttributeColumn( exmess.Message.sentWhen)), scrolltable.UnsortableColumn(exmess.Message.read))) f.jsClass = u'Quotient.Search.SearchResults' f.setFragmentParent(self) f.docFactory = webtheme.getLoader(f.fragmentName) return f return tags.h2['No results'] renderer(search)
class BlogPostBlurbEditor(liveform.LiveForm): """ Fragment for rendering blog post editing UI """ jsClass = u'Hyperbola.BlogPostBlurbEditorController' fragmentName = 'edit-blog-post' def __init__(self, blogPost): super(BlogPostBlurbEditor, self).__init__( lambda *a, **k: blogPost.edit(newAuthor=blogPost.author, *a, **k), (liveform.Parameter( 'newTitle', liveform.TEXT_INPUT, unicode), liveform.Parameter( 'newBody', liveform.TEXT_INPUT, unicode), liveform.Parameter( 'newTags', liveform.TEXT_INPUT, parseTags))) self.blogPost = blogPost def title(self, req, tag): """ @return: title of our blurb """ return self.blogPost.title page.renderer(title) def body(self, req, tag): """ @return: body of our blurb """ return self.blogPost.body page.renderer(body) def tags(self, req, tag): """ @return tags of our blurb """ return ', '.join(self.blogPost.tags()) page.renderer(tags)
class FileChooser(athena.LiveElement): implements(IFileObserver) jsClass = u'WebbyVellum.FileChooser' docFactory = loaders.xmlfile(RESOURCE('elements/FileChooser')) def __init__(self, user, *a, **kw): super(FileChooser, self).__init__(*a, **kw) self.user = user def chooser(self, req, tag): # get file notifications from the user. set this as early as possible # in the render (which is here) self.user.addObserver(self) self.page.notifyOnDisconnect().addBoth( lambda reason: self.user.removeObserver(self)) return tag[self._getIconsFromDatabase()] page.renderer(chooser) def _getIconsFromDatabase(self): """ @return a list of the choosericons, pre-rendering. """ db = theGlobal['database'] _fileitems = db.query(data.FileMeta, data.FileMeta.user == self.user, sort=data.FileMeta.filename.ascending) ret = [self._newIconFromItem(fi) for fi in _fileitems] return ret def _newIconFromItem(self, fileitem): ch = ChooserIcon(self.user, fileitem) ch.setFragmentParent(self) return ch def fileAdded(self, fileitem): """ Construct a new icon and send it to the browser """ icon = self._newIconFromItem(fileitem) return self.callRemote('fileAdded', icon) def fileRemoved(self, fileitem): """ Get a reference to the LiveElement for that item, and make a .remove call on it directly """ TODO return eelf.fileItems[fileitem].remove(FOO) def fileModified(self, fileitem): """ Get a reference to the LiveElement for that item, and make a .modify call in it. TODO Which parts need to be sent? """ TODO return self.fileItems[fileitem].modify(FOO)
class AnyLiveElement(athena.LiveElement): """ Just some L{LiveElement} subclass, such as an application might define. """ def foo(self, request, tag): requests.append(request) return tag page.renderer(foo)
class OldStyleElement(Element): docFactory = stan("Hello, world") def rend(self, ctx, data): return invisible(render=directive("foo"))[Element.rend(self, ctx, data)] def foo(self, request, tag): renders.append((self, request)) return p[tag] renderer(foo)
class MainPage(athena.LiveElement): jsClass = u"WebInterface.PLC" docFactory = loaders.stan( tags.invisible[tags.div(render=tags.directive('liveElement'))[tags.div( id='content')[tags.div(render=tags.directive('PLCElement'))]], tags.a(href='settings')['Settings']]) def __init__(self, *a, **kw): athena.LiveElement.__init__(self, *a, **kw) self.pcl_state = False self.HMI = None self.resetPLCStartedHMI() def setPLCState(self, state): self.pcl_state = state if self.HMI is not None: self.callRemote('updateHMI') def setPLCStartedHMI(self, hmi): self.PLCStartedHMIClass = hmi def resetPLCStartedHMI(self): self.PLCStartedHMIClass = DefaultPLCStartedHMI def getHMI(self): return self.HMI def HMIexec(self, function, *args, **kwargs): if self.HMI is not None: getattr(self.HMI, function, lambda: None)(*args, **kwargs) athena.expose(HMIexec) def resetHMI(self): self.HMI = None def PLCElement(self, ctx, data): return self.getPLCElement() renderer(PLCElement) def getPLCElement(self): self.detachFragmentChildren() if self.pcl_state: f = self.PLCStartedHMIClass() else: f = PLCStoppedHMI() f.setFragmentParent(self) self.HMI = f return f athena.expose(getPLCElement) def detachFragmentChildren(self): for child in self.liveFragmentChildren[:]: child.detach()
class _ThemedMixin(object): """ Mixin for L{nevow.inevow.IRenderer} implementations which want to use the theme system. """ implements(ixmantissa.ITemplateNameResolver) def __init__(self, fragmentParent=None): """ Create a themed fragment with the given parent. @param fragmentParent: An object to pass to C{setFragmentParent}. If not None, C{self.setFragmentParent} is called immediately. It is suggested but not required that you set this here; if not, the resulting fragment will be initialized in an inconsistent state. You must call setFragmentParent to correct this before this fragment is rendered. """ super(_ThemedMixin, self).__init__() if fragmentParent is not None: self.setFragmentParent(fragmentParent) def head(self): """ Don't do anything. """ def rend(self, context, data): """ Automatically retrieve my C{docFactory} based on C{self.fragmentName} before invoking L{athena.LiveElement.rend}. """ if self.docFactory is None: self.docFactory = self.getDocFactory(self.fragmentName) return super(_ThemedMixin, self).rend(context, data) def pythonClass(self, request, tag): """ This renderer is available on all themed fragments. It returns the fully qualified python name of the class of the fragment being rendered. """ return reflect.qual(self.__class__) page.renderer(pythonClass) def render_pythonClass(self, ctx, data): return self.pythonClass(inevow.IRequest(ctx), ctx.tag) # ITemplateNameResolver def getDocFactory(self, fragmentName, default=None): f = getattr(self.page, "getDocFactory", getLoader) return f(fragmentName, default)
class PreferenceCollectionFragment(athena.LiveElement): """ L{inevow.IRenderer} adapter for L{xmantissa.ixmantissa.IPreferenceCollection}. """ docFactory = loaders.stan(tags.directive('fragments')) liveFormClass = PreferenceCollectionLiveForm def __init__(self, collection): super(PreferenceCollectionFragment, self).__init__() self.collection = collection def fragments(self, req, tag): """ Render our preference collection, any child preference collections we discover by looking at self.tab.children, and any fragments returned by its C{getSections} method. Subtabs and C{getSections} fragments are rendered as fieldsets inside the parent preference collection's tab. """ f = self._collectionToLiveform() if f is not None: yield tags.fieldset[tags.legend[self.tab.name], f] for t in self.tab.children: f = inevow.IRenderer(self.collection.store.getItemByID(t.storeID)) f.tab = t if hasattr(f, 'setFragmentParent'): f.setFragmentParent(self) yield f for f in self.collection.getSections() or (): f = ixmantissa.INavigableFragment(f) f.setFragmentParent(self) f.docFactory = getLoader(f.fragmentName) yield tags.fieldset[tags.legend[f.title], f] renderer(fragments) def _collectionToLiveform(self): params = self.collection.getPreferenceParameters() if not params: return None f = self.liveFormClass(lambda **k: self._savePrefs(params, k), params, description=self.tab.name) f.setFragmentParent(self) return f def _savePrefs(self, params, values): for (k, v) in values.iteritems(): setattr(self.collection, k, v) return self._collectionToLiveform()
class EndowDepriveFragment(webtheme.ThemedElement): fragmentName = 'user-detail' def __init__(self, fragmentParent, username, loginAccount, which): super(EndowDepriveFragment, self).__init__(fragmentParent) self.account = loginAccount self.which = which self.username = username def _endow(self, **kw): subs = self.account.avatars.open() def endowall(): for product in kw.values(): if product is not None: getattr(product, self.which)(subs) subs.transact(endowall) def productForm(self, request, tag): """ Render a L{liveform.LiveForm} -- the main purpose of this fragment -- which will allow the administrator to endow or deprive existing users using Products. """ def makeRemover(i): def remover(s3lected): if s3lected: return self.products[i] return None return remover f = liveform.LiveForm( self._endow, [liveform.Parameter( 'products' + str(i), liveform.FORM_INPUT, liveform.LiveForm( makeRemover(i), [liveform.Parameter( 's3lected', liveform.RADIO_INPUT, bool, repr(p), )], '', ), ) for (i, p) in enumerate(self.products)], self.which.capitalize() + u' ' + self.username) f.setFragmentParent(self) return f renderer(productForm)
class BlogPostBlurbViewerDetail(_BlogPostBlurbViewer): """ L{_BlogPostBlurbViewer} subclass which includes renderers specific to the detail page """ fragmentName = 'view-blurb/detail/' + FLAVOR.BLOG_POST def blogTitle(self, request, tag): """ Return the title of the blog our blurb was posted in """ return self.original.parent.title page.renderer(blogTitle) def blogBody(self, request, tag): """ Return the body (subtitle) of the blog our blurb was posted in """ return self.original.parent.body page.renderer(blogBody)
class NodeLocationSubElement1(LiveElement): docFactory = loaders.stan( tags.div(render=tags.directive('liveElement'))[ tags.invisible(render=tags.directive('bar')), tags.label(_class='foo', _for="username"), tags.input(_class='foo', id='username')]) def bar(self, req, tag): e = NodeLocationSubElement2() e.setFragmentParent(self) return e renderer(bar)
class _TextLikeParameterView(_ParameterViewMixin, Element): """ View definition base class for L{Parameter} instances which are simple text inputs. """ def default(self, request, tag): """ Render the initial value of the wrapped L{Parameter} instance. """ if self.parameter.default is not None: tag[self.parameter.default] return tag renderer(default)
class PreferenceCollectionLiveForm(LiveForm): """ L{xmantissa.liveform.LiveForm} subclass which switches the docfactory, the jsClass, and overrides the submit button renderer. """ jsClass = u'Mantissa.Preferences.PrefCollectionLiveForm' def __init__(self, *a, **k): super(PreferenceCollectionLiveForm, self).__init__(*a, **k) self.docFactory = getLoader('liveform-compact') def submitbutton(self, request, tag): return tags.input(type='submit', name='__submit__', value='Save') renderer(submitbutton)
class BlogBlurbViewer(BlurbViewer): """ L{BlurbViewer} subclass for rendering blurbs of type L{FLAVOR.BLOG} """ fragmentName = 'view-blurb/' + FLAVOR.BLOG jsClass = u'Hyperbola.BlogBlurbController' def _getAllTags(self): """ Get all the tags which have been applied to blurbs in the same store as the underlying item of our blurb. @rtype: C{list} of C{unicode} """ store = sharing.itemFromProxy(self.original).store # query instead of using Catalog so that tags only applied to # PastBlurb items don't get included return list(store.query( Tag, Tag.object == Blurb.storeID).getColumn('name').distinct()) def _getChildBlurbs(self, request): """ Get the child blurbs of this blurb, filtering by the selected tag @rtype: C{list} of L{xmantissa.sharing.SharedProxy} """ tag = self._getSelectedTag(request) if tag is not None: return list(self.original.viewByTag( self.getRole(), tag.decode('utf-8'))) return list(self.original.view(self.getRole())) def tags(self, request, tag): """ Render all tags """ iq = inevow.IQ(self.docFactory) selTag = self._getSelectedTag(request) for tag in self._getAllTags(): if tag == selTag: pattern = 'selected-tag' else: pattern = 'tag' yield iq.onePattern(pattern).fillSlots('name', tag) page.renderer(tags)
class BlogListFragment(athena.LiveElement): """ Fragment which renders a list of all blogs """ docFactory = webtheme.ThemedDocumentFactory( 'hyperbola-blog-list', '_resolver') def __init__(self, page, hyperbola): """ @type hyperbola: L{hyperbola.hyperbola_model.HyperbolaPublicPresence """ self.setFragmentParent(page) self.hyperbola = hyperbola self._resolver = ixmantissa.ITemplateNameResolver(self.hyperbola.store) super(BlogListFragment, self).__init__() def _getPostURL(self, blog): """ Figure out a URL which could be used for posting to C{blog} @type blog: L{xmantissa.sharing.SharedProxy} @rtype: L{nevow.url.URL} """ site = ixmantissa.ISiteURLGenerator(self.hyperbola.store.parent) blogURL = websharing.linkTo(blog) siteURL = site.encryptedRoot() blogURL.netloc = siteURL.netloc blogURL.scheme = siteURL.scheme return blogURL.child('post') def blogs(self, req, tag): """ Render all blogs """ p = inevow.IQ(self.docFactory).patternGenerator('blog') webapp = ixmantissa.IWebTranslator(self.hyperbola.store) blogs = list() primaryRole = sharing.getSelfRole(self.hyperbola.store) for blog in self.hyperbola.getTopLevelFor(primaryRole): blogs.append(p.fillSlots( 'title', blog.title).fillSlots( 'link', websharing.linkTo(blog)).fillSlots( 'post-url', self._getPostURL(blog))) return tag[blogs] page.renderer(blogs)
class ChannelLayout(page.Element): docFactory = loaders.xmlfile(RESOURCE('elements/ChannelLayout')) def __init__(self, controlBar, topicBar, mapDiv, channelDiv, chatEntry): self.controlBar = controlBar self.topicBar = topicBar self.mapDiv = mapDiv self.channelDiv = channelDiv self.chatEntry = chatEntry def layout(self, req, tag): tag.fillSlots('controlBar', self.controlBar) tag.fillSlots('topicBar', self.topicBar) tag.fillSlots('mapDiv', self.mapDiv) tag.fillSlots('channelDiv', self.channelDiv) tag.fillSlots('chatEntry', self.chatEntry) return tag page.renderer(layout)
class ChooserIcon(athena.LiveElement): docFactory = loaders.xmlfile(RESOURCE('elements/ChooserIcon')) jsClass = u'WebbyVellum.ChooserIcon' def __init__(self, user, fileitem, *a, **kw): super(ChooserIcon, self).__init__(*a, **kw) self.fileitem = fileitem self.user = user def chooserIcon(self, req, tag): fi = self.fileitem tag.fillSlots('filename', fi.filename) if fi.mimeType.startswith(u'image/') and fi.thumbnail is not None: tag.fillSlots('icon', '/files/%s/thumb' % (fi.md5, )) else: tag.fillSlots('icon', '/static/%s' % (iconForMimeType(fi.mimeType), )) return tag page.renderer(chooserIcon)
class TestError(athena.LiveElement): """ An element rendering an error that occurred during test collection. """ docFactory = loaders.stan(tags.div(render=tags.directive('error'))) def __init__(self, holder): holder.run(self) def addError(self, holder, error): self._error = error def head(self): """ We have nothing to render in <head>. """ def error(self, req, tag): return tag(_class='test-suite')[tags.pre[self._error.getTraceback()]] page.renderer(error)
class ButtonRenderingMixin: """ Convenience mixin to render pretty buttons. I can be mixed-in with a L{rend.Fragment} or a L{page.Element} """ _buttonPattern = None def button(self, request, tag): if self._buttonPattern is None: self._buttonPattern = inevow.IQ( getLoader('button')).patternGenerator('button') # take the contents of the tag and stuff it inside the button pattern, # and copy over any attributes button = self._buttonPattern() button.attributes.update(tag.attributes) return button.fillSlots('content', tag.children) page.renderer(button) def render_button(self, ctx, data): return self.button(inevow.IRequest(ctx), ctx.tag)
class FormInputParameterView(_ParameterViewMixin, athena.LiveElement): """ L{IParameterView} adapter for C{FORM_INPUT} L{Parameter}s. @ivar parameter: the parameter being viewed. @type parameter: L{Parameter} """ implements(IParameterView) patternName = 'form' def __init__(self, parameter): _ParameterViewMixin.__init__(self, parameter) athena.LiveElement.__init__(self) def input(self, request, tag): """ Add the wrapped form, as a subform, as a child of the given tag. """ subform = self.parameter.coercer.asSubForm(self.parameter.name) subform.setFragmentParent(self) return tag[subform] renderer(input)
class PreferenceEditor(athena.LiveElement): """ L{xmantissa.ixmantissa.INavigableFragment} adapter for L{xmantissa.prefs.PreferenceAggregator}. Responsible for rendering all installed L{xmantissa.ixmantissa.IPreferenceCollection}s """ implements(ixmantissa.INavigableFragment) title = 'Settings' fragmentName = 'preference-editor' def __init__(self, aggregator): self.aggregator = aggregator super(PreferenceEditor, self).__init__() def tabbedPane(self, req, tag): """ Render a tabbed pane tab for each top-level L{xmantissa.ixmantissa.IPreferenceCollection} tab """ navigation = webnav.getTabs(self.aggregator.getPreferenceCollections()) pages = list() for tab in navigation: f = inevow.IRenderer(self.aggregator.store.getItemByID( tab.storeID)) f.tab = tab if hasattr(f, 'setFragmentParent'): f.setFragmentParent(self) pages.append((tab.name, f)) f = tabbedPane.TabbedPaneFragment(pages, name='preference-editor') f.setFragmentParent(self) return f renderer(tabbedPane) def head(self): return tabbedPane.tabbedPaneGlue.inlineCSS
return powerupCoercer def makePowerupSelector(self, desc): return liveform.Parameter('selectedPowerup', liveform.CHECKBOX_INPUT, bool, desc) def powerupConfigurationParameter(self, (name, desc, p)): return liveform.Parameter( name, liveform.FORM_INPUT, liveform.LiveForm(self.makePowerupCoercer(p), [self.makePowerupSelector(desc)], name)) def productConfigurationForm(self, request, tag): productList = liveform.LiveForm(self.coerceProduct, [self.powerupConfigurationParameter(pi) for pi in self.getInstallablePowerups()], u"Installable Powerups") productList.setFragmentParent(self) return productList renderer(productConfigurationForm) def configuredProducts(self, request, tag): for prod in self.original.store.parent.query(Product): yield repr(prod.types) renderer(configuredProducts) registerAdapter(ProductFragment, ProductConfiguration, INavigableFragment)
class InnerElement(Element): def innerMethod(self, request, tag): return "Hello, world." renderer(innerMethod)
class OuterElement(Element): def outerMethod(self, request, tag): return tag[InnerElement( docFactory=stan(directive("innerMethod")))] renderer(outerMethod)
class RenderfulElement(Element): def renderMethod(self, request, tag): return tag[Element(docFactory=stan("Hello, world."))] renderer(renderMethod)