diff --git a/res/main.less b/res/main.less index 7c2c484..66e885e 100644 --- a/res/main.less +++ b/res/main.less @@ -305,6 +305,42 @@ margin-right: 1em; } +.ske-list { + font-size: zmall; + background-color: rgba(0,0, 0, 0.01); + padding: 0.5em; + border: 2px solid gray; + margin: 1em; + + .ske-line { + display: block; + margin-top: 0.2em; + } +} + +#ske-button { + padding-bottom: 0; +} + +// spinner +.loadingspinner { + pointer-events: none; + width: 4em; + height: 4em; + border: 0.5em solid transparent; + border-color: @white; + border-top-color: @blue; + border-radius: 50%; + animation: loadingspin 1s linear infinite; + margin: 0 auto; +} + +@keyframes loadingspin { + 100% { + transform: rotate(360deg) + } +} + // TODO: // #log { // overflow: scroll; @@ -343,6 +379,16 @@ span.translation-original span { } } + // --- I don't know how to properly fix this :( +.ske-right-button { + margin-top: 0; + height: 2.1em; +} +.ske-mid-input { + padding-right: 1em; +} + // --- + // remove me .blk { &:before { diff --git a/src/message/__init__.py b/src/message/__init__.py index 0ced64e..039c309 100644 --- a/src/message/__init__.py +++ b/src/message/__init__.py @@ -6,6 +6,7 @@ from message.show_menu import ShowTranslationMenu, ShowSenseMenu, ShowExampleMen from message.sense_edit import SenseMoveUp, SenseMoveDown, SenseBin from message.example_edit import ExampleMoveUp, ExampleMoveDown, ExampleBin, ExampleRoleChange, ExampleComponentAdd, ExampleComponentRemove, EditExampleText, ToggleExamples, ToggleClusters from message.delete_messages import DeleteComment, DeleteVariants, DeleteRelatedEntries, DeleteEntryLabels +from message.ske_messages import ShowSkeModal, SearchInSkeModal, SkeInsert from message.message import msg diff --git a/src/message/ske_messages.py b/src/message/ske_messages.py new file mode 100644 index 0000000..8d3c361 --- /dev/null +++ b/src/message/ske_messages.py @@ -0,0 +1,137 @@ +from message.simple_messages import ClickMessage, DataChgClickMessage +from message.message import msg, Message +from view import modals +from browser import window, document +from lib.snabbdom import h + +from model.example.example import Example +from model.example.corpus_example import CorpusExample +from model.example.component_lexeme import ComponentLexeme + + +class SkeExample: + def __init__(self, line): + self.left = "" + self.right = "" + self.mid = "" + + for left_el in line.Left: + self.left += left_el.str + + for right_el in line.Right: + self.right += right_el.str + + for mid_el in line.Kwic: + self.mid += mid_el.str + + def view(self): + return [h("span", {}, self.left + " "), + h("span", {"style": {"font-weight": "bold"}}, self.mid), + h("span", {}, self.right)] + + +class SkeCollocation: + def __init__(self, data): + self.text = data.cm + + def view(self): + return h("span", {}, self.text) + + +def get_parser(ske_index_type): + if ske_index_type == 0: + return lambda data: [SkeExample(line) for line in data.Lines] + elif ske_index_type == 1: + return lambda data: [SkeCollocation(item) for item in data.Items] + else: + raise "unknown ske index type" + + +class SkeModal(ClickMessage): + def on_event(self, event): + # event could be data if this is the return from external library + if type(event) in [list, int]: + self.add_arg(event) + else: + if len(self._args) < 3: + self.add_arg(None) + super().on_event(event) + + def update_model(self, model): + search_term = self.get_arg(0, str) + ske_index = self.get_arg(1, int) + ske_lookup = model.ske.url_for_kind_index(ske_index) + + # could be none if empty + data = self.get_arg(2) + if data is None: + model.ske.request(search_term, + msg(SkeModal, search_term, ske_index), + ske_lookup, + {"additional_refs": "s.id,p.id", + "error_callback": msg(SkeModal, search_term, ske_index), + "data_parser": get_parser(ske_index)}) + + model.modal_set(lambda: modals.ske_list(search_term, data, model.entry.senses, model.ske.request_kinds)) + + def reset(self): + return False + + +class ShowSkeModal(SkeModal): + def on_event(self, event): + # if just showing first time, than show empty results and let user click search + self.add_arg("") + super().on_event(event) + + +class SearchInSkeModal(SkeModal): + def on_event(self, event): + self.add_arg(document.getElementById("ske-search").value) + self.add_arg(document.getElementById("ske-select").selectedIndex) + super().on_event(event) + + +class SkeInsert(DataChgClickMessage): + def update_model(self, model): + data = self.get_arg(0) + + if type(data) is not list: + return + + if len(data) == 0: + return + + if not isinstance(data[0], SkeExample): + return + + sense_num = document.getElementById("ske-sense-select").selectedIndex + sense = model.entry.senses[sense_num] + + elements = document.getElementsByClassName("ske-line-check") + assert(len(elements) == len(data)) + + for ex, element in zip(data, elements): + if not element.checked: + continue + + new_example = Example() + new_example.inner = CorpusExample() + + lex_left = ComponentLexeme() + lex_left.text = ex["left"] + lex_left.role = "other" + + lex_mid = ComponentLexeme() + lex_mid.text = ex["mid"] + lex_mid.role = "headword" + + lex_right = ComponentLexeme() + lex_right.text = ex["right"] + lex_right.role = "other" + + new_example.components.extend([lex_left, lex_mid, lex_right]) + + # now add it to senses + sense.examples.append(new_example) + diff --git a/src/view/modals.py b/src/view/modals.py index e50f9f4..ec6e35f 100644 --- a/src/view/modals.py +++ b/src/view/modals.py @@ -129,3 +129,38 @@ def do_chosen_examples(example_list, entry): options.append(h("br", {}, [])) return modal_template(options, "Examples picker", (message.DoChosenExamples, example_list)) + + +def ske_list(search_term, data, senses, ske_kinds): + list_contents = [] + ske_list_hidden = False + + if data is None: + list_contents.append(h("div.loadingspinner", {}, "")) + elif type(data) is list: + for line in data: + list_contents.append(h("label.ske-line", {}, [ + h("input.ske-line-check", {"props": { "type": "checkbox" }}, ""), + h("span.checkable", {}, line.view())])) + elif type(data) is str: + ske_list_hidden = True + else: + list_contents.append(h("span.error", {}, "Something went wrong in SKE: {}".format(data))) + + contents = [ + h("div.flex.three", {}, [ + h("select#ske-select.third", {}, [ + h("option", {}, "{}".format(x)) for x in ske_kinds]), + h("label.third.ske-mid-input", {}, [ + h("input#ske-search", {"props": {"value": search_term, "type": "text"}}, "")]), + h("span.third.button.ske-right-button", + {"on": {"click": message.msg(message.SearchInSkeModal)}}, "Isci")]), + 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)) diff --git a/src/view/view.py b/src/view/view.py index add6750..d95168b 100644 --- a/src/view/view.py +++ b/src/view/view.py @@ -42,7 +42,8 @@ class View: txt_clusters = "Hide clusters" if model.clusters_shown else "Show clusters" return [h("span.button.toggle", {"on": {"click": msg(ToggleExamples)}}, txt_examples), - h("span.button.toggle", {"on": {"click": msg(ToggleClusters)}}, txt_clusters)] + h("span.button.toggle", {"on": {"click": msg(ToggleClusters)}}, txt_clusters), + View.view_ske_button(model)] @staticmethod def view_translations(translations, parent, model): @@ -53,6 +54,20 @@ class View: result.append(h("button.add-button", {"on": {"click": msg(ShowAddTranslation, parent)}}, "+")) return result + @staticmethod + def view_ske_button(model): + return h( + "span#ske-button.button.toggle", + { "on": {"click": msg(ShowSkeModal, model.entry.headword, 0)} }, + h("svg#ske-img", { + "attrs": { + "xmlns": "http://www.w3.org/2000/svg", + "height": "1.4em", + "viewBox": "0 0 9.82 9.82" }}, + h("path", {"attrs": { + "d": "M0 5C0 .1 0 .1 4.9.1s4.9 0 4.9 4.9 0 4.9-4.9 4.9S0 9.9 0 5zm6.05 4.36C9.28 8.518 10.46 4.68 8.3 2c-.432-.54-2.04.978-2.05 1.93-.001.227.01.233.486.233 1.58.001 1.8 2.17.26 2.42-2.44.396-2.43-3.48.018-5.05.52-.334.53-.296-.125-.602-4.62-2.16-8.77 3.6-5.2 7.24.624.638.99.562 1.6-.328.543-.798.56-1.23.047-1.23-1.12 0-1.77-.88-1.32-1.77.564-1.1 2.2-.863 2.64.4.385 1.12.006 2.36-1.03 3.36-.61.588-.594.62.38.838.398.09 1.57.048 2.03-.072z", + "fill": "#fff"}}))) + @staticmethod def view_menu(location, menu_target, entry): style = {