refactoring view, now combining modals and view into one module.
Also common modal components can now be nicely separated and reused
This commit is contained in:
2
src/view/__init__.py
Normal file
2
src/view/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
import view.modals
|
||||
from view.view import View
|
||||
30
src/view/modal_templates.py
Normal file
30
src/view/modal_templates.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import message
|
||||
from lib.snabbdom import h
|
||||
|
||||
def modal_template(content, title, msg, prop):
|
||||
reset = message.msg(message.ModalNotOkClose)
|
||||
return [
|
||||
h("header", {}, [
|
||||
h("h3", {}, title),
|
||||
h("label.close", {"on": {"click": reset}}, "×")]),
|
||||
h("section.content", {}, content ),
|
||||
h("footer", {}, [
|
||||
h("a.button", {"on": {"click": message.msg(msg, prop)}}, "OK"),
|
||||
h("label.button.dangerous", {"on": {"click": reset}}, "Cancel")])]
|
||||
|
||||
|
||||
def one_question_modal(title, msg, question, current_value, prop):
|
||||
content = [
|
||||
h("span", {}, question),
|
||||
h("label", {}, [
|
||||
h("input#modal-input", {"props": {"type": "text", "value": current_value}}, "")])]
|
||||
return modal_template(content, title, msg, prop)
|
||||
|
||||
|
||||
def list_adder(title, element_list_getter, add_click_message):
|
||||
content = [h("span", {}, title)]
|
||||
for slabel in element_list_getter():
|
||||
content.append(h("label", {}, [
|
||||
h("input.list-adder-input", {"props": {"type": "text", "value": slabel}}, "")]))
|
||||
content.append(h("button", {"on": {"click": add_click_message}}, "+"))
|
||||
return content
|
||||
83
src/view/modals.py
Normal file
83
src/view/modals.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from lib.snabbdom import h
|
||||
import message
|
||||
from model.translation import TAGS
|
||||
from view.modal_templates import *
|
||||
|
||||
|
||||
def edit_translation(translation, cluster_idx, num_clusters, cls, prop):
|
||||
def split_line2(left, right):
|
||||
return h("div.flex.two", {}, [
|
||||
h("span.third.span-left-of-input", {}, left), h("span.two-third", {}, right)])
|
||||
|
||||
def split_line3(left, center, right):
|
||||
return h("div.flex.three", {}, [
|
||||
h("span.third.span-left-of-input", {}, left), h("span.third", {}, center), h("span.third", {}, right)])
|
||||
|
||||
def dropdown_right(tag_name):
|
||||
left = tag_name + ":"
|
||||
|
||||
values = TAGS[tag_name]
|
||||
selected_value = translation.tags[tag_name] if tag_name in translation.tags else None
|
||||
|
||||
options = [h("option", {}, [])]
|
||||
for value in values:
|
||||
options.append(h("option", {"props": {"selected": selected_value == value}}, value))
|
||||
center = h("select#{}-s".format(tag_name), {}, options)
|
||||
|
||||
right_value = selected_value if selected_value not in values and selected_value is not None else ""
|
||||
right = h("input#{}-o".format(tag_name),
|
||||
{"props": {"type": "text", "value": right_value, "placeholder": "drugo"}},
|
||||
[])
|
||||
|
||||
return split_line3(left, center, right)
|
||||
|
||||
# first line: transalation itself
|
||||
content = [split_line2("Prevedek:",
|
||||
h("input#etv", {"props": {"type": "text", "value": translation.translation}}, "")),
|
||||
split_line2("Razlaga:",
|
||||
h("input#ete", {"props": {"type": "text", "value": translation.explanation}}, ""))]
|
||||
|
||||
# cluster number
|
||||
options = [h("option", {"props": {"selected": idx == cluster_idx}}, str(idx + 1)) for idx in range(num_clusters + 1)]
|
||||
content.append(split_line2("Stevilka gruce:", h("select#cluster-num", {}, options)))
|
||||
|
||||
# tags
|
||||
content.append(h("h4", {}, "Tags"))
|
||||
for tag in TAGS.keys():
|
||||
content.append(dropdown_right(tag))
|
||||
|
||||
return modal_template(content, "Translation", cls, prop)
|
||||
|
||||
|
||||
def edit_sense_label(sense):
|
||||
content = [h("span", {}, "Edit sense labels")]
|
||||
|
||||
for slabel in sense.copy().labels:
|
||||
content.append(h("label", {}, [
|
||||
h("input.sense-edit-input", {"props": {"type": "text", "value": slabel}}, "")]))
|
||||
|
||||
content.append(h("button", {"on": {"click": message.msg(message.AddSenseLabel, sense)}}, "+"))
|
||||
|
||||
return modal_template(content, "Sense", message.EditSenseLabel, sense)
|
||||
|
||||
|
||||
def edit_example_translation(example):
|
||||
etl_getter = lambda: example.copy().translations
|
||||
content = list_adder("Edit example translations", etl_getter, message.msg(message.AddExampleTranslation, example))
|
||||
return modal_template(content, "Example Translations", message.EditExampleTranslation, example)
|
||||
|
||||
|
||||
def add_sense(sense):
|
||||
return one_question_modal("Add sense", message.AddSense, "Add sense with a label", "", sense)
|
||||
|
||||
|
||||
def edit_sense_definition(sense):
|
||||
return one_question_modal("Sense definition", message.EditSenseDefinition, "Edit sense definition", sense.definition, sense)
|
||||
|
||||
|
||||
def edit_comment(comment):
|
||||
return one_question_modal("Comment", message.EditComment, "Edit comment", comment, None)
|
||||
|
||||
|
||||
def edit_example(example):
|
||||
return one_question_modal("Example", message.EditExample, "Edit example", example.example, example)
|
||||
117
src/view/view.py
Normal file
117
src/view/view.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from lib.snabbdom import h, patch
|
||||
from message import *
|
||||
import random
|
||||
|
||||
from export import export_to_xml
|
||||
|
||||
|
||||
class View:
|
||||
def __init__(self, container):
|
||||
self.vdom = h('div', {}, "Loading...")
|
||||
self.model = None
|
||||
patch(container, self.vdom)
|
||||
|
||||
def view(self, model):
|
||||
self.model = model
|
||||
new_vdom = self._view()
|
||||
patch(self.vdom, new_vdom)
|
||||
self.vdom = new_vdom
|
||||
|
||||
def _view(self):
|
||||
return h("div", {"on": { "click": msg(Reset) }}, [
|
||||
View.view_entry(self.model.entry),
|
||||
# h("button.blk", {"on": { "click": lambda _: console.log(export_to_xml(self.model)) } }, "XML2Console"),
|
||||
View.view_menu(self.model.menu_location, self.model.menu_shown, self.model.translation),
|
||||
View.view_modal(self.model.modal_shown, self.model.modal)])
|
||||
|
||||
@staticmethod
|
||||
def view_entry(entry):
|
||||
view_sense_list = [View.view_sense(sense, idx) for idx, sense in enumerate(entry.senses)]
|
||||
|
||||
return h("div#entry", {}, [
|
||||
h("div#entry-status", {}, entry.status),
|
||||
h("div#entry-header", {}, [
|
||||
h("span#headword", {}, entry.headword),
|
||||
h("span#grammar", {}, entry.grammar),
|
||||
h("button#comment.warning", {"on": {"click": msg(ShowCommentEdit)}}, entry.comment)]),
|
||||
h("div#sense-container", {}, view_sense_list),
|
||||
h("button.add-button", {"on": {"click": msg(ShowSenseAdd)}}, "+")])
|
||||
|
||||
@staticmethod
|
||||
def view_sense(sense, senseNum):
|
||||
examples = [View.view_example(example) for example in sense.examples]
|
||||
|
||||
return h("div.elm-div", {}, [
|
||||
h("div.sense-num", {}, str(senseNum + 1)),
|
||||
h("div.sense", {}, [
|
||||
h("span.sense-label-list", { "on": { "click": msg(ShowSenseLabelEdit, sense) }}, [
|
||||
h("span.sense-label", {}, slabel) for slabel in sense.labels ]),
|
||||
h("span.sense-definition", { "on": { "click": msg(ShowSenseDefinitionEdit, sense) }}, sense.definition),
|
||||
h("div", {}, View.view_translations(sense.translations, sense)),
|
||||
h("div", {}, examples)])])
|
||||
|
||||
@staticmethod
|
||||
def view_example(example):
|
||||
return h("div.example", {}, [
|
||||
h("div.example-dot", {}, "▣"),
|
||||
h("div.example-rest", {}, [
|
||||
h("span.example-text", {"on": {"click": msg(ShowExampleEdit, example)} }, example.example),
|
||||
h("div.example-translation-list", { "on": {"click": msg(ShowExampleTranslationEdit, example)} }, [
|
||||
h("div.example-translation", {}, [
|
||||
h("span.example-arrow", {}, "↪"),
|
||||
h("span", {}, t)])
|
||||
for t in example.translations])])])
|
||||
|
||||
@staticmethod
|
||||
def view_translations(translations, sense):
|
||||
result = []
|
||||
for cluster in translations:
|
||||
result.append(h("div.translation-div-cluster", {}, [View.view_one_translation(t) for t in cluster]))
|
||||
|
||||
result.append(h("button.add-button", {"on": {"click": msg(ShowAddTranslation, sense)}}, "+"))
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def view_one_translation(translation):
|
||||
elements = []
|
||||
|
||||
if translation.tags:
|
||||
tags = h("div.translation-tags", {}, [
|
||||
h("span", {"attr": {"title": key}}, value)
|
||||
for key, value in translation.tags.items()])
|
||||
elements.append(tags)
|
||||
|
||||
elements.append(h("span.translation-text", {}, translation.translation))
|
||||
if translation.source:
|
||||
elements.append(h("span.translation-source", {}, translation.source))
|
||||
|
||||
explanation_class = ".translation-explanation" if translation.translation else ""
|
||||
elements.append(h("span{}".format(explanation_class), {}, translation.explanation))
|
||||
|
||||
return h("div.translation-div", {"on": {"click": msg(ShowMenu, translation) }}, elements)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def view_menu(location, menu_shown, translation):
|
||||
style = {
|
||||
"left": "{}px".format(location[0]),
|
||||
"top": "{}px".format(location[1])
|
||||
}
|
||||
if menu_shown:
|
||||
style["opacity"] = "1"
|
||||
style["visibility"] = "visible"
|
||||
|
||||
return h("span.popup-menu", { "style": style }, [
|
||||
h("button.shyButton", { "on": {"click": msg(ShowEditTranslation, translation)}}, "✎"),
|
||||
h("button.shyButton", { "on": {"click": msg(MoveRight, translation)}}, "→"),
|
||||
h("button.shyButton", { "on": {"click": msg(MoveLeft, translation)}}, "←"),
|
||||
h("button.shyButton", { "on": {"click": msg(BinTranslation, translation)}}, "🗑")])
|
||||
|
||||
|
||||
@staticmethod
|
||||
def view_modal(modal_shown, modal):
|
||||
return h("div.modal", {}, [
|
||||
h("input", { "props": {"type": "checkbox", "checked": modal_shown} }, ""),
|
||||
h("label.overlay", {}, ""),
|
||||
h("article", {"on": { "click": msg(NoReset) }}, modal())])
|
||||
|
||||
Reference in New Issue
Block a user