diff --git a/.DS_Store b/.DS_Store index 4837e51..2bf305b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.env b/.env index 895f64e..82490c4 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -REACT_APP_API_URL=https://api.harmonydata.ac.uk/ +REACT_APP_API_URL=https://api.harmonydata.ac.uk REACT_APP_API_EXAMPLES=$REACT_APP_API_URL/text/examples REACT_APP_API_PARSE=$REACT_APP_API_URL/text/parse REACT_APP_API_MATCH=$REACT_APP_API_URL/text/match diff --git a/.env.development b/.env.development index 895f64e..82490c4 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,4 @@ -REACT_APP_API_URL=https://api.harmonydata.ac.uk/ +REACT_APP_API_URL=https://api.harmonydata.ac.uk REACT_APP_API_EXAMPLES=$REACT_APP_API_URL/text/examples REACT_APP_API_PARSE=$REACT_APP_API_URL/text/parse REACT_APP_API_MATCH=$REACT_APP_API_URL/text/match diff --git a/.gitignore b/.gitignore index 1892a38..fbd521c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,37 @@ -/build +# Dependencies /node_modules -/testPDFs -package-lock.json -/wireframes -package-lock.json -functions/venv -functions/__pycache__ +/.pnp +.pnp.js + +# Testing +/coverage + +# Next.js +/.next/ +/out/ + +# Production +/build + +# Misc +.DS_Store +*.pem + +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Local env files +.env*.local + +# Vercel +.vercel + +# TypeScript +*.tsbuildinfo +next-env.d.ts + +# Extension files +/extensions/ +harmonydata.github.io.code-workspace diff --git a/README.md b/README.md index 885d81a..045ee43 100644 --- a/README.md +++ b/README.md @@ -118,3 +118,123 @@ The alternative method is to call the globally available function `createHarmony You can raise an issue in the [issue tracker](https://github.com/harmonydata/harmony/issues), and you can open a [pull request](https://github.com/harmonydata/harmony/pulls). Please contact us at https://harmonydata.ac.uk/contact or write to thomas@fastdatascience.com if you would like to be involved in the project. + +# Harmony Browser Extensions + +Browser extensions for sending selected text to Harmony. Available for Chrome, Firefox, and Safari. + +## Features + +- Right-click to send selected text to Harmony +- Popup interface for pasting text from PDFs +- Seamless integration with Harmony Data platform +- Cross-browser support + +## Development + +The extensions are built using vanilla JavaScript and browser-specific Extension APIs. Each browser extension is located in its own directory: + +- `extensions/chrome/`: Chrome extension +- `extensions/firefox/`: Firefox add-on +- `extensions/safari/`: Safari extension + +### Common Components + +Each extension shares similar core functionality: +- Context menu integration +- Popup interface +- Text selection handling +- PDF text extraction + +### Local Development + +1. Clone the repository: + ```bash + git clone https://github.com/harmonydata/harmony-browser-extension.git + cd harmony-browser-extension + ``` + +2. Install dependencies: + ```bash + npm install + ``` + +3. Load the extension in your browser: + + **Chrome:** + - Open Chrome and go to `chrome://extensions/` + - Enable "Developer mode" + - Click "Load unpacked" and select the `extensions/chrome` directory + + **Firefox:** + - Open Firefox and go to `about:debugging` + - Click "This Firefox" on the left + - Click "Load Temporary Add-on" + - Select the `extensions/firefox/manifest.json` file + + **Safari:** + - Open Safari and go to Safari > Settings > Extensions + - Enable "Developer mode" + - Click "Load Extension" + - Select the `extensions/safari` directory + +## Publishing + +The extensions are automatically published to their respective stores when changes are pushed to the main branch. This is handled by GitHub Actions. + +### Chrome Web Store + +1. Go to the [Chrome Web Store Developer Dashboard](https://chrome.google.com/webstore/devconsole) +2. Create a new item or select your existing extension +3. Get your Extension ID from the URL +4. Go to the "API Access" tab +5. Create a new API key: + - Click "Create new credentials" + - Choose "Chrome Web Store API" + - Save the Client ID and Client Secret + +### Firefox Add-ons + +1. Go to the [Firefox Add-ons Developer Hub](https://addons.mozilla.org/developers/) +2. Create a new add-on or select your existing one +3. Get your Add-on ID +4. Generate API credentials in the Developer Hub + +### Safari Extensions + +1. Go to the [Apple Developer Portal](https://developer.apple.com) +2. Create a new Safari extension or select your existing one +3. Get your Extension ID +4. Generate API credentials in the Developer Portal + +### Configuring GitHub Secrets + +Add the following secrets to your GitHub repository (Settings > Secrets and variables > Actions): + +**Chrome:** +- `CHROME_EXTENSION_ID` +- `CHROME_CLIENT_ID` +- `CHROME_CLIENT_SECRET` +- `CHROME_REFRESH_TOKEN` + +**Firefox:** +- `FIREFOX_EXTENSION_ID` +- `FIREFOX_API_KEY` +- `FIREFOX_API_SECRET` + +**Safari:** +- `SAFARI_EXTENSION_ID` +- `SAFARI_API_KEY` +- `SAFARI_API_SECRET` + +## Contributing + +1. Fork the repository +2. Create your feature branch (`git checkout -b feature/amazing-feature`) +3. Commit your changes (`git commit -m 'Add some amazing feature'`) +4. Push to the branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/plugin/.DS_Store b/plugin/.DS_Store deleted file mode 100644 index d8d844a..0000000 Binary files a/plugin/.DS_Store and /dev/null differ diff --git a/plugin/Screenshot 640.png b/plugin/Screenshot 640.png deleted file mode 100644 index 4f76bf5..0000000 Binary files a/plugin/Screenshot 640.png and /dev/null differ diff --git a/plugin/background.js b/plugin/background.js deleted file mode 100644 index 61e00f1..0000000 --- a/plugin/background.js +++ /dev/null @@ -1,145 +0,0 @@ -importScripts("./js-base64/base64.js"); - -const harmonyURL = "https://harmonydata.ac.uk/app/#/"; - -const createHarmonyUrl = ({ questions, instrument_name }) => { - if ( - Array.isArray(questions) && - questions.length && - questions.every( - (q) => - typeof q === "string" || - q instanceof String || - (q.question_text && - (typeof q.question_text === "string" || - q.question_text instanceof String)) - ) - ) { - const qArray = questions.map((q, i) => { - return { - question_no: q.question_no || i, - question_text: q.question_text || q, - }; - }); - const iArray = { instrument_name: instrument_name, questions: qArray }; - return harmonyURL + "import/" + Base64.encode(JSON.stringify(iArray), true); - } else { - throw new Error( - "questions is not properly formatted - it must be an array of question texts, or an array of objects which each must have a question_text property" - ); - } -}; - -// Create context menu item -chrome.runtime.onInstalled.addListener(() => { - // Create different menu items for PDFs and regular pages - chrome.contextMenus.create({ - id: "sendToHarmony", - title: "Send to Harmony", - contexts: ["selection"], - }); - // Initialize history in storage - chrome.storage.local.set({ history: [] }); -}); - -// Function to open Harmony URL in new tab -function openHarmonyTab(url) { - chrome.tabs.create({ url: url }); -} - -// Listen for messages from popup -chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { - if (request.action === "openHarmonyUrl") { - findOrCreateHarmonyTab(request.url); - return true; - } - if (request.action === "processPdfText") { - processSelection(request.text, request.tab); - return true; - } -}); - -chrome.contextMenus.onClicked.addListener(async function (info, tab) { - if (info.menuItemId === "sendToHarmony") { - if (tab?.id === -1 || tab?.url?.toLowerCase().includes("pdf")) { - // For PDF tabs, show popup - chrome.action.openPopup(); - return; - } - - // For non-PDF tabs, use scripting API - try { - const resultArray = await chrome.scripting.executeScript({ - target: { tabId: tab.id }, - function: () => { - const selection = document.getSelection(); - return selection ? selection.toString() : ""; - }, - }); - const selectedText = resultArray[0]?.result || ""; - if (selectedText) { - processSelection(selectedText, tab); - } - } catch (error) { - console.error("Error getting selected text:", error); - chrome.action.setBadgeText({ text: "!" }); - chrome.action.setBadgeBackgroundColor({ color: "#F44336" }); - setTimeout(() => { - chrome.action.setBadgeText({ text: "" }); - }, 2000); - } - } -}); - -async function processSelection(selectedText, tab) { - if (!selectedText) { - return; // Handle cases where no text is selected - } - - // Process the selected text here... - const questionsArray = selectedText - .split(/\r?\n|\s*/i) - .filter((line) => line.trim() !== ""); - - try { - // Create the Harmony URL with the selected text as a question - const harmonyUrl = createHarmonyUrl({ - questions: questionsArray, - instrument_name: `Imported from ${tab.title} ${tab.url}`, - }); - - // Store in history - chrome.storage.local.get(["history"], function (result) { - const history = result.history || []; - history.unshift({ - text: - selectedText.substring(0, 100) + - (selectedText.length > 100 ? "..." : ""), - url: tab.url, - timestamp: new Date().toISOString(), - harmonyUrl: harmonyUrl, - }); - // Keep only last 10 items - if (history.length > 10) history.pop(); - chrome.storage.local.set({ history: history }); - }); - - // Open or update the Harmony tab - await findOrCreateHarmonyTab(harmonyUrl); - - // Show success notification - chrome.action.setBadgeText({ text: "✓" }); - chrome.action.setBadgeBackgroundColor({ color: "#4CAF50" }); - setTimeout(() => { - chrome.action.setBadgeText({ text: "" }); - }, 2000); - } catch (error) { - // Show error notification - chrome.action.setBadgeText({ text: "!" }); - chrome.action.setBadgeBackgroundColor({ color: "#F44336" }); - setTimeout(() => { - chrome.action.setBadgeText({ text: "" }); - }, 2000); - console.error("Error:", error); - } -} diff --git a/plugin/icons/128.png b/plugin/icons/128.png deleted file mode 100644 index b966681..0000000 Binary files a/plugin/icons/128.png and /dev/null differ diff --git a/plugin/icons/16.png b/plugin/icons/16.png deleted file mode 100644 index 8a249d6..0000000 Binary files a/plugin/icons/16.png and /dev/null differ diff --git a/plugin/icons/48.png b/plugin/icons/48.png deleted file mode 100644 index 3473e60..0000000 Binary files a/plugin/icons/48.png and /dev/null differ diff --git a/plugin/icons/Thumbs.db b/plugin/icons/Thumbs.db deleted file mode 100644 index cba85a4..0000000 Binary files a/plugin/icons/Thumbs.db and /dev/null differ diff --git a/plugin/js-base64/LICENSE.md b/plugin/js-base64/LICENSE.md deleted file mode 100644 index fd579a4..0000000 --- a/plugin/js-base64/LICENSE.md +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014, Dan Kogai -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of {{{project}}} nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugin/js-base64/README.md b/plugin/js-base64/README.md deleted file mode 100644 index 19b0709..0000000 --- a/plugin/js-base64/README.md +++ /dev/null @@ -1,169 +0,0 @@ -[![CI via GitHub Actions](https://github.com/dankogai/js-base64/actions/workflows/node.js.yml/badge.svg)](https://github.com/dankogai/js-base64/actions/workflows/node.js.yml) - -# base64.js - -Yet another [Base64] transcoder. - -[Base64]: http://en.wikipedia.org/wiki/Base64 - -## Install - -```shell -$ npm install --save js-base64 -``` - -## Usage - -### In Browser - -Locally… - -```html - -``` - -… or Directly from CDN. In which case you don't even need to install. - -```html - -``` - -This good old way loads `Base64` in the global context (`window`). Though `Base64.noConflict()` is made available, you should consider using ES6 Module to avoid tainting `window`. - -### As an ES6 Module - -locally… - -```javascript -import { Base64 } from 'js-base64'; -``` - -```javascript -// or if you prefer no Base64 namespace -import { encode, decode } from 'js-base64'; -``` - -or even remotely. - -```html - -``` - -```html - -``` - -### node.js (commonjs) - -```javascript -const {Base64} = require('js-base64'); -``` - -Unlike the case above, the global context is no longer modified. - -You can also use [esm] to `import` instead of `require`. - -[esm]: https://github.com/standard-things/esm - -```javascript -require=require('esm')(module); -import {Base64} from 'js-base64'; -``` - -## SYNOPSIS - -```javascript -let latin = 'dankogai'; -let utf8 = '小飼弾' -let u8s = new Uint8Array([100,97,110,107,111,103,97,105]); -Base64.encode(latin); // ZGFua29nYWk= -Base64.encode(latin, true); // ZGFua29nYWk skips padding -Base64.encodeURI(latin); // ZGFua29nYWk -Base64.btoa(latin); // ZGFua29nYWk= -Base64.btoa(utf8); // raises exception -Base64.fromUint8Array(u8s); // ZGFua29nYWk= -Base64.fromUint8Array(u8s, true); // ZGFua29nYW which is URI safe -Base64.encode(utf8); // 5bCP6aO85by+ -Base64.encode(utf8, true) // 5bCP6aO85by- -Base64.encodeURI(utf8); // 5bCP6aO85by- -``` - -```javascript -Base64.decode( 'ZGFua29nYWk=');// dankogai -Base64.decode( 'ZGFua29nYWk'); // dankogai -Base64.atob( 'ZGFua29nYWk=');// dankogai -Base64.atob( '5bCP6aO85by+');// '小飼弾' which is nonsense -Base64.toUint8Array('ZGFua29nYWk=');// u8s above -Base64.decode( '5bCP6aO85by+');// 小飼弾 -// note .decodeURI() is unnecessary since it accepts both flavors -Base64.decode( '5bCP6aO85by-');// 小飼弾 -``` - -```javascript -Base64.isValid(0); // false: 0 is not string -Base64.isValid(''); // true: a valid Base64-encoded empty byte -Base64.isValid('ZA=='); // true: a valid Base64-encoded 'd' -Base64.isValid('Z A='); // true: whitespaces are okay -Base64.isValid('ZA'); // true: padding ='s can be omitted -Base64.isValid('++'); // true: can be non URL-safe -Base64.isValid('--'); // true: or URL-safe -Base64.isValid('+-'); // false: can't mix both -``` - -### Built-in Extensions - -By default `Base64` leaves built-in prototypes untouched. But you can extend them as below. - -```javascript -// you have to explicitly extend String.prototype -Base64.extendString(); -// once extended, you can do the following -'dankogai'.toBase64(); // ZGFua29nYWk= -'小飼弾'.toBase64(); // 5bCP6aO85by+ -'小飼弾'.toBase64(true); // 5bCP6aO85by- -'小飼弾'.toBase64URI(); // 5bCP6aO85by- ab alias of .toBase64(true) -'小飼弾'.toBase64URL(); // 5bCP6aO85by- an alias of .toBase64URI() -'ZGFua29nYWk='.fromBase64(); // dankogai -'5bCP6aO85by+'.fromBase64(); // 小飼弾 -'5bCP6aO85by-'.fromBase64(); // 小飼弾 -'5bCP6aO85by-'.toUint8Array();// u8s above -``` - -```javascript -// you have to explicitly extend Uint8Array.prototype -Base64.extendUint8Array(); -// once extended, you can do the following -u8s.toBase64(); // 'ZGFua29nYWk=' -u8s.toBase64URI(); // 'ZGFua29nYWk' -u8s.toBase64URL(); // 'ZGFua29nYWk' an alias of .toBase64URI() -``` - -```javascript -// extend all at once -Base64.extendBuiltins() -``` - -## `.decode()` vs `.atob` (and `.encode()` vs `btoa()`) - -Suppose you have: - -``` -var pngBase64 = - "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="; -``` - -Which is a Base64-encoded 1x1 transparent PNG, **DO NOT USE** `Base64.decode(pngBase64)`.  Use `Base64.atob(pngBase64)` instead.  `Base64.decode()` decodes to UTF-8 string while `Base64.atob()` decodes to bytes, which is compatible to browser built-in `atob()` (Which is absent in node.js).  The same rule applies to the opposite direction. - -Or even better, `Base64.toUint8Array(pngBase64)`. - -## Brief History - -* Since version 3.3 it is written in TypeScript. Now `base64.mjs` is compiled from `base64.ts` then `base64.js` is generated from `base64.mjs`. -* Since version 3.7 `base64.js` is ES5-compatible again (hence IE11-compatible). -* Since 3.0 `js-base64` switch to ES2015 module so it is no longer compatible with legacy browsers like IE (see above) diff --git a/plugin/js-base64/base64.d.mts b/plugin/js-base64/base64.d.mts deleted file mode 100644 index e44249c..0000000 --- a/plugin/js-base64/base64.d.mts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * base64.ts - * - * Licensed under the BSD 3-Clause License. - * http://opensource.org/licenses/BSD-3-Clause - * - * References: - * http://en.wikipedia.org/wiki/Base64 - * - * @author Dan Kogai (https://github.com/dankogai) - */ -declare const version = "3.7.7"; -/** - * @deprecated use lowercase `version`. - */ -declare const VERSION = "3.7.7"; -/** - * polyfill version of `btoa` - */ -declare const btoaPolyfill: (bin: string) => string; -/** - * does what `window.btoa` of web browsers do. - * @param {String} bin binary string - * @returns {string} Base64-encoded string - */ -declare const _btoa: (bin: string) => string; -/** - * converts a Uint8Array to a Base64 string. - * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5 - * @returns {string} Base64 string - */ -declare const fromUint8Array: (u8a: Uint8Array, urlsafe?: boolean) => string; -/** - * @deprecated should have been internal use only. - * @param {string} src UTF-8 string - * @returns {string} UTF-16 string - */ -declare const utob: (u: string) => string; -/** - * converts a UTF-8-encoded string to a Base64 string. - * @param {boolean} [urlsafe] if `true` make the result URL-safe - * @returns {string} Base64 string - */ -declare const encode: (src: string, urlsafe?: boolean) => string; -/** - * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5. - * @returns {string} Base64 string - */ -declare const encodeURI: (src: string) => string; -/** - * @deprecated should have been internal use only. - * @param {string} src UTF-16 string - * @returns {string} UTF-8 string - */ -declare const btou: (b: string) => string; -/** - * polyfill version of `atob` - */ -declare const atobPolyfill: (asc: string) => string; -/** - * does what `window.atob` of web browsers do. - * @param {String} asc Base64-encoded string - * @returns {string} binary string - */ -declare const _atob: (asc: string) => string; -/** - * converts a Base64 string to a Uint8Array. - */ -declare const toUint8Array: (a: string) => Uint8Array; -/** - * converts a Base64 string to a UTF-8 string. - * @param {String} src Base64 string. Both normal and URL-safe are supported - * @returns {string} UTF-8 string - */ -declare const decode: (src: string) => string; -/** - * check if a value is a valid Base64 string - * @param {String} src a value to check - */ -declare const isValid: (src: any) => boolean; -/** - * extend String.prototype with relevant methods - */ -declare const extendString: () => void; -/** - * extend Uint8Array.prototype with relevant methods - */ -declare const extendUint8Array: () => void; -/** - * extend Builtin prototypes with relevant methods - */ -declare const extendBuiltins: () => void; -declare const gBase64: { - version: string; - VERSION: string; - atob: (asc: string) => string; - atobPolyfill: (asc: string) => string; - btoa: (bin: string) => string; - btoaPolyfill: (bin: string) => string; - fromBase64: (src: string) => string; - toBase64: (src: string, urlsafe?: boolean) => string; - encode: (src: string, urlsafe?: boolean) => string; - encodeURI: (src: string) => string; - encodeURL: (src: string) => string; - utob: (u: string) => string; - btou: (b: string) => string; - decode: (src: string) => string; - isValid: (src: any) => boolean; - fromUint8Array: (u8a: Uint8Array, urlsafe?: boolean) => string; - toUint8Array: (a: string) => Uint8Array; - extendString: () => void; - extendUint8Array: () => void; - extendBuiltins: () => void; -}; -export { version }; -export { VERSION }; -export { _atob as atob }; -export { atobPolyfill }; -export { _btoa as btoa }; -export { btoaPolyfill }; -export { decode as fromBase64 }; -export { encode as toBase64 }; -export { utob }; -export { encode }; -export { encodeURI }; -export { encodeURI as encodeURL }; -export { btou }; -export { decode }; -export { isValid }; -export { fromUint8Array }; -export { toUint8Array }; -export { extendString }; -export { extendUint8Array }; -export { extendBuiltins }; -export { gBase64 as Base64 }; diff --git a/plugin/js-base64/base64.d.ts b/plugin/js-base64/base64.d.ts deleted file mode 100644 index e44249c..0000000 --- a/plugin/js-base64/base64.d.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * base64.ts - * - * Licensed under the BSD 3-Clause License. - * http://opensource.org/licenses/BSD-3-Clause - * - * References: - * http://en.wikipedia.org/wiki/Base64 - * - * @author Dan Kogai (https://github.com/dankogai) - */ -declare const version = "3.7.7"; -/** - * @deprecated use lowercase `version`. - */ -declare const VERSION = "3.7.7"; -/** - * polyfill version of `btoa` - */ -declare const btoaPolyfill: (bin: string) => string; -/** - * does what `window.btoa` of web browsers do. - * @param {String} bin binary string - * @returns {string} Base64-encoded string - */ -declare const _btoa: (bin: string) => string; -/** - * converts a Uint8Array to a Base64 string. - * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5 - * @returns {string} Base64 string - */ -declare const fromUint8Array: (u8a: Uint8Array, urlsafe?: boolean) => string; -/** - * @deprecated should have been internal use only. - * @param {string} src UTF-8 string - * @returns {string} UTF-16 string - */ -declare const utob: (u: string) => string; -/** - * converts a UTF-8-encoded string to a Base64 string. - * @param {boolean} [urlsafe] if `true` make the result URL-safe - * @returns {string} Base64 string - */ -declare const encode: (src: string, urlsafe?: boolean) => string; -/** - * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5. - * @returns {string} Base64 string - */ -declare const encodeURI: (src: string) => string; -/** - * @deprecated should have been internal use only. - * @param {string} src UTF-16 string - * @returns {string} UTF-8 string - */ -declare const btou: (b: string) => string; -/** - * polyfill version of `atob` - */ -declare const atobPolyfill: (asc: string) => string; -/** - * does what `window.atob` of web browsers do. - * @param {String} asc Base64-encoded string - * @returns {string} binary string - */ -declare const _atob: (asc: string) => string; -/** - * converts a Base64 string to a Uint8Array. - */ -declare const toUint8Array: (a: string) => Uint8Array; -/** - * converts a Base64 string to a UTF-8 string. - * @param {String} src Base64 string. Both normal and URL-safe are supported - * @returns {string} UTF-8 string - */ -declare const decode: (src: string) => string; -/** - * check if a value is a valid Base64 string - * @param {String} src a value to check - */ -declare const isValid: (src: any) => boolean; -/** - * extend String.prototype with relevant methods - */ -declare const extendString: () => void; -/** - * extend Uint8Array.prototype with relevant methods - */ -declare const extendUint8Array: () => void; -/** - * extend Builtin prototypes with relevant methods - */ -declare const extendBuiltins: () => void; -declare const gBase64: { - version: string; - VERSION: string; - atob: (asc: string) => string; - atobPolyfill: (asc: string) => string; - btoa: (bin: string) => string; - btoaPolyfill: (bin: string) => string; - fromBase64: (src: string) => string; - toBase64: (src: string, urlsafe?: boolean) => string; - encode: (src: string, urlsafe?: boolean) => string; - encodeURI: (src: string) => string; - encodeURL: (src: string) => string; - utob: (u: string) => string; - btou: (b: string) => string; - decode: (src: string) => string; - isValid: (src: any) => boolean; - fromUint8Array: (u8a: Uint8Array, urlsafe?: boolean) => string; - toUint8Array: (a: string) => Uint8Array; - extendString: () => void; - extendUint8Array: () => void; - extendBuiltins: () => void; -}; -export { version }; -export { VERSION }; -export { _atob as atob }; -export { atobPolyfill }; -export { _btoa as btoa }; -export { btoaPolyfill }; -export { decode as fromBase64 }; -export { encode as toBase64 }; -export { utob }; -export { encode }; -export { encodeURI }; -export { encodeURI as encodeURL }; -export { btou }; -export { decode }; -export { isValid }; -export { fromUint8Array }; -export { toUint8Array }; -export { extendString }; -export { extendUint8Array }; -export { extendBuiltins }; -export { gBase64 as Base64 }; diff --git a/plugin/js-base64/base64.js b/plugin/js-base64/base64.js deleted file mode 100644 index dc837a7..0000000 --- a/plugin/js-base64/base64.js +++ /dev/null @@ -1,314 +0,0 @@ -// -// THIS FILE IS AUTOMATICALLY GENERATED! DO NOT EDIT BY HAND! -// -; -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' - ? module.exports = factory() - : typeof define === 'function' && define.amd - ? define(factory) : - // cf. https://github.com/dankogai/js-base64/issues/119 - (function () { - // existing version for noConflict() - var _Base64 = global.Base64; - var gBase64 = factory(); - gBase64.noConflict = function () { - global.Base64 = _Base64; - return gBase64; - }; - if (global.Meteor) { // Meteor.js - Base64 = gBase64; - } - global.Base64 = gBase64; - })(); -}((typeof self !== 'undefined' ? self - : typeof window !== 'undefined' ? window - : typeof global !== 'undefined' ? global - : this), function () { - 'use strict'; - /** - * base64.ts - * - * Licensed under the BSD 3-Clause License. - * http://opensource.org/licenses/BSD-3-Clause - * - * References: - * http://en.wikipedia.org/wiki/Base64 - * - * @author Dan Kogai (https://github.com/dankogai) - */ - var version = '3.7.7'; - /** - * @deprecated use lowercase `version`. - */ - var VERSION = version; - var _hasBuffer = typeof Buffer === 'function'; - var _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined; - var _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined; - var b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - var b64chs = Array.prototype.slice.call(b64ch); - var b64tab = (function (a) { - var tab = {}; - a.forEach(function (c, i) { return tab[c] = i; }); - return tab; - })(b64chs); - var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; - var _fromCC = String.fromCharCode.bind(String); - var _U8Afrom = typeof Uint8Array.from === 'function' - ? Uint8Array.from.bind(Uint8Array) - : function (it) { return new Uint8Array(Array.prototype.slice.call(it, 0)); }; - var _mkUriSafe = function (src) { return src - .replace(/=/g, '').replace(/[+\/]/g, function (m0) { return m0 == '+' ? '-' : '_'; }); }; - var _tidyB64 = function (s) { return s.replace(/[^A-Za-z0-9\+\/]/g, ''); }; - /** - * polyfill version of `btoa` - */ - var btoaPolyfill = function (bin) { - // console.log('polyfilled'); - var u32, c0, c1, c2, asc = ''; - var pad = bin.length % 3; - for (var i = 0; i < bin.length;) { - if ((c0 = bin.charCodeAt(i++)) > 255 || - (c1 = bin.charCodeAt(i++)) > 255 || - (c2 = bin.charCodeAt(i++)) > 255) - throw new TypeError('invalid character found'); - u32 = (c0 << 16) | (c1 << 8) | c2; - asc += b64chs[u32 >> 18 & 63] - + b64chs[u32 >> 12 & 63] - + b64chs[u32 >> 6 & 63] - + b64chs[u32 & 63]; - } - return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc; - }; - /** - * does what `window.btoa` of web browsers do. - * @param {String} bin binary string - * @returns {string} Base64-encoded string - */ - var _btoa = typeof btoa === 'function' ? function (bin) { return btoa(bin); } - : _hasBuffer ? function (bin) { return Buffer.from(bin, 'binary').toString('base64'); } - : btoaPolyfill; - var _fromUint8Array = _hasBuffer - ? function (u8a) { return Buffer.from(u8a).toString('base64'); } - : function (u8a) { - // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326 - var maxargs = 0x1000; - var strs = []; - for (var i = 0, l = u8a.length; i < l; i += maxargs) { - strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs))); - } - return _btoa(strs.join('')); - }; - /** - * converts a Uint8Array to a Base64 string. - * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5 - * @returns {string} Base64 string - */ - var fromUint8Array = function (u8a, urlsafe) { - if (urlsafe === void 0) { urlsafe = false; } - return urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a); - }; - // This trick is found broken https://github.com/dankogai/js-base64/issues/130 - // const utob = (src: string) => unescape(encodeURIComponent(src)); - // reverting good old fationed regexp - var cb_utob = function (c) { - if (c.length < 2) { - var cc = c.charCodeAt(0); - return cc < 0x80 ? c - : cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6)) - + _fromCC(0x80 | (cc & 0x3f))) - : (_fromCC(0xe0 | ((cc >>> 12) & 0x0f)) - + _fromCC(0x80 | ((cc >>> 6) & 0x3f)) - + _fromCC(0x80 | (cc & 0x3f))); - } - else { - var cc = 0x10000 - + (c.charCodeAt(0) - 0xD800) * 0x400 - + (c.charCodeAt(1) - 0xDC00); - return (_fromCC(0xf0 | ((cc >>> 18) & 0x07)) - + _fromCC(0x80 | ((cc >>> 12) & 0x3f)) - + _fromCC(0x80 | ((cc >>> 6) & 0x3f)) - + _fromCC(0x80 | (cc & 0x3f))); - } - }; - var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; - /** - * @deprecated should have been internal use only. - * @param {string} src UTF-8 string - * @returns {string} UTF-16 string - */ - var utob = function (u) { return u.replace(re_utob, cb_utob); }; - // - var _encode = _hasBuffer - ? function (s) { return Buffer.from(s, 'utf8').toString('base64'); } - : _TE - ? function (s) { return _fromUint8Array(_TE.encode(s)); } - : function (s) { return _btoa(utob(s)); }; - /** - * converts a UTF-8-encoded string to a Base64 string. - * @param {boolean} [urlsafe] if `true` make the result URL-safe - * @returns {string} Base64 string - */ - var encode = function (src, urlsafe) { - if (urlsafe === void 0) { urlsafe = false; } - return urlsafe - ? _mkUriSafe(_encode(src)) - : _encode(src); - }; - /** - * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5. - * @returns {string} Base64 string - */ - var encodeURI = function (src) { return encode(src, true); }; - // This trick is found broken https://github.com/dankogai/js-base64/issues/130 - // const btou = (src: string) => decodeURIComponent(escape(src)); - // reverting good old fationed regexp - var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; - var cb_btou = function (cccc) { - switch (cccc.length) { - case 4: - var cp = ((0x07 & cccc.charCodeAt(0)) << 18) - | ((0x3f & cccc.charCodeAt(1)) << 12) - | ((0x3f & cccc.charCodeAt(2)) << 6) - | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000; - return (_fromCC((offset >>> 10) + 0xD800) - + _fromCC((offset & 0x3FF) + 0xDC00)); - case 3: - return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12) - | ((0x3f & cccc.charCodeAt(1)) << 6) - | (0x3f & cccc.charCodeAt(2))); - default: - return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6) - | (0x3f & cccc.charCodeAt(1))); - } - }; - /** - * @deprecated should have been internal use only. - * @param {string} src UTF-16 string - * @returns {string} UTF-8 string - */ - var btou = function (b) { return b.replace(re_btou, cb_btou); }; - /** - * polyfill version of `atob` - */ - var atobPolyfill = function (asc) { - // console.log('polyfilled'); - asc = asc.replace(/\s+/g, ''); - if (!b64re.test(asc)) - throw new TypeError('malformed base64.'); - asc += '=='.slice(2 - (asc.length & 3)); - var u24, bin = '', r1, r2; - for (var i = 0; i < asc.length;) { - u24 = b64tab[asc.charAt(i++)] << 18 - | b64tab[asc.charAt(i++)] << 12 - | (r1 = b64tab[asc.charAt(i++)]) << 6 - | (r2 = b64tab[asc.charAt(i++)]); - bin += r1 === 64 ? _fromCC(u24 >> 16 & 255) - : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255) - : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255); - } - return bin; - }; - /** - * does what `window.atob` of web browsers do. - * @param {String} asc Base64-encoded string - * @returns {string} binary string - */ - var _atob = typeof atob === 'function' ? function (asc) { return atob(_tidyB64(asc)); } - : _hasBuffer ? function (asc) { return Buffer.from(asc, 'base64').toString('binary'); } - : atobPolyfill; - // - var _toUint8Array = _hasBuffer - ? function (a) { return _U8Afrom(Buffer.from(a, 'base64')); } - : function (a) { return _U8Afrom(_atob(a).split('').map(function (c) { return c.charCodeAt(0); })); }; - /** - * converts a Base64 string to a Uint8Array. - */ - var toUint8Array = function (a) { return _toUint8Array(_unURI(a)); }; - // - var _decode = _hasBuffer - ? function (a) { return Buffer.from(a, 'base64').toString('utf8'); } - : _TD - ? function (a) { return _TD.decode(_toUint8Array(a)); } - : function (a) { return btou(_atob(a)); }; - var _unURI = function (a) { return _tidyB64(a.replace(/[-_]/g, function (m0) { return m0 == '-' ? '+' : '/'; })); }; - /** - * converts a Base64 string to a UTF-8 string. - * @param {String} src Base64 string. Both normal and URL-safe are supported - * @returns {string} UTF-8 string - */ - var decode = function (src) { return _decode(_unURI(src)); }; - /** - * check if a value is a valid Base64 string - * @param {String} src a value to check - */ - var isValid = function (src) { - if (typeof src !== 'string') - return false; - var s = src.replace(/\s+/g, '').replace(/={0,2}$/, ''); - return !/[^\s0-9a-zA-Z\+/]/.test(s) || !/[^\s0-9a-zA-Z\-_]/.test(s); - }; - // - var _noEnum = function (v) { - return { - value: v, enumerable: false, writable: true, configurable: true - }; - }; - /** - * extend String.prototype with relevant methods - */ - var extendString = function () { - var _add = function (name, body) { return Object.defineProperty(String.prototype, name, _noEnum(body)); }; - _add('fromBase64', function () { return decode(this); }); - _add('toBase64', function (urlsafe) { return encode(this, urlsafe); }); - _add('toBase64URI', function () { return encode(this, true); }); - _add('toBase64URL', function () { return encode(this, true); }); - _add('toUint8Array', function () { return toUint8Array(this); }); - }; - /** - * extend Uint8Array.prototype with relevant methods - */ - var extendUint8Array = function () { - var _add = function (name, body) { return Object.defineProperty(Uint8Array.prototype, name, _noEnum(body)); }; - _add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); }); - _add('toBase64URI', function () { return fromUint8Array(this, true); }); - _add('toBase64URL', function () { return fromUint8Array(this, true); }); - }; - /** - * extend Builtin prototypes with relevant methods - */ - var extendBuiltins = function () { - extendString(); - extendUint8Array(); - }; - var gBase64 = { - version: version, - VERSION: VERSION, - atob: _atob, - atobPolyfill: atobPolyfill, - btoa: _btoa, - btoaPolyfill: btoaPolyfill, - fromBase64: decode, - toBase64: encode, - encode: encode, - encodeURI: encodeURI, - encodeURL: encodeURI, - utob: utob, - btou: btou, - decode: decode, - isValid: isValid, - fromUint8Array: fromUint8Array, - toUint8Array: toUint8Array, - extendString: extendString, - extendUint8Array: extendUint8Array, - extendBuiltins: extendBuiltins - }; - // - // export Base64 to the namespace - // - // ES5 is yet to have Object.assign() that may make transpilers unhappy. - // gBase64.Base64 = Object.assign({}, gBase64); - gBase64.Base64 = {}; - Object.keys(gBase64).forEach(function (k) { return gBase64.Base64[k] = gBase64[k]; }); - return gBase64; -})); diff --git a/plugin/js-base64/base64.mjs b/plugin/js-base64/base64.mjs deleted file mode 100644 index fe9cfa5..0000000 --- a/plugin/js-base64/base64.mjs +++ /dev/null @@ -1,294 +0,0 @@ -/** - * base64.ts - * - * Licensed under the BSD 3-Clause License. - * http://opensource.org/licenses/BSD-3-Clause - * - * References: - * http://en.wikipedia.org/wiki/Base64 - * - * @author Dan Kogai (https://github.com/dankogai) - */ -const version = '3.7.7'; -/** - * @deprecated use lowercase `version`. - */ -const VERSION = version; -const _hasBuffer = typeof Buffer === 'function'; -const _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined; -const _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined; -const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; -const b64chs = Array.prototype.slice.call(b64ch); -const b64tab = ((a) => { - let tab = {}; - a.forEach((c, i) => tab[c] = i); - return tab; -})(b64chs); -const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; -const _fromCC = String.fromCharCode.bind(String); -const _U8Afrom = typeof Uint8Array.from === 'function' - ? Uint8Array.from.bind(Uint8Array) - : (it) => new Uint8Array(Array.prototype.slice.call(it, 0)); -const _mkUriSafe = (src) => src - .replace(/=/g, '').replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_'); -const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, ''); -/** - * polyfill version of `btoa` - */ -const btoaPolyfill = (bin) => { - // console.log('polyfilled'); - let u32, c0, c1, c2, asc = ''; - const pad = bin.length % 3; - for (let i = 0; i < bin.length;) { - if ((c0 = bin.charCodeAt(i++)) > 255 || - (c1 = bin.charCodeAt(i++)) > 255 || - (c2 = bin.charCodeAt(i++)) > 255) - throw new TypeError('invalid character found'); - u32 = (c0 << 16) | (c1 << 8) | c2; - asc += b64chs[u32 >> 18 & 63] - + b64chs[u32 >> 12 & 63] - + b64chs[u32 >> 6 & 63] - + b64chs[u32 & 63]; - } - return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc; -}; -/** - * does what `window.btoa` of web browsers do. - * @param {String} bin binary string - * @returns {string} Base64-encoded string - */ -const _btoa = typeof btoa === 'function' ? (bin) => btoa(bin) - : _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64') - : btoaPolyfill; -const _fromUint8Array = _hasBuffer - ? (u8a) => Buffer.from(u8a).toString('base64') - : (u8a) => { - // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326 - const maxargs = 0x1000; - let strs = []; - for (let i = 0, l = u8a.length; i < l; i += maxargs) { - strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs))); - } - return _btoa(strs.join('')); - }; -/** - * converts a Uint8Array to a Base64 string. - * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5 - * @returns {string} Base64 string - */ -const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a); -// This trick is found broken https://github.com/dankogai/js-base64/issues/130 -// const utob = (src: string) => unescape(encodeURIComponent(src)); -// reverting good old fationed regexp -const cb_utob = (c) => { - if (c.length < 2) { - var cc = c.charCodeAt(0); - return cc < 0x80 ? c - : cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6)) - + _fromCC(0x80 | (cc & 0x3f))) - : (_fromCC(0xe0 | ((cc >>> 12) & 0x0f)) - + _fromCC(0x80 | ((cc >>> 6) & 0x3f)) - + _fromCC(0x80 | (cc & 0x3f))); - } - else { - var cc = 0x10000 - + (c.charCodeAt(0) - 0xD800) * 0x400 - + (c.charCodeAt(1) - 0xDC00); - return (_fromCC(0xf0 | ((cc >>> 18) & 0x07)) - + _fromCC(0x80 | ((cc >>> 12) & 0x3f)) - + _fromCC(0x80 | ((cc >>> 6) & 0x3f)) - + _fromCC(0x80 | (cc & 0x3f))); - } -}; -const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; -/** - * @deprecated should have been internal use only. - * @param {string} src UTF-8 string - * @returns {string} UTF-16 string - */ -const utob = (u) => u.replace(re_utob, cb_utob); -// -const _encode = _hasBuffer - ? (s) => Buffer.from(s, 'utf8').toString('base64') - : _TE - ? (s) => _fromUint8Array(_TE.encode(s)) - : (s) => _btoa(utob(s)); -/** - * converts a UTF-8-encoded string to a Base64 string. - * @param {boolean} [urlsafe] if `true` make the result URL-safe - * @returns {string} Base64 string - */ -const encode = (src, urlsafe = false) => urlsafe - ? _mkUriSafe(_encode(src)) - : _encode(src); -/** - * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5. - * @returns {string} Base64 string - */ -const encodeURI = (src) => encode(src, true); -// This trick is found broken https://github.com/dankogai/js-base64/issues/130 -// const btou = (src: string) => decodeURIComponent(escape(src)); -// reverting good old fationed regexp -const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; -const cb_btou = (cccc) => { - switch (cccc.length) { - case 4: - var cp = ((0x07 & cccc.charCodeAt(0)) << 18) - | ((0x3f & cccc.charCodeAt(1)) << 12) - | ((0x3f & cccc.charCodeAt(2)) << 6) - | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000; - return (_fromCC((offset >>> 10) + 0xD800) - + _fromCC((offset & 0x3FF) + 0xDC00)); - case 3: - return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12) - | ((0x3f & cccc.charCodeAt(1)) << 6) - | (0x3f & cccc.charCodeAt(2))); - default: - return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6) - | (0x3f & cccc.charCodeAt(1))); - } -}; -/** - * @deprecated should have been internal use only. - * @param {string} src UTF-16 string - * @returns {string} UTF-8 string - */ -const btou = (b) => b.replace(re_btou, cb_btou); -/** - * polyfill version of `atob` - */ -const atobPolyfill = (asc) => { - // console.log('polyfilled'); - asc = asc.replace(/\s+/g, ''); - if (!b64re.test(asc)) - throw new TypeError('malformed base64.'); - asc += '=='.slice(2 - (asc.length & 3)); - let u24, bin = '', r1, r2; - for (let i = 0; i < asc.length;) { - u24 = b64tab[asc.charAt(i++)] << 18 - | b64tab[asc.charAt(i++)] << 12 - | (r1 = b64tab[asc.charAt(i++)]) << 6 - | (r2 = b64tab[asc.charAt(i++)]); - bin += r1 === 64 ? _fromCC(u24 >> 16 & 255) - : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255) - : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255); - } - return bin; -}; -/** - * does what `window.atob` of web browsers do. - * @param {String} asc Base64-encoded string - * @returns {string} binary string - */ -const _atob = typeof atob === 'function' ? (asc) => atob(_tidyB64(asc)) - : _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary') - : atobPolyfill; -// -const _toUint8Array = _hasBuffer - ? (a) => _U8Afrom(Buffer.from(a, 'base64')) - : (a) => _U8Afrom(_atob(a).split('').map(c => c.charCodeAt(0))); -/** - * converts a Base64 string to a Uint8Array. - */ -const toUint8Array = (a) => _toUint8Array(_unURI(a)); -// -const _decode = _hasBuffer - ? (a) => Buffer.from(a, 'base64').toString('utf8') - : _TD - ? (a) => _TD.decode(_toUint8Array(a)) - : (a) => btou(_atob(a)); -const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/')); -/** - * converts a Base64 string to a UTF-8 string. - * @param {String} src Base64 string. Both normal and URL-safe are supported - * @returns {string} UTF-8 string - */ -const decode = (src) => _decode(_unURI(src)); -/** - * check if a value is a valid Base64 string - * @param {String} src a value to check - */ -const isValid = (src) => { - if (typeof src !== 'string') - return false; - const s = src.replace(/\s+/g, '').replace(/={0,2}$/, ''); - return !/[^\s0-9a-zA-Z\+/]/.test(s) || !/[^\s0-9a-zA-Z\-_]/.test(s); -}; -// -const _noEnum = (v) => { - return { - value: v, enumerable: false, writable: true, configurable: true - }; -}; -/** - * extend String.prototype with relevant methods - */ -const extendString = function () { - const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body)); - _add('fromBase64', function () { return decode(this); }); - _add('toBase64', function (urlsafe) { return encode(this, urlsafe); }); - _add('toBase64URI', function () { return encode(this, true); }); - _add('toBase64URL', function () { return encode(this, true); }); - _add('toUint8Array', function () { return toUint8Array(this); }); -}; -/** - * extend Uint8Array.prototype with relevant methods - */ -const extendUint8Array = function () { - const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body)); - _add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); }); - _add('toBase64URI', function () { return fromUint8Array(this, true); }); - _add('toBase64URL', function () { return fromUint8Array(this, true); }); -}; -/** - * extend Builtin prototypes with relevant methods - */ -const extendBuiltins = () => { - extendString(); - extendUint8Array(); -}; -const gBase64 = { - version: version, - VERSION: VERSION, - atob: _atob, - atobPolyfill: atobPolyfill, - btoa: _btoa, - btoaPolyfill: btoaPolyfill, - fromBase64: decode, - toBase64: encode, - encode: encode, - encodeURI: encodeURI, - encodeURL: encodeURI, - utob: utob, - btou: btou, - decode: decode, - isValid: isValid, - fromUint8Array: fromUint8Array, - toUint8Array: toUint8Array, - extendString: extendString, - extendUint8Array: extendUint8Array, - extendBuiltins: extendBuiltins -}; -// makecjs:CUT // -export { version }; -export { VERSION }; -export { _atob as atob }; -export { atobPolyfill }; -export { _btoa as btoa }; -export { btoaPolyfill }; -export { decode as fromBase64 }; -export { encode as toBase64 }; -export { utob }; -export { encode }; -export { encodeURI }; -export { encodeURI as encodeURL }; -export { btou }; -export { decode }; -export { isValid }; -export { fromUint8Array }; -export { toUint8Array }; -export { extendString }; -export { extendUint8Array }; -export { extendBuiltins }; -// and finally, -export { gBase64 as Base64 }; diff --git a/plugin/js-base64/package.json b/plugin/js-base64/package.json deleted file mode 100644 index 477bbc5..0000000 --- a/plugin/js-base64/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "js-base64", - "version": "3.7.7", - "description": "Yet another Base64 transcoder in pure-JS", - "main": "base64.js", - "module": "base64.mjs", - "types": "base64.d.ts", - "sideEffects": false, - "files": [ - "base64.js", - "base64.mjs", - "base64.d.ts", - "base64.d.mts" - ], - "exports": { - ".": { - "import": { - "types": "./base64.d.mts", - "default": "./base64.mjs" - }, - "require": { - "types": "./base64.d.ts", - "default": "./base64.js" - } - }, - "./package.json": "./package.json" - }, - "scripts": { - "test": "make clean && make test" - }, - "devDependencies": { - "@types/node": "^20.11.5", - "mocha": "^10.2.0", - "typescript": "^5.3.3" - }, - "repository": "git+https://github.com/dankogai/js-base64.git", - "keywords": [ - "base64", - "binary" - ], - "author": "Dan Kogai", - "license": "BSD-3-Clause" -} diff --git a/plugin/manifest.json b/plugin/manifest.json deleted file mode 100644 index c549681..0000000 --- a/plugin/manifest.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "manifest_version": 3, - "name": "Send to Harmony", - "version": "1.0", - "description": "Send selected text to Harmony with a right-click. For PDFs, use the popup to paste your selected text.", - "permissions": ["contextMenus", "storage", "scripting", "activeTab", "tabs"], - "icons": { - "16": "icons/16.png", - "48": "icons/48.png", - "128": "icons/128.png" - }, - "background": { - "service_worker": "background.js" - }, - "action": { - "default_popup": "popup.html", - "default_icon": { - "16": "icons/16.png", - "48": "icons/48.png", - "128": "icons/128.png" - }, - "context_menus": [ - { - "id": "sendToHarmony", - "title": "Send to Harmony", - "contexts": ["selection"] - } - ] - }, - "host_permissions": [] -} diff --git a/plugin/popup.html b/plugin/popup.html deleted file mode 100644 index ac4e106..0000000 --- a/plugin/popup.html +++ /dev/null @@ -1,109 +0,0 @@ - - - - Send to Harmony - - - -
- -

