Example #1
0
class select(CompositePres):
    def __init__(self, option_value_content_pairs, value, on_choose=None):
        """
		HTML select control

		:param option_value_content_pairs: a sequence of tuple-pairs describing the options. Each pair is of the form (value, text)
		:param value: the initial value
		:param on_choose: a callback function of the form fn(event, value) that is invoked when the user makes a choice
		"""
        self.__options = [
            Html(
                '<option value="{0}"{1}>'.format(
                    opt_value, (' selected' if opt_value == value else '')),
                content, '</option>')
            for opt_value, content in option_value_content_pairs
        ]
        self.choose = EventHandler()
        if on_choose is not None:
            self.choose.connect(on_choose)

    def pres(self, pres_ctx):
        p = Html(
            *(['<select>'] + self.__options +
              ['</select>'])).js_function_call('larch.controls.initSelect')
        p = p.with_event_handler('select_choose',
                                 lambda event: self.choose(event, event.data))
        p = p.use_js('/static/larch/larch_ui.js').use_css(
            '/static/larch/larch_ui.css')
        return p
Example #2
0
class spinner(CompositePres):
    def __init__(self, on_change=None, value=0, input_name='spinner'):
        """
		jQuery UI spinner control

		:param on_change: callback that is invoked when the spinner's value changes; function(value)
		:param value: [optional] initial value
		:param input_name: [optional] name attribute for input tag
		"""
        self.change = EventHandler()

        self.__value = value
        self.__input_name = input_name
        self.__channel = MessageChannel()

        if on_change is not None:
            self.change.connect(on_change)

    def __on_spinner_change(self, event):
        self.change(event, event.data)

    def set_value(self, value):
        self.__channel.send(value)

    def pres(self, pres_ctx):
        spin = Html('<input name={0} value={1} />'.format(
            self.__input_name, self.__value))
        spin = spin.js_function_call('larch.controls.initSpinner',
                                     self.__channel)
        spin = spin.with_event_handler("spinner_change",
                                       self.__on_spinner_change)
        spin = spin.use_js('/static/larch/larch_ui.js').use_css(
            '/static/larch/larch_ui.css')
        return spin
Example #3
0
class focusable(CompositePres):
    def __init__(self, contents, on_gain_focus=None, on_lose_focus=None):
        """
		Make an element focusable
		:param contents: contents that are to be made focusable
		:param on_gain_focus: [optional] a function of the form function(event) that is invoked when the element gains focus
		:param on_lose_focus: [optional] a function of the form function(event) that is invoked when the element loses focus
		:return: the control
		"""
        self.__contents = contents
        self.gain_focus = EventHandler()
        self.lose_focus = EventHandler()
        if on_gain_focus is not None:
            self.gain_focus.connect(on_gain_focus)
        if on_lose_focus is not None:
            self.lose_focus.connect(on_lose_focus)

    def pres(self, pres_ctx):
        p = Html(self.__contents).js_function_call(
            'larch.controls.initFocusable').js_shutdown_function_call(
                'larch.controls.shutdownFocusable')
        p = p.with_event_handler('gain_focus', self.gain_focus)
        p = p.with_event_handler('lose_focus', self.lose_focus)
        p = p.use_js('/static/larch/larch_ui.js').use_css(
            '/static/larch/larch_ui.css')
        return p
