diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 346e34a3..f2e77e77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,7 @@ dependencies: graphql: 16.0.1 graphql-tag: 2.12.6_graphql@16.0.1 js-cookie: 2.2.1 + jszip: 3.7.1 markdown-it: 12.2.0 markdown-it-link-attributes: 3.0.0 mnemonist: 0.38.5 @@ -85,7 +86,6 @@ dependencies: raven-js: 3.27.2 react: 17.0.2 safe-regex: 2.1.1 - sass: 1.43.4 sortablejs: 1.14.0 sourcemapped-stacktrace: 1.1.11 text-diff: 1.0.1 @@ -117,9 +117,9 @@ devDependencies: extract-loader: 2.0.1 file-loader: 4.3.0_webpack@4.46.0 json-loader: 0.5.7 - jszip: 3.7.1 raw-loader: 3.1.0_webpack@4.46.0 rimraf: 3.0.2 + sass: 1.43.4 sass-loader: 7.3.1_webpack@4.46.0 semver: 7.3.5 terser-webpack-plugin: 4.2.3_webpack@4.46.0 @@ -988,6 +988,7 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.0 + dev: true /aproba/1.2.0: resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} @@ -1173,6 +1174,7 @@ packages: /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} + dev: true /binary/0.3.0: resolution: {integrity: sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=} @@ -1260,6 +1262,7 @@ packages: engines: {node: '>=8'} dependencies: fill-range: 7.0.1 + dev: true /brorand/1.1.0: resolution: {integrity: sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=} @@ -1513,6 +1516,7 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.2 + dev: true /chownr/1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -1760,7 +1764,6 @@ packages: /core-util-is/1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: true /create-ecdh/4.0.4: resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} @@ -2593,6 +2596,7 @@ packages: engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 + dev: true /finalhandler/1.1.2: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} @@ -2748,6 +2752,7 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true + dev: true optional: true /fstream/1.0.12: @@ -2804,6 +2809,7 @@ packages: engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 + dev: true /glob/7.2.0: resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} @@ -3107,7 +3113,7 @@ packages: /immediate/3.0.6: resolution: {integrity: sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=} - dev: true + dev: false /import-fresh/3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} @@ -3157,7 +3163,6 @@ packages: /inherits/2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true /internal-ip/6.2.0: resolution: {integrity: sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==} @@ -3243,6 +3248,7 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 + dev: true /is-boolean-object/1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} @@ -3327,6 +3333,7 @@ packages: /is-extglob/2.1.1: resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} engines: {node: '>=0.10.0'} + dev: true /is-fullwidth-code-point/3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -3338,6 +3345,7 @@ packages: engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 + dev: true /is-ip/3.1.0: resolution: {integrity: sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==} @@ -3368,6 +3376,7 @@ packages: /is-number/7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + dev: true /is-path-cwd/2.2.0: resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} @@ -3466,7 +3475,6 @@ packages: /isarray/1.0.0: resolution: {integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=} - dev: true /isexe/2.0.0: resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} @@ -3564,7 +3572,7 @@ packages: pako: 1.0.11 readable-stream: 2.3.7 set-immediate-shim: 1.0.1 - dev: true + dev: false /kind-of/3.2.2: resolution: {integrity: sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=} @@ -3602,7 +3610,7 @@ packages: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} dependencies: immediate: 3.0.6 - dev: true + dev: false /linkify-it/3.0.3: resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} @@ -4079,6 +4087,7 @@ packages: /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + dev: true /npm-run-path/4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} @@ -4314,7 +4323,6 @@ packages: /pako/1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - dev: true /parallel-transform/1.2.0: resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==} @@ -4425,6 +4433,7 @@ packages: /picomatch/2.3.0: resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==} engines: {node: '>=8.6'} + dev: true /pify/2.3.0: resolution: {integrity: sha1-7RQaasBDqEnqWISY59yosVMw6Qw=} @@ -4548,7 +4557,6 @@ packages: /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - dev: true /process/0.11.10: resolution: {integrity: sha1-czIwDoQBYb2j5podHZGn1LwW8YI=} @@ -4719,7 +4727,6 @@ packages: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 - dev: true /readable-stream/3.6.0: resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} @@ -4745,6 +4752,7 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.0 + dev: true /rechoir/0.7.1: resolution: {integrity: sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==} @@ -4889,7 +4897,6 @@ packages: /safe-buffer/5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true /safe-buffer/5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -4931,7 +4938,7 @@ packages: hasBin: true dependencies: chokidar: 3.5.2 - dev: false + dev: true /schema-utils/1.0.0: resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==} @@ -5045,7 +5052,7 @@ packages: /set-immediate-shim/1.0.1: resolution: {integrity: sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=} engines: {node: '>=0.10.0'} - dev: true + dev: false /set-value/4.1.0: resolution: {integrity: sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==} @@ -5353,7 +5360,6 @@ packages: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 - dev: true /string_decoder/1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -5547,6 +5553,7 @@ packages: engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 + dev: true /to-regex/3.0.2: resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} @@ -5697,7 +5704,6 @@ packages: /util-deprecate/1.0.2: resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} - dev: true /util/0.10.3: resolution: {integrity: sha1-evsa/lCAUkZInj23/g7TeTNqwPk=} diff --git a/src/sites/twitch-twilight/modules/chat/input.jsx b/src/sites/twitch-twilight/modules/chat/input.jsx index 008086ff..6feccf01 100644 --- a/src/sites/twitch-twilight/modules/chat/input.jsx +++ b/src/sites/twitch-twilight/modules/chat/input.jsx @@ -606,7 +606,7 @@ export default class Input extends Module { results = Array.isArray(results) ? results.concat(emoji) : emoji; } - results = t.sortFavorites(results); + results = t.sortEmotes(results, input); return limitResults && results.length > 25 ? results.slice(0, 25) : results; } @@ -647,21 +647,49 @@ export default class Input extends Module { // eslint-disable-next-line class-methods-use-this - sortFavorites(results) { - if (!this.chat.context.get('chat.tab-complete.prioritize-favorites')) { - return results; + sortEmotes(emotes, input) { + const preferFavorites = this.chat.context.get('chat.tab-complete.prioritize-favorites'); + const lowerCaseInput = input.toLowerCase(); + + const locale = new Intl.Collator(); + const localeCI = new Intl.Collator(undefined, {sensitivity: 'accent'}); // case insensitive + + const startsWithInput = new Set(); + const startsWithInputCI = new Set(); // case insensitive + for (let i = 0; i < emotes.length; ++i) { + const str = emotes[i].replacement; + if (str.startsWith(input)) + startsWithInput.add(str); + else if (str.toLowerCase().startsWith(lowerCaseInput)) + startsWithInputCI.add(str); } - return results.sort((a, b) => { - if (a.favorite) { - return b.favorite ? a.replacement.localeCompare(b.replacement) : -1; - } - else if (b.favorite) { - return 1; - } - else { - a.replacement.localeCompare(b.replacement) - } + return emotes.sort((a, b) => { + const aStr = a.replacement; + const bStr = b.replacement; + + // Prefer favorites over non-favorites, if enabled + if (preferFavorites && (a.favorite ^ b.favorite)) + return 0 - a.favorite + b.favorite; + + // Prefer case-sensitive prefix matches + const aStartsWithInput = startsWithInput.has(aStr); + const bStartsWithInput = startsWithInput.has(bStr); + if (aStartsWithInput && bStartsWithInput) + return locale.compare(aStr, bStr); + else if (aStartsWithInput) return -1; + else if (bStartsWithInput) return 1; + + // Else prefer case-insensitive prefix matches + const aStartsWithInputCI = aStartsWithInput || startsWithInputCI.has(aStr); + const bStartsWithInputCI = bStartsWithInput || startsWithInputCI.has(bStr); + if (aStartsWithInputCI && bStartsWithInputCI) + return localeCI.compare(aStr, bStr); + else if (aStartsWithInputCI) return -1; + else if (bStartsWithInputCI) return 1; + + // Else alphabetize + return locale.compare(aStr, bStr); }); }