Send to Harmony

-

- Select text you would like to harmonise, right-click, and choose "Send - to Harmony". -

-

- Harmony will open in a new tab with your items ready to harmonise, vist - other websites to add further items to your harmonisation. -

- - - -
-

Recent Imports

-
-
No imports yet
-
-
-
- - - diff --git a/plugin/popup.js b/plugin/popup.js deleted file mode 100644 index 1ef2f02..0000000 --- a/plugin/popup.js +++ /dev/null @@ -1,89 +0,0 @@ -// Check if we're dealing with a PDF tab -chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { - const currentTab = tabs[0]; - if (currentTab?.id === -1 || currentTab?.url?.toLowerCase().includes("pdf")) { - document.getElementById("pdfInput").style.display = "block"; - } -}); - -// Handle PDF text submission -document.getElementById("submitPdf").addEventListener("click", function () { - const text = document.getElementById("pdfText").value; - if (text) { - chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { - const currentTab = tabs[0]; - chrome.runtime.sendMessage({ - action: "processPdfText", - text: text, - tab: currentTab, - }); - window.close(); - }); - } -}); - -// Function to format relative time -function getRelativeTime(timestamp) { - const now = new Date(); - const past = new Date(timestamp); - const diffInSeconds = Math.floor((now - past) / 1000); - - if (diffInSeconds < 60) { - return "just now"; - } else if (diffInSeconds < 3600) { - const minutes = Math.floor(diffInSeconds / 60); - return `${minutes} minute${minutes > 1 ? "s" : ""} ago`; - } else if (diffInSeconds < 86400) { - const hours = Math.floor(diffInSeconds / 3600); - return `${hours} hour${hours > 1 ? "s" : ""} ago`; - } else { - const days = Math.floor(diffInSeconds / 86400); - return `${days} day${days > 1 ? "s" : ""} ago`; - } -} - -// Update history list -function updateHistory() { - chrome.storage.local.get(["history"], function (result) { - const historyList = document.getElementById("historyList"); - const history = result.history || []; - - if (history.length === 0) { - historyList.innerHTML = '
No imports yet
'; - return; - } - - historyList.innerHTML = history - .map( - (item) => ` -
-
${item.text}
-
From: ${item.url}
-
${getRelativeTime(item.timestamp)}
-
- ` - ) - .join(""); - - // Make history items clickable to reopen in Harmony - const historyItems = historyList.getElementsByClassName("history-item"); - Array.from(historyItems).forEach((item, index) => { - item.style.cursor = "pointer"; - item.addEventListener("click", () => { - // Send message to background script to open URL - chrome.runtime.sendMessage({ - action: "openHarmonyUrl", - url: history[index].harmonyUrl, - }); - // Close the popup - window.close(); - }); - }); - }); -} - -// Update history when popup opens -document.addEventListener("DOMContentLoaded", updateHistory); - -// Update history every minute to refresh relative times -setInterval(updateHistory, 60000); diff --git a/src/components/App.js b/src/components/App.js index 2afe226..dd3561d 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -118,11 +118,14 @@ function App() { } exampleInstruments() .then((data) => { - setExistingInstruments(data); - console.log(data); + if (Array.isArray(data)) { + setExistingInstruments(data); + } else { + console.error("Error fetching example instruments", data); + } }) .catch((e) => { - console.log(e); + console.error("Error fetching example instruments", e); }); }, [exampleInstruments]); @@ -151,10 +154,24 @@ function App() { if (fileInfos) return match(fileInfos, forceModel).then((data) => { let simpleApi = simplifyApi(data, fileInfos); + + // Filter existing computedMatches to remove any references to removed instruments + setComputedMatches(prev => { + if (!prev) return prev; + const validQuestionIndices = new Set( + fileInfos.flatMap((f, i) => + f.questions.map((_, qIdx) => qIdx) + ) + ); + return prev.filter(match => + validQuestionIndices.has(match.qi) && validQuestionIndices.has(match.mqi) + ); + }); + setApiData(simpleApi); }); }, - [history, fileInfos] + [match, fileInfos] ); useEffect(() => { diff --git a/src/contexts/DataContext.js b/src/contexts/DataContext.js index dd1714a..cd114e6 100644 --- a/src/contexts/DataContext.js +++ b/src/contexts/DataContext.js @@ -30,7 +30,7 @@ export function DataProvider({ children }) { return new Promise(async (resolve, reject) => { var retries = 3; var response; - while (retries > 0 && !(response && response.ok)) { + while (retries > 0) { try { const controller = new AbortController(); const id = setTimeout(() => controller.abort(), timeout); @@ -48,20 +48,39 @@ export function DataProvider({ children }) { signal: controller.signal, }); clearTimeout(id); + + // Handle 404 immediately + if (response.status === 404) { + reject(new Error("Resource not found")); + return; + } + + // Handle other non-200 responses + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + // Success case + resolve(response.json()); + return; } catch (e) { - console.log(e); - reject(e); + console.log("Post error:", e); + retries--; + if (retries === 0) { + reject(e); + } else { + await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second before retry + } } - retries--; } - resolve(response.json()); }); }; + const retryableGetData = async ({ url = "", timeout = 5000 }) => { return new Promise(async (resolve, reject) => { var retries = 3; var response; - while (retries > 0 && !(response && response.ok)) { + while (retries > 0) { try { const controller = new AbortController(); const id = setTimeout(() => controller.abort(), timeout); @@ -78,26 +97,30 @@ export function DataProvider({ children }) { signal: controller.signal, }); clearTimeout(id); - // If successful, resolve immediately - if (response.ok) { - resolve(response.json()); - return; // Exit the loop and promise + + // Handle 404 immediately + if (response.status === 404) { + reject(new Error("Resource not found")); + return; + } + + // Handle other non-200 responses + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); } + + // Success case + resolve(response.json()); + return; } catch (e) { - console.log("Get rejection", e); - // Only reject if there are no more retries + console.log("Get error:", e); + retries--; if (retries === 0) { reject(e); + } else { + await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second before retry } } - retries--; - if (retries > 0) { - await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second - } - } - // If the loop completes without a successful response, reject - if (!(response && response.ok)) { - reject(new Error("Failed to fetch data after multiple retries")); } }); };