Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin from release -> master #44

Merged
merged 8 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
Binary file added plugin/.DS_Store
Binary file not shown.
Binary file added plugin/Screenshot 640.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
145 changes: 145 additions & 0 deletions plugin/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
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*<br\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);
}
}
Binary file added plugin/icons/128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugin/icons/16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugin/icons/48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plugin/icons/Thumbs.db
Binary file not shown.
27 changes: 27 additions & 0 deletions plugin/js-base64/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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.
169 changes: 169 additions & 0 deletions plugin/js-base64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
[![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
<script src="base64.js"></script>
```

… or Directly from CDN. In which case you don't even need to install.

```html
<script src="https://cdn.jsdelivr.net/npm/[email protected]/base64.min.js"></script>
```

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
<script type="module">
// note jsdelivr.net does not automatically minify .mjs
import { Base64 } from 'https://cdn.jsdelivr.net/npm/[email protected]/base64.mjs';
</script>
```

```html
<script type="module">
// or if you prefer no Base64 namespace
import { encode, decode } from 'https://cdn.jsdelivr.net/npm/[email protected]/base64.mjs';
</script>
```

### 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)
Loading
Loading