mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
web: take keymap plugin from prosemirror-keymap
we'll be using this later on for everything keyboard related. it is simple implementation that normalizes key codes across platforms
This commit is contained in:
135
apps/web/package-lock.json
generated
135
apps/web/package-lock.json
generated
@@ -50,6 +50,7 @@
|
||||
"react-virtuoso": "2.4.0",
|
||||
"showdown": "github:thecodrr/showdown",
|
||||
"timeago.js": "^4.0.2",
|
||||
"w3c-keyname": "^2.2.6",
|
||||
"web-streams-polyfill": "^3.1.1",
|
||||
"wouter": "^2.7.3",
|
||||
"zustand": "^3.3.1"
|
||||
@@ -14298,7 +14299,6 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -14406,7 +14406,6 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -15238,7 +15237,6 @@
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -16720,7 +16718,6 @@
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.8.2",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -17004,6 +17001,11 @@
|
||||
"browser-process-hrtime": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
|
||||
"integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg=="
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
@@ -19042,10 +19044,12 @@
|
||||
}
|
||||
},
|
||||
"@csstools/postcss-unset-value": {
|
||||
"version": "1.0.2"
|
||||
"version": "1.0.2",
|
||||
"requires": {}
|
||||
},
|
||||
"@csstools/selector-specificity": {
|
||||
"version": "2.0.2"
|
||||
"version": "2.0.2",
|
||||
"requires": {}
|
||||
},
|
||||
"@develar/schema-utils": {
|
||||
"version": "2.6.5",
|
||||
@@ -19067,7 +19071,8 @@
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
@@ -20678,10 +20683,12 @@
|
||||
}
|
||||
},
|
||||
"acorn-import-assertions": {
|
||||
"version": "1.8.0"
|
||||
"version": "1.8.0",
|
||||
"requires": {}
|
||||
},
|
||||
"acorn-jsx": {
|
||||
"version": "5.3.2"
|
||||
"version": "5.3.2",
|
||||
"requires": {}
|
||||
},
|
||||
"acorn-node": {
|
||||
"version": "1.8.2",
|
||||
@@ -20997,7 +21004,8 @@
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2"
|
||||
"version": "3.5.2",
|
||||
"requires": {}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1"
|
||||
@@ -21046,7 +21054,8 @@
|
||||
}
|
||||
},
|
||||
"babel-plugin-named-asset-import": {
|
||||
"version": "0.3.8"
|
||||
"version": "0.3.8",
|
||||
"requires": {}
|
||||
},
|
||||
"babel-plugin-polyfill-corejs2": {
|
||||
"version": "0.3.2",
|
||||
@@ -21722,7 +21731,8 @@
|
||||
}
|
||||
},
|
||||
"css-declaration-sorter": {
|
||||
"version": "6.3.0"
|
||||
"version": "6.3.0",
|
||||
"requires": {}
|
||||
},
|
||||
"css-has-pseudo": {
|
||||
"version": "3.0.4",
|
||||
@@ -21783,7 +21793,8 @@
|
||||
}
|
||||
},
|
||||
"css-prefers-color-scheme": {
|
||||
"version": "6.0.3"
|
||||
"version": "6.0.3",
|
||||
"requires": {}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "4.3.0",
|
||||
@@ -21867,7 +21878,8 @@
|
||||
}
|
||||
},
|
||||
"cssnano-utils": {
|
||||
"version": "3.1.0"
|
||||
"version": "3.1.0",
|
||||
"requires": {}
|
||||
},
|
||||
"csso": {
|
||||
"version": "4.2.0",
|
||||
@@ -22809,7 +22821,8 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-react-hooks": {
|
||||
"version": "4.6.0"
|
||||
"version": "4.6.0",
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-plugin-testing-library": {
|
||||
"version": "5.6.0",
|
||||
@@ -23275,7 +23288,8 @@
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2"
|
||||
"version": "3.5.2",
|
||||
"requires": {}
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "6.0.0",
|
||||
@@ -23578,7 +23592,8 @@
|
||||
}
|
||||
},
|
||||
"goober": {
|
||||
"version": "2.1.11"
|
||||
"version": "2.1.11",
|
||||
"requires": {}
|
||||
},
|
||||
"got": {
|
||||
"version": "9.6.0",
|
||||
@@ -23799,7 +23814,8 @@
|
||||
}
|
||||
},
|
||||
"icss-utils": {
|
||||
"version": "5.1.0"
|
||||
"version": "5.1.0",
|
||||
"requires": {}
|
||||
},
|
||||
"idb": {
|
||||
"version": "7.0.2"
|
||||
@@ -24368,7 +24384,8 @@
|
||||
}
|
||||
},
|
||||
"jest-pnp-resolver": {
|
||||
"version": "1.2.2"
|
||||
"version": "1.2.2",
|
||||
"requires": {}
|
||||
},
|
||||
"jest-regex-util": {
|
||||
"version": "27.5.1"
|
||||
@@ -24883,7 +24900,8 @@
|
||||
}
|
||||
},
|
||||
"localforage-driver-commons": {
|
||||
"version": "1.0.3"
|
||||
"version": "1.0.3",
|
||||
"requires": {}
|
||||
},
|
||||
"localforage-driver-memory": {
|
||||
"version": "1.0.5",
|
||||
@@ -25727,7 +25745,8 @@
|
||||
}
|
||||
},
|
||||
"postcss-browser-comments": {
|
||||
"version": "4.0.0"
|
||||
"version": "4.0.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-calc": {
|
||||
"version": "8.2.4",
|
||||
@@ -25801,16 +25820,20 @@
|
||||
}
|
||||
},
|
||||
"postcss-discard-comments": {
|
||||
"version": "5.1.2"
|
||||
"version": "5.1.2",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-discard-duplicates": {
|
||||
"version": "5.1.0"
|
||||
"version": "5.1.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-discard-empty": {
|
||||
"version": "5.1.1"
|
||||
"version": "5.1.1",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-discard-overridden": {
|
||||
"version": "5.1.0"
|
||||
"version": "5.1.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-double-position-gradients": {
|
||||
"version": "3.1.2",
|
||||
@@ -25826,7 +25849,8 @@
|
||||
}
|
||||
},
|
||||
"postcss-flexbugs-fixes": {
|
||||
"version": "5.0.2"
|
||||
"version": "5.0.2",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-focus-visible": {
|
||||
"version": "6.0.4",
|
||||
@@ -25841,10 +25865,12 @@
|
||||
}
|
||||
},
|
||||
"postcss-font-variant": {
|
||||
"version": "5.0.0"
|
||||
"version": "5.0.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-gap-properties": {
|
||||
"version": "3.0.5"
|
||||
"version": "3.0.5",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-image-set-function": {
|
||||
"version": "4.0.7",
|
||||
@@ -25861,7 +25887,8 @@
|
||||
}
|
||||
},
|
||||
"postcss-initial": {
|
||||
"version": "4.0.1"
|
||||
"version": "4.0.1",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-js": {
|
||||
"version": "4.0.0",
|
||||
@@ -25905,10 +25932,12 @@
|
||||
}
|
||||
},
|
||||
"postcss-logical": {
|
||||
"version": "5.0.4"
|
||||
"version": "5.0.4",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-media-minmax": {
|
||||
"version": "5.0.0"
|
||||
"version": "5.0.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-merge-longhand": {
|
||||
"version": "5.1.6",
|
||||
@@ -25955,7 +25984,8 @@
|
||||
}
|
||||
},
|
||||
"postcss-modules-extract-imports": {
|
||||
"version": "3.0.0"
|
||||
"version": "3.0.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-modules-local-by-default": {
|
||||
"version": "4.0.0",
|
||||
@@ -25999,7 +26029,8 @@
|
||||
}
|
||||
},
|
||||
"postcss-normalize-charset": {
|
||||
"version": "5.1.0"
|
||||
"version": "5.1.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-normalize-display-values": {
|
||||
"version": "5.1.0",
|
||||
@@ -26073,7 +26104,8 @@
|
||||
}
|
||||
},
|
||||
"postcss-page-break": {
|
||||
"version": "3.0.4"
|
||||
"version": "3.0.4",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-place": {
|
||||
"version": "7.0.5",
|
||||
@@ -26155,7 +26187,8 @@
|
||||
}
|
||||
},
|
||||
"postcss-replace-overflow-wrap": {
|
||||
"version": "4.0.0"
|
||||
"version": "4.0.0",
|
||||
"requires": {}
|
||||
},
|
||||
"postcss-selector-not": {
|
||||
"version": "6.0.1",
|
||||
@@ -26441,7 +26474,6 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -26518,7 +26550,6 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -26549,7 +26580,8 @@
|
||||
"version": "3.0.4"
|
||||
},
|
||||
"react-loading-skeleton": {
|
||||
"version": "3.1.0"
|
||||
"version": "3.1.0",
|
||||
"requires": {}
|
||||
},
|
||||
"react-modal": {
|
||||
"version": "3.15.1",
|
||||
@@ -27029,7 +27061,6 @@
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -27053,7 +27084,8 @@
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2"
|
||||
"version": "3.5.2",
|
||||
"requires": {}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1"
|
||||
@@ -27501,7 +27533,8 @@
|
||||
"version": "3.1.1"
|
||||
},
|
||||
"style-loader": {
|
||||
"version": "3.3.1"
|
||||
"version": "3.3.1",
|
||||
"requires": {}
|
||||
},
|
||||
"style-value-types": {
|
||||
"version": "4.1.4",
|
||||
@@ -28007,8 +28040,7 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.8.2",
|
||||
"dev": true
|
||||
"version": "4.8.2"
|
||||
},
|
||||
"unbox-primitive": {
|
||||
"version": "1.0.2",
|
||||
@@ -28176,6 +28208,11 @@
|
||||
"browser-process-hrtime": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"w3c-keyname": {
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz",
|
||||
"integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg=="
|
||||
},
|
||||
"w3c-xmlserializer": {
|
||||
"version": "2.0.0",
|
||||
"requires": {
|
||||
@@ -28373,7 +28410,8 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.8.1"
|
||||
"version": "8.8.1",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -28669,7 +28707,8 @@
|
||||
}
|
||||
},
|
||||
"wouter": {
|
||||
"version": "2.7.5"
|
||||
"version": "2.7.5",
|
||||
"requires": {}
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
@@ -28692,7 +28731,8 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.9"
|
||||
"version": "7.5.9",
|
||||
"requires": {}
|
||||
},
|
||||
"xdg-basedir": {
|
||||
"version": "4.0.0",
|
||||
@@ -28752,7 +28792,8 @@
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"zustand": {
|
||||
"version": "3.7.2"
|
||||
"version": "3.7.2",
|
||||
"requires": {}
|
||||
},
|
||||
"zx": {
|
||||
"version": "7.0.8",
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"react-virtuoso": "2.4.0",
|
||||
"showdown": "github:thecodrr/showdown",
|
||||
"timeago.js": "^4.0.2",
|
||||
"w3c-keyname": "^2.2.6",
|
||||
"web-streams-polyfill": "^3.1.1",
|
||||
"wouter": "^2.7.3",
|
||||
"zustand": "^3.3.1"
|
||||
@@ -80,12 +81,12 @@
|
||||
"lorem-ipsum": "^2.0.4",
|
||||
"patch-package": "^6.4.7",
|
||||
"progress-bar-webpack-plugin": "^2.1.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"source-map-explorer": "^2.5.2",
|
||||
"typescript": "^4.8.2",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"worker-loader": "^3.0.8",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
"overrides": {
|
||||
"react@>17": "17.0.2",
|
||||
|
||||
113
apps/web/src/common/key-handler.ts
Normal file
113
apps/web/src/common/key-handler.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable header/header */
|
||||
/*
|
||||
Copyright (C) 2015-2017 by Marijn Haverbeke <marijnh@gmail.com> and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
import { base, keyName } from "w3c-keyname";
|
||||
|
||||
export type Command = () => boolean;
|
||||
const mac =
|
||||
typeof navigator != "undefined"
|
||||
? /Mac|iP(hone|[oa]d)/.test(navigator.platform)
|
||||
: false;
|
||||
|
||||
function normalizeKeyName(name: string) {
|
||||
const parts = name.split(/-(?!$)/);
|
||||
let result = parts[parts.length - 1];
|
||||
if (result == "Space") result = " ";
|
||||
let alt, ctrl, shift, meta;
|
||||
for (let i = 0; i < parts.length - 1; i++) {
|
||||
const mod = parts[i];
|
||||
if (/^(cmd|meta|m)$/i.test(mod)) meta = true;
|
||||
else if (/^a(lt)?$/i.test(mod)) alt = true;
|
||||
else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
|
||||
else if (/^s(hift)?$/i.test(mod)) shift = true;
|
||||
else if (/^mod$/i.test(mod)) {
|
||||
if (mac) meta = true;
|
||||
else ctrl = true;
|
||||
} else throw new Error("Unrecognized modifier name: " + mod);
|
||||
}
|
||||
if (alt) result = "Alt-" + result;
|
||||
if (ctrl) result = "Ctrl-" + result;
|
||||
if (meta) result = "Meta-" + result;
|
||||
if (shift) result = "Shift-" + result;
|
||||
return result;
|
||||
}
|
||||
|
||||
function normalize(map: { [key: string]: Command }) {
|
||||
const copy: { [key: string]: Command } = Object.create(null);
|
||||
for (const prop in map) copy[normalizeKeyName(prop)] = map[prop];
|
||||
return copy;
|
||||
}
|
||||
|
||||
function modifiers(name: string, event: KeyboardEvent, shift: boolean) {
|
||||
if (event.altKey) name = "Alt-" + name;
|
||||
if (event.ctrlKey) name = "Ctrl-" + name;
|
||||
if (event.metaKey) name = "Meta-" + name;
|
||||
if (shift !== false && event.shiftKey) name = "Shift-" + name;
|
||||
return name;
|
||||
}
|
||||
|
||||
// Given a set of bindings (using the same format as
|
||||
// [`keymap`](#keymap.keymap)), return a [keydown
|
||||
// handler](#view.EditorProps.handleKeyDown) that handles them.
|
||||
export function keydownHandler(
|
||||
bindings: Record<string, Command>
|
||||
): (event: KeyboardEvent) => boolean {
|
||||
const map = normalize(bindings);
|
||||
return function (event) {
|
||||
const name = keyName(event),
|
||||
isChar = name.length == 1 && name != " ";
|
||||
let baseName: string;
|
||||
const direct = map[modifiers(name, event, !isChar)];
|
||||
if (direct && direct()) {
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
isChar &&
|
||||
(event.shiftKey ||
|
||||
event.altKey ||
|
||||
event.metaKey ||
|
||||
name.charCodeAt(0) > 127) &&
|
||||
(baseName = base[event.keyCode]) &&
|
||||
baseName != name
|
||||
) {
|
||||
// Try falling back to the keyCode when there's a modifier
|
||||
// active or the character produced isn't ASCII, and our table
|
||||
// produces a different name from the the keyCode. See #668,
|
||||
// #1060
|
||||
const fromCode = map[modifiers(baseName, event, true)];
|
||||
if (fromCode && fromCode()) {
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
} else if (isChar && event.shiftKey) {
|
||||
// Otherwise, if shift is active, also try the binding with the
|
||||
// Shift- prefix enabled. See #997
|
||||
const withShift = map[modifiers(name, event, true)];
|
||||
if (withShift && withShift()) {
|
||||
event.preventDefault();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user