diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 32e63c30a..725905508 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,8 +13,9 @@ jobs: strategy: matrix: - # Having "" here enables the `node-version-file` option - node-version: ["", 18, 20] + # From lowest supported version up to the one pinned in .nvmrc + # The empty string enables the `node-version-file` option which reads from .nvmrc + node-version: [18, ""] steps: - name: Checkout main repo diff --git a/.nvmrc b/.nvmrc index 48ef2c10b..a3597ecbd 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.9 +20.11 diff --git a/CHANGELOG.md b/CHANGELOG.md index d9dd93710..d9565bb00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [9.5.1] - 2024-02-12 + +### Changed + +- Logos with taglines + +### Fixed + +- Improve UX for "in order" option [#335](https://github.com/spraakbanken/korp-frontend/issues/335) +- Unnecessary scrollbars in the corpus selector info panel [#333](https://github.com/spraakbanken/korp-frontend/issues/333) +- Bug with undefined `arguments` +- On repetition error (all tokens repeat from 0), restore red outline for input +- Use `` to constraint CQP subqueries (from statistics rows etc) + ## [9.5.0] - 2023-01-22 ### Added @@ -73,7 +87,7 @@ - Most bug fixes was related to the refactoring breaking things - Lots of bug fixes for the sidebar - +[9.5.1]: https://github.com/spraakbanken/korp-frontend/releases/tag/v9.5.1 [9.5.0]: https://github.com/spraakbanken/korp-frontend/releases/tag/v9.5.0 [9.4.4]: https://github.com/spraakbanken/korp-frontend/releases/tag/v9.4.4 [9.4.3]: https://github.com/spraakbanken/korp-frontend/releases/tag/v9.4.3 diff --git a/app/config/statistics_config.js b/app/config/statistics_config.js index d7eb5ad6c..5fba282bf 100644 --- a/app/config/statistics_config.js +++ b/app/config/statistics_config.js @@ -21,7 +21,7 @@ let getCqp = function (hitValues, ignoreCase) { } tokens.push("[" + andExpr.join(" & ") + "]") } - return tokens.join(" ") + return ` ${tokens.join(" ")} []* ` } let reduceCqp = function (type, tokens, ignoreCase) { diff --git a/app/img/korp_slogan.svg b/app/img/korp_slogan.svg new file mode 100755 index 000000000..182c67085 --- /dev/null +++ b/app/img/korp_slogan.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/img/korp_slogan_en.svg b/app/img/korp_slogan_en.svg new file mode 100755 index 000000000..5a9f4c886 --- /dev/null +++ b/app/img/korp_slogan_en.svg @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/img/sprakbanken_text_slogan.svg b/app/img/sprakbanken_text_slogan.svg new file mode 100755 index 000000000..b2f33cc9d --- /dev/null +++ b/app/img/sprakbanken_text_slogan.svg @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/img/sprakbanken_text_slogan_en.svg b/app/img/sprakbanken_text_slogan_en.svg new file mode 100755 index 000000000..8deb79c4e --- /dev/null +++ b/app/img/sprakbanken_text_slogan_en.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/scripts/components/advanced_search.js b/app/scripts/components/advanced_search.js index b1f4451db..f818c54ad 100644 --- a/app/scripts/components/advanced_search.js +++ b/app/scripts/components/advanced_search.js @@ -34,8 +34,15 @@ export const advancedSearchComponent = { on-search="$ctrl.onSearch()" on-search-save="$ctrl.onSearchSave(name)" > - - + + `, bindings: {}, controller: [ @@ -46,8 +53,6 @@ export const advancedSearchComponent = { const $ctrl = this $ctrl.inOrder = $location.search().in_order == null - /** Whether the "in order" option is applicable. */ - $ctrl.inOrderEnabled = true if ($location.search().search && $location.search().search.split("|")) { var [type, ...expr] = $location.search().search.split("|") @@ -61,14 +66,10 @@ export const advancedSearchComponent = { } $ctrl.onSearch = () => { - // The "in order" option should be available only if >1 token and no wildcards. - const cqpObjs = CQP.parse($ctrl.cqp) - $ctrl.inOrderEnabled = cqpObjs.length > 1 && !CQP.hasWildcards(cqpObjs) - $location.search("search", null) $location.search("page", null) $location.search("within", null) - $location.search("in_order", !$ctrl.inOrder && $ctrl.inOrderEnabled ? false : null) + $location.search("in_order", !$ctrl.inOrder ? false : null) $timeout(() => $location.search("search", `cqp|${$ctrl.cqp}`), 0) } diff --git a/app/scripts/components/corpus_chooser/corpus_chooser.js b/app/scripts/components/corpus_chooser/corpus_chooser.js index c6fc652f0..8afe485e0 100644 --- a/app/scripts/components/corpus_chooser/corpus_chooser.js +++ b/app/scripts/components/corpus_chooser/corpus_chooser.js @@ -54,7 +54,7 @@ export const corpusChooserComponent = { {{ $ctrl.selectedNumberOfSentences | prettyNumber }} {{'corpselector_sentences_long' | loc:$root.lang}}

