diff --git a/app/scripts/app.ts b/app/scripts/app.ts index b31777061..ea206aa58 100644 --- a/app/scripts/app.ts +++ b/app/scripts/app.ts @@ -26,9 +26,11 @@ import "@/components/searchtabs" import "@/components/frontpage" import "@/components/results" import "@/components/korp-error" +import "@/services/store" import { JQueryExtended } from "./jquery.types" import { LocationService } from "./urlparams" import { LocLangMap } from "@/i18n/types" +import { StoreService } from "./services/store" // load all custom components let customComponents: Record = {} @@ -95,6 +97,7 @@ korpApp.run([ "$q", "$timeout", "$uibModal", + "store", async function ( $rootScope: RootScope, $location: LocationService, @@ -103,7 +106,8 @@ korpApp.run([ tmhDynamicLocaleCache: ICacheObject, $q: IQService, $timeout: ITimeoutService, - $uibModal: ui.bootstrap.IModalService + $uibModal: ui.bootstrap.IModalService, + store: StoreService ) { const s = $rootScope s._settings = settings @@ -265,6 +269,20 @@ korpApp.run([ }, }) } else { + // Sync corpus selection between location and store + store.watch("selectedCorpusIds", (corpusIds) => { + settings.corpusListing.select(corpusIds) + $location.search("corpus", corpusIds.join(",")) + }) + $rootScope.$watch( + () => $location.search().corpus, + (corpusIdsComma) => { + const corpusIds = corpusIdsComma ? corpusIdsComma.split(",") : [] + settings.corpusListing.select(corpusIds) + store.set("selectedCorpusIds", corpusIds) + } + ) + // here $timeout must be used so that message is not sent before all controllers/componenters are initialized settings.corpusListing.select(selectedIds) $timeout(() => $rootScope.$broadcast("initialcorpuschooserchange", selectedIds), 0) diff --git a/app/scripts/components/corpus-chooser/corpus-chooser.ts b/app/scripts/components/corpus-chooser/corpus-chooser.ts index 520d70746..ad0f6d3b9 100644 --- a/app/scripts/components/corpus-chooser/corpus-chooser.ts +++ b/app/scripts/components/corpus-chooser/corpus-chooser.ts @@ -17,10 +17,12 @@ import { import "@/components/corpus-chooser/corpus-time-graph" import "@/components/corpus-chooser/info-box" import "@/components/corpus-chooser/tree" +import "@/services/store" import { RootScope } from "@/root-scope.types" import { LocationService } from "@/urlparams" import { CorpusTransformed } from "@/settings/config-transformed.types" import { LangString } from "@/i18n/types" +import { StoreService } from "@/services/store" type CorpusChooserController = IController & { credentials: string[] @@ -131,8 +133,8 @@ angular.module("korpApp").component("corpusChooser", { bindings: {}, controller: [ "$rootScope", - "$location", - function ($rootScope: RootScope, $location: LocationService) { + "store", + function ($rootScope: RootScope, store: StoreService) { const $ctrl = this as CorpusChooserController statemachine.listen("login", function () { @@ -187,14 +189,7 @@ angular.module("korpApp").component("corpusChooser", { select(corpusIds, true) // Sync when corpus selection is modified elsewhere. - $rootScope.$watch( - () => $location.search().corpus, - (corpusIdsComma) => { - const corpusIds = corpusIdsComma ? corpusIdsComma.split(",") : [] - select(corpusIds) - } - ) - $rootScope.$on("corpuschooserchange", (e, selected) => select(selected)) + store.watch("selectedCorpusIds", updateSelection) }) $ctrl.updateSelectedCount = (selection) => { @@ -233,14 +228,21 @@ angular.module("korpApp").component("corpusChooser", { } } + /** Apply a selection made locally */ function select(corporaIds: string[], force?: boolean) { // Exit if no actual change const selectedIds = settings.corpusListing.mapSelectedCorpora((corpus) => corpus.id) if (!force && _.isEqual(corporaIds, selectedIds)) return + const selection = updateSelection(corporaIds) + store.set("selectedCorpusIds", selection) + } + + /** Filter requested corpus selection and update internal state */ + function updateSelection(corpusIds: string[]): string[] { const selection = filterCorporaOnCredentials( Object.values(settings.corpora), - corporaIds, + corpusIds, $ctrl.credentials ) @@ -251,9 +253,7 @@ angular.module("korpApp").component("corpusChooser", { $ctrl.firstCorpus = settings.corpora[selection[0]].title } - settings.corpusListing.select(selection) - $rootScope.$broadcast("corpuschooserchange", selection) - $location.search("corpus", selection.join(",")) + return selection } $ctrl.onShowInfo = (node: ChooserFolderSub | CorpusTransformed) => { diff --git a/app/scripts/components/corpus-chooser/corpus-time-graph.ts b/app/scripts/components/corpus-chooser/corpus-time-graph.ts index 9382799cf..86665e029 100644 --- a/app/scripts/components/corpus-chooser/corpus-time-graph.ts +++ b/app/scripts/components/corpus-chooser/corpus-time-graph.ts @@ -13,12 +13,15 @@ import { } from "@/timeseries" import { html } from "@/util" import { RootScope } from "@/root-scope.types" +import { StoreService } from "@/services/store" +import "@/services/store" angular.module("korpApp").component("corpusTimeGraph", { template: html``, controller: [ "$rootScope", - function ($rootScope: RootScope) { + "store", + function ($rootScope: RootScope, store: StoreService) { const { min, max } = getSpan() const datasetsDated = [ @@ -128,7 +131,7 @@ angular.module("korpApp").component("corpusTimeGraph", { }, }) - $rootScope.$on("corpuschooserchange", () => { + store.watch("selectedCorpusIds", () => { updateSelectedData() // `'none'` to disable animations. Animations would be nice, but they look weird when new data has different min/max year. // TODO Do animations look better if data is given as array including empty years, not a record? diff --git a/app/scripts/components/extended/cqp-term.js b/app/scripts/components/extended/cqp-term.js index 6748f9669..383d5c5b5 100644 --- a/app/scripts/components/extended/cqp-term.js +++ b/app/scripts/components/extended/cqp-term.js @@ -5,6 +5,7 @@ import settings from "@/settings" import { html, valfilter } from "@/util" const minusImage = require("../../../img/minus.png") import "@/components/extended/cqp-value" +import "@/services/store" /** * TODO @@ -55,9 +56,11 @@ angular.module("korpApp").component("extendedCqpTerm", { change: "&", }, controller: [ + "$location", "$rootScope", "$timeout", - function ($rootScope, $timeout) { + "store", + function ($location, $rootScope, $timeout, store) { const ctrl = this ctrl.valfilter = valfilter @@ -69,9 +72,13 @@ angular.module("korpApp").component("extendedCqpTerm", { ctrl.term.val = "" ctrl.change() } - $rootScope.$on("corpuschooserchange", (e, selected) => $timeout(() => onCorpusChange(e, selected), 0)) + store.watch("selectedCorpusIds", () => $timeout(() => onCorpusChange(), 0)) + $rootScope.$watch( + () => $location.search().parallel_corpora, + () => $timeout(() => onCorpusChange()) + ) - onCorpusChange(null, settings.corpusListing.selected) + onCorpusChange() } ctrl.localChange = (term) => { @@ -79,7 +86,8 @@ angular.module("korpApp").component("extendedCqpTerm", { ctrl.change() } - const onCorpusChange = function (event, selected) { + function onCorpusChange() { + const selected = store.get("selectedCorpusIds") // TODO: respect the setting 'wordAttributeSelector' and similar if (!(selected && selected.length)) { return diff --git a/app/scripts/components/extended/extended-parallel.js b/app/scripts/components/extended/extended-parallel.js index 4c0854c39..1554143f1 100644 --- a/app/scripts/components/extended/extended-parallel.js +++ b/app/scripts/components/extended/extended-parallel.js @@ -6,6 +6,7 @@ import { expandOperators } from "@/cqp_parser/cqp" import { html } from "@/util" import { matomoSend } from "@/matomo" import "@/services/searches" +import "@/services/store" import "@/components/extended/tokens" angular.module("korpApp").component("extendedParallel", { @@ -63,7 +64,8 @@ angular.module("korpApp").component("extendedParallel", { "$rootScope", "$timeout", "searches", - function ($location, $rootScope, $timeout, searches) { + "store", + function ($location, $rootScope, $timeout, searches, store) { const ctrl = this ctrl.initialized = false @@ -72,7 +74,7 @@ angular.module("korpApp").component("extendedParallel", { ctrl.onLangChange() ctrl.initialized = true - $rootScope.$on("corpuschooserchange", () => ctrl.onLangChange(false)) + store.watch("selectedCorpusIds", () => ctrl.onLangChange()) } ctrl.negates = [] @@ -140,15 +142,10 @@ angular.module("korpApp").component("extendedParallel", { return output } - ctrl.onLangChange = function (broadcast = true) { + ctrl.onLangChange = function () { var currentLangList = _.map(ctrl.langs, "lang") settings.corpusListing.setActiveLangs(currentLangList) $location.search("parallel_corpora", currentLangList.join(",")) - - // hacky fix to make attributes update when switching languages - if (ctrl.initialized && broadcast) { - $rootScope.$broadcast("corpuschooserchange", [""]) - } searches.langDef.resolve() } diff --git a/app/scripts/components/extended/extended-standard.js b/app/scripts/components/extended/extended-standard.js index 05b42e51d..7c5dfd851 100644 --- a/app/scripts/components/extended/extended-standard.js +++ b/app/scripts/components/extended/extended-standard.js @@ -7,6 +7,7 @@ import { expandOperators, mergeCqpExprs, parse, stringify, supportsInOrder } fro import { html } from "@/util" import { matomoSend } from "@/matomo" import "@/services/compare-searches" +import "@/services/store" import "@/components/extended/tokens" import "@/components/search-submit" import "@/global-filter/global-filters" @@ -50,9 +51,10 @@ angular.module("korpApp").component("extendedStandard", { "$location", "$rootScope", "$scope", - "compareSearches", "$timeout", - function ($location, $rootScope, $scope, compareSearches, $timeout) { + "compareSearches", + "store", + function ($location, $rootScope, $scope, $timeout, compareSearches, store) { const ctrl = this $scope.freeOrder = $location.search().in_order != null @@ -153,7 +155,7 @@ angular.module("korpApp").component("extendedStandard", { return output } - $rootScope.$on("corpuschooserchange", function () { + store.watch("selectedCorpusIds", () => { ctrl.withins = ctrl.getWithins() ctrl.within = ctrl.withins[0] && ctrl.withins[0].value }) diff --git a/app/scripts/components/extended/struct-token.js b/app/scripts/components/extended/struct-token.js index 28566637f..8c02f256c 100644 --- a/app/scripts/components/extended/struct-token.js +++ b/app/scripts/components/extended/struct-token.js @@ -2,6 +2,7 @@ import angular from "angular" import settings from "@/settings" import { html } from "@/util" +import "@/services/store" angular.module("korpApp").component("extendedStructToken", { template: html` @@ -55,7 +56,8 @@ angular.module("korpApp").component("extendedStructToken", { }, controller: [ "$scope", - function ($scope) { + "store", + function ($scope, store) { const ctrl = this ctrl.$onInit = () => { @@ -70,7 +72,7 @@ angular.module("korpApp").component("extendedStructToken", { ctrl.change() } - $scope.$on("corpuschooserchange", onCorpusChange) + store.watch("selectedCorpusIds", onCorpusChange) } const onCorpusChange = () => { diff --git a/app/scripts/components/extended/widgets/common.ts b/app/scripts/components/extended/widgets/common.ts index 149665eb8..dd731f269 100644 --- a/app/scripts/components/extended/widgets/common.ts +++ b/app/scripts/components/extended/widgets/common.ts @@ -7,8 +7,9 @@ import "@/directives/escaper" import { IController, IScope } from "angular" import { Condition } from "@/cqp_parser/cqp.types" import { StructService, StructServiceOptions } from "@/backend/struct-service" -import { RootScope } from "@/root-scope.types" import { LocMap } from "@/i18n/types" +import { StoreService } from "@/services/store" +import "@/services/store" export type WidgetDefinition = Widget | WidgetWithOptions export type WidgetWithOptions = (options: T) => Widget @@ -44,10 +45,10 @@ export const selectTemplate = html`