From cf5127dcec83429de5bc126eb14bfba12d7b11f6 Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 24 Jan 2021 22:30:53 +0100 Subject: [PATCH] split up search definition options to more classes --- src/public/app/widgets/search_definition.js | 201 ++++-------------- .../search_options/abstract_search_option.js | 32 +++ .../app/widgets/search_options/ancestor.js | 57 +++++ .../app/widgets/search_options/fast_search.js | 26 +++ .../search_options/include_archived_notes.js | 26 +++ .../app/widgets/search_options/order_by.js | 61 ++++++ .../widgets/search_options/search_string.js | 69 ++++++ 7 files changed, 310 insertions(+), 162 deletions(-) create mode 100644 src/public/app/widgets/search_options/abstract_search_option.js create mode 100644 src/public/app/widgets/search_options/ancestor.js create mode 100644 src/public/app/widgets/search_options/fast_search.js create mode 100644 src/public/app/widgets/search_options/include_archived_notes.js create mode 100644 src/public/app/widgets/search_options/order_by.js create mode 100644 src/public/app/widgets/search_options/search_string.js diff --git a/src/public/app/widgets/search_definition.js b/src/public/app/widgets/search_definition.js index 3b4467cb8..f39c5c966 100644 --- a/src/public/app/widgets/search_definition.js +++ b/src/public/app/widgets/search_definition.js @@ -1,11 +1,10 @@ import noteAutocompleteService from "../services/note_autocomplete.js"; -import SpacedUpdate from "../services/spaced_update.js"; import server from "../services/server.js"; import TabAwareWidget from "./tab_aware_widget.js"; import treeCache from "../services/tree_cache.js"; import ws from "../services/ws.js"; import toastService from "../services/toast.js"; -import utils from "../services/utils.js"; + import DeleteNoteSearchAction from "./search_actions/delete_note.js"; import DeleteLabelSearchAction from "./search_actions/delete_label.js"; import DeleteRelationSearchAction from "./search_actions/delete_relation.js"; @@ -13,7 +12,12 @@ import RenameLabelSearchAction from "./search_actions/rename_label.js"; import SetLabelValueSearchAction from "./search_actions/set_label_value.js"; import SetRelationTargetSearchAction from "./search_actions/set_relation_target.js"; import RenameRelationSearchAction from "./search_actions/rename_relation.js"; -import ExecuteScriptSearchAction from "./search_actions/execute_script.js"; +import ExecuteScriptSearchAction from "./search_actions/execute_script.js" +import SearchString from "./search_options/search_string.js"; +import FastSearch from "./search_options/fast_search.js"; +import Ancestor from "./search_options/ancestor.js"; +import IncludeArchivedNotes from "./search_options/include_archived_notes.js"; +import OrderBy from "./search_options/order_by.js"; const TPL = `
@@ -42,35 +46,14 @@ const TPL = `
- - - - - - - - - - - - - - - - - - - - - - - - - + @@ -203,6 +127,14 @@ const TPL = ` `; +const OPTION_CLASSES = [ + SearchString, + Ancestor, + FastSearch, + IncludeArchivedNotes, + OrderBy +]; + const ACTION_CLASSES = {}; for (const clazz of [ @@ -236,50 +168,15 @@ export default class SearchDefinitionWidget extends TabAwareWidget { this.contentSized(); this.overflowing(); - this.$searchString = this.$widget.find(".search-string"); - this.$searchString.on('input', () => this.searchStringSU.scheduleUpdate()); - utils.bindElShortcut(this.$searchString, 'return', async () => { - await this.searchStringSU.updateNowIfNecessary(); - - this.refreshResults(); - }); - - this.searchStringSU = new SpacedUpdate(async () => { - const searchString = this.$searchString.val(); - - await this.setAttribute('label', 'searchString', searchString); - - if (this.note.title.startsWith('Search: ')) { - await server.put(`notes/${this.noteId}/change-title`, { - title: 'Search: ' + (searchString.length < 30 ? searchString : `${searchString.substr(0, 30)}…`) - }); - } - }, 1000); - - this.$ancestor = this.$widget.find('.ancestor'); - noteAutocompleteService.initNoteAutocomplete(this.$ancestor); - - this.$ancestor.on('autocomplete:closed', async () => { - const ancestorOfNoteId = this.$ancestor.getSelectedNoteId(); - - await this.setAttribute('relation', 'ancestor', ancestorOfNoteId); - }); - this.$widget.on('click', '[data-search-option-add]', async event => { - const searchOption = $(event.target).attr('data-search-option-add'); + const searchOptionName = $(event.target).attr('data-search-option-add'); + const clazz = OPTION_CLASSES.find(SearchOptionClass => SearchOptionClass.optionName === searchOptionName); - if (searchOption === 'fastSearch') { - await this.setAttribute('label', 'fastSearch'); + if (clazz) { + await clazz.create(this.noteId); } - else if (searchOption === 'orderBy') { - await this.setAttribute('label', 'orderBy', 'relevancy'); - await this.setAttribute('label', 'orderDirection', 'asc'); - } - else if (searchOption === 'includeArchivedNotes') { - await this.setAttribute('label', 'includeArchivedNotes'); - } - else if (searchOption === 'ancestor') { - await this.setAttribute('relation', 'ancestor', 'root'); + else { + logError(`Unknown search option ${searchOptionName}`); } this.refresh(); @@ -307,19 +204,7 @@ export default class SearchDefinitionWidget extends TabAwareWidget { this.refresh(); }); - this.$orderBy = this.$widget.find('select[name=orderBy]'); - this.$orderBy.on('change', async () => { - const orderBy = this.$orderBy.val(); - - await this.setAttribute('label', 'orderBy', orderBy); - }); - - this.$orderDirection = this.$widget.find('select[name=orderDirection]'); - this.$orderDirection.on('change', async () => { - const orderDirection = this.$orderDirection.val(); - - await this.setAttribute('label', 'orderDirection', orderDirection); - }); + this.$searchOptions = this.$widget.find('.search-options'); this.$actionOptions = this.$widget.find('.action-options'); @@ -358,12 +243,6 @@ export default class SearchDefinitionWidget extends TabAwareWidget { this.$searchAndExecuteButton.on('click', () => this.searchAndExecute()); } - async setAttribute(type, name, value = '') { - await server.put(`notes/${this.noteId}/set-attribute`, { type, name, value }); - - await ws.waitForMaxKnownEntityChangeId(); - } - async refreshResults() { await treeCache.reloadNotes([this.noteId]); @@ -372,22 +251,21 @@ export default class SearchDefinitionWidget extends TabAwareWidget { async refreshWithNote(note) { this.$component.show(); - this.$searchString.val(this.note.getLabelValue('searchString')); - for (const attrName of ['includeArchivedNotes', 'ancestor', 'fastSearch', 'orderBy']) { - const has = note.hasLabel(attrName) || note.hasRelation(attrName); + this.$searchOptions.empty(); - this.$widget.find(`[data-search-option-add='${attrName}'`).toggle(!has); - this.$widget.find(`[data-search-option-conf='${attrName}'`).toggle(has); - } + for (const OptionClass of OPTION_CLASSES) { + const {attributeType, optionName} = OptionClass; - const ancestorNoteId = this.note.getRelationValue('ancestor'); + const attr = this.note.getAttribute(attributeType, optionName); - await this.$ancestor.setNote(ancestorNoteId); + this.$widget.find(`[data-search-option-add='${optionName}'`).toggle(!attr); +console.log(optionName, attr); + if (attr) { + const searchOption = new OptionClass(attr, this.note); - if (note.hasLabel('orderBy')) { - this.$orderBy.val(note.getLabelValue('orderBy')); - this.$orderDirection.val(note.getLabelValue('orderDirection') || 'asc'); + this.$searchOptions.append(searchOption.render()); + } } this.$actionOptions.empty(); @@ -418,11 +296,10 @@ export default class SearchDefinitionWidget extends TabAwareWidget { } this.$searchAndExecuteButton.css('visibility', actionLabels.length > 0 ? 'visible' : 'hidden'); - - //this.refreshResults(); // important specifically when this search note was not yet refreshed } focusOnSearchDefinitionEvent() { + // FIXME this.$searchString.focus(); } diff --git a/src/public/app/widgets/search_options/abstract_search_option.js b/src/public/app/widgets/search_options/abstract_search_option.js new file mode 100644 index 000000000..00cb042a5 --- /dev/null +++ b/src/public/app/widgets/search_options/abstract_search_option.js @@ -0,0 +1,32 @@ +import server from "../../services/server.js"; +import ws from "../../services/ws.js"; + +export default class AbstractSearchOption { + constructor(attribute, note) { + this.attribute = attribute; + this.note = note; + } + + static async setAttribute(noteId, type, name, value = '') { + await server.put(`notes/${noteId}/set-attribute`, { type, name, value }); + + await ws.waitForMaxKnownEntityChangeId(); + } + + render() { + try { + const $rendered = this.doRender(); + + $rendered.attr('data-attribute-id', this.attribute.attributeId); + + return $rendered; + } + catch (e) { + logError(`Failed rendering search option: ${JSON.stringify(this.attribute.dto)} with error: ${e.message} ${e.stack}`); + return null; + } + } + + // to be overriden + doRender() {} +} diff --git a/src/public/app/widgets/search_options/ancestor.js b/src/public/app/widgets/search_options/ancestor.js new file mode 100644 index 000000000..b10350d1c --- /dev/null +++ b/src/public/app/widgets/search_options/ancestor.js @@ -0,0 +1,57 @@ +import AbstractSearchOption from "./abstract_search_option.js"; +import noteAutocompleteService from "../../services/note_autocomplete.js"; + +const TPL = ` + + + + +`; + +export default class Ancestor extends AbstractSearchOption { + static get optionName() { return "ancestor" }; + static get attributeType() { return "relation" }; + + static async create(noteId) { + await AbstractSearchOption.setAttribute(noteId, 'relation', 'ancestor', 'root'); + } + + doRender() { + const $option = $(TPL); + const $ancestor = $option.find('.ancestor'); + noteAutocompleteService.initNoteAutocomplete($ancestor); + + $ancestor.on('autocomplete:closed', async () => { + const ancestorOfNoteId = $ancestor.getSelectedNoteId(); + + await this.setAttribute('relation', 'ancestor', ancestorOfNoteId); + }); + + const ancestorNoteId = this.note.getRelationValue('ancestor'); + + $ancestor.setNote(ancestorNoteId); + + return $option; + } +} diff --git a/src/public/app/widgets/search_options/fast_search.js b/src/public/app/widgets/search_options/fast_search.js new file mode 100644 index 000000000..17873c18e --- /dev/null +++ b/src/public/app/widgets/search_options/fast_search.js @@ -0,0 +1,26 @@ +import AbstractSearchOption from "./abstract_search_option.js"; + +const TPL = ` + + + +`; + +export default class FastSearch extends AbstractSearchOption { + static get optionName() { return "fastSearch" }; + static get attributeType() { return "label" }; + + static async create(noteId) { + await AbstractSearchOption.setAttribute(noteId,'label', 'fastSearch'); + } + + doRender() { + return $(TPL); + } +} diff --git a/src/public/app/widgets/search_options/include_archived_notes.js b/src/public/app/widgets/search_options/include_archived_notes.js new file mode 100644 index 000000000..a4704f674 --- /dev/null +++ b/src/public/app/widgets/search_options/include_archived_notes.js @@ -0,0 +1,26 @@ +import AbstractSearchOption from "./abstract_search_option.js"; + +const TPL = ` + + + +`; + +export default class IncludeArchivedNotes extends AbstractSearchOption { + static get optionName() { return "includeArchivedNotes" }; + static get attributeType() { return "label" }; + + static async create(noteId) { + await AbstractSearchOption.setAttribute(noteId,'label', 'includeArchivedNotes'); + } + + doRender() { + return $(TPL); + } +} diff --git a/src/public/app/widgets/search_options/order_by.js b/src/public/app/widgets/search_options/order_by.js new file mode 100644 index 000000000..525227ab7 --- /dev/null +++ b/src/public/app/widgets/search_options/order_by.js @@ -0,0 +1,61 @@ +import AbstractSearchOption from "./abstract_search_option.js"; + +const TPL = ` + + + + +`; + +export default class OrderBy extends AbstractSearchOption { + static get optionName() { return "orderBy" }; + static get attributeType() { return "label" }; + + static async create(noteId) { + await AbstractSearchOption.setAttribute(noteId, 'label', 'orderBy', 'relevancy'); + await AbstractSearchOption.setAttribute(noteId, 'label', 'orderDirection', 'asc'); + } + + doRender() { + const $option = $(TPL); + + const $orderBy = $option.find('select[name=orderBy]'); + $orderBy.on('change', async () => { + const orderBy = $orderBy.val(); + + await this.setAttribute('label', 'orderBy', orderBy); + }); + $orderBy.val(this.note.getLabelValue('orderBy')); + + const $orderDirection = $option.find('select[name=orderDirection]'); + $orderDirection.on('change', async () => { + const orderDirection = $orderDirection.val(); + + await this.setAttribute('label', 'orderDirection', orderDirection); + }); + $orderDirection.val(this.note.getLabelValue('orderDirection') || 'asc'); + + return $option; + } +} diff --git a/src/public/app/widgets/search_options/search_string.js b/src/public/app/widgets/search_options/search_string.js new file mode 100644 index 000000000..4e7fcc624 --- /dev/null +++ b/src/public/app/widgets/search_options/search_string.js @@ -0,0 +1,69 @@ +import AbstractSearchOption from "./abstract_search_option.js"; +import utils from "../../services/utils.js"; +import SpacedUpdate from "../../services/spaced_update.js"; +import server from "../../services/server.js"; + +const TPL = ` + + + + +`; + +export default class SearchString extends AbstractSearchOption { + static get optionName() { return "searchString" }; + static get attributeType() { return "label" }; + + static async create(noteId) { + await AbstractSearchOption.setAttribute(noteId, 'label', 'searchString'); + } + + doRender() { + const $option = $(TPL); + const $searchString = $option.find('.search-string'); + $searchString.on('input', () => this.spacedUpdate.scheduleUpdate()); + + utils.bindElShortcut($searchString, 'return', async () => { + await this.spacedUpdate.updateNowIfNecessary(); + + this.refreshResults(); // FIXME!!! + }); + + this.spacedUpdate = new SpacedUpdate(async () => { + const searchString = $searchString.val(); + + await this.setAttribute('label', 'searchString', searchString); + + if (this.note.title.startsWith('Search: ')) { + await server.put(`notes/${this.note.noteId}/change-title`, { + title: 'Search: ' + (searchString.length < 30 ? searchString : `${searchString.substr(0, 30)}…`) + }); + } + }, 1000); + + $searchString.val(this.note.getLabelValue('searchString')); + + return $option; + } +}
Search string: - - -
Add search option: + +
- Ancestor: -
- -
-
- -
- - - Fast search - - -
- - - Include archived notes - - -
- - - Order by - - - - - - -
Search string: + + +
+ + + Fast search + + +
+ + + Include archived notes + + +
+ + + Order by + + + + + + +
Search string: + + +