#!/usr/bin/env python3 # -*- coding:utf-8 -*- from flexx import flx import ipfsdocs from ipfsdocs.common import ( BootstrapButton, BootstrapDropdown, URL, ) from ipfsdocs.log import info from ipfsdocs.downloadmanager import DownloadHandler class Navigation(flx.Widget): CSS = """ .flx-Navigation > ul, .flx-Navigation > ul > li, .flx-Navigation > ul > li > button { height:100%; } .flx-Navigation { overflow-x: scroll; } """ def _create_dom(self): global document outer = document.createElement("nav") inner = document.createElement("ul") inner.classList.add("pagination") outer.appendChild(inner) return outer def clicked_on(self, text): if text == "<": self.root.state.set_page(self.root.state.page - 1) elif text == ">": self.root.state.set_page(self.root.state.page + 1) else: number = int(text) - 1 self.root.state.set_page(number) def _render_dom(self): if self.root.state.number_of_pages == 0: return [] def render_item(text, disabled=False, active=False): return flx.create_element( "li", {"class": f"page-item {'active' if active else ''} {'disabled' if disabled else ''}"}, flx.create_element( "button", { "class": f"page-link", "onclick": lambda: self.clicked_on(text), }, flx.create_element( "span", {"aria-hidden": "true"}, str(text) ) ) ) return [ flx.create_element( "ul", {"class": "pagination"}, [ render_item("<", self.root.state.page == 0) ] + [ render_item(page + 1, False, page == self.root.state.page) for page in range(self.root.state.number_of_pages) ] + [ render_item(">", (self.root.state.page + 1) == self.root.state.number_of_pages) ] ) ] class SelectionHandler(BootstrapDropdown): def init(self): self.set_text("\uf058") self.set_items( [ ("select_page", "\uf15b"), ("select_all", "\uf0ac"), (None,), ("clean", "\uf12d"), (None,), ("toggle_show", ""), ("toggle_range", ""), ] ) self.update_on_selection() self.update_toggle_range_mode() self.update_selection_only_message() @flx.reaction("root.state.selection", "root.state.number_of_elements") def update_text_on_selection(self): self.set_text( f"\uf058 ({len(self.root.state.selection.items())}/{(self.root.state.number_of_elements)})" ) @flx.reaction("root.state.readonly") def hide_when_readonly(self): self.set_css_class("d-none") @flx.action def update_disabled_on_selection(self): self._mutate_disabled_items( { "clean": not self.root.state.selection, "toggle_show": not self.root.state.selection, }, "insert" ) @flx.reaction("root.frontend.selection_only") def update_selection_only_message(self): if self.root and self.root.frontend and self.root.frontend.selection_only: self.override("toggle_show", "\uf205 \uf00c") else: self.override("toggle_show", "\uf204 \uf00c") @flx.reaction("root.frontend.range_mode") def update_toggle_range_mode(self): if self.root and self.root.frontend and self.root.frontend.range_mode: self.override("toggle_range", "\uf205 \uf1de") else: self.override("toggle_range", "\uf204 \uf1de") @flx.reaction("clicked") def on_clicked(self, *events): for event in events: if event.id == "clean": self.root.state.set_selection({}) self.root.frontend.set_cid_extremum("") elif event.id == "toggle_show": self.root.frontend.set_selection_only(not self.root.frontend.selection_only) elif event.id == "everything": self.root.frontend.set_selection_only(False) elif event.id == "select_all": self.select_all() elif event.id == "select_page": self.select_page() elif event.id == "toggle_range": self.root.frontend.set_range_mode(not self.root.frontend.range_mode) self.root.frontend.set_cid_extremum("") @flx.action def select_page(self): selection = {} self.root.state.page * self.root.state.number_per_page for info_ in self.root.state.query_results[ self.root.state.page * self.root.state.number_per_page : (self.root.state.page + 1) * self.root.state.number_per_page ]: selection[info_["cid"]] = True self.root.state._mutate_selection(selection, "insert") @flx.action def select_all(self): selection = {} for info_ in self.root.state.query_results: selection[info_["cid"]] = True self.root.state._mutate_selection(selection, "insert") @flx.reaction("root.state.selection") def update_on_selection(self): self.update_disabled_on_selection() class ShareHandler(BootstrapDropdown): def init(self): self.set_text("\uf1e0") self.set_items( [ ("all", "\uf0ac"), ("selection", "\uf00c"), ] ) self.toggle_share_on_selection() @flx.reaction("root.state.readonly") def hide_when_readonly(self): self.set_css_class("d-none") @flx.reaction("clicked") def on_clicked(self, *events): for event in events: if event.id == "all": self.root.jssays.share_all() elif event.id == "selection": self.root.jssays.share_selection() @flx.reaction("root.state.selection") def toggle_share_on_selection(self): self.update_disabled_on_selection() @flx.action def update_disabled_on_selection(self): self._mutate_disabled_items( {"selection": not self.root.state.selection}, "insert" ) class EditHandler(BootstrapDropdown): def init(self): self.set_text("\uf00c \uf061") self.set_items( [ ("todo", "todo"), ("next", "next"), ("done", "done"), ("delete", "\uf1f8"), (None,), ("move", "\uf1ea"), (None,), ("tag", "\uf02b"), (None,), ("owner", "\uf007"), (None,), ("date", "\uf073"), ] ) self.update_disabled() @flx.reaction("root.state.selection") def toggle_disabled(self): self.update_disabled() @flx.action def update_disabled(self): self.set_disabled(not self.root.state.selection) @flx.reaction("root.state.readonly") def hide_when_readonly(self): self.set_css_class("d-none") @flx.reaction("clicked") def on_clicked(self, *events): for event in events: if event.id == "delete": self.ask_delete() elif event.id == "done": self.root.jssays.move_selection_to_state("done") elif event.id == "next": self.root.jssays.move_selection_to_state("next") elif event.id == "todo": self.root.jssays.move_selection_to_state("todo") elif event.id == "move": self.root.frontend.move_handler.display() elif event.id == "tag": self.root.frontend.set_tag_modal.display() elif event.id == "owner": self.root.frontend.set_owner_modal.display() elif event.id == "date": self.root.frontend.set_date_modal.display() def ask_delete(self): self.root.frontend.confirm.display( f"{len(self.root.state.selection.items())} \uf15b \uf061 \uf1f8", self.delete ) def delete(self): self.root.jssays.move_selection_to_state("delete") class Footer(flx.HBox): def init(self): # allow elements to overflow to allow dropdown and stuffs like that self.apply_style("overflow: visible;") with flx.VBox(): flx.Label(text=f"IPFSDocs {ipfsdocs.__version__}") flx.Widget(flex=1) with flx.VBox(style="overflow: visible;"): with flx.HBox(style="overflow: visible;"): self.selection_handler = SelectionHandler() self.edit = EditHandler() flx.Label(text=" ", css_class="bg-secondary rounded-pill") self.share = ShareHandler() self.download = DownloadHandler() with flx.HBox(): self.navigation = Navigation(flex=0.1) flx.Widget(flex=1) self.options = BootstrapButton( text="\uf013", flex=0.01, ) self.fullscreen = BootstrapButton( text="\uf0b2", disabled=True, flex=0.01, ) @flx.reaction("fullscreen.pointer_click") def say_fullscreen(self): self.root.jssays.fullscreen() @flx.reaction("options.pointer_click") def open_options(self): self.root.frontend.options_handler.display() @flx.reaction("root.state.number_of_elements") def toggle_fullscreen_on_result(self): self.fullscreen.set_disabled(not self.root.state.number_of_elements)