From 2cfabd5f74fea8522949ff9165ccb1b119bc0a6c Mon Sep 17 00:00:00 2001 From: David Bau Date: Tue, 30 Aug 2022 03:00:59 -0400 Subject: [PATCH] Add checkbox widget. --- baukit/__init__.py | 2 +- baukit/labwidget.py | 48 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/baukit/__init__.py b/baukit/__init__.py index 6a3136d..9f6f676 100644 --- a/baukit/__init__.py +++ b/baukit/__init__.py @@ -1,6 +1,6 @@ from .labwidget import Model, Widget, Trigger, Property, Event from .labwidget import Button, Label, Textbox, Numberbox, Range, ColorPicker -from .labwidget import Choice, Menu, Datalist, Div, ClickDiv, Img +from .labwidget import Checkbox, Choice, Menu, Datalist, Div, ClickDiv, Img from .labwidget import Textarea from .paintwidget import PaintWidget from .plotwidget import PlotWidget diff --git a/baukit/labwidget.py b/baukit/labwidget.py index 0be31b9..3fcf250 100644 --- a/baukit/labwidget.py +++ b/baukit/labwidget.py @@ -783,7 +783,7 @@ class Choice(Widget): }); element.innerHTML = lines.join(); } - model.on('choices horizontal', render); + model.on('choices', render); model.on('value', (ev) => { [...element.querySelectorAll('input')].forEach((e) => { e.checked = (e.value == ev.value); @@ -806,6 +806,52 @@ class Choice(Widget): out.append(html.escape(str(value))) return ''.join(out) +class Checkbox(Widget): + """ + A True/False checkbox with a label. + """ + + def __init__(self, label=None, value=False, + **kwargs): + super().__init__(**kwargs) + self.label = Property(label) + self.value = Property(value) + + def widget_js(self): + # Note that the 'input' event would enable during-drag feedback, + # but this is pretty slow on google colab. + return minify(''' + function esc(unsafe) { + return unsafe.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); + } + function render() { + element.innerHTML = '' + } + model.on('label', render); + model.on('value', (ev) => { + element.check.checked = (!!ev.value); + }); + element.addEventListener('change', (e) => { + model.set('value', element.check.checked); + }); + ''') + + def widget_html(self): + out = [] + with show.enter('form', self.std_attrs(), + show.style(whiteSpace='nowrap'), out=out): + with show.enter('label', out=out): + show.emit(show.PLAIN('input', + show.style(margin='auto'), + (show.attr(checked=None) if self.value else None), + name='check', type='checkbox'), out=out) + with show.enter('div', out=out): + out.append(html.escape(str(self.label))) + return ''.join(out) + class Menu(Widget): """ A dropdown choice.