Example #4
0
class button(CompositePres):
    def __init__(self,
                 text=None,
                 action_fn=None,
                 primary_icon=None,
                 secondary_icon=None,
                 disabled=False):
        """
		Create a JQuery UI button
		:param text: the button content (can include HTML)
		:param action_fn: a callback that is invoked when the button is pressed, of the form function(event)
		:param primary_icon: primary icon (see JQuery UI icon classes)
		:param secondary_icon: secondary icon (see JQuery UI icon classes)
		:param disabled: disable the button
		:return: the button control
		"""
        self.__text = text
        self.clicked = EventHandler()
        self.__primary_icon = primary_icon
        self.__secondary_icon = secondary_icon
        self.__disabled = disabled
        if action_fn is not None:
            self.clicked.connect(action_fn)

    def pres(self, pres_ctx):
        options = {}
        if self.__disabled is not False:
            options['disabled'] = True

        if self.__primary_icon is not None or self.__secondary_icon is not None:
            icons = {}
            if self.__primary_icon is not None:
                icons['primary'] = self.__primary_icon
            if self.__secondary_icon is not None:
                icons['secondary'] = self.__secondary_icon
            options['icons'] = icons

        if self.__text is not None:
            p = Html(
                '<button type="button" onclick="{0}">'.format(
                    post_event_js_code_for_handler('clicked')), self.__text,
                '</button>').js_function_call('larch.controls.initButton',
                                              options)
        else:
            options['text'] = False
            p = Html('<button type="button" onclick="{0}"></button>'
                     ).js_function_call('larch.controls.initButton', options)
        p = p.with_event_handler('clicked', self.clicked).use_js(
            '/static/larch/larch_ui.js').use_css('/static/larch/larch_ui.css')
        return p
Example #5
0
class item(CompositePres):
    def __init__(self, item_content, on_select=None):
        """
		Create a menu item control. Must be placed within a menu control, created with :menu:.

		:param item_content: the HTML content of the menu item
		:param on_select: a callback invoked when the menu item is activated by the user
		:return: the menu item control
		"""
        self.__item_content = item_content
        self.select = EventHandler()
        if on_select is not None:
            self.select.connect(on_select)

    def pres(self, pres_ctx):
        p = Html('<li><a>', self.__item_content, '</a></li>')
        p = p.with_event_handler('menu_select', self.select)
        return p
Example #6
0
class select (CompositePres):
	def __init__(self, option_value_content_pairs, value, on_choose=None):
		"""
		HTML select control

		:param option_value_content_pairs: a sequence of tuple-pairs describing the options. Each pair is of the form (value, text)
		:param value: the initial value
		:param on_choose: a callback function of the form fn(event, value) that is invoked when the user makes a choice
		"""
		self.__options = [Html('<option value="{0}"{1}>'.format(opt_value, (' selected'   if opt_value == value   else '')), content, '</option>')   for opt_value, content in option_value_content_pairs]
		self.choose = EventHandler()
		if on_choose is not None:
			self.choose.connect(on_choose)


	def pres(self, pres_ctx):
		p = Html(*(['<select>'] + self.__options + ['</select>'])).js_function_call('larch.controls.initSelect')
		p = p.with_event_handler('select_choose', lambda event: self.choose(event, event.data))
		p = p.use_js('/files/static/larch/larch_ui.js').use_css('/files/static/larch/larch_ui.css')
		return p
Example #7
0
class action_link (CompositePres):
	def __init__(self, link_text, action_fn=None, css_class=None):
		"""
		Create an action link that invokes a function in response to the user clicking it
		:param link_text: the link text
		:param action_fn:  a callback that is called when the link is clicked, of the form function(event)
		:param css_class: an optional css class
		:return: the control
		"""
		self.__link_text = link_text
		self.clicked = EventHandler()
		if action_fn is not None:
			self.clicked.connect(action_fn)
		self.__css_class = css_class

	def pres(self, pres_ctx):
		css = ' class="{0}"'.format(self.__css_class)   if self.__css_class is not None   else ''
		p = Html('<a {2}href="javascript:" onclick="{0}">{1}</a>'.format(post_event_js_code_for_handler('clicked'), self.__link_text, css))
		p = p.with_event_handler('clicked', self.clicked)
		return p
