first commit

This commit is contained in:
2019-11-05 22:18:20 +01:00
commit 1699990c02
22 changed files with 633 additions and 0 deletions

4
src/browser/__init__.py Normal file
View File

@@ -0,0 +1,4 @@
from browser.internal import Document, Window # type: ignore
document = Document()
window = Window()

15
src/browser/internal.py Normal file
View File

@@ -0,0 +1,15 @@
# type: ignore
class Document:
def __getattr__(self, attr):
return lambda x: document[attr](x)
class Window:
def __getattr__(self, attr):
return lambda x: window[attr](x)

76
src/main.py Normal file
View File

@@ -0,0 +1,76 @@
from snabbdom import h, patch
from browser import document
from model import Model
from view import View
from update import update
model = Model()
def main(xml_str):
model.import_xml(xml_str)
update.set_view(View(document.getElementById("app")))
update.set_model(model)
update.update_model()
main("""<entry>
<head>
<status>A</status>
<headword>
<lemma>adolescenca</lemma>
</headword>
<grammar>
<category>samostalnik</category>
</grammar>
<comment></comment>
</head>
<body>
<senseList>
<sense>
<labelList>
<label>tehnika</label>
</labelList>
<definitionList>
<definition type="indicator">obdobje</definition>
</definitionList>
<translationContainerList>
<translationContainer cluster="1">
<translation>preizkus</translation>
<explanation>explainme!</explanation>
<tagsContainer>
<tag><type>podrocje</type><value>biologija</value></tag>
</tagsContainer>
</translationContainer>
<translationContainer cluster="1">
<translation>fsd</translation>
</translationContainer>
<translationContainer cluster="2">
<translation>preskus</translation>
</translationContainer>
<translationContainer cluster="2">
<translation>sdfsd</translation>
<tagsContainer>
<tag><type>podrocje</type><value>ozboltologija</value></tag>
</tagsContainer>
</translationContainer>
<translationContainer cluster="3">
<translation>fsd</translation>
</translationContainer>
</translationContainerList>
<exampleContainerList>
<exampleContainer>
<example>The test was interesting.</example>
<translationContainer>
<translation>Preizkus je bil zanimiv.</translation>
</translationContainer>
</exampleContainer>
</exampleContainerList>
</sense>
</senseList>
</body>
</entry>""")

9
src/message/__init__.py Normal file
View File

@@ -0,0 +1,9 @@
from message.simple_messages import ListItemClick
def msg(message_class):
from update import update
def callback(arg):
message_instance = message_class(arg)
update.schedule(message_instance)
return callback

3
src/message/message.py Normal file
View File

@@ -0,0 +1,3 @@
class Message:
def update_model(self, model):
raise NotImplementedError("This message does not implement update_model method")

View File

@@ -0,0 +1,10 @@
from message.message import Message
class ListItemClick(Message):
def __init__(self, num):
self.num = num
def update_model(self, model):
print(self.num)
model.names.splice(self.num, 1)

1
src/model/__init__.py Normal file
View File

@@ -0,0 +1 @@
from model.model import Model

17
src/model/entry.py Normal file
View File

@@ -0,0 +1,17 @@
from model.sense import Sense
class Entry:
def __init__(self, entry_xml):
status = entry_xml.querySelector("head status")
headword = entry_xml.querySelector("head headword lemma")
grammar = entry_xml.querySelector("head grammar category")
comment = entry_xml.querySelector("head comment")
self.status = status.textContent if status else ""
self.headword = headword.textContent if headword else ""
self.grammar = grammar.textContent if grammar else ""
self.comment = comment.textContent if comment else ""
self.senses = [Sense(sense_xml) for sense_xml in
entry_xml.querySelectorAll("body senseList sense")]

8
src/model/example.py Normal file
View File

@@ -0,0 +1,8 @@
class Example:
def __init__(self, example_xml):
example = example_xml.querySelector("example")
translation = example_xml.querySelector("translationContainer translation")
self.example = example.textContent if example else ""
self.translation = translation.textContent if translation else ""

25
src/model/model.py Normal file
View File

@@ -0,0 +1,25 @@
from model.entry import Entry
class Model:
def __init__(self, names):
self.entry = None
self.log = []
self.names = ["Ozbolt", "Katarina"]
def import_xml(self, xml_text):
parser = __new__(DOMParser())
xmlDoc = parser.parseFromString(xml_text, "text/xml")
self.entry = Entry(xmlDoc.querySelector("entry"))
# type alias Model =
# { shown: Bool
# , editable: Bool
# , entry: Maybe Entry
# , newXml: Bool
# , xml: Maybe String
# , xmlObject: Maybe Xml2.Value
# , log: List LogEntry
# }

