fix: tag search causing regex exception (#938)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { splitQueryInString } from '@/utils/stringUtils';
|
||||
import { SNTag } from '@standardnotes/snjs';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useEffect, useRef } from 'preact/hooks';
|
||||
@@ -71,7 +72,7 @@ export const AutocompleteTagResult = observer(
|
||||
|
||||
useEffect(() => {
|
||||
if (focusedTagResultUuid === tagResult.uuid) {
|
||||
tagResultRef.current!.focus();
|
||||
tagResultRef.current?.focus();
|
||||
appState.noteTags.setFocusedTagResultUuid(undefined);
|
||||
}
|
||||
}, [appState.noteTags, focusedTagResultUuid, tagResult]);
|
||||
@@ -92,9 +93,8 @@ export const AutocompleteTagResult = observer(
|
||||
{prefixTitle && <span className="grey-2">{prefixTitle}</span>}
|
||||
{autocompleteSearchQuery === ''
|
||||
? title
|
||||
: title
|
||||
.split(new RegExp(`(${autocompleteSearchQuery})`, 'gi'))
|
||||
.map((substring, index) => (
|
||||
: splitQueryInString(title, autocompleteSearchQuery).map(
|
||||
(substring, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className={`${
|
||||
@@ -106,7 +106,8 @@ export const AutocompleteTagResult = observer(
|
||||
>
|
||||
{substring}
|
||||
</span>
|
||||
))}
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
65
app/assets/javascripts/utils/stringUtils.spec.ts
Normal file
65
app/assets/javascripts/utils/stringUtils.spec.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
getIndexOfQueryInString,
|
||||
splitQueryInString,
|
||||
splitRangeWithinString,
|
||||
} from './stringUtils';
|
||||
|
||||
describe('string utils', () => {
|
||||
describe('splitRangeWithinString', () => {
|
||||
it('should return whole string if range is invalid or out of bounds', () => {
|
||||
const string = 'test-string';
|
||||
|
||||
const outOfBoundsStartResult = splitRangeWithinString(string, 15, 0);
|
||||
expect(outOfBoundsStartResult).toStrictEqual(['test-string']);
|
||||
|
||||
const outOfBoundsEndResult = splitRangeWithinString(string, 0, -15);
|
||||
expect(outOfBoundsEndResult).toStrictEqual(['test-string']);
|
||||
|
||||
const invalidRangeResult = splitRangeWithinString(string, 15, 0);
|
||||
expect(invalidRangeResult).toStrictEqual(['test-string']);
|
||||
});
|
||||
|
||||
it('should return split string if range is valid', () => {
|
||||
const string = 'test-string';
|
||||
|
||||
const case1 = splitRangeWithinString(string, 0, 3);
|
||||
expect(case1).toStrictEqual(['tes', 't-string']);
|
||||
|
||||
const case2 = splitRangeWithinString(string, 2, 6);
|
||||
expect(case2).toStrictEqual(['te', 'st-s', 'tring']);
|
||||
|
||||
const case3 = splitRangeWithinString(string, 4, 9);
|
||||
expect(case3).toStrictEqual(['test', '-stri', 'ng']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIndexOfQueryInString', () => {
|
||||
it('should get correct index of query in string', () => {
|
||||
const string = 'tEsT-sTrInG';
|
||||
|
||||
const indexOfQuery1 = getIndexOfQueryInString(string, 'tRi');
|
||||
expect(indexOfQuery1).toBe(6);
|
||||
|
||||
const indexOfQuery2 = getIndexOfQueryInString(string, 'StR');
|
||||
expect(indexOfQuery2).toBe(5);
|
||||
|
||||
const indexOfQuery3 = getIndexOfQueryInString(string, 'stringUtils');
|
||||
expect(indexOfQuery3).toBe(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('splitQueryInString', () => {
|
||||
it('should split string if it includes the query', () => {
|
||||
const string = 'TeSt-StRiNg';
|
||||
|
||||
const query1Result = splitQueryInString(string, 'T-sTr');
|
||||
expect(query1Result).toStrictEqual(['TeS', 't-StR', 'iNg']);
|
||||
|
||||
const query2Result = splitQueryInString(string, 'InG');
|
||||
expect(query2Result).toStrictEqual(['TeSt-StR', 'iNg']);
|
||||
|
||||
const query3Result = splitQueryInString(string, 'invalid query');
|
||||
expect(query3Result).toStrictEqual(['TeSt-StRiNg']);
|
||||
});
|
||||
});
|
||||
});
|
||||
39
app/assets/javascripts/utils/stringUtils.ts
Normal file
39
app/assets/javascripts/utils/stringUtils.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
export const splitRangeWithinString = (
|
||||
string: string,
|
||||
start: number,
|
||||
end: number
|
||||
) => {
|
||||
const isStartOutOfBounds = start > string.length || start < 0;
|
||||
const isEndOutOfBounds = end > string.length || end < 0;
|
||||
const isInvalidRange = start > end;
|
||||
|
||||
if (isStartOutOfBounds || isEndOutOfBounds || isInvalidRange) {
|
||||
return [string];
|
||||
} else {
|
||||
return [
|
||||
string.slice(0, start),
|
||||
string.slice(start, end),
|
||||
string.slice(end),
|
||||
].filter((slice) => slice.length > 0);
|
||||
}
|
||||
};
|
||||
|
||||
export const getIndexOfQueryInString = (string: string, query: string) => {
|
||||
const lowercasedTitle = string.toLowerCase();
|
||||
const lowercasedQuery = query.toLowerCase();
|
||||
return lowercasedTitle.indexOf(lowercasedQuery);
|
||||
};
|
||||
|
||||
export const splitQueryInString = (string: string, query: string) => {
|
||||
const indexOfQueryInTitle = getIndexOfQueryInString(string, query);
|
||||
|
||||
if (indexOfQueryInTitle < 0) {
|
||||
return [string];
|
||||
}
|
||||
|
||||
return splitRangeWithinString(
|
||||
string,
|
||||
indexOfQueryInTitle,
|
||||
indexOfQueryInTitle + query.length
|
||||
);
|
||||
};
|
||||
@@ -70,11 +70,11 @@
|
||||
"@reach/listbox": "^0.16.2",
|
||||
"@reach/tooltip": "^0.16.2",
|
||||
"@standardnotes/components": "1.7.12",
|
||||
"@standardnotes/features": "1.35.0",
|
||||
"@standardnotes/features": "1.35.1",
|
||||
"@standardnotes/filepicker": "1.10.0",
|
||||
"@standardnotes/settings": "1.13.1",
|
||||
"@standardnotes/sncrypto-web": "1.8.0",
|
||||
"@standardnotes/snjs": "2.86.2",
|
||||
"@standardnotes/snjs": "2.86.4",
|
||||
"@zip.js/zip.js": "^2.4.7",
|
||||
"mobx": "^6.5.0",
|
||||
"mobx-react-lite": "^3.3.0",
|
||||
|
||||
109
yarn.lock
109
yarn.lock
@@ -2345,6 +2345,13 @@
|
||||
dependencies:
|
||||
"@standardnotes/common" "^1.16.0"
|
||||
|
||||
"@standardnotes/applications@^1.2.3":
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/applications/-/applications-1.2.3.tgz#03f9067c20fb2960560bc084e9e37981044ee373"
|
||||
integrity sha512-YiQZzjiApTGSOUosidks99O3I1AQv5gzJ12+yc99GKYno564nn0QHOUMKqIgMJsEG+Yp6gJ2QpgzC/0hmUUlVQ==
|
||||
dependencies:
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
|
||||
"@standardnotes/auth@^3.17.7":
|
||||
version "3.17.7"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.17.7.tgz#cb53b415c9a5a61a8721d7099d0d13d8ab79b597"
|
||||
@@ -2353,25 +2360,46 @@
|
||||
"@standardnotes/common" "^1.16.0"
|
||||
jsonwebtoken "^8.5.1"
|
||||
|
||||
"@standardnotes/auth@^3.17.8":
|
||||
version "3.17.8"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.17.8.tgz#b74fb5a8b6b7176d2ea8d175dcd76532caa5d367"
|
||||
integrity sha512-/VkfzhYJkYW7cct0O3How5UVs4o3CG331uOrQawabeAUVXNNqnKkofFzsDX+LEhLGxwR2iwxRqszzEwSsOj0OA==
|
||||
dependencies:
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
jsonwebtoken "^8.5.1"
|
||||
|
||||
"@standardnotes/common@^1.16.0":
|
||||
version "1.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.16.0.tgz#d80c00a4e7fefa6ac03946abaaffccb2fe29e882"
|
||||
integrity sha512-C4Hy+G4GsKrTF4SqHrZmPu/S6eQbQC+VqlAp6BcZcEofwP7ZHVAi1todxAEED+5wPXz5VT+ctCUeoJpHtikHfA==
|
||||
|
||||
"@standardnotes/common@^1.16.1":
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.16.1.tgz#428bbd7c0ca2293e97dd0bcb033c20b3da093c16"
|
||||
integrity sha512-4Uo1f0dpbWWiOVku/zxOQ7vhE5VnJbmPpWADA92Q0yTL94KRi2R39cjb/sazQqX7RVX03LpYaswyXUmH8zas1w==
|
||||
|
||||
"@standardnotes/components@1.7.12":
|
||||
version "1.7.12"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.12.tgz#c87c3c8d90c0030b711d4f59aae47e14c745ea2a"
|
||||
integrity sha512-geE3xpBagZFJCucvFymUK4qIWT45nb8OXGW8Ck0EJothVSbz4rF3MJJ/W1pvI6+kYKbT12AaUoGecL6uKxi+1Q==
|
||||
|
||||
"@standardnotes/domain-events@^2.25.0":
|
||||
version "2.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.25.0.tgz#73d003967cb2b8af8afc6d26360d9af99db928fe"
|
||||
integrity sha512-o9k07Urfs8u04P9TGS7vA/ol5PQ6pi7BeejHWbWInCQ/kXgHcVHJkWBPsEPRxDboLzhju7ivbzUMYlEBmkj1vw==
|
||||
"@standardnotes/domain-events@^2.25.1":
|
||||
version "2.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.25.1.tgz#3a9fa51243a036cae30beba8b83b369d598ecc80"
|
||||
integrity sha512-4rOojrgVYT5QZM8kSSumP5eqGZdUjH8rs9Y7IiW5zSVi2Idq78WhLu33WTDbRn47WTsDZGkeQSRxaPPkBLabmg==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.17.7"
|
||||
"@standardnotes/features" "^1.35.0"
|
||||
"@standardnotes/auth" "^3.17.8"
|
||||
"@standardnotes/features" "^1.35.1"
|
||||
|
||||
"@standardnotes/features@1.35.0", "@standardnotes/features@^1.35.0":
|
||||
"@standardnotes/features@1.35.1", "@standardnotes/features@^1.35.1":
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.35.1.tgz#1c641dc0c55cc0f90321101bb05066d008b89c92"
|
||||
integrity sha512-nNyo83k+9UPOKALqJSVtqTaDq0hWHSQYlRBBQ1Vx7snC9Rxrlsgq2EO2k16ZIsRZiJbUlI0eK8uWwMey4p+L4Q==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.17.8"
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
|
||||
"@standardnotes/features@^1.35.0":
|
||||
version "1.35.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.35.0.tgz#2f3d1f1e7831ec86cf265227f4b61fbf5e245aa2"
|
||||
integrity sha512-ysibgtv9KoxYsD7f77Vn4DmViDnWeLANGtGwn6uUBnQbKHzuClFmSqBfAB7rmpu+1IRc+dfL8TlkPIwY2xvWqw==
|
||||
@@ -2394,6 +2422,16 @@
|
||||
"@standardnotes/features" "^1.35.0"
|
||||
"@standardnotes/utils" "^1.4.0"
|
||||
|
||||
"@standardnotes/payloads@^1.4.14":
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/payloads/-/payloads-1.4.14.tgz#f89eebc1d3920d4759b38bfad892f821d48cf1bd"
|
||||
integrity sha512-Ym9zH6IykNLNk+QrmRAaPCq5n5trLNRbWppdQmMWnQyeOOiNStd+pvVsFRCVumxDImova8KrFEdGmnTnzns+TQ==
|
||||
dependencies:
|
||||
"@standardnotes/applications" "^1.2.3"
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
"@standardnotes/features" "^1.35.1"
|
||||
"@standardnotes/utils" "^1.4.1"
|
||||
|
||||
"@standardnotes/responses@1.3.14", "@standardnotes/responses@^1.3.14":
|
||||
version "1.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.3.14.tgz#6a5d34490cb7a26dce0af23da8aa832aac7ca3f7"
|
||||
@@ -2404,7 +2442,17 @@
|
||||
"@standardnotes/features" "^1.35.0"
|
||||
"@standardnotes/payloads" "^1.4.13"
|
||||
|
||||
"@standardnotes/services@1.6.3", "@standardnotes/services@^1.6.3":
|
||||
"@standardnotes/responses@^1.3.15":
|
||||
version "1.3.15"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.3.15.tgz#dd56c96fce38213603b8eaf61383e7c3ea0773d0"
|
||||
integrity sha512-zJMeRxmq19RID8fLwgndVYdwMNO+y6EDTjHfKzO/ndmHY6CefNgsrVQLgcG26CIfv3Ivg4LpJLwclAmOB70Sjw==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.17.8"
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
"@standardnotes/features" "^1.35.1"
|
||||
"@standardnotes/payloads" "^1.4.14"
|
||||
|
||||
"@standardnotes/services@1.6.3":
|
||||
version "1.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.6.3.tgz#27223ea7bb28334e3118ba9351c752b3584f3c63"
|
||||
integrity sha512-p5wjHF0xaInMGQE2wVelboGp+YAYZtIQMOkA++hrIWuwziH+G+Hq2NthHtopx72kGzK8VZ+1Ay+9CRwXx+SMrg==
|
||||
@@ -2414,6 +2462,16 @@
|
||||
"@standardnotes/responses" "^1.3.14"
|
||||
"@standardnotes/utils" "^1.4.0"
|
||||
|
||||
"@standardnotes/services@^1.6.4":
|
||||
version "1.6.4"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.6.4.tgz#132836c70ed68302759e9607595c5390e8a847d5"
|
||||
integrity sha512-g7NGoN1IuXYIbnIkqaQo+J2vjHtk6Yy+suI/o8as0oDAvl4ygVykEZTx6tnl4GjQblLhJK4j9za5+V9uCn1sQg==
|
||||
dependencies:
|
||||
"@standardnotes/applications" "^1.2.3"
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
"@standardnotes/responses" "^1.3.15"
|
||||
"@standardnotes/utils" "^1.4.1"
|
||||
|
||||
"@standardnotes/settings@1.13.1", "@standardnotes/settings@^1.13.1":
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/settings/-/settings-1.13.1.tgz#c0f8558079da178667e7addd569b6953cd5e6bc2"
|
||||
@@ -2433,22 +2491,22 @@
|
||||
buffer "^6.0.3"
|
||||
libsodium-wrappers "^0.7.9"
|
||||
|
||||
"@standardnotes/snjs@2.86.2":
|
||||
version "2.86.2"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.86.2.tgz#8fd238cd49a5a2a47a20a9615d204da609000595"
|
||||
integrity sha512-tM+QHmnKHf3bNYW5FHZNmW16dpaU43tjzjdD9fGLbBvWXVF+6LrZXkYopNPD3TihoIzmuR3AZddfp99UGDZyNQ==
|
||||
"@standardnotes/snjs@2.86.4":
|
||||
version "2.86.4"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.86.4.tgz#d0cc9d1e1e890d192bf252b19f06775902bfc6f0"
|
||||
integrity sha512-Cp9nQ7a+Tjr/PVp72+qAgOaDetjyItuc9SwvnsPp4SlKku4KtCsIRQODPZfpF9ifxV/QIii+ZQbqk2ankHUQ0g==
|
||||
dependencies:
|
||||
"@standardnotes/applications" "^1.2.2"
|
||||
"@standardnotes/auth" "^3.17.7"
|
||||
"@standardnotes/common" "^1.16.0"
|
||||
"@standardnotes/domain-events" "^2.25.0"
|
||||
"@standardnotes/features" "^1.35.0"
|
||||
"@standardnotes/payloads" "^1.4.13"
|
||||
"@standardnotes/responses" "^1.3.14"
|
||||
"@standardnotes/services" "^1.6.3"
|
||||
"@standardnotes/applications" "^1.2.3"
|
||||
"@standardnotes/auth" "^3.17.8"
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
"@standardnotes/domain-events" "^2.25.1"
|
||||
"@standardnotes/features" "^1.35.1"
|
||||
"@standardnotes/payloads" "^1.4.14"
|
||||
"@standardnotes/responses" "^1.3.15"
|
||||
"@standardnotes/services" "^1.6.4"
|
||||
"@standardnotes/settings" "^1.13.1"
|
||||
"@standardnotes/sncrypto-common" "^1.7.3"
|
||||
"@standardnotes/utils" "^1.4.0"
|
||||
"@standardnotes/utils" "^1.4.1"
|
||||
|
||||
"@standardnotes/stylekit@5.17.0":
|
||||
version "5.17.0"
|
||||
@@ -2472,6 +2530,15 @@
|
||||
dompurify "^2.3.6"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@standardnotes/utils@^1.4.1":
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/utils/-/utils-1.4.1.tgz#ce185e1ace6b1d4db43e7b7025747c0b7427438f"
|
||||
integrity sha512-ouLfnVdwXQOBjxuxSJ9kPZmC9K+Qqq66V/Jlp0W1n6l6ywhBeS6Yv+oGTG4yvDNZeyP1myUF6VY4F9hJ8Y9wRQ==
|
||||
dependencies:
|
||||
"@standardnotes/common" "^1.16.1"
|
||||
dompurify "^2.3.6"
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@svgr/babel-plugin-add-jsx-attribute@^6.0.0":
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz#bd6d1ff32a31b82b601e73672a789cc41e84fe18"
|
||||
|
||||
Reference in New Issue
Block a user