#!/usr/bin/env python3 # -*- coding:utf-8 -*- from pscript import RawJS from flexx import flx URL = "https://konubinix.eu" # URL = "http://192.168.1.2:9999" class BootstrapButton(flx.Widget): text = flx.StringProp("", settable=True) disabled = flx.BoolProp(False, settable=True) button_style = flx.EnumProp(["PRIMARY", "SECONDARY"], "PRIMARY", settable=True) def _render_dom(self): return [self.text] def _create_dom(self): return flx.create_element( "button", {"class": f"btn btn-{self.button_style.lower()}", "type": "button"}, self.text ) @flx.reaction('disabled') def __disabled_changed(self, *events): if events[-1].new_value: self.node.classList.add("disabled") self.node.setAttribute("disabled", "disabled") else: self.node.classList.remove("disabled") self.node.removeAttribute("disabled") class Modal(flx.Label): title = flx.StringProp("", settable=True) shown = flx.BoolProp(settable=True) def _render_dom(self): global document button = document.createElement("button") button.classList.add("btn") button.classList.add("btn-secondary") button.setAttribute("data-dismiss", "modal") button.innerText = "Close" return flx.create_element( "div", {"class": "modal fade"}, flx.create_element( "div", {"class": "modal-dialog"}, flx.create_element( "div", {"class": "modal-content"}, flx.create_element( "div", {"class": "modal-header"}, flx.create_element( "h5", {"class": "modal-title"}, self.title ) ), flx.create_element( "div", {"class": "modal-body"}, super()._render_dom() ), flx.create_element( "div", {"class": "modal-footer"}, button ) ) ) ) def display(self): global window window.setTimeout(lambda: RawJS("$")(self.node).modal(), 0) self.root.frontend.set_inmodal(True) self.set_shown(True) RawJS("$")(self.node).on("hidden.bs.modal", lambda: self.onhidden()) def onhidden(self): self.set_shown(False) self.root.frontend.set_inmodal(False) class BootstrapDropdown(flx.Widget): CSS = """ .flx-BootstrapDropdown { overflow: visible; } .flx-BootstrapDropdown > button { height: 100%; width: 100%; } """ items = flx.ListProp(settable=True) text = flx.StringProp("", settable=True) disabled_items = flx.DictProp(settable=True) override_text = flx.DictProp(settable=True) button_style = flx.EnumProp(["PRIMARY", "SECONDARY"], "PRIMARY", settable=True) disabled = flx.BoolProp(settable=True) def _create_dom(self): return flx.create_element( "div", {"class": "dropdown"} ) @flx.action def override(self, id, text): self._mutate_override_text({id: text}, "insert") def _render_dom(self): def render_item(id, text): global document if id is None: el = document.createElement("div") el.classList.add("dropdown-divider") else: el = document.createElement("button") el.onclick = lambda: self.clicked(id) el.innerText = text el.classList.add("dropdown-item") if self.disabled_items.get(id): el.classList.add("disabled") return el dropdown_button = document.createElement("button") if self.disabled: dropdown_button.classList.add("disabled") dropdown_button.classList.add("btn") dropdown_button.classList.add(f"btn-{self.button_style.lower()}") dropdown_button.classList.add("dropdown-toggle") dropdown_button.setAttribute("type", "button") dropdown_button.setAttribute("data-toggle", "dropdown") dropdown_button.innerText = self.text return [ dropdown_button, flx.create_element( "div", {"class": "dropdown-menu"}, [ render_item(id, self.override_text.get(id, text)) for id, text in self.items ] ) ] @flx.emitter def clicked(self, id): return {"id": id} def positivemod(a, b): return ((a % b) + b) % b class DatePicker(flx.Widget): date = flx.StringProp(settable=True) CSS = """ .flx-DatePicker { width: 8em!important; /* empirically, the size of YYYY/MM/DD */ } """ def _create_dom(self): global window, document node = window.document.createElement('input') node.classList.add("form-control") node.setAttribute("type", "text") node.placeholder = "\uf073" self.elem = RawJS('$')(node) self.datepicker = self.elem.datepicker( { "todayBtn": "linked", "clearBtn": True, "todayHighlight": True, "autoclose": True, "disableTouchKeyboard": True, "language": "fr", "weekStart": 1, "calendarWeeks": True, } ) global moment self.elem.on( "changeDate", lambda: self.on_change_date() ) self.elem.on( "clearDate", lambda: self.set_date("") ) return node def on_change_date(self): date = self.elem.datepicker("getUTCDate") if date is None: self.set_date("") else: self.set_date(self.date_to_string(date)) def date_to_string(self, date): global moment return moment(date).format("YYYY-MM-DD") def get_datepicker_date_string(self): return self.date_to_string(self.elem.datepicker('getUTCDate')) @flx.reaction("date") def update_date(self): global moment if self.date == "": self.elem.datepicker("clearDates") elif self.date != self.get_datepicker_date_string(): self.elem.datepicker( "setUTCDate", moment(self.date).toDate() ) class HR(flx.Widget): def _create_dom(self): return flx.create_element("hr") class BootstrapInput(flx.HBox): icon_text = flx.StringProp(settable=True) def _render_dom(self): return flx.create_element( "div", {"class": "input-group"}, flx.create_element( "div", {"class": "input-group-prepend"}, flx.create_element( "span", {"class": "input-group-text"}, self.icon_text, ) ), self.children[0].outernode, ) def get_from_localstorage(name): global JSON return JSON.parse( window.localStorage.getItem(name) or "{}" ) def set_to_localstorage(name, value): global window, JSON window.localStorage.setItem( name, JSON.stringify(value) )