27
src/model/sense.py Normal file
View File

@@ -0,0 +1,27 @@
from model.example import Example
from model.translation import Translation
class Sense:
def __init__(self, sense_xml):
label = sense_xml.querySelector("labelList label")
definition = sense_xml.querySelector("definitionList definition")
self.label = label.textContent if label else ""
self.definition = definition.textContent if definition else ""
self.examples = [Example(example_xml) for example_xml in
sense_xml.querySelectorAll("exampleContainerList exampleContainer")]
translations = []
max_num_cluster = 0
for translation_xml in sense_xml.querySelectorAll("translationContainerList translationContainer"):
num_cluster = int(translation_xml.getAttribute("cluster"))
max_num_cluster = max(max_num_cluster, num_cluster)
translations.append((num_cluster, Translation(translation_xml)))
self.translations = [[] for _ in range(max_num_cluster)]
for clusterNum, translation in translations:
self.translations[clusterNum - 1].append(translation)

10
src/model/translation.py Normal file
View File

@@ -0,0 +1,10 @@
class Translation:
def __init__(self, translation_xml):
translation = translation_xml.querySelector("translation")
self.translation = translation.textContent if translation else ""
self.tags = {}
for tag_xml in translation_xml.querySelectorAll("tagsContainer tag"):
t_type = tag_xml.querySelector("type").textContent
t_value = tag_xml.querySelector("value").textContent
self.tags[t_type] = t_value

17
src/snabbdom.py Normal file
View File

@@ -0,0 +1,17 @@
__pragma__ ('noanno')
__pragma__ ('js', """
var snabbdom = require('snabbdom.js');
var s_patch = snabbdom.init([ // Init patch function with chosen modules
require('snabbdom/modules/class').default, // makes it easy to toggle classes
require('snabbdom/modules/props').default, // for setting properties on DOM elements
require('snabbdom/modules/style').default, // handles styling on elements with support for animations
require('snabbdom/modules/eventlisteners').default, // attaches event listeners
]);
var s_h = require('snabbdom/h').default; // helper function for creating vnodes
""", None)
# export the symbols
h = s_h
patch = s_patch

27
src/update.py Normal file
View File

@@ -0,0 +1,27 @@
class Update:
def __init__(self):
self.message_queue = []
self.model = None
self.view = None
def update_model(self):
for msg in self.message_queue:
msg.update_model(self.model)
self.message_queue = []
self.view.view(self.model)
def schedule(self, msg):
self.message_queue.append(msg)
# for now, directly clearing message queue
self.update_model()
def set_model(self, model):
self.model = model
def set_view(self, view):
self.view = view
update = Update()

98
src/view.py Normal file
View File

@@ -0,0 +1,98 @@
from snabbdom import h, patch
from message import ListItemClick, msg
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 View.view_entry(self.model.entry)
def view_list_elements(self):
def callback(num):
return msg(lambda: ListItemClick(num))
list_elements = [
h('li', {"on": {"click": callback(idx)}}, name)
for idx, name in enumerate(self.model.names)
]
return h('ol', {}, list_elements)
@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("span#comment", {}, entry.comment)]),
h("div#sense-container", {}, view_sense_list)])
@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", {}, sense.label),
h("span.sense-definition", {}, sense.definition),
h("div", {}, View.view_translations(sense.translations)),
h("div", {}, examples),
h("input#translation-add",
{"attr": {"type": "button", "value": "+", "title": "Dodaj prevedek / HUN"}},
[])])])
@staticmethod
def view_example(example):
return h("div.example", {}, [
h("div.example-dot", {}, ""),
h("div.example-rest", {}, [
h("span.example-text", {}, example.example),
h("div.example-translation", {}, [
h("span.example-arrow", {}, ""),
h("span", {}, example.translation)])])])
@staticmethod
def view_translations(translations):
joiner = lambda: h("span.translation-semicolon", {}, ";")
result = []
for cluster in translations:
result.extend([View.view_one_translation(t) for t in cluster])
result.append(joiner())
result.pop()
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))
#elements.append(h("select.translation-select", {}, [
# h("option", {"style": {"color": "black"}, {"attr": {"value": "edit", "title": "Spremeni"}}}, "✎"),
# h("option", {"style": {"color": "black"}, {"attr": {"value": "right", "title": "Desno"}}}, "→"),
# h("option", {"style": {"color": "black"}, {"attr": {"value": "left", "title": "Levo"}}}, "←"),
# h("option", {"style": {"color": "black"}, {"attr": {"value": "bin", "title": "Odstrani"}}}, "🗑")]))
return h("div.translation-div", {}, elements)