Example #8
0
class button (CompositePres):
	def __init__(self, text=None, action_fn=None, primary_icon=None, secondary_icon=None, disabled=False):
		"""
		Create a JQuery UI button
		:param text: the button content (can include HTML)
		:param action_fn: a callback that is invoked when the button is pressed, of the form function(event)
		:param primary_icon: primary icon (see JQuery UI icon classes)
		:param secondary_icon: secondary icon (see JQuery UI icon classes)
		:param disabled: disable the button
		:return: the button control
		"""
		self.__text = text
		self.clicked = EventHandler()
		self.__primary_icon = primary_icon
		self.__secondary_icon = secondary_icon
		self.__disabled = disabled
		if action_fn is not None:
			self.clicked.connect(action_fn)


	def pres(self, pres_ctx):
		options = {}
		if self.__disabled is not False:
			options['disabled'] = True

		if self.__primary_icon is not None  or  self.__secondary_icon is not None:
			icons = {}
			if self.__primary_icon is not None:
				icons['primary'] = self.__primary_icon
			if self.__secondary_icon is not None:
				icons['secondary'] = self.__secondary_icon
			options['icons'] = icons

		if self.__text is not None:
			p = Html('<button type="button" onclick="{0}">'.format(post_event_js_code_for_handler('clicked')), self.__text, '</button>').js_function_call('larch.controls.initButton', options)
		else:
			options['text'] = False
			p = Html('<button type="button" onclick="{0}"></button>').js_function_call('larch.controls.initButton', options)
		p = p.with_event_handler('clicked', self.clicked).use_js('/files/static/larch/larch_ui.js').use_css('/files/static/larch/larch_ui.css')
		return p
Example #9
0
class text_entry(CompositePres):
    def __init__(self, text, immediate_events=False, on_edit=None, width=None):
        """
		Create a text entry control
		:param text: the initial text to display in the control
		:param immediate_events: if True, an event will be emitted each time the text is edited (on each keypress)
		:param on_edit: a callback invoked in response to edits, of the form function(modified_text)
		:param width: width of the control; ints or longs will be interpreted as width in pixels, otherwise use string in CSS form, e.g. '100px', '10em' or '50%'
		:return: the editor control
		"""
        self.edit = EventHandler()

        if isinstance(width, int) or isinstance(width, long):
            width = '{0}px'.format(width)

        self.__text = text
        self.__immediate_events = immediate_events
        self.__width = width

        if on_edit is not None:
            self.edit.connect(on_edit)

        self.__channel = MessageChannel()

    def set_text(self, text):
        self.__channel.send(text)

    def pres(self, pres_ctx):
        sz = ''
        if self.__width is not None:
            sz = ' style="width: {0};"'.format(self.__width)
        p = Html('<input type="text" value="{0}"{1}></input>'.format(
            self.__text,
            sz)).js_function_call('larch.controls.initTextEntry',
                                  self.__immediate_events, self.__channel)
        p = p.with_event_handler('text_entry_edit',
                                 lambda event: self.edit(event, event.data))
        p = p.use_js('/static/larch/larch_ui.js').use_css(
            '/static/larch/larch_ui.css')
        return p
Example #10
0
class form(CompositePres):
    def __init__(self, contents, on_submit=None):
        """
		Wrap the contents in a form that will be sent to Larch

		:param contents: The contents of the form, including the enclosing <form> tag
		:param on_submit: A callback invoked when the form is submitted. Callback signature: function(event); the form data is accessible through event.data
		:return: the form control
		"""
        self.__contents = contents
        self.submit = EventHandler()
        if on_submit is not None:
            self.submit.connect(on_submit)

    def pres(self, pres_ctx):
        p = Html('<form enctype="multipart/form-data">', self.__contents,
                 '</form>').js_function_call(
                     'larch.controls.initForm').with_event_handler(
                         'form_submit', self.submit)
        p = p.use_js('/static/jquery/js/jquery.form.min.js').use_js(
            '/static/larch/larch_ui.js').use_css('/static/larch/larch_ui.css')
        return p
