diff --git a/res/main.less b/res/main.less index a748ea7..3ac6415 100644 --- a/res/main.less +++ b/res/main.less @@ -12,6 +12,28 @@ border: 1px solid #ccc; } +.cluster-list-button { + padding: 0.2em; + margin-left: .2em; + background-color: #ddd; + color: @black; + background-color: @silver; + height: 1em; + width: 1em; + vertical-align: middle; + line-height: 0; + font-family: "Lucida Console", Monaco, monospace; +} + +.cluster-button-checked { + color: @silver; + background-color: @black; +} + +.example-clusters { + float: right; +} + ._hoverable { &:hover { background-color: @silver; @@ -208,6 +230,7 @@ .example-rest { border: 1px transparent solid; + width: 100%; } .example-chosen { diff --git a/src/model/example.py b/src/model/example.py index 1d517bb..4b52def 100644 --- a/src/model/example.py +++ b/src/model/example.py @@ -3,30 +3,7 @@ from model.translation import from_container_list class Example(Editable): - @staticmethod - def add_clusters(entry): - nocluster_examples = [] - taken_clusters = [] - - # gahter all taken cluster numbers and all examples without clusters - for sense in entry.senses: - for example in sense.examples: - cluster = example.get_cluster() - if cluster == -1: - nocluster_examples.append(example) - elif cluster is not None: - taken_clusters.append(cluster) - - cnum = 1 - for example in nocluster_examples: - while cnum in taken_clusters: - cnum += 1 - taken_clusters.append(cnum) - - example.set_cluster(cnum) - - - def __init__(self, example_xml): + def __init__(self, example_xml, cluster_info): self.translations = from_container_list(example_xml.querySelectorAll("translationContainer")) inner_xml = example_xml.querySelector("corpusExample") @@ -34,7 +11,7 @@ class Example(Editable): self.inner = CorpusExample(inner_xml) else: inner_xml = example_xml.querySelector("multiwordExample") - self.inner = MultiwordExample(inner_xml) + self.inner = MultiwordExample(inner_xml, cluster_info) all_components = [ComponentLexeme(el) for el in inner_xml.childNodes] self.components = [comp for comp in all_components if comp.isValid()] @@ -57,14 +34,11 @@ class Example(Editable): def get_cluster(self): return self.inner.get_cluster() - def get_valid_cluster(self): - return self.inner.get_valid_cluster() - def set_cluster(self, cluster): self.inner.cluster = cluster def is_collocation(self): - return type(self.inner) is CorpusExample + return self.get_view_type() == 2 def get_view_type(self): # as per the bosses, these are the rules for different colors @@ -92,27 +66,39 @@ class CorpusExample: def get_cluster(self): return None - def get_valid_cluster(self): - return None - class MultiwordExample: - def __init__(self, example_xml): + def __init__(self, example_xml, cluster_info): self.other_attributes = {} for oth_attr in ["lexical_unit_id", "structure_id", "structureName", "audio", "frequency", "logDice"]: if example_xml.hasAttribute(oth_attr): self.other_attributes[oth_attr] = example_xml.getAttribute(oth_attr) - self.cluster_valid = False - self.cluster = -1 - if example_xml.hasAttribute("cluster"): - self.cluster_valid = True - self.cluster = int(example_xml.getAttribute("cluster")) + self.cluster = self._determine_cluster_number(example_xml, cluster_info) if example_xml.hasAttribute("type"): - self.type = example_xml.getAttribute(oth_attr) + self.type = example_xml.getAttribute("type") else: self.type = None + + def _determine_cluster_number(self, example_xml, cluster_info): + # since cluster numbers can be fairly fragmented, this is defragmentation + # we do need to get info about sense examples to do this, that is why we have cluster_info + if cluster_info is None: + cluster_mappings, cluster_begin = {}, 0 + else: + cluster_mappings, cluster_begin = cluster_info + + + if not example_xml.hasAttribute("cluster"): + cluster = len(cluster_mappings) + cluster_begin + cluster_mappings[cluster] = cluster + else: + cluster = int(example_xml.getAttribute("cluster")) + if cluster not in cluster_mappings: + cluster_mappings[cluster] = len(cluster_mappings) + cluster_begin + + return cluster_mappings[cluster] def export(self, doc): result = doc.createElement("multiwordExample") @@ -130,9 +116,6 @@ class MultiwordExample: def get_cluster(self): return self.cluster - - def get_valid_cluster(self): - return self.cluster if self.cluster_valid else None class ComponentLexeme(Editable): diff --git a/src/model/model.py b/src/model/model.py index 77a2c73..7cd6291 100644 --- a/src/model/model.py +++ b/src/model/model.py @@ -25,9 +25,6 @@ class Model: # choosing and hiding examples self.chosen_examples = [] self.examples_shown = True - - self.reset() - self.modal_reset() def reset(self): # do both resets at once @@ -56,7 +53,5 @@ class Model: parser = __new__(DOMParser()) xmlDoc = parser.parseFromString(xml_text, "text/xml") self.entry = Entry(xmlDoc.querySelector("entry")) - - # we need to fix the example clusters - Example.add_clusters(self.entry) + self.reset() diff --git a/src/model/sense.py b/src/model/sense.py index 8646ae6..6e0ec75 100644 --- a/src/model/sense.py +++ b/src/model/sense.py @@ -4,19 +4,42 @@ from model.editable import Editable from model.tags import import_label_list +cluster_min = 0 + + class Sense(Editable): def __init__(self, sense_xml): + global cluster_min + self.definition = {} for definition in sense_xml.querySelectorAll("definitionList definition"): key = definition.getAttribute("type") self.definition[key] = definition.textContent self.labels = import_label_list("sense > labelList label", sense_xml) - self.examples = [Example(example_xml) for example_xml in - sense_xml.querySelectorAll("exampleContainerList exampleContainer")] - self.translations = from_container_list( sense_xml.querySelectorAll("translationContainerList translationContainer")) + + cluster_mappings = {} + cluster_info = (cluster_mappings, cluster_min) + + self.examples = [Example(example_xml, cluster_info) for example_xml in + sense_xml.querySelectorAll("exampleContainerList exampleContainer")] + + # set limit for example cluster + self.reserved_example = max(cluster_mappings.values()) + 1 + cluster_min = self.reserved_example + 1 def merge_labels(self): return ", ".join(val for _, val in self.labels) + + def example_clusters(self): + result = set() + for ex in self.examples: + cluster = ex.get_cluster() + if cluster is not None: + result.add(cluster) + result.add(self.reserved_example) + + return sorted(result) + diff --git a/src/view/modals.py b/src/view/modals.py index e9d96d3..634b97d 100644 --- a/src/view/modals.py +++ b/src/view/modals.py @@ -1,6 +1,7 @@ from lib.snabbdom import h import message from view.modal_templates import * +from view.utils import show_toggle_cluster_buttons def edit_translation(translation, cluster_idx, num_clusters, cls): @@ -63,6 +64,13 @@ def edit_example(example): h("div.three-fifth", {}, middle), h("div.one-fifth", {}, buttons_right(idx))])) + cluster = example.get_cluster() + if cluster is not None: + divs.append(h("hr", {}, [])) + divs.append(h("div.flex.five.example-component", {}, [ + h("div.one-fifth", {}, "Cluster"), + h("div.four-fifth", {}, show_toggle_cluster_buttons(list(range(10))))])) + return modal_template(divs, "Edit Example", message.EditExampleText(example_original)) @@ -92,15 +100,24 @@ def edit_comment(comment): def do_chosen_examples(example_list, entry): - # assert len(example_list) > 0 - - sense_of_first_example = None + example_senses = [] for idx, sense in enumerate(entry.senses): for ex in sense.examples: - if ex == example_list[0]: - sense_of_first_example = idx + if ex in example_list: + example_senses.append(idx) break + sense_of_first_example = example_senses[0] + + # determine if one can choose clusters + # this can happen ef every example from same sense and every example a collocation + can_choose_cluster = len(set(example_senses)) == 1 + idx = 0 + while can_choose_cluster and idx < len(example_list): + can_choose_cluster = example_list[idx].is_collocation() + idx += 1 + console.log(can_choose_cluster) + options = [h("p", {}, "Choose sense for examples")] for idx, sense in enumerate(entry.senses): text = "{}: {}".format(idx + 1, sense.definition["indicator"]) diff --git a/src/view/utils.py b/src/view/utils.py index 847a31d..29d9a04 100644 --- a/src/view/utils.py +++ b/src/view/utils.py @@ -1,5 +1,19 @@ from export import export_to_xml from browser import window +from lib.snabbdom import h + + +NUM2STR = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + +def show_toggle_cluster_buttons(sense, example): + result = [] + for opt in sense.example_clusters(): + tag = "input.cluster-list-button" + if opt == example.get_cluster(): + tag += ".cluster-button-checked" + + result.append(h(tag, {"attrs": {"value": NUM2STR[opt], "type": "button"}}, [])) + return result def clean_label(label): diff --git a/src/view/view.py b/src/view/view.py index b52ed79..6895ad2 100644 --- a/src/view/view.py +++ b/src/view/view.py @@ -98,7 +98,7 @@ class View: @staticmethod def view_sense(sense, senseNum, model): - examples = [View.view_example(example, model) for example in sense.examples] + examples = [View.view_example(example, sense, model) for example in sense.examples] result = h("div.elm-div", {}, [ h("div.sense-num", {"on": {"click": msg(ShowSenseMenu(sense))}}, str(senseNum + 1)), @@ -111,7 +111,7 @@ class View: return result @staticmethod - def view_example(example, model): + def view_example(example, sense, model): example_tag = "div.example-rest" if example in model.chosen_examples: example_tag += ".example-chosen" @@ -140,6 +140,7 @@ class View: h("div.example-dot", dot_attr, "▣"), h(example_tag, {}, [ h("span.example-text", {"on": {"click": msg(ShowExampleMenu(example))} }, example_content), + h("div.example-clusters", {}, show_toggle_cluster_buttons(sense, example)), h("div.example-translation-list", {}, [ h("div.example-translation", {}, View.view_translations(example.translations, example, model))])])])