From a22490c0fc0fcb24a1a66bffc24a052d4c4a790e Mon Sep 17 00:00:00 2001 From: matic_t Date: Wed, 15 Jul 2020 04:17:58 -0700 Subject: [PATCH] homonymy basic implementation --- res/vsms1.xml | 7 +++- src/export.py | 69 ++++++++++++++++-------------- src/message/__init__.py | 8 ++-- src/message/delete_messages.py | 20 ++++++--- src/message/show_messages.py | 42 +++++++++++-------- src/message/simple_edits.py | 45 +++++++++++--------- src/model/entry.py | 57 ++++++++++++++----------- src/view/modals.py | 77 ++++++++++++++++++---------------- 8 files changed, 186 insertions(+), 139 deletions(-) diff --git a/res/vsms1.xml b/res/vsms1.xml index 448161b..02b498b 100644 --- a/res/vsms1.xml +++ b/res/vsms1.xml @@ -4,7 +4,12 @@ LBS - aplikativen + aplikativen3 + + bolníšnica + xyz + abc + pridevnik diff --git a/src/export.py b/src/export.py index 3a0b049..2a237ab 100644 --- a/src/export.py +++ b/src/export.py @@ -11,7 +11,6 @@ def export_to_xml(model): def export_entry(entry): parser = __new__(DOMParser()) doc = parser.parseFromString("", "text/xml") - entry_xml = doc.firstChild # create head @@ -21,7 +20,7 @@ def export_entry(entry): status = doc.createElement("status") status.textContent = entry.status head.appendChild(status) - + headword = doc.createElement("headword") headword_lemma = doc.createElement("lemma") headword_lemma.textContent = entry.headword @@ -29,7 +28,15 @@ def export_entry(entry): headword_lemma.setAttribute("type", entry.headword_type) headword.appendChild(headword_lemma) head.appendChild(headword) - + + homonyms = doc.createElement("homonymy") + headword.appendChild(homonyms) + + for h in entry.homonymy: + homonymy = doc.createElement("homonymyFeature") + homonymy.textContent = h + homonyms.appendChild(homonymy) + # if({}) works uncorrectly in transcrypt if len(entry.lexical_unit) > 0: lexunit = doc.createElement("lexicalUnit") @@ -38,86 +45,86 @@ def export_entry(entry): lexeme = doc.createElement("lexeme") lexeme.setAttribute("lexical_unit_lexeme_id", entry.lexical_unit["id"]) lexeme.textContent = entry.lexical_unit["text"] - + lexunit.appendChild(lexeme) head.appendChild(lexunit) - + grammar = doc.createElement("grammar") grammar_category = doc.createElement("category") grammar_category.textContent = entry.grammar grammar.appendChild(grammar_category) head.appendChild(grammar) - + if len(entry.measure) > 0: measure_list = doc.createElement("measureList") measure = doc.createElement("measure") measure.setAttribute("source", entry.measure["source"]) measure.setAttribute("type", entry.measure["type"]) measure.textContent = entry.measure["text"] - + measure_list.appendChild(measure) head.appendChild(measure_list) - + variants = doc.createElement("variantList") head.appendChild(variants) - + for v in entry.variants: variant = doc.createElement("variant") variant.textContent = v variants.appendChild(variant) - + relist = doc.createElement("relatedEntryList") head.appendChild(relist) - + for re in entry.related_entries: relateEntry = doc.createElement("relatedEntry") relateEntry.textContent = re relist.appendChild(relateEntry) - + head.appendChild(_export_label_list(doc, entry.labels)) - + comment = doc.createElement("comment") comment.textContent = entry.comment head.appendChild(comment) - + # now lets do body body = doc.createElement("body") entry_xml.appendChild(body) - + sense_list = doc.createElement("senseList") body.appendChild(sense_list) - + for sense in entry.senses: sense_list.appendChild(export_sense(doc, sense)) - + return doc - + def export_sense(doc, sense): sense_xml = doc.createElement("sense") sense_xml.appendChild(_export_label_list(doc, sense.labels)) - + definition_list = doc.createElement("definitionList") sense_xml.appendChild(definition_list) - + for typ, text in sense.definition.items(): definition = doc.createElement("definition") definition.textContent = text definition.setAttribute("type", typ) definition_list.appendChild(definition) - + translation_container_list = doc.createElement("translationContainerList") export_translation_list(doc, sense, translation_container_list) sense_xml.appendChild(translation_container_list) - + example_container_list = doc.createElement("exampleContainerList") sense_xml.appendChild(example_container_list) - + for example in sense.examples: example_container = example.export(doc) export_translation_list(doc, example, example_container) example_container_list.appendChild(example_container) - + return sense_xml def export_translation_list(doc, py_parent, xml_parent): @@ -126,32 +133,32 @@ def export_translation_list(doc, py_parent, xml_parent): translation_container = export_translation(doc, translation) translation_container.setAttribute("cluster", str(cidx + 1)) xml_parent.appendChild(translation_container) - + def export_translation(doc, translation): translation_xml = doc.createElement("translationContainer") translation_xml.appendChild(_export_label_list(doc, translation.tags)) - + actual_t = doc.createElement("translation") actual_t.textContent = translation.translation actual_t.setAttribute("targetLang", translation.targetLang) - + if translation.source: actual_t.setAttribute("source", translation.source) translation_xml.appendChild(actual_t) - + explanation = doc.createElement("explanation") explanation.textContent = translation.explanation translation_xml.appendChild(explanation) - + return translation_xml - + def _export_label_list(doc, lst): result = doc.createElement("labelList") for key, value in lst: key, value = export_tag(key, value) - + label_el = doc.createElement("label") label_el.textContent = value label_el.setAttribute('type', key) diff --git a/src/message/__init__.py b/src/message/__init__.py index 033717f..0e18322 100644 --- a/src/message/__init__.py +++ b/src/message/__init__.py @@ -1,13 +1,13 @@ from message.simple_messages import NoReset, Reset, ModalNotOkClose, ClickMessage, DataChgClickMessage, KeyboardPress, NoAction from message.translation_edit import EditTranslation, MoveRight, MoveLeft, BinTranslation -from message.show_messages import ShowEntryLabelsEdit, ShowEditTranslation, ShowSenseLabelEdit, ShowSenseDefinitionEdit, ShowCommentEdit, ShowAddTranslation, ShowExampleEdit, ShowVariantsEdit, ShowRelatedEntriesEdit -from message.simple_edits import EditSenseLabel, EditSenseDefinition, EditComment, AddSenseLabel, AddSense, AddExampleTranslation, DoChosenExamples, AddToLabelList, AddToGenericList, EditVariants, EditRelatedEntries, EditEntryLabels, ExampleClusterEdit, ExampleClusterAdd +from message.show_messages import ShowEntryLabelsEdit, ShowEditTranslation, ShowSenseLabelEdit, ShowSenseDefinitionEdit, ShowCommentEdit, ShowAddTranslation, ShowExampleEdit, ShowVariantsEdit, ShowHomonymyEdit, ShowRelatedEntriesEdit +from message.simple_edits import EditSenseLabel, EditSenseDefinition, EditComment, AddSenseLabel, AddSense, AddExampleTranslation, DoChosenExamples, AddToLabelList, AddToGenericList, EditVariants, EditHomonymy, EditRelatedEntries, EditEntryLabels, ExampleClusterEdit, ExampleClusterAdd from message.show_menu import ShowTranslationMenu, ShowSenseMenu, ShowExampleMenu from message.sense_edit import SenseMoveUp, SenseMoveDown, SenseBin, AddMultiwordExample from message.example_edit import ExampleMoveUp, ExampleMoveDown, ExampleBin, ExampleRoleChange, ExampleComponentSpace, ExampleComponentAdd, ExampleComponentRemove, EditExampleText, ToggleExamples, ToggleClusters -from message.delete_messages import DeleteComment, DeleteVariants, DeleteRelatedEntries, DeleteEntryLabels +from message.delete_messages import DeleteComment, DeleteVariants, DeleteHomonymy, DeleteRelatedEntries, DeleteEntryLabels from message.ske_messages import ShowSkeModal, SearchInSkeModal, SkeInsert from message.message import msg, delayed_msg - + diff --git a/src/message/delete_messages.py b/src/message/delete_messages.py index b8f866d..19635ec 100644 --- a/src/message/delete_messages.py +++ b/src/message/delete_messages.py @@ -6,18 +6,26 @@ from message.simple_messages import NoReset class DeleteComment(NoReset): def update_model(self, model): document.getElementById("modal-question").value = "" - - + + class DeleteVariants(NoReset): def update_model(self, model): for el in document.getElementsByClassName("list-adder-input"): el.value = "" - - + + class DeleteRelatedEntries(DeleteVariants): pass - - + + + +class DeleteHomonymy(NoReset): + def update_model(self, model): + for el in document.getElementsByClassName("list-adder-input"): + el.value = "" + + + class DeleteEntryLabels(NoReset): def update_model(self, model): for sel in document.getElementsByClassName("label-value"): diff --git a/src/message/show_messages.py b/src/message/show_messages.py index 57e9071..cefdefd 100644 --- a/src/message/show_messages.py +++ b/src/message/show_messages.py @@ -3,16 +3,16 @@ from message.simple_messages import ClickMessage from model import Example, Sense, Translation from view import modals - - + + class ShowSenseLabelEdit(ClickMessage): def update_model(self, model): model.sense = self.get_arg(0, Sense) - + model.sense.make_copy() model.modal_set(lambda: modals.edit_sense_label(model.sense)) - - + + class ShowSenseDefinitionEdit(ClickMessage): def update_model(self, model): model.sense = self.get_arg(0, Sense) @@ -22,35 +22,41 @@ class ShowSenseDefinitionEdit(ClickMessage): class ShowCommentEdit(ClickMessage): def update_model(self, model): model.modal_set(lambda: modals.edit_comment(model.entry.comment)) - - + + class ShowVariantsEdit(ClickMessage): def update_model(self, model): model.entry.make_copy() model.modal_set(lambda: modals.edit_variants(model.entry)) - - + + +class ShowHomonymyEdit(ClickMessage): + def update_model(self, model): + model.entry.make_copy() + model.modal_set(lambda: modals.edit_homonymy(model.entry)) + + class ShowRelatedEntriesEdit(ClickMessage): def update_model(self, model): model.entry.make_copy() model.modal_set(lambda: modals.edit_related_entries(model.entry)) - - + + class ShowExampleEdit(ClickMessage): def update_model(self, model): example = self.get_arg(0, Example) sense = self.get_arg(1, Sense) example.make_copy() model.modal_set(lambda: modals.edit_example(example, sense)) - - + + class ShowEditTranslation(ClickMessage): def update_model(self, model): translation = self.get_arg(0, Translation) - + # Get translation location (cidx, idx), (parent, cluster) = EditTranslation.get_translation_location(model.entry, translation) - + translation.make_copy() num_clusters = len(parent.translations) model.modal_set(lambda: modals.edit_translation( @@ -61,10 +67,10 @@ class ShowAddTranslation(ClickMessage): def update_model(self, model): chosen_sense_or_example = self.get_arg(0) translation = Translation() - + translation.make_copy() model.modal_set(lambda: modals.edit_translation( - translation, + translation, chosen_sense_or_example, -1, len(chosen_sense_or_example.translations), @@ -75,4 +81,4 @@ class ShowEntryLabelsEdit(ClickMessage): def update_model(self, model): model.entry.make_copy() model.modal_set(lambda: modals.edit_entry_labels(model.entry)) - + diff --git a/src/message/simple_edits.py b/src/message/simple_edits.py index e373eb4..0141b58 100644 --- a/src/message/simple_edits.py +++ b/src/message/simple_edits.py @@ -22,20 +22,20 @@ class AddToGenericList(NoReset): def update_model(self, model): list_getter = self.get_arg(0) list_getter().append("") - + def data_change(self): return False - - + + class AddToLabelList(NoReset): def update_model(self, model): list_to_add_to = self.get_arg(0, list) thing_to_add_getter = self.get_arg(1) thing_to_add = thing_to_add_getter() - + # just adding to the copy to show in the modal list_to_add_to.append(thing_to_add) - + def data_change(self): return False @@ -45,14 +45,14 @@ class AddSense(Message): sense = Sense() sense.definition = {"indicator": "New Sense"} model.entry.senses.append(sense) - - + + class EditSenseDefinition(QuestionMessage): def update_model(self, model): sense = self.get_arg(0, Sense) sense.definition["indicator"] = self.new_text - - + + class EditComment(QuestionMessage): def update_model(self, model): model.entry.comment = self.new_text @@ -61,24 +61,24 @@ class EditComment(QuestionMessage): class DoChosenExamples(Message): def update_model(self, model): chosen_examples = self.get_arg(0, list) - + inputs = document.getElementsByClassName("checkable-input") selected = None for idx, el in enumerate(inputs): if el.checked: selected = idx break - + # none was selected if selected is None: return - + # first, remove the selected examples from wherever they were for sense in model.entry.senses: for example in chosen_examples: if example in sense.examples: sense.examples.remove(example) - + # now, append selected examples to chosen sense model.entry.senses[selected].examples.extend(chosen_examples) @@ -87,8 +87,13 @@ class EditVariants(Message): def update_model(self, model): variants = common_accessors.generic_list_getter() model.entry.variants = variants - - + +class EditHomonymy(Message): + def update_model(self, model): + homonymy = common_accessors.generic_list_getter() + model.entry.homonymy = homonymy + + class EditRelatedEntries(Message): def update_model(self, model): related_entries = common_accessors.generic_list_getter() @@ -99,17 +104,17 @@ class EditEntryLabels(Message): def update_model(self, model): labels = common_accessors.label_list_getter() model.entry.labels = labels - - + + class ExampleClusterEdit(DataChgClickMessage): def update_model(self, model): example = self.get_arg(0, Example) cluster = self.get_arg(1, int) example.set_cluster(cluster) - - + + class ExampleClusterAdd(DataChgClickMessage): def update_model(self, model): example = self.get_arg(0, Example) example.set_cluster(ExampleClusters.first_empty_cluster()) - + diff --git a/src/model/entry.py b/src/model/entry.py index 036aec6..19f739a 100644 --- a/src/model/entry.py +++ b/src/model/entry.py @@ -12,6 +12,7 @@ class Entry(Data): def __init__(self): self.status = "" self.headword = "" + self.homonymy = [] self.headword_type = None self.grammar = "" self.comment = "" @@ -21,26 +22,28 @@ class Entry(Data): self.measure = {} self.labels = [] self.senses = [] - + def import_xml(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.headword_type = headword.getAttribute("type") if headword else None self.grammar = grammar.textContent if grammar else "" self.comment = comment.textContent if comment else "" self.variants = [v.textContent for v in entry_xml.querySelectorAll("head variantList variant")] + self.homonymy = [v.textContent for v in entry_xml.querySelectorAll("head headword homonymy homonymyFeature ")] self.related_entries = [re.textContent for re in entry_xml.querySelectorAll("head relatedEntryList relatedEntry")] - + lex_unit = entry_xml.querySelector("lexical_unit lexeme,lexicalUnit lexeme") if lex_unit: self.lexical_unit['id'] = lex_unit.getAttribute("lexical_unit_lexeme_id") self.lexical_unit['text'] = lex_unit.textContent - + measure = entry_xml.querySelector("measureList measure") if measure: self.measure["source"] = measure.getAttribute("source") @@ -48,19 +51,19 @@ class Entry(Data): self.measure["text"] = measure.textContent self.labels = import_label_list("head labelList label", entry_xml) - + for i, sense_xml in enumerate(entry_xml.querySelectorAll("body senseList sense")): sense = Sense() sense.import_xml(sense_xml, i) self.senses.append(sense) - - + + def view(self, model): view_sense_list = [sense.view(model, idx) for idx, sense in enumerate(self.senses)] - + buttons_left = self._view_button_section(model) buttons_right = View.view_toggle_buttons(model) - + return h("div#entry", {}, [ h("div#entry-status", {}, self.status), h("div#entry-header", {}, [ @@ -72,51 +75,57 @@ class Entry(Data): h("div.one-fifth", {}, buttons_right)]), h("div#sense-container", {}, view_sense_list), h("button.add-button", {"on": {"click": M.msg(M.AddSense)}}, "+")]) - - + + def _view_button_section(self, model): clk = lambda cls: {"on": {"click": M.msg(cls)}} buttons = [ h("button.normal", clk(M.ShowVariantsEdit), "Variante"), h("button.success", clk(M.ShowRelatedEntriesEdit), "Povezano"), h("button.success", clk(M.ShowEntryLabelsEdit), "Oznake"), - h("button.normal", clk(M.ShowCommentEdit), "Opombe")] - + h("button.normal", clk(M.ShowCommentEdit), "Opombe"), + h("button.normal", clk(M.ShowHomonymyEdit), "Homonomije"),] + view_buttons = [] view_table = [] - + if len(self.variants) == 0: view_buttons.append(buttons[0]) else: view_table.append((buttons[0], ", ".join(self.variants))) - + + if len(self.homonymy) == 0: + view_buttons.append(buttons[4]) + else: + view_table.append((buttons[4], ", ".join(self.homonymy))) + if len(self.related_entries) == 0: view_buttons.append(buttons[1]) else: view_table.append((buttons[1], ", ".join(self.related_entries))) - + if len(self.labels) == 0: view_buttons.append(buttons[2]) else: labels = ", ".join([clean_label(val) for _, val in self.labels]) view_table.append((buttons[2], labels)) - + if self.comment == "": view_buttons.append(buttons[3]) else: view_table.append((buttons[3], self.comment)) - + table_rows = [ - h("tr", {}, [ h("td", {}, btn), h("td", {}, content)]) + h("tr", {}, [ h("td", {}, btn), h("td", {}, content)]) for btn, content in view_table] - + view_buttons.append(h("table", {}, table_rows)) return h("div", {}, view_buttons) - - + + def get_measure_text(self): return self.measure["text"] if "text" in self.measure else "" - + def remove_translation(self, translation): for sense in self.senses: for cluster in sense.translations: @@ -128,4 +137,4 @@ class Entry(Data): if translation in cluster: cluster.remove(translation) return - + diff --git a/src/view/modals.py b/src/view/modals.py index 005817f..2a0a49e 100644 --- a/src/view/modals.py +++ b/src/view/modals.py @@ -9,53 +9,53 @@ def edit_translation(translation, parent, cluster_idx, num_clusters, cls): def split_line2(left, right): return h("div.flex.two", {}, [ h("span.third.span-left-of-input", {}, left), h("span.two-third", {}, right)]) - + content = [] if type(parent) is model.Example: content.extend([ h("span.translation-original-title", {}, "Primer: "), h("span.translation-original", {}, parent.simple_view()), h("hr", {}, None)]) - + # first line: transalation itself content.extend([ - split_line2("Prevedek:", + split_line2("Prevedek:", h("textarea#etv", {"props": {"value": translation.translation}}, "")), - split_line2("Razlaga:", + split_line2("Razlaga:", h("textarea#ete", {"props": {"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))) - + content.append(h("h4", {}, "Tags")) content.extend(label_list_editor(translation.copy().tags, [message.AddToLabelList, translation.copy().tags])) - + return modal_template(content, "Translation", cls) def edit_sense_label(sense): content = label_list_editor(sense.copy().labels, [message.AddToLabelList, sense.copy().labels]) return modal_template(content, "Translation", (message.EditSenseLabel, sense)) - + def edit_example(example, sense): example_original = example example = example_original.copy() - + def role_msg(idx, role): return message.msg(message.ExampleRoleChange, example_original, idx, role) - + divs = [] def list_of_right_buttons(idx, component): result = [ - h("span.example-component-button.example-component-headword", + h("span.example-component-button.example-component-headword", {"on": {"click": role_msg(idx, "headword")}}, "H"), h("span.example-component-button.example-component-collocate", {"on": {"click": role_msg(idx, "collocate")}}, "C"), h("span.example-component-button.example-component-other", {"on": {"click": role_msg(idx, "other")}}, "O")] - + if example.is_multiword(): additional_class = ".example-component-no-space" if component.no_space else "" click_message = message.msg(message.ExampleComponentSpace, example_original, idx) @@ -64,32 +64,32 @@ def edit_example(example, sense): else: result.append(h("span.example-component-button.example-component-none", {"on": {"click": role_msg(idx, "none")}}, "N")) - + result.extend([ h("span.example-component-button", {"on": {"click": message.msg(message.ExampleComponentAdd, example_original, idx)}}, "+"), h("span.example-component-button", {"on": {"click": message.msg(message.ExampleComponentRemove, example_original, idx)}}, "-")]) - + return result - + for idx, component in enumerate(example.components): role_txt = component.role if component.role is not None else "none" color_class = ".example-component-" + role_txt - + left = [h("span" + color_class, {}, role_txt)] - + if component.role is None: middle = [h("textarea.example-component-text", {"props": {"value": component.text}}, "")] else: middle = [h("input.example-component-text", {"props": {"type": "text", "value": component.text}}, "")] - + divs.append(h("div.flex.five.example-component", {}, [ - h("div.one-fifth", {}, left), - h("div.three-fifth", {}, middle), + h("div.one-fifth", {}, left), + h("div.three-fifth", {}, middle), h("div.one-fifth", {}, list_of_right_buttons(idx, component))])) - - return modal_template(divs, "Edit Example", + + return modal_template(divs, "Edit Example", (message.EditExampleText, example_original, sense)) @@ -99,6 +99,13 @@ def edit_variants(entry): return modal_template(content, "Add or remove variants", (message.EditVariants,), (message.DeleteVariants,)) +def edit_homonymy(entry): + console.log(entry) + hget = lambda: entry.copy().homonymy + content = generic_list_editor("Homonymy", hget) + return modal_template(content, "Add or remove homonymy features", (message.EditHomonymy,), (message.DeleteHomonymy,)) + + def edit_related_entries(entry): reget = lambda: entry.copy().related_entries content = generic_list_editor("Related entries", reget) @@ -125,29 +132,29 @@ def do_chosen_examples(example_list, entry): if ex in example_list: example_senses.append(idx) break - + sense_of_first_example = example_senses[0] - + options = [h("p", {}, "Choose sense for examples")] for idx, sense in enumerate(entry.senses): text = "{}: {}".format(idx + 1, sense.definition["indicator"]) id_ = "choose-example-{}".format(idx) - + props = {"type": "radio", "name": "choose-example"} - if idx == sense_of_first_example: + if idx == sense_of_first_example: props["checked"] = True - + options.append(h("input#{}.checkable-input".format(id_), {"props": props}, [])) options.append(h("label.checkable", {"attrs": {"for": id_}}, text)) options.append(h("br", {}, [])) - + return modal_template(options, "Examples picker", (message.DoChosenExamples, example_list)) def ske_list(search_term, data, page_num, senses, ske_kinds): list_contents = [] ske_list_hidden = False - + if data is None: list_contents.append(h("div.loadingspinner", {}, "")) elif type(data) is list: @@ -159,7 +166,7 @@ def ske_list(search_term, data, page_num, senses, ske_kinds): ske_list_hidden = True else: list_contents.append(h("span.error", {}, "Something went wrong in SKE: {}".format(data))) - + contents = [ h("div.flex.four", {}, [ h("select#ske-select.fourth", {}, [ @@ -168,18 +175,18 @@ def ske_list(search_term, data, page_num, senses, ske_kinds): h("input#ske-search", {"props": {"value": search_term, "type": "text"}}, "")]), h("label.fourth.ske-mid-input", {}, [ h("input#ske-page-num", {"attrs": { - "value": str(page_num), + "value": str(page_num), "type": "number", "min": 1, "step": 1}}, "")]), - h("span.fourth.button.ske-right-button", + h("span.fourth.button.ske-right-button", {"on": {"click": message.msg(message.SearchInSkeModal)}}, "Isci")]), - h("div.ske-list", - {"style": {"visibility": "hidden" if ske_list_hidden else "visible"}}, + h("div.ske-list", + {"style": {"visibility": "hidden" if ske_list_hidden else "visible"}}, list_contents), h("div.flex.three", {}, [ h("span.third", {}, "Vstavi v:"), h("select#ske-sense-select.two-third", {}, [ h("option", {}, "{} {}".format( idx + 1, sense.definition["indicator"])) for idx, sense in enumerate(senses)])])] - + return modal_template(contents, "SKE", (message.SkeInsert, data))