Example #11
0
class action_link(CompositePres):
    def __init__(self, link_text, action_fn=None, css_class=None):
        """
		Create an action link that invokes a function in response to the user clicking it
		:param link_text: the link text
		:param action_fn:  a callback that is called when the link is clicked, of the form function(event)
		:param css_class: an optional css class
		:return: the control
		"""
        self.__link_text = link_text
        self.clicked = EventHandler()
        if action_fn is not None:
            self.clicked.connect(action_fn)
        self.__css_class = css_class

    def pres(self, pres_ctx):
        css = ' class="{0}"'.format(
            self.__css_class) if self.__css_class is not None else ''
        p = Html('<a {2}href="javascript:" onclick="{0}">{1}</a>'.format(
            post_event_js_code_for_handler('clicked'), self.__link_text, css))
        p = p.with_event_handler('clicked', self.clicked)
        return p
Example #12
0
class text_entry (CompositePres):
	def __init__(self, text, immediate_events=False, on_edit=None, width=None):
		"""
		Create a text entry control
		:param text: the initial text to display in the control
		:param immediate_events: if True, an event will be emitted each time the text is edited (on each keypress)
		:param on_edit: a callback invoked in response to edits, of the form function(modified_text)
		:param width: width of the control; ints or longs will be interpreted as width in pixels, otherwise use string in CSS form, e.g. '100px', '10em' or '50%'
		:return: the editor control
		"""
		self.edit = EventHandler()

		if isinstance(width, int)  or  isinstance(width, long):
			width = '{0}px'.format(width)

		self.__text = text
		self.__immediate_events = immediate_events
		self.__width = width

		if on_edit is not None:
			self.edit.connect(on_edit)

		self.__channel = MessageChannel()


	def set_text(self, text):
		self.__channel.send(text)


	def pres(self, pres_ctx):
		sz = ''
		if self.__width is not None:
			sz = ' style="width: {0};"'.format(self.__width)
		p = Html('<input type="text" value="{0}"{1}></input>'.format(self.__text, sz)).js_function_call('larch.controls.initTextEntry', self.__immediate_events, self.__channel)
		p = p.with_event_handler('text_entry_edit', lambda event: self.edit(event, event.data))
		p = p.use_js('/files/static/larch/larch_ui.js').use_css('/files/static/larch/larch_ui.css')
		return p
Example #13
0
class ckeditor(CompositePres):
    def __init__(self,
                 text,
                 immediate_events=False,
                 use_edit_button=False,
                 config=None,
                 on_edit=None,
                 on_focus=None,
                 on_blur=None):
        """
		Create a ckEditor based rich text editor control
		:param text: The text to display in the editor
		:param immediate_events: If true, an event is emitted on each edit (key press)
		:param use_edit_button: If true, the user must click an edit button to make the text editable
		:param config: configuration options; see ckEditor documentation
		:param on_edit: a callback invoked in response to edits, of the form function(event, modified_html_text)
		:param on_focus: a callback invoked when the editor receives focus; of the form function(event)
		:param on_blur: a callback invoked when the editor loses focus; of the form function(event)
		:return: the ckEditor control
		"""
        if text == '':
            text = '<p></p>'
        if config is None:
            config = {}

        self.__text = text
        self.__config = config
        self.__immediate_events = immediate_events
        self.__use_edit_button = use_edit_button
        self.edit = EventHandler()
        self.focus = EventHandler()
        self.blur = EventHandler()
        if on_edit is not None:
            self.edit.connect(on_edit)
        if on_focus is not None:
            self.focus.connect(on_focus)
        if on_blur is not None:
            self.blur.connect(on_blur)

        self.__channel = MessageChannel()

    def set_text(self, text):
        self.__channel.send(text)

    def pres(self, pres_ctx):
        if self.__use_edit_button:
            p = Html(
                u'<div class="__larch_ui_ckeditor_edit_container"><div>{text}</div></div>'
                .format(text=self.__text)).js_function_call(
                    'larch.controls.initCKEditorWithEditButton', self.__config,
                    self.__immediate_events, self.__channel)
        else:
            p = Html(u'<div contenteditable="true">{text}</div>'.format(
                text=self.__text))
            p = p.js_function_call('larch.controls.initCKEditor',
                                   self.__config, self.__immediate_events,
                                   self.__channel)
            p = p.js_shutdown_function_call('larch.controls.shutdownCKEditor')

        p = p.use_js('/static/ckeditor/ckeditor.js')
        p = p.use_js('/static/larch/larch_ui.js').use_css(
            '/static/larch/larch_ui.css')
        p = p.with_event_handler('ckeditor_edit',
                                 lambda event: self.edit(event, event.data))
        p = p.with_event_handler('ckeditor_focus', self.focus)
        p = p.with_event_handler('ckeditor_blur', self.blur)
        return p
