def test_res_order(self): """ Expect [foo1 foo3 foo2 foo4] since foo2 depends on foo3 """ foo1 = twc.JSLink(link='foo1') foo3 = twc.JSLink(link='foo3') foo2 = twc.JSLink(link='foo2', resources=[foo3]) foo4 = twc.JSLink(link='foo4') wa = TestWidget(id='a', resources=[foo1, foo2, foo4]) rl = testapi.request(1, mw) wa.display() rl = twc.core.request_local() lnk = lambda r: r.link eq_(map(lnk, rl['resources']), map(lnk, [foo1, foo3, foo2, foo4]))
class CalendarDatePicker(twf.widgets.InputField): """ A JavaScript calendar system for picking dates. The date format can be configured on the validator. """ resources = [ twc.CSSLink(modname='tw2.dynforms', filename='static/calendar/calendar-system.css'), twc.JSLink(modname='tw2.dynforms', filename='static/calendar/calendar.js'), twc.JSLink(modname='tw2.dynforms', filename='static/calendar/calendar-setup.js'), twc.Link(id='cal', modname='tw2.dynforms', filename='static/office-calendar.png'), ] language = twc.Param('Short country code for language to use, e.g. fr, de', default='en') show_time = twc.Variable('Whether to display the time', default=False) value = twc.Param('The default value is the current date/time', default=None) validator = twc.DateValidator template = "genshi:tw2.dynforms.templates.calendar" type = 'text' def prepare(self): if not self.value: # XXX -- Doing this instead of twc.Deferred consciously. # twc.Deferred is/was nice, but the execution in post_define(...) of # cls._deferred = [k for k, v in cls.__dict__.iteritems() # if isinstance(v, pm.Deferred)] # with dir(..) instead of vars(..) is too costly. This is the only # place I'm aware of that actually uses deferred params. - threebean self.value = dt.datetime.now() super(CalendarDatePicker, self).prepare() self.safe_modify('resources') self.resources.extend([ twc.JSLink(parent=self.__class__, modname='tw2.dynforms', filename='static/calendar/lang/calendar-%s.js' % self.language), ]) self.add_call( twc.js_function('Calendar.setup')(dict( inputField=self.compound_id, ifFormat=self.validator.format, button=self.compound_id + ':trigger', showsTime=self.show_time)))
def prepare(self): super(BrowseWidget, self).prepare() tw2.jqplugins.ui.set_ui_theme_name('pepper-grinder') if self.value: self.name, self.widget, self.demo = self.value if self.source: self.resources.extend([ tw2.jquery.jquery_js, tw2.jqplugins.ui.jquery_ui_js, tw2.jqplugins.ui.jquery_ui_css, twc.JSLink(modname=__name__, filename='static/js/source.js') ]) if getattr(self.widget, '_hide_docs', False) and self.demo: self.demo.resources.extend([ tw2.jquery.jquery_js, twc.JSLink(modname=__name__, filename='static/js/browser.js') ]) self.params = sorted(self.widget._params.values(), key=lambda p: p._seq) self.child_params = [ p for p in self.widget._all_params.values() if p.child_param and not p.internal ] self.child_params.sort(key=lambda p: p._seq) req_prm = [ p.name for p in self.params if p.default is twc.Required ] if self.demo: try: self.demo = self.demo(id='demo', parent=self.__class__).req() self.demo.prepare() except Exception as e: warnings.warn(six.text_type(e)) self.demo = None elif not req_prm or req_prm == ['id']: # auto demo try: self.demo = self.widget(id='demo', parent=self.__class__).req() self.demo.prepare() except Exception as e: warnings.warn(six.text_type(e)) self.demo = None else: self.demo = None
def prepare(self): if not self.value: # XXX -- Doing this instead of twc.Deferred consciously. # twc.Deferred is/was nice, but the execution in post_define(...) of # cls._deferred = [k for k, v in cls.__dict__.iteritems() # if isinstance(v, pm.Deferred)] # with dir(..) instead of vars(..) is too costly. This is the only # place I'm aware of that actually uses deferred params. - threebean self.value = dt.datetime.now() super(CalendarDatePicker, self).prepare() self.safe_modify('resources') self.resources.extend([ twc.JSLink(parent=self.__class__, modname='tw2.dynforms', filename='static/calendar/lang/calendar-%s.js' % self.language), ]) self.add_call( twc.js_function('Calendar.setup')(dict( inputField=self.compound_id, ifFormat=self.validator.format, button=self.compound_id + ':trigger', showsTime=self.show_time)))
class CustomisedForm(twf.Form): """A form that allows specification of several useful client-side behaviours.""" blank_deleted = twc.Param( 'Blank out any invisible form fields before submitting. This is needed for GrowingGrid.', default=True) disable_enter = twc.Param( 'Disable the enter button (except with textarea fields). This reduces the chance of users accidentally submitting the form.', default=True) prevent_multi_submit = twc.Param( 'When the user clicks the submit button, disable it, to prevent the user causing multiple submissions.', default=True) resources = [twc.JSLink(modname=__name__, filename="static/dynforms.js")] def prepare(self): super(CustomisedForm, self).prepare() if self.blank_deleted: self.safe_modify('attrs') self.attrs['onsubmit'] = 'twd_blank_deleted()' if self.disable_enter: self.safe_modify('resources') self.resources.append( twc.JSSource(src='document.onkeypress = twd_suppress_enter;')) if self.prevent_multi_submit: self.submit.safe_modify('attrs') self.submit.attrs['onclick'] = 'return twd_no_multi_submit(this);'
def get_calendar_lang_file_link(self, lang): """ Returns a CalendarLangFileLink containing a list of name patterns to try in turn to find the correct calendar locale file to use. """ fname = 'static/calendar/lang/calendar-%s.js' % lang.lower() return twc.JSLink(modname='tw2.forms', filename=fname)
def test_link_reg(self): testapi.request(1, mw) wa = twc.JSLink(modname='tw2.core', filename='test_templates/simple_mako.mak').req() wa.prepare() assert ( wa.link == '/resources/tw2.core/test_templates/simple_mako.mak') tst_mw.get(wa.link)
class TabView(twf.widgets.BaseLayout): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/tabview/assets/skins/sam/tabview.css"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/element/element-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/tabview/tabview-min.js"), ] template = "genshi:tw2.yui.templates.tabview" # These don't apply; hide from widget browser hover_help = twc.Variable() help_text = twc.Variable() container_attrs = twc.Variable()
def test_mime_type(self): testapi.request(1, mw) wa = twc.JSLink(modname='tw2.core', filename='test_templates/simple_genshi.html').req() wa.prepare() resp = tst_mw.get(wa.link) assert (resp.content_type == 'text/html') assert (resp.charset == 'UTF-8')
class ColorPicker(YuiWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/colorpicker/assets/skins/sam/colorpicker.css"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/dragdrop/dragdrop-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/animation/animation-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/slider/slider-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/element/element-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/colorpicker/colorpicker-min.js"), twc.Link(id='picker_thumb', modname=__name__, filename="static/" + yui_version + "/colorpicker/assets/picker_thumb.png"), twc.Link(id='hue_thumb', modname=__name__, filename="static/" + yui_version + "/colorpicker/assets/hue_thumb.png"), ] template = "genshi:tw2.yui.templates.colorpicker" rgb = twc.Variable(default='[0xFF,0xFF,0xFF]') def prepare(self): self.safe_modify('options') if self.value and re.match('^#[0-9a-fA-F]{6}$', self.value): self.rgb = twc.encoder.encode( [int(self.value[i:i + 2], 16) for i in (1, 3, 5)]) self.options['images'] = { 'PICKER_THUMB': '/resources/tw2.yui.widgets/static/' + yui_version + '/colorpicker/assets/picker_thumb.png', 'HUE_THUMB': '/resources/tw2.yui.widgets/static/' + yui_version + '/colorpicker/assets/hue_thumb.png', } super(ColorPicker, self).prepare()
def prepare(self): orbited_url = '%s://%s:%s' % ( self.orbited_scheme, self.orbited_host, self.orbited_port, ) orbited_js = twc.JSLink(link=orbited_url + '/static/Orbited.js', resources=[tw2.jquery.jquery_js]) self.resources.append(orbited_js)
class LogReader(YuiWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/logger/assets/skins/sam/logger.css"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/logger/logger-min.js"), ] template = "genshi:tw2.yui.templates.logreader"
def test_res_nodupe(self): wa = TestWidget(id='a', resources=[js]) wb = TestWidget(id='b', resources=[twc.JSLink(link='paj')]) wc = TestWidget(id='c', resources=[twc.JSLink(link='test')]) wd = TestWidget(id='d', resources=[css]) we = TestWidget(id='e', resources=[twc.CSSLink(link='joe')]) rl = testapi.request(1, mw) wa.display() wb.display() rl = twc.core.request_local() r = rl['resources'] assert (len(rl['resources']) == 1) wc.display() assert (len(rl['resources']) == 2) wd.display() we.display() assert (len(rl['resources']) == 3)
class Calendar(YuiWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/calendar/assets/skins/sam/calendar.css"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/calendar/calendar-min.js"), ] template = "genshi:tw2.yui.templates.calendar"
class DataSource(YuiWidget): resources = [ # don't use YuiWidget.resources twc.JSLink(modname=__name__, filename="static/" + yui_version + "/datasource/datasource-min.js"), ] def prepare(self): self.safe_modify('options') self.options['responseSchema'] = self.responseSchema super(DataSource, self).prepare()
class ColorizedMessagesWidget(BusmonWidget): id = 'colorized-messages' template = "mako:busmon.templates.colorized_messages" resources = BusmonWidget.resources + [ twc.CSSLink(link="css/monokai.css"), twc.JSLink(link="javascript/markup.js"), ] css_class = "hll" topic = "*" onmessage = """
class HidingComponentMixin(twc.Widget): """This widget is a $$ with additional functionality to hide or show other widgets in the form, depending on the value selected. The widget must be used inside a hiding container, e.g. HidingTableLayout.""" resources = [twc.JSLink(modname=__name__, filename='static/dynforms.js')] mapping = twc.Param( 'A dictionary that maps selection values to visible controls', request_local=False) def prepare(self): super(HidingComponentMixin, self).prepare() self.safe_modify('resources') self.add_call( twc.js_function('twd_hiding_init')(self.compound_id, self.mapping))
def setUp(self): global _request_local _request_local = {} self.mw = twc.make_middleware(self) self.app = wt.TestApp(self.mw) js = twc.JSLink(link='paj') css = twc.CSSLink(link='joe') TestWidget = twc.Widget( template='genshi:tw2.core.test_templates.inner_genshi', test='test', ) self.inject_widget = TestWidget(id='a', resources=[js, css])
class Slider(YuiWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/slider/assets/skins/sam/slider.css"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/animation/animation-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/dragdrop/dragdrop-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/slider/slider-min.js"), twc.Link( id='thumb', modname=__name__, filename='static/' + yui_version + '/slider/assets/thumb-n.gif'), ] template = "genshi:tw2.yui.templates.slider" size = twc.Param('Size in pixels of control', default=200) min = twc.Param('Minimum effective value', default=0) max = twc.Param('Maximum effective value', default=100)
class AutoComplete(twf.TextField, YuiWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/autocomplete/assets/skins/sam/autocomplete.css"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/json/json-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/element/element-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/animation/animation-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/datasource/datasource-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/autocomplete/autocomplete-min.js"), ] template = "genshi:tw2.yui.templates.autocomplete" attrs = {'style': 'width:15em;'} datasrc = twc.Param('DataSource to use') value = twc.Param(attribute=True) @classmethod def post_define(cls): if hasattr(cls, 'datasrc'): cls.datasrc = cls.datasrc(parent=cls, id='datasrc') def __init__(self, **kw): super(AutoComplete, self).__init__(**kw) self.datasrc = self.datasrc.req() def prepare(self): super(AutoComplete, self).prepare() self.datasrc.prepare()
class TreeView(YuiWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/treeview/assets/skins/sam/treeview.css"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/treeview/treeview-min.js"), ] template = "genshi:tw2.yui.templates.treeview" content = twc.Param('Content', default=[]) def prepare(self): super(TreeView, self).prepare() self.content = twc.encoder.encode(self.content)
class YuiWidget(twc.Widget): resources = [ twc.DirLink(modname=__name__, filename="static/" + yui_version + "/"), twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/fonts/fonts-min.css"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/yahoo-dom-event/yahoo-dom-event.js"), ] options = twc.Param( 'Configuration options for the widget. See the YUI docs for available options.', default={}) def prepare(self): super(YuiWidget, self).prepare() self.options = twc.encoder.encode(self.options)
class GrowingGridLayout(twf.GridLayout): """A GridLayout that can dynamically grow on the client, with delete and undo functionality. This is useful for allowing users to enter a list of items that can vary in length. To function correctly, the widget must appear inside a CustomisedForm.""" resources = [ twc.Link(id='undo', modname=__name__, filename="static/undo.png"), twc.JSLink(modname=__name__, filename="static/dynforms.js"), ] template = 'genshi:tw2.dynforms.templates.growing_grid_layout' # TBD: support these properly & min/max repetitions = twc.Variable() extra_reps = twc.Variable(default=1) mix_reps = twc.Variable() max_reps = twc.Variable() @classmethod def post_define(cls): if hasattr(cls.child, 'children'): if not hasattr(cls.child.children, 'del'): # TBD: 'del' in ... cls.child = cls.child(children=list(cls.child.children) + [DeleteButton(id='del', label='')]) def prepare(self): if not hasattr(self, '_validated'): self.value = [None] + (self.value or []) super(GrowingGridLayout, self).prepare() # First and last rows have delete hidden (and hidingbutton) and get onchange for r in (self.children[0], self.children[self.repetitions - 1]): for c in r.children: c.safe_modify('attrs') if c.id == 'del': c.attrs['style'] = 'display:none;' + c.attrs.get( 'style', '') else: c.attrs['onchange'] = 'twd_grow_add(this);' + c.attrs.get( 'onchange', '') # First row is hidden hidden_row = self.children[0] hidden_row.safe_modify('attrs') hidden_row.attrs['style'] = 'display:none;' + hidden_row.attrs.get( 'style', '') def _validate(self, value, state=None): value = [v for v in value if not ('del.x' in v and 'del.y' in v)] return twc.RepeatingWidget._validate( self, [None] + twf.StripBlanks().to_python(value), state)[1:]
class DataTable(YuiWidget, twc.CompoundWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/datatable/assets/skins/sam/datatable.css"), twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/button/assets/skins/sam/button.css"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/dom/dom-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/event/element-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/dragdrop/dragdrop-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/element/element-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/datasource/datasource-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/event-delegate/event-delegate-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/datatable/datatable-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/button/button-min.js"), ] template = "genshi:tw2.yui.templates.datatable" children = twc.Param( 'Columns for the table. These must be tw2.yui.Column widgets.') columns = twc.Variable() def prepare(self): super(DataTable, self).prepare() self.columns = twc.encoder.encode([c.options for c in self.c]) self.buttons = twc.encoder.encode( dict( (c.id, c.link) for c in self.c if isinstance(c, ButtonColumn))) self.value = twc.encoder.encode(self.value)
class XHRDataSource(DataSource): resources = DataSource.resources + [ twc.JSLink(modname=__name__, filename="static/" + yui_version + "/connection/connection-min.js"), ] template = "genshi:tw2.yui.templates.xhrdatasource" responseSchema = twc.Param('responseSchema', default={'resultsList': 'result'}) options = { 'responseType': 3, # YAHOO.util.XHRDataSource.TYPE_JSON } @classmethod def request(self, req): resp = webob.Response(request=req, content_type="application/json; charset=UTF8") resp.body = twc.encoder.encode(self.ajax_request(req)) return resp
class LinkContainer(twc.DisplayOnlyWidget): """This widget provides a "View" link adjacent to any other widget required. This link is visible only when a value is selected, and allows the user to view detailed information on the current selection.""" template = "genshi:tw2.dynforms.templates.link_container" resources = [twc.JSLink(modname=__name__, filename='static/dynforms.js')] link = twc.Param( 'The link target. If a $ character is present in the URL, it is replaced with the current value of the widget.' ) view_text = twc.Param('Text to appear in the link', default='View') id_suffix = 'view' def prepare(self): super(LinkContainer, self).prepare() self.child.safe_modify('attrs') self.child.attrs['onchange'] = ( ('twd_link_onchange(this, "%s");' % self.link) + self.child.attrs.get('onchange', '')) if not self.child.value: self.attrs['style'] = 'display:none;' + self.attrs.get('style', '')
class UserProfile(twc.Widget): template = "mako:github2fedmsg.widgets.templates.profile" user = twc.Param("An instance of the User SQLAlchemy model.") resources = [ twc.JSLink(filename="static/profile.js"), ] show_buttons = twc.Param("show my buttons?", default=False) def prepare(self): """ Query github for some information before display """ oauth_creds = dict(access_token=self.user.oauth_access_token) # Try to refresh list of repos only if the user has none. if self.user.github_username and \ self.user.oauth_access_token and \ not self.user.all_repos: self.user.sync_repos(oauth_creds) def make_button(self, repo): # TODO -- Can we use resource_url here? username = repo.user.username github_username = repo.user.github_username home = self.request.route_url('home') link = home + 'api/%s/%s/%s/toggle' % (username, github_username, repo.name) click = 'onclick="subscribe(\'%s\')"' % link if repo.enabled: cls, text = "btn-success", "On" else: cls, text = "btn-default", "Off" return "<button id='%s-%s' class='btn %s' %s>%s</button>" % ( github_username, repo.name, cls, click, text) @property def request(self): return pyramid.threadlocal.get_current_request()
def __call__(self, environ, start_response): """Invoke the Controller""" # TGController.__call__ dispatches to the Controller method # the request is routed to. This routing information is # available in environ['pylons.routes_dict'] request.identity = request.environ.get('repoze.who.identity') tmpl_context.identity = request.identity # Include jquery on every page. tw2.jquery.jquery_js.req().prepare() if 'login' not in environ['PATH_INFO']: for link in ["query.js", "cards.js", "navigation.js"]: twc.JSLink(link="javascript/%s" % link).req().prepare() tmpl_context.hotkeys_dialog = fedoratagger.widgets.dialog.HotkeysDialog tmpl_context.search_dialog = fedoratagger.widgets.dialog.SearchDialog tmpl_context.add_dialog = fedoratagger.widgets.dialog.AddTagDialog tmpl_context.leaderboard_dialog = fedoratagger.widgets.dialog.LeaderboardDialog tmpl_context.user_widget = fedoratagger.widgets.user.UserWidget return TGController.__call__(self, environ, start_response)
class Editor(twf.TextArea, YuiWidget): resources = YuiWidget.resources + [ twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/menu/assets/skins/sam/menu.css"), twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/button/assets/skins/sam/button.css"), twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/container/assets/skins/sam/container.css"), twc.CSSLink(modname=__name__, filename="static/" + yui_version + "/editor/assets/skins/sam/editor.css"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/animation/animation-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/element/element-min.js"), twc.JSLink( modname=__name__, filename="static/" + yui_version + "/container/container-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/menu/menu-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/button/button-min.js"), twc.JSLink(modname=__name__, filename="static/" + yui_version + "/editor/editor-min.js"), ] template = "genshi:tw2.yui.templates.editor" options = {'handleSubmit': 1} # default to a fairly large size rows = 20 cols = 100
================================================================== .. moduleauthor:: Luke Macken <*****@*****.**> """ import tw2.core as twc from moksha.wsgi.widgets.api.socket import AbstractMokshaSocket from kitchen.iterutils import iterate orbited_host = twc.Required orbited_port = twc.Required orbited_scheme = twc.Required jsio_js = twc.JSLink( filename='static/jsio/jsio.js', modname=__name__) amqp_resources = twc.DirLink( filename='static/', modname=__name__) def amqp_subscribe(topic): """ Return a javascript callback that subscribes to a given topic, or a list of topics. """ sub = """ moksha.debug("Subscribing to the '%(topic)s' topic"); var receiver = moksha_amqp_session.receiver('amq.topic/%(topic)s') receiver.onReady = raw_msg_callback;