diff --git a/build/build_and_upload.sh.template b/build/build_and_upload.sh.template index 987e470..093b516 100755 --- a/build/build_and_upload.sh.template +++ b/build/build_and_upload.sh.template @@ -4,10 +4,10 @@ ############################################################################# # Alter these variables -#USERNAME= vps_sign_in(probably name@lexonomy.cjvt.si -#VPS_PASSWORD= vps password -#VPS_USERNAME= user name inside vps(probably name from @lexonomy) -#API_KEY= $(cat path/to/api/token/file) +#USERNAME=vps_sign_in(probably name@lexonomy.cjvt.si +#VPS_PASSWORD=vps password +#VPS_USERNAME=user name inside vps(probably name from @lexonomy) +#API_KEY=$(cat path/to/api/token/file) # Exit if no argument is passed on run if [[ -z "$1" ]]; then @@ -24,4 +24,4 @@ tar czf - ./config.json ./bundle.js ./local.js ./main.css ./main.html | ssh $USE # Create a simlink on VPS that will enable specific plugin on https://lexonomy.cjvt.si/ # Routes must be absolute or it doesn't work. -ssh -t $USERNAME -p $VPS_PASSWORD "sudo ln -s /home/$VPS_USERNAME/plugins/$PLUGIN_NAME /home/ozbolt/plugins/$PLUGIN_NAME" +ssh -t $USERNAME -p $VPS_PASSWORD "sudo -s unlink /home/ozbolt/plugins/$PLUGIN_NAME || true && sudo ln -s /home/$VPS_USERNAME/plugins/$PLUGIN_NAME /home/ozbolt/plugins/$PLUGIN_NAME" 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..ed28df7 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,18 @@ def export_entry(entry): headword_lemma.setAttribute("type", entry.headword_type) headword.appendChild(headword_lemma) head.appendChild(headword) - + + homonymy = doc.createElement("homonymy") + headword.appendChild(homonymy) + + for hFeature in entry.homonymy: + feature = doc.createElement("homonymyFeature") + feature.textContent = hFeature.value +# Can't use hFeature.name, because Python has name reserver and so it becomes py_name in JS + feature.setAttribute("name", hFeature["name"]) + homonymy.appendChild(feature) + + # if({}) works uncorrectly in transcrypt if len(entry.lexical_unit) > 0: lexunit = doc.createElement("lexicalUnit") @@ -38,86 +48,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 +136,42 @@ 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) - + + explanationList = doc.createElement("explanationList") + + for explanation in translation.explanationList: + el = doc.createElement("explanation") + el.textContent = explanation + explanationList.appendChild(el) + + translation_xml.appendChild(explanationList) + + 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/common_accessors.py b/src/message/common_accessors.py index 67259af..6618233 100644 --- a/src/message/common_accessors.py +++ b/src/message/common_accessors.py @@ -8,28 +8,43 @@ def generic_list_getter(): if result_candidate != "": result.append(result_candidate) return result - + +# Formats data from inputs to name-value objects +def homonymy_list_getter(): + result = [] + for row in document.getElementsByClassName("label-list-row"): + value = row.querySelector(".value-input").value + name = row.querySelector(".name-input").value + + if ("" in [name, value]): + continue + + result.append({"name": name, "value": value}) + + return result + + def label_list_getter(): result = [] for row in document.getElementsByClassName("label-list-row"): ltype = row.querySelector(".label-type") lvalue = row.querySelector(".label-value") lother = row.querySelector(".label-value-other") - + if lother is None: continue - + value = lother.value if not value: - value = lvalue.options[lvalue.selectedIndex].text - + value = lvalue.options[lvalue.selectedIndex].text + if not value: continue - + result.append((ltype.textContent, value)) - + kontrastivno = document.getElementById("kontrastivno-input").checked; if kontrastivno: result.append(("razmerje", "kontrastivno")) - + return result 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..0ba1d03 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.homonymy_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/message/translation_edit.py b/src/message/translation_edit.py index 51a4dae..daa07bd 100644 --- a/src/message/translation_edit.py +++ b/src/message/translation_edit.py @@ -6,26 +6,27 @@ from model.translation import Translation from model.sense import Sense - + class EditTranslation(DataChgClickMessage): def update_model(self, model): self.translation = self.get_arg(0, Translation) self.old_cluster_idx = self.get_arg(1, int) - + self.translation.translation = document.getElementById("etv").value - self.translation.explanation = document.getElementById("ete").value - +# This could be dangerous if generic_list_getter is getting data from any other list as well. + self.translation.explanationList = common_accessors.generic_list_getter() + # common_accessors.label_list_getter() self.translation.tags = common_accessors.label_list_getter() - + # check if empty, remove! if self.translation.is_empty(): model.entry.remove_translation(self.translation) return - + new_cluster_idx = int(document.getElementById("cluster-num").value) - 1 self.handle_cluster_change(new_cluster_idx, model) - + @staticmethod def get_translation_location(entry, translation): def find_in_clusters(parent): @@ -34,7 +35,7 @@ class EditTranslation(DataChgClickMessage): if search_translation == translation: return (ci, ti), (parent, cluster) return None - + for sense in entry.senses: res = find_in_clusters(sense) if res is not None: @@ -43,21 +44,21 @@ class EditTranslation(DataChgClickMessage): res = find_in_clusters(example) if res is not None: return res - + window.console.log("should not be here...") - - + + def handle_cluster_change(self, new_cluster_idx, model): if self.old_cluster_idx == new_cluster_idx: return - + (cidx, tidx), (parent, cluster) = EditTranslation.get_translation_location(model.entry, self.translation) self.do_cluster_change(parent, cluster, cidx, tidx, new_cluster_idx) - + def do_cluster_change(self, sense_or_example, cluster, cidx, tidx, new_cluster_idx): # remove the translation from the old cluster cluster.splice(tidx, 1) - + # we maybe are creating a new cluster, handle that if len(sense_or_example.translations) == new_cluster_idx: sense_or_example.translations.append([self.translation]) @@ -66,12 +67,12 @@ class EditTranslation(DataChgClickMessage): sense_or_example.translations[new_cluster_idx].append(self.translation) else: raise ValueError("Bad new cluster idx :(") - + # we still hold cluster reference, check if empty and remove if necessary # we cant do this earlier since indexes change and yeah, fun stuff if len(cluster) == 0: sense_or_example.translations.splice(cidx, 1) - + class MoveRight(DataChgClickMessage): def update_model(self, model): @@ -80,8 +81,8 @@ class MoveRight(DataChgClickMessage): if idx != len(cluster) - 1: cluster[idx], cluster[idx + 1] = cluster[idx + 1], cluster[idx] model.translation = None - - + + class MoveLeft(DataChgClickMessage): def update_model(self, model): translation = self.get_arg(0, Translation) @@ -89,8 +90,8 @@ class MoveLeft(DataChgClickMessage): if idx != 0 and len(cluster) > 1: cluster[idx], cluster[idx - 1] = cluster[idx - 1], cluster[idx] model.translation = None - - + + class BinTranslation(DataChgClickMessage): def update_model(self, model): translation = self.get_arg(0, Translation) @@ -101,7 +102,7 @@ class BinTranslation(DataChgClickMessage): else: cluster.splice(tidx, 1) model.translation = None - + class AddTranslation(EditTranslation): def handle_cluster_change(self, new_cluster_idx, _): @@ -110,4 +111,4 @@ class AddTranslation(EditTranslation): # we make a dummy cluster, cluster_idx and translation_idx # we give a correct new_cluster_idx self.do_cluster_change(self.get_arg(2), [None, None], None, None, new_cluster_idx) - + diff --git a/src/model/entry.py b/src/model/entry.py index 036aec6..46dc5f4 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,27 @@ 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 = [{"value": v.textContent, "name": v.getAttribute("name")} 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 +50,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 +74,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((h["name"] + ": " + h.value) for h in 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 +136,4 @@ class Entry(Data): if translation in cluster: cluster.remove(translation) return - + diff --git a/src/model/example/component_lexeme.py b/src/model/example/component_lexeme.py index 5757316..8ff0f90 100644 --- a/src/model/example/component_lexeme.py +++ b/src/model/example/component_lexeme.py @@ -23,7 +23,7 @@ class ComponentLexeme(Data): if xml.hasAttribute("space"): self.no_space = xml.getAttribute("space") == "false" - for oth_attr in ["lexical_unit_lexeme_id", "slolex", "kol"]: + for oth_attr in ["lexical_unit_lexeme_id", "slolex", "kol", "sloleks"]: if xml.hasAttribute(oth_attr): self.other_attributes[oth_attr] = xml.getAttribute(oth_attr) diff --git a/src/model/translation.py b/src/model/translation.py index e84d593..d1f10d3 100644 --- a/src/model/translation.py +++ b/src/model/translation.py @@ -9,21 +9,21 @@ import message as M def from_container_list(translation_list_container_xml): translations = [] max_num_cluster = 0 - + for translation_xml in translation_list_container_xml: num_cluster = 1 # default cluster if translation_xml.hasAttribute("cluster"): num_cluster = int(translation_xml.getAttribute("cluster")) - + max_num_cluster = max(max_num_cluster, num_cluster) t = Translation() t.import_xml(translation_xml) translations.append((num_cluster, t)) - + result = [[] for _ in range(max_num_cluster)] for clusterNum, translation in translations: result[clusterNum - 1].append(translation) - + return result @@ -33,40 +33,47 @@ class Translation(Data): self.source = "" self.targetLang = "" self.explanation = "" + self.explanationList = [] self.tags = [] - + def import_xml(self, translation_xml): translation = translation_xml.querySelector("translation") - + if translation: self.translation = translation.textContent self.source = translation.getAttribute("source") if translation.hasAttribute("source") else "" self.targetLang = translation.getAttribute("targetLang") if translation.hasAttribute("targetLang") else "" - + + explanationList = translation_xml.querySelectorAll("explanationList explanation") + + for explanation in explanationList: + self.explanationList.append(explanation.textContent if explanation else "") + explanation = translation_xml.querySelector("explanation") self.explanation = explanation.textContent if explanation else "" self.tags = import_label_list("labelList label", translation_xml) - - + def view(self, model): elements = [] - + if self.tags: tags = h("div.translation-tags", {}, [ - h("span", {"attr": {"title": key}}, clean_label(value)) + h("span", {"attr": {"title": key}}, clean_label(value)) for key, value in self.tags]) elements.append(tags) - + elements.append(h("span.translation-text", {}, self.translation)) if self.source: elements.append(h("span.translation-source", {}, self.source)) - + explanation_class = ".translation-explanation" if self.translation else "" - elements.append(h("span{}".format(explanation_class), {}, self.explanation)) - + +# elements.append(h("span{}".format(explanation_class), {}, self.explanations)) + elements.append(h("span{}".format(explanation_class), {}, ", ".join(self.explanationList))) + return h("div.translation-div", {"on": {"click": M.msg(M.ShowTranslationMenu, self) }}, elements) - + def is_empty(self): result = True result = result and self.translation == "" diff --git a/src/update.py b/src/update.py index 0e29bdb..43d0580 100644 --- a/src/update.py +++ b/src/update.py @@ -9,34 +9,34 @@ class Update: # check if completely no action needed if msg.no_action(): return - + # by default, no need to redraw entry entry_redraw = False - + # check if we need to signal the data change if msg.data_change(): screenful.changed() entry_redraw = True - + # redraw of view can happen even if no data changed entry_redraw |= msg.entry_redraw() - + # check if we need to reset the model reset = msg.reset() - + if reset: self.model.pre_reset() - + # actually run the update_model msg.update_model(self.model) msg.clear_args() - + # post reset comes now if reset: self.model.post_reset() self.view.view(self.model, entry_redraw) - + def set_model(self, model): self.model = model diff --git a/src/view/modal_templates.py b/src/view/modal_templates.py index 104320e..82a7e71 100644 --- a/src/view/modal_templates.py +++ b/src/view/modal_templates.py @@ -5,37 +5,37 @@ from browser import document def modal_template(content, title, msg, delete_msg=None): reset = message.msg(message.ModalNotOkClose) - + footer = [] - + if msg is not None: footer.append(h("a#modal-ok.button", {"on": {"click": message.msg(*msg)}}, "OK")) - + footer.append(h("label.button.dangerous", {"on": {"click": reset}}, "Cancel")) if delete_msg is not None: footer.append(h("label.button.warning.modal-delete", {"on": {"click": message.msg(*delete_msg)}}, "🗑")) - + return [ h("header", {}, [ h("h3", {}, title), h("label.close", {"on": {"click": reset}}, "×")]), h("section.content", {}, content ), h("footer", {}, footer)] - - + + def _question(question, current_value, input_element): props = {"value": current_value} if input_element == "input": props["type"] = "text" - + return [ h("span", {}, question), h("label", {}, [ h("{}#modal-question".format(input_element), {"props": props}, "")])] - + def big_question(question, current_value): return _question(question, current_value, "textarea") - + def question(question, current_value): return _question(question, current_value, "input") @@ -47,28 +47,47 @@ def generic_list_editor(title, element_list_getter): content.append(h("button", {"on": {"click": message.msg(message.AddToGenericList, element_list_getter)}}, "+")) return content +def homonymy_editor(title, current_labels): + def split_line2(left, right): + cls = "flex.two{}".format(".label-list-row") + return h("div.{}".format(cls), {}, [ + h("div.half", {}, left), h("div.half", {}, right)]) + + content = [h("p", {}, title)] + for i, feature in enumerate(current_labels()): + name = [] + value = [] + name.append(h("label", {"attrs": {"for": i}}, "Name:")) + name.append(h("input.name-input", {"props": {"type": "text", "value": feature["name"], "id": i}}, "")) + value.append(h("label", {"attrs": {"for": i + "-value"}}, "Value:")) + value.append(h("input.value-input", {"props": {"type": "text", "value": feature["value"], "id": i + "-value"}}, "")) + + content.append(split_line2(name, value)) + content.append(h("button", {"on": {"click": message.msg(message.AddToGenericList, current_labels)}}, "+")) + + return content def label_list_editor(current_labels, add_label_message_class): def split_line3(left, center, right, is_llr=True): cls = "flex.three{}".format(".label-list-row" if is_llr else "") return h("div.{}".format(cls), {}, [ h("span.third", {}, left), h("span.third", {}, center), h("span.third", {}, right)]) - + def dropdown_right(label_type, label): left = h("span.label-type", {}, label_type) - + options = [h("option", {}, [])] for value in TAGS[label_type]: options.append(h("option", {"props": {"selected": label == value}}, value)) center = h("select.label-value", {}, options) - + right_value = label if label not in TAGS[label_type] else "" - right = h("input.label-value-other", - {"props": {"type": "text", "value": right_value, "placeholder": "drugo"}}, + right = h("input.label-value-other", + {"props": {"type": "text", "value": right_value, "placeholder": "drugo"}}, []) - + return split_line3(left, center, right) - + content = [] kontrastivno = False for key, value in current_labels: @@ -76,27 +95,27 @@ def label_list_editor(current_labels, add_label_message_class): if value == "kontrastivno": kontrastivno = True continue - + content.append(dropdown_right(key, value)) - + # add a way to get new element to add to tag list def get_new_label_type(): select = document.getElementById("new-tag-select") return (select.options[select.selectedIndex].text, "") add_label_message_class.append(get_new_label_type) - + content.append(split_line3( h("", {}, []), h("label", {}, [ h("input#kontrastivno-input", {"props": {"type": "checkbox", "checked": kontrastivno}}, []), h("span.checkable", {}, "kontrastivno")]), h("", {}, []))) - + left = h("span", {}, "Add more!") center = h("select#new-tag-select", {}, [h("option", {}, ltype) for ltype in TAGS.keys()]) right = h("button", {"style": {"float": "right"}, "on": {"click": message.msg(*add_label_message_class)}}, "+") content.append(split_line3(left, center, right, False)) - + content.append(h("hr", {}, [])) - + return content diff --git a/src/view/modals.py b/src/view/modals.py index 005817f..d9ca6e2 100644 --- a/src/view/modals.py +++ b/src/view/modals.py @@ -9,53 +9,52 @@ 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:", - h("textarea#etv", {"props": {"value": translation.translation}}, "")), - split_line2("Razlaga:", - h("textarea#ete", {"props": {"value": translation.explanation}}, ""))]) - + split_line2("Prevedek:", h("textarea#etv", {"props": {"value": translation.translation}}, ""))]) + + content.extend(generic_list_editor("Razlage:", lambda: translation.explanationList)) + # 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 +63,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 +98,12 @@ def edit_variants(entry): return modal_template(content, "Add or remove variants", (message.EditVariants,), (message.DeleteVariants,)) +def edit_homonymy(entry): + hget = lambda: entry.copy().homonymy + content = homonymy_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 +130,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 +164,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 +173,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))