Example #14
0
class code_mirror(CompositePres):
    def __init__(self,
                 text,
                 immediate_events=False,
                 config=None,
                 on_edit=None,
                 on_focus=None,
                 on_blur=None,
                 modes=None):
        """
		Create a CodeMirror based code editor control
		:param text: the initial text to display in the control
		:param immediate_events: if True, an event will be emitted each time the text is edited (on each keypress)
		:param config: configuration options (see CodeMirror documentation)
		:param on_edit: a callback invoked in response to edits, of the form function(event, modified_text)
		:param on_focus: a callback invoked when the editor receives focus; of the form function(event)
		:param on_blur: a callback invoked when the editor loses focus; of the form function(event)
		:param modes: a list of names of language plugins to load (e.g. 'python', 'javascript', 'glsl', etc; see CodeMirror documentation)
		:return: the editor control
		"""
        if config is None:
            config = {}
        if modes is None:
            modes = []

        self.__text = text
        self.__immediate_events = immediate_events
        self.__config = config
        self.edit = EventHandler()
        self.focus = EventHandler()
        self.blur = EventHandler()
        if on_edit is not None:
            self.edit.connect(on_edit)
        if on_focus is not None:
            self.focus.connect(on_focus)
        if on_blur is not None:
            self.blur.connect(on_blur)
        self.__modes = modes

        self.__channel = MessageChannel()

    def set_text(self, text):
        self.__channel.send(text)

    def pres(self, pres_ctx):
        textarea = Html(u'<textarea>{text}</textarea>'.format(
            text=Html.escape_str(self.__text)))
        textarea = textarea.js_function_call('larch.controls.initCodeMirror',
                                             self.__config,
                                             self.__immediate_events,
                                             self.__channel)
        p = Html('<div>', textarea, '</div>')
        p = p.use_css('/static/codemirror-3.14/lib/codemirror.css')
        p = p.use_js('/static/codemirror-3.14/lib/codemirror.js')
        for mode in self.__modes:
            p = p.use_js(
                '/static/codemirror-3.14/mode/{0}/{0}.js'.format(mode))
        for addon in _addon_js:
            p = p.use_js('/static/codemirror-3.14/addon/{0}'.format(addon))
        for addon in _addon_css:
            p = p.use_css('/static/codemirror-3.14/addon/{0}'.format(addon))
        if _code_mirror_theme is not None:
            p = p.use_css('/static/codemirror-3.14/theme/{0}.css'.format(
                _code_mirror_theme))
        p = p.use_js('/static/larch/larch_ui.js').use_css(
            '/static/larch/larch_ui.css')
        p = p.with_event_handler('code_mirror_edit',
                                 lambda event: self.edit(event, event.data))
        p = p.with_event_handler('code_mirror_focus', self.focus)
        p = p.with_event_handler('code_mirror_blur', self.blur)
        return p