- + `, diff --git a/app/scripts/components/extended/extended_tokens.js b/app/scripts/components/extended/extended_tokens.js index 18cb3982a..c343a8099 100644 --- a/app/scripts/components/extended/extended_tokens.js +++ b/app/scripts/components/extended/extended_tokens.js @@ -14,6 +14,7 @@ export const extendedTokensComponent = { parallell-lang="$ctrl.parallellLang" toggle-start="$ctrl.toggleStart($index)()" toggle-end="$ctrl.toggleEnd($index)()" + repeat-error="$ctrl.repeatError" > +
{{'repeat_error' | loc:$root.lang}}
+ +
+ {{'order_error' | loc:$root.lang}} +
+ - + {{'and' | loc:$root.lang}} {{'within' | loc:$root.lang}} @@ -35,21 +41,23 @@ export const extendedStandardComponent = { controller: [ "$location", "$rootScope", + "$scope", "compareSearches", "$timeout", - function ($location, $rootScope, compareSearches, $timeout) { + function ($location, $rootScope, $scope, compareSearches, $timeout) { const ctrl = this ctrl.lang = $rootScope.lang - ctrl.inOrder = $location.search().in_order == null + $scope.inOrder = $location.search().in_order == null /** Whether the "in order" option is applicable. */ ctrl.inOrderEnabled = true + ctrl.orderError = false // TODO this is *too* weird function triggerSearch() { $location.search("search", null) $location.search("page", null) - $location.search("in_order", !ctrl.inOrder && ctrl.inOrderEnabled ? false : null) + $location.search("in_order", !$scope.inOrder && ctrl.inOrderEnabled ? false : null) $timeout(function () { $location.search("search", "cqp") if (!_.keys(settings["default_within"]).includes(ctrl.within)) { @@ -87,13 +95,29 @@ export const extendedStandardComponent = { c.log("Error", e) } - // The "in order" option should be available only if >1 token and no wildcards. - const cqpObjs = CQP.parse(cqp) - ctrl.inOrderEnabled = cqpObjs.length > 1 && !CQP.hasWildcards(cqpObjs) + ctrl.validateInOrder() $location.search("cqp", cqp) } + $scope.$watch("inOrder", () => { + ctrl.validateInOrder() + }) + + /** Trigger error if the "in order" option is incompatible with the query */ + ctrl.validateInOrder = () => { + const cqpObjs = CQP.parse(ctrl.cqp) + if (!CQP.supportsInOrder(cqpObjs)) { + // If query doesn't support free word order, and the "in order" checkbox has been unchecked, + // then disable search, show explanation and let user resolve the conflict + ctrl.orderError = !$scope.inOrder + ctrl.inOrderEnabled = !$scope.inOrder + } else { + ctrl.orderError = false + ctrl.inOrderEnabled = true + } + } + ctrl.cqp = $location.search().cqp ctrl.repeatError = false diff --git a/app/scripts/components/extended/token.js b/app/scripts/components/extended/token.js index c4b18e62b..436f7ee32 100644 --- a/app/scripts/components/extended/token.js +++ b/app/scripts/components/extended/token.js @@ -63,6 +63,7 @@ export const extendedTokenComponent = { showClose: "=", token: "=", parallellLang: "<", + repeatError: "<", remove: "&", change: "&", toggleStart: "&", diff --git a/app/scripts/components/header.js b/app/scripts/components/header.js index bd9e07193..c5d9b892d 100644 --- a/app/scripts/components/header.js +++ b/app/scripts/components/header.js @@ -1,6 +1,8 @@ /** @format */ -import korpLogo from "../../img/korp.svg" -import sbxLogo from "../../img/sprakbanken_text.svg" +import korpLogo from "../../img/korp_slogan.svg" +import korpLogoEn from "../../img/korp_slogan_en.svg" +import sbxLogo from "../../img/sprakbanken_text_slogan.svg" +import sbxLogoEn from "../../img/sprakbanken_text_slogan_en.svg" import guLogo from "../../img/gu_logo_sv_head.svg" let html = String.raw @@ -99,9 +101,10 @@ export const headerComponent = { -
+ diff --git a/app/scripts/components/kwic.js b/app/scripts/components/kwic.js index cde39a778..6cd06ba8f 100644 --- a/app/scripts/components/kwic.js +++ b/app/scripts/components/kwic.js @@ -23,7 +23,7 @@ export const kwicComponent = { ng-class="{odd : $index % 2 != 0, even : $index % 2 == 0}" ng-click="$ctrl.pageEvent(corpus.page)" uib-tooltip="{{corpus.rtitle | locObj:lang}}: {{corpus.abs}}" - uib-tooltip-placement='{{$last? "left":"top"}}' + tooltip-placement='{{$last? "left":"top"}}' append-to-body="false" > diff --git a/app/scripts/components/simple_search.js b/app/scripts/components/simple_search.js index 3a9aa9ca7..25c1fb74c 100644 --- a/app/scripts/components/simple_search.js +++ b/app/scripts/components/simple_search.js @@ -91,7 +91,7 @@ export const simpleSearchComponent = { ctrl.inOrder = $location.search().in_order == null /** Whether the "in order" option is applicable. */ - ctrl.inOrderEnabled = true + ctrl.inOrderEnabled = false ctrl.prefix = $location.search().prefix != null ctrl.mid_comp = $location.search().mid_comp != null ctrl.suffix = $location.search().suffix != null @@ -233,6 +233,7 @@ export const simpleSearchComponent = { ctrl.lemgram = search.val } $rootScope.simpleCQP = CQP.expandOperators(ctrl.getCQP()) + ctrl.updateInOrderEnabled() ctrl.doSearch() } }) @@ -246,9 +247,12 @@ export const simpleSearchComponent = { ctrl.currentText = null } - // The "in order" option should be available only if >1 token. - const cqpObjs = CQP.parse(ctrl.getCQP()) - ctrl.inOrderEnabled = cqpObjs.length > 1 && !CQP.hasWildcards(cqpObjs) + ctrl.updateInOrderEnabled() + } + + ctrl.updateInOrderEnabled = () => { + const cqpObjs = CQP.parse(ctrl.getCQP() || "[]") + ctrl.inOrderEnabled = CQP.supportsInOrder(cqpObjs) } ctrl.doSearch = function () { diff --git a/app/scripts/controllers/statistics_controller.js b/app/scripts/controllers/statistics_controller.js index 2a9a1aa46..8c845e144 100644 --- a/app/scripts/controllers/statistics_controller.js +++ b/app/scripts/controllers/statistics_controller.js @@ -95,8 +95,9 @@ korpApp.directive("statsResultCtrl", () => ({ }) }, (textStatus, err) => { + const arguments_ = arguments $timeout(() => { - c.log("fail", arguments) + c.log("fail", arguments_) c.log( "stats fail", s.loading, diff --git a/app/scripts/cqp_parser/cqp.js b/app/scripts/cqp_parser/cqp.js index d0e667987..3fd20d450 100644 --- a/app/scripts/cqp_parser/cqp.js +++ b/app/scripts/cqp_parser/cqp.js @@ -204,12 +204,15 @@ window.CQP = { }, /** Check if a query has any wildcards (`[]`) */ - hasWildcards(cqpObjs) { - for (const token of cqpObjs) { - // Stringify individual token - const str = CQP.stringify([token]) - if (str.indexOf("[]") === 0) return true - } - return false - }, + hasWildcard: (cqpObjs) => cqpObjs.some((token) => CQP.stringify([token]).indexOf("[]") === 0), + + /** Check if a query has any tokens with repetition */ + hasRepetition: (cqpObjs) => cqpObjs.some((token) => token.repeat), + + /** Check if a query has any structure boundaries, e.g. sentence start */ + hasStruct: (cqpObjs) => cqpObjs.some((token) => token.struct), + + /** Determine whether a query will work with the in_order option */ + supportsInOrder: (cqpObjs) => + cqpObjs.length > 1 && !CQP.hasWildcard(cqpObjs) && !CQP.hasRepetition(cqpObjs) && !CQP.hasStruct(cqpObjs), } diff --git a/app/styles/styles.scss b/app/styles/styles.scss index 5400a0a3d..4069775f9 100644 --- a/app/styles/styles.scss +++ b/app/styles/styles.scss @@ -2335,7 +2335,7 @@ li.active a span .num-to-find { } .input-error { - border:red 2px solid; + outline:red 2px solid; } // TODO we should not do this, update boostrap instead? diff --git a/app/translations/locale-eng.json b/app/translations/locale-eng.json index 1b22ab144..8cf591b46 100644 --- a/app/translations/locale-eng.json +++ b/app/translations/locale-eng.json @@ -346,6 +346,8 @@ "add_filter_value": "Add", "repeat_error": "Error: Not possible to repeat from 0 for all tokens.", + "order_error": "Error: Disabling \"in order\" requires multiple tokens, no repetition, no boundaries and no wildcards.", + "order_help": "Disabling the \"in order\" option is compatible with queries that have multiple tokens, no repetition, no boundaries and no wildcards.", "choose_value": "Choose a value", "login_needed_for_corpora": "Login needed for access to", diff --git a/app/translations/locale-swe.json b/app/translations/locale-swe.json index 15f92292e..47efddf31 100644 --- a/app/translations/locale-swe.json +++ b/app/translations/locale-swe.json @@ -344,6 +344,8 @@ "add_filter_value": "Lägg till", "repeat_error": "Fel: Det går inte att upprepa från 0 på alla token.", + "order_error": "Fel: Det går bara att välja bort \"i följd\" om sökfrågan har flera tokens samt inga repetitioner, gränser eller tomma token.", + "order_help": "Att välja bort \"i följd\" är kompatibelt med sökfrågor som har flera tokens samt inga repetitioner, gränser eller tomma token.", "choose_value": "Välj ett värde", "login_needed_for_corpora": "Inloggning behövs för åtkomst till", diff --git a/package.json b/package.json index e7dc3c084..479bc70b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "korp-frontend", - "version": "9.5.0", + "version": "9.5.1", "dependencies": { "@fortawesome/fontawesome-free": "6.2.1", "angular": "1.8.3",