Example #15
0
class range_slider (CompositePres):
	def __init__(self, release_fn=None, slide_fn=None, width=None, values=None, min=None, max=None, step=None,
		 orientation=None, animate=False, disabled=False):
		"""
		Create a JQuery UI slider - with the range option enabled

		:param release_fn: a function to be invoked when the user releases the slider, of the form function(event, value)
		:param slide_fn: a function to be invoked when the user drags the slider, of the form function(event, value)
		:param width: the width of the slider, specified as a CSS value e.g. 200px (200 pixels) or 50%, or as an integer value that will be converted to pixels
		:param values: a pair of values representing the lower and upper bound
		:param min: the minimum value
		:param max: the maximum value
		:param step: the size of steps between positions on the slider
		:param orientation: either 'horizontal' or 'vertical'
		:param animate: if True, or if a numeric value in milliseconds specifying the animation length, this will cause the slider to animate when the user clicks to position it directly
		:param disabled: if True, causes the slider to appear disabled
		:return: the slider control
		"""

		self.release = EventHandler()
		self.slide = EventHandler()
		if release_fn is not None:
			self.release.connect(release_fn)
		if slide_fn is not None:
			self.slide.connect(slide_fn)
		self.__channel = MessageChannel()

		self.__width = '{0}px'.format(width) if isinstance(width, int) or isinstance(width, long)   else width

		options = {}
		if values is not None:
			options['values'] = values
		options['range'] = True
		if min is not None:
			options['min'] = min
		if max is not None:
			options['max'] = max
		if step is not None:
			options['step'] = step
		if orientation is not None:
			options['orientation'] = orientation
		if animate is not False:
			options['animate'] = animate
		if disabled:
			options['disabled'] = True
		self.__options = options


	def set_values(self, values):
		self.__channel.send(values)


	def pres(self, pres_ctx):
		if self.__width is None:
			div = Html('<div></div>')
		else:
			div = Html('<div style="width: {0};"></div>'.format(self.__width))
		div = div.js_function_call('larch.controls.initRangeSlider', True, self.__options, self.__channel)
		div = div.with_event_handler("slider_change", lambda event: self.release(event, event.data))
		div = div.with_event_handler("slider_slide", lambda event: self.slide(event, event.data))
		div = div.use_js('/static/larch/larch_ui.js').use_css('/static/larch/larch_ui.css')
		return div
Example #16
0
class range_slider (CompositePres):
	def __init__(self, release_fn=None, slide_fn=None, width=None, values=None, min=None, max=None, step=None,
		 orientation=None, animate=False, disabled=False):
		"""
		Create a JQuery UI slider - with the range option enabled

		:param release_fn: a function to be invoked when the user releases the slider, of the form function(event, value)
		:param slide_fn: a function to be invoked when the user drags the slider, of the form function(event, value)
		:param width: the width of the slider, specified as a CSS value e.g. 200px (200 pixels) or 50%, or as an integer value that will be converted to pixels
		:param values: a pair of values representing the lower and upper bound
		:param min: the minimum value
		:param max: the maximum value
		:param step: the size of steps between positions on the slider
		:param orientation: either 'horizontal' or 'vertical'
		:param animate: if True, or if a numeric value in milliseconds specifying the animation length, this will cause the slider to animate when the user clicks to position it directly
		:param disabled: if True, causes the slider to appear disabled
		:return: the slider control
		"""

		self.release = EventHandler()
		self.slide = EventHandler()
		if release_fn is not None:
			self.release.connect(release_fn)
		if slide_fn is not None:
			self.slide.connect(slide_fn)
		self.__channel = MessageChannel()

		self.__width = '{0}px'.format(width) if isinstance(width, int) or isinstance(width, long)   else width

		options = {}
		if values is not None:
			options['values'] = values
		options['range'] = True
		if min is not None:
			options['min'] = min
		if max is not None:
			options['max'] = max
		if step is not None:
			options['step'] = step
		if orientation is not None:
			options['orientation'] = orientation
		if animate is not False:
			options['animate'] = animate
		if disabled:
			options['disabled'] = True
		self.__options = options


	def set_values(self, values):
		self.__channel.send(values)


	def pres(self, pres_ctx):
		if self.__width is None:
			div = Html('<div></div>')
		else:
			div = Html('<div style="width: {0};"></div>'.format(self.__width))
		div = div.js_function_call('larch.controls.initRangeSlider', True, self.__options, self.__channel)
		div = div.with_event_handler("slider_change", lambda event: self.release(event, event.data))
		div = div.with_event_handler("slider_slide", lambda event: self.slide(event, event.data))
		div = div.use_js('/files/static/larch/larch_ui.js').use_css('/files/static/larch/larch_ui.css')
		return div