From 7c4f41f54d9dbef46e04450e2735b4c55c2fa7ff Mon Sep 17 00:00:00 2001
From: alonemazin <10653747+alonemazin@users.noreply.github.com>
Date: Sun, 1 May 2022 20:08:22 +0300
Subject: [PATCH 1/2] Add new features "Customize UI" and "Sidebar View"
---
src/public/interface/nattybox.html | 46 ++
src/public/styles/deck.css | 20 +-
src/public/styles/options.css | 25 +-
src/src/Deck.js | 179 +++---
src/src/Prompt.js | 419 +++++++-------
src/src/UIElement.js | 77 +--
src/src/nattynote.js | 557 +++++++++---------
src/src/player.js | 175 +++---
src/src/scripts/nattybox.js | 890 ++++++++++++++++-------------
src/src/settings.js | 21 +-
src/src/utils.js | 123 ++--
11 files changed, 1381 insertions(+), 1151 deletions(-)
diff --git a/src/public/interface/nattybox.html b/src/public/interface/nattybox.html
index 47d319f..da048cd 100644
--- a/src/public/interface/nattybox.html
+++ b/src/public/interface/nattybox.html
@@ -73,6 +73,52 @@
. */
-import userSettings from "./settings";
-import { UIElement } from "./UIElement";
-import player from "./player";
-import { matchKey, goToEOL } from "./utils";
-
-export class Deck extends UIElement {
- constructor() {
- const input = document.createElement(`div`);
- input.id = `input`;
- input.setAttribute(`contenteditable`, ``);
- const style = [`styles/deck.css`];
- super(input, style);
- this.addEventListeners();
- this.show();
- this._timeoutID = 0;
- this.metadata = undefined;
- }
-
- addEventListeners() {
- const observer = new MutationObserver(
- function () {
- if (this._timeoutID) {
- clearTimeout(this._timeoutID);
- }
-
- this._timeoutID = setTimeout(this.sync.bind(this), 2000);
- }.bind(this)
- );
- observer.observe(this.current, {
- attributes: false,
- childList: true,
- subtree: true,
- characterData: true,
- });
-
- this.current.addEventListener(
- `keydown`,
- function (e) {
- e.stopPropagation();
- if (e.code === `Escape` || matchKey(e, userSettings.kybndg.deckBlur)) {
- this.current.blur();
- player.video.focus();
- player.video.scrollIntoView({ block: `end`, behavior: `smooth` });
- }
- }.bind(this)
- );
- }
-
- clear() {
- this.current.innerHTML = ``;
- }
-
- appendChild(child) {
- if (child instanceof HTMLElement) {
- this.current.append(child);
- } else if (child instanceof HTMLCollection) {
- this.current.append(...child);
- } else {
- const p = document.createElement(`p`);
- p.innerHTML = child;
- this.current.appendChild(p);
- }
-
- this._scrollTillEnd();
- }
- _goToEOL() {
- goToEOL(this.current);
- }
- _scrollTillEnd() {
- this.current.scrollTop = this.current.scrollHeight;
- }
-
- sync(metadata) {
- this.metadata = metadata ? metadata : this.metadata;
- if (
- this.current?.innerHTML &&
- this.current?.isConnected &&
- this.current?.classList.contains(`block`)
- ) {
- chrome.storage.local.set({
- [this.metadata.vidId]: {
- content: this.current.innerHTML,
- timestamp: Date.now(),
- ...this.metadata,
- },
- });
- }
- }
-}
+ import userSettings from "./settings";
+ import { UIElement } from "./UIElement";
+ import player from "./player";
+ import { matchKey, goToEOL } from "./utils";
+
+ export class Deck extends UIElement {
+ constructor() {
+ const input = document.createElement(`div`);
+ input.id = `input`;
+ input.setAttribute(`contenteditable`, ``);
+ const style = [`styles/deck.css`];
+ super(input, style);
+ this.addEventListeners();
+ this.show();
+ this._timeoutID = 0;
+ this.metadata = undefined;
+ }
+
+ addEventListeners() {
+ const observer = new MutationObserver(
+ function () {
+ if (this._timeoutID) {
+ clearTimeout(this._timeoutID);
+ }
+
+ this._timeoutID = setTimeout(this.sync.bind(this), 2000);
+ }.bind(this)
+ );
+ observer.observe(this.current, {
+ attributes: false,
+ childList: true,
+ subtree: true,
+ characterData: true,
+ });
+
+ this.current.addEventListener(
+ `keydown`,
+ function (e) {
+ e.stopPropagation();
+ if (e.code === `Escape` || matchKey(e, userSettings.kybndg.deckBlur)) {
+ this.current.blur();
+ player.video.focus();
+ player.video.scrollIntoView({ block: `end`, behavior: `smooth` });
+ }
+ }.bind(this)
+ );
+ }
+
+ clear() {
+ this.current.innerHTML = ``;
+ }
+
+ appendChild(child) {
+ if (child instanceof HTMLElement) {
+ this.current.append(child);
+ } else if (child instanceof HTMLCollection) {
+ this.current.append(...child);
+ } else {
+ const p = document.createElement(`p`);
+ p.innerHTML = child;
+ this.current.appendChild(p);
+ }
+
+ this._scrollTillEnd();
+ }
+ _goToEOL() {
+ goToEOL(this.current);
+ }
+ _scrollTillEnd() {
+ this.current.scrollTop = this.current.scrollHeight;
+ }
+
+ sync(metadata) {
+ this.metadata = metadata ? metadata : this.metadata;
+ if (
+ this.current?.innerHTML &&
+ this.current?.isConnected &&
+ this.current?.classList.contains(`block`)
+ ) {
+ chrome.storage.local.set({
+ [this.metadata.vidId]: {
+ content: this.current.innerHTML,
+ timestamp: Date.now(),
+ ...this.metadata,
+ },
+ });
+ }
+ }
+ }
+
\ No newline at end of file
diff --git a/src/src/Prompt.js b/src/src/Prompt.js
index 3e5b4f9..f274166 100644
--- a/src/src/Prompt.js
+++ b/src/src/Prompt.js
@@ -12,212 +12,213 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see
. */
-import {UIElement} from "./UIElement";
-import userSettings from "./settings";
-import {goToEOL, matchKey} from "./utils";
-import close from "./icons/close.svg";
-
-export default class Prompt extends UIElement {
- constructor() {
- const container = document.createElement(`div`);
- const input = document.createElement(`div`);
- const toolbar = document.createElement(`div`);
- const wrapper = document.createElement(`div`);
- const thumbnail = document.createElement(`img`);
- const closeDiv = document.createElement(`div`);
-
- thumbnail.id = `thumbnail`;
- thumbnail.classList.add(`none`);
-
- closeDiv.id = `closeBtn`;
- closeDiv.innerHTML = close;
-
- toolbar.appendChild(closeDiv);
-
- toolbar.id = `toolbar`;
- container.id = `container`;
- input.id = `input`;
- input.setAttribute(`contenteditable`, ``);
- container.appendChild(toolbar);
- container.appendChild(input);
- container.input = input;
-
- wrapper.id = `wrapper`;
- wrapper.appendChild(container);
- wrapper.appendChild(thumbnail);
- wrapper.input = input;
- wrapper.thumbnail = thumbnail;
-
- const style = [`styles/prompt.css`];
- super(wrapper, style);
-
- closeDiv.addEventListener(`click`, this._escape.bind(this));
- closeDiv.title = `Esc`;
-
- console.log(this.current.input);
-
- this.addEventListners();
- this.hide();
- this.hint = ``;
- this.tooltip = toolbar;
- this.makeDrag();
- }
-
- makeDrag() {
- this.tooltip.onmousedown = function (event) {
- // ref: https://javascript.info/mouse-drag-and-drop
- /*
- TODO: improve UX;
- 1. Bound the box to the current page.
- 2. Add option to save the state.
- */
- const {current} = this;
- const {tooltip} = this;
-
- tooltip.style.cursor = `grabbing`;
- const shiftX = event.clientX - current.getBoundingClientRect().left;
- const shiftY = event.clientY - current.getBoundingClientRect().top;
-
- moveAt(event.pageX, event.pageY);
-
- function moveAt(pageX, pageY) {
- current.style.left = `${pageX - shiftX}px`;
- current.style.top = `${pageY - shiftY}px`;
- }
-
- function onMouseMove(event) {
- moveAt(event.pageX, event.pageY);
- }
-
- document.addEventListener(`mousemove`, onMouseMove);
-
- document.addEventListener(`mouseup`, function F() {
- document.removeEventListener(`mousemove`, onMouseMove);
- document.removeEventListener(`mouseup`, F);
-
- tooltip.style.cursor = `grab`;
- });
- }.bind(this);
-
- this.tooltip.ondragstart = function () {
- return false;
- };
- }
-
- showThumbnail(src) {
- this.current.thumbnail.src = src;
- this.current.thumbnail.classList.remove(`none`);
- this.current.thumbnail.classList.add(`block`);
- }
-
- _clearThumbnail() {
- this.current.thumbnail.src = ``;
- this.current.thumbnail.classList.add(`none`);
- this.current.thumbnail.classList.remove(`block`);
- }
-
- show() {
- super.show();
- setTimeout(() => {
- this.current.input.focus({preventScroll: true});
- }, 0);
- }
-
- hide() {
- this.current.input.blur();
- super.hide();
- }
-
- updateHint(hint) {
- if (
- this.hint instanceof HTMLElement &&
- this.current.input.contains(this.hint)
- ) {
- this.current.input.removeChild(this.hint);
- }
-
- this.hint = hint;
- if (!this.hint) {
- return;
- }
- this.hint = document.createElement(`span`);
- this.hint.appendChild(document.createTextNode(hint));
- this.hint.classList.add(`hint`);
- this.hint.setAttribute(`contenteditable`, `false`);
- this._insertHint();
- }
-
- _insertHint() {
- if (
- !this.current.input.innerText &&
- this.hint &&
- !this.current.input.contains(this.hint)
- ) {
- // if prompt is empty, show hint
- this.current.input.appendChild(this.hint);
- this._goToEOL();
- }
- }
-
- _goToEOL() {
- goToEOL(this.current.input);
- }
-
- _escape() {
- this.current.input.blur();
- this.hide();
- this.current.input.innerHTML = ``;
- document.dispatchEvent(new CustomEvent(`nn-prompt-exit`));
- this._clearThumbnail();
- }
-
- addEventListners() {
- this.current.input.addEventListener(`keydown`, (e) => {
- e.stopPropagation();
-
- if (e.code === `Tab`) {
- e.preventDefault();
- }
-
- if (this.hint && this.current.input.contains(this.hint)) {
- if (e.code === `Backspace`) {
- this.current.input.removeChild(this.hint);
- }
-
- if (e.code === `Tab` || e.code === `Enter`) {
- this.current.input.removeChild(this.hint);
- const el = document.createTextNode(this.hint.innerText);
- this.current.input.appendChild(el);
- this._goToEOL();
- }
- }
-
- if (matchKey(e, userSettings.kybndg.commitNote)) {
- const event = new CustomEvent(`nn-add-note`, {
- bubbles: true,
- detail: {note: this.current.input.innerHTML},
- });
- document.dispatchEvent(event);
- this.current.input.innerHTML = ``;
- this.hide();
- this._clearThumbnail();
- } else if (
- e.code === `Escape` ||
- matchKey(e, userSettings.kybndg.exitPrompt)
- ) {
- this._escape();
- }
- });
-
- this.current.input.addEventListener(`input`, () => {
- this._insertHint();
- if (
- this.hint &&
- this.current.input.contains(this.hint) &&
- this.current.input.childNodes.length > 1
- ) {
- this.current.input.removeChild(this.hint);
- }
- });
- }
-}
+ import {UIElement} from "./UIElement";
+ import userSettings from "./settings";
+ import {goToEOL, matchKey} from "./utils";
+ import close from "./icons/close.svg";
+
+ export default class Prompt extends UIElement {
+ constructor() {
+ const container = document.createElement(`div`);
+ const input = document.createElement(`div`);
+ const toolbar = document.createElement(`div`);
+ const wrapper = document.createElement(`div`);
+ const thumbnail = document.createElement(`img`);
+ const closeDiv = document.createElement(`div`);
+
+ thumbnail.id = `thumbnail`;
+ thumbnail.classList.add(`none`);
+
+ closeDiv.id = `closeBtn`;
+ closeDiv.innerHTML = close;
+
+ toolbar.appendChild(closeDiv);
+
+ toolbar.id = `toolbar`;
+ container.id = `container`;
+ input.id = `input`;
+ input.setAttribute(`contenteditable`, ``);
+ container.appendChild(toolbar);
+ container.appendChild(input);
+ container.input = input;
+
+ wrapper.id = `wrapper`;
+ wrapper.appendChild(container);
+ wrapper.appendChild(thumbnail);
+ wrapper.input = input;
+ wrapper.thumbnail = thumbnail;
+
+ const style = [`styles/prompt.css`];
+ super(wrapper, style);
+
+ closeDiv.addEventListener(`click`, this._escape.bind(this));
+ closeDiv.title = `Esc`;
+
+ console.log(this.current.input);
+
+ this.addEventListners();
+ this.hide();
+ this.hint = ``;
+ this.tooltip = toolbar;
+ this.makeDrag();
+ }
+
+ makeDrag() {
+ this.tooltip.onmousedown = function (event) {
+ // ref: https://javascript.info/mouse-drag-and-drop
+ /*
+ TODO: improve UX;
+ 1. Bound the box to the current page.
+ 2. Add option to save the state.
+ */
+ const {current} = this;
+ const {tooltip} = this;
+
+ tooltip.style.cursor = `grabbing`;
+ const shiftX = event.clientX - current.getBoundingClientRect().left;
+ const shiftY = event.clientY - current.getBoundingClientRect().top;
+
+ moveAt(event.pageX, event.pageY);
+
+ function moveAt(pageX, pageY) {
+ current.style.left = `${pageX - shiftX}px`;
+ current.style.top = `${pageY - shiftY}px`;
+ }
+
+ function onMouseMove(event) {
+ moveAt(event.pageX, event.pageY);
+ }
+
+ document.addEventListener(`mousemove`, onMouseMove);
+
+ document.addEventListener(`mouseup`, function F() {
+ document.removeEventListener(`mousemove`, onMouseMove);
+ document.removeEventListener(`mouseup`, F);
+
+ tooltip.style.cursor = `grab`;
+ });
+ }.bind(this);
+
+ this.tooltip.ondragstart = function () {
+ return false;
+ };
+ }
+
+ showThumbnail(src) {
+ this.current.thumbnail.src = src;
+ this.current.thumbnail.classList.remove(`none`);
+ this.current.thumbnail.classList.add(`block`);
+ }
+
+ _clearThumbnail() {
+ this.current.thumbnail.src = ``;
+ this.current.thumbnail.classList.add(`none`);
+ this.current.thumbnail.classList.remove(`block`);
+ }
+
+ show() {
+ super.show();
+ setTimeout(() => {
+ this.current.input.focus({preventScroll: true});
+ }, 0);
+ }
+
+ hide() {
+ this.current.input.blur();
+ super.hide();
+ }
+
+ updateHint(hint) {
+ if (
+ this.hint instanceof HTMLElement &&
+ this.current.input.contains(this.hint)
+ ) {
+ this.current.input.removeChild(this.hint);
+ }
+
+ this.hint = hint;
+ if (!this.hint) {
+ return;
+ }
+ this.hint = document.createElement(`span`);
+ this.hint.appendChild(document.createTextNode(hint));
+ this.hint.classList.add(`hint`);
+ this.hint.setAttribute(`contenteditable`, `false`);
+ this._insertHint();
+ }
+
+ _insertHint() {
+ if (
+ !this.current.input.innerText &&
+ this.hint &&
+ !this.current.input.contains(this.hint)
+ ) {
+ // if prompt is empty, show hint
+ this.current.input.appendChild(this.hint);
+ this._goToEOL();
+ }
+ }
+
+ _goToEOL() {
+ goToEOL(this.current.input);
+ }
+
+ _escape() {
+ this.current.input.blur();
+ this.hide();
+ this.current.input.innerHTML = ``;
+ document.dispatchEvent(new CustomEvent(`nn-prompt-exit`));
+ this._clearThumbnail();
+ }
+
+ addEventListners() {
+ this.current.input.addEventListener(`keydown`, (e) => {
+ e.stopPropagation();
+
+ if (e.code === `Tab`) {
+ e.preventDefault();
+ }
+
+ if (this.hint && this.current.input.contains(this.hint)) {
+ if (e.code === `Backspace`) {
+ this.current.input.removeChild(this.hint);
+ }
+
+ if (e.code === `Tab` || e.code === `Enter`) {
+ this.current.input.removeChild(this.hint);
+ const el = document.createTextNode(this.hint.innerText);
+ this.current.input.appendChild(el);
+ this._goToEOL();
+ }
+ }
+
+ if (matchKey(e, userSettings.kybndg.commitNote)) {
+ const event = new CustomEvent(`nn-add-note`, {
+ bubbles: true,
+ detail: {note: this.current.input.innerHTML},
+ });
+ document.dispatchEvent(event);
+ this.current.input.innerHTML = ``;
+ this.hide();
+ this._clearThumbnail();
+ } else if (
+ e.code === `Escape` ||
+ matchKey(e, userSettings.kybndg.exitPrompt)
+ ) {
+ this._escape();
+ }
+ });
+
+ this.current.input.addEventListener(`input`, () => {
+ this._insertHint();
+ if (
+ this.hint &&
+ this.current.input.contains(this.hint) &&
+ this.current.input.childNodes.length > 1
+ ) {
+ this.current.input.removeChild(this.hint);
+ }
+ });
+ }
+ }
+
\ No newline at end of file
diff --git a/src/src/UIElement.js b/src/src/UIElement.js
index ec9a449..2b8212e 100644
--- a/src/src/UIElement.js
+++ b/src/src/UIElement.js
@@ -12,38 +12,47 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see
. */
-export class UIElement {
- constructor(DOMElement, styles = []) {
- this.current = DOMElement;
- this.root = document.createElement(`div`);
- this.shadow = this.root.attachShadow({mode: `open`});
- this.shadow.appendChild(this.current);
- styles.unshift(`styles/common.css`);
- styles.map((style) => this.addStyle(style));
- }
+ import { refreshUI } from "./utils";
- addStyle(relPath) {
- if (!relPath) return;
- const href = chrome.runtime.getURL(relPath);
- const linkEl = document.createElement(`link`);
- linkEl.rel = `stylesheet`;
- linkEl.type = `text/css`;
- linkEl.href = href;
- this.shadow.appendChild(linkEl);
- }
-
- show() {
- this.current.classList.remove(`none`);
- this.current.classList.add(`block`);
- }
-
- hide() {
- this.current.blur();
- this.current.classList.remove(`block`);
- this.current.classList.add(`none`);
- }
-
- render(parent = document.body) {
- parent.appendChild(this.root);
- }
-}
+ export class UIElement {
+ constructor(DOMElement, styles = []) {
+ this.current = DOMElement;
+ this.root = document.createElement(`div`);
+ // this.root.style.setProperty('--background', userSettings?.cu?.backgroundColor);
+ this.shadow = this.root.attachShadow({mode: `open`});
+ this.shadow.appendChild(this.current);
+ styles.unshift(`styles/common.css`);
+ styles.map((style) => this.addStyle(style));
+ }
+
+ addStyle(relPath) {
+ if (!relPath) return;
+ const href = chrome.runtime.getURL(relPath);
+ const linkEl = document.createElement(`link`);
+ linkEl.rel = `stylesheet`;
+ linkEl.type = `text/css`;
+ linkEl.href = href;
+ this.shadow.appendChild(linkEl);
+ }
+
+ show() {
+ refreshUI()
+ this.current.classList.remove(`none`);
+ this.current.classList.add(`block`);
+ }
+
+ hide() {
+ this.current.blur();
+ this.current.classList.remove(`block`);
+ this.current.classList.add(`none`);
+ }
+
+ render(parent = document.body, topappend = Boolean) {
+ if (topappend) {
+ parent.prepend(this.root);
+ }else {
+ parent.appendChild(this.root);
+ }
+ }
+ }
+
\ No newline at end of file
diff --git a/src/src/nattynote.js b/src/src/nattynote.js
index d4a988e..742735c 100644
--- a/src/src/nattynote.js
+++ b/src/src/nattynote.js
@@ -12,281 +12,282 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see
. */
-import userSettings from "./settings";
-import { getCurrentURL, goToEOL, matchKey, formatTime } from "./utils";
-import player from "./player";
-import Prompt from "./Prompt";
-import { Deck } from "./Deck";
-
-const state = {
- shouldPlayAfterPrompt: false,
- currentURL: null,
- isMainEvtListenerConsumed: true,
- updateURL() {
- this.currentURL = new URL(getCurrentURL());
- },
-};
-
-// JIT placeholder calculator
-const apropos = {
- get VID_URL() {
- return state.currentURL;
- },
- get VID_ID() {
- return (
- this.VID_URL.searchParams.get(`v`) ||
- [...this.VID_URL.pathname.matchAll(/\/embed\/(.+)\/?/g)]?.[0]?.[1]
- );
- },
- TS_RAW: null,
- NOTE: null,
- SCREENSHOT_SRC: null,
- set note(note) {
- this.NOTE = note;
- },
- get NOW() {
- return new Date().toLocaleString();
- },
- get TS_FORMATTED() {
- return this.TS_RAW ? formatTime(this.TS_RAW) : ``;
- },
- get SCREENSHOT_FORMATTED() {
- return this.SCREENSHOT_SRC ? format(userSettings.tmplts.screenshot) : ``;
- },
- get VID_TITLE() {
- return player.title;
- },
- get CH_NAME() {
- return player.channelName;
- },
-
- takeTimestamp() {
- this.TS_RAW = player.currentTime();
- },
- async takeScreenshot() {
- this.SCREENSHOT_SRC = await player.screenshot();
- },
- clear() {
- this.SCREENSHOT_SRC = null;
- this.NOTE = null;
- this.TS_RAW = null;
- },
-};
-
-const prompt = new Prompt();
-const deck = new Deck();
-
-/* Video changed --> cleanup */
-state.observer = new MutationObserver(() => {
- const currentURL = getCurrentURL();
-
- if (currentURL !== state.currentURL?.toString()) {
- console.log(`Video is changing!`);
- deck.sync();
- state.updateURL();
- prompt._escape();
- deck.hide();
- deck.clear();
- init();
- }
-});
-
-state.observer.observe(document, {
- attributes: false,
- childList: true,
- subtree: true,
-});
-
-function handelUIRender() {
- if (!prompt.root.isConnected) {
- prompt.render(document.body);
- }
-
- if (!deck.root.isConnected) {
- if (apropos.VID_URL.pathname.match(/\/embed\/(.+)\/?/g)) {
- deck.render(document.body);
- document.body.style.overflowY = `auto`;
- } else {
- deck.render(document.querySelector(`#page-manager div#info`));
- }
- }
-
- deck.show();
-}
-
-async function init() {
- //TODO: replace with a promise-based `local.get` as soon as Firefox supports Manifest V3
- console.log(`Init: called!`);
- await new Promise(function (resolve, reject) {
- if (!getVidId()) {
- reject();
- }
-
- const vidId = getVidId();
- chrome.storage.local.get(vidId, function (store) {
- if (store && store[vidId]) {
- resolve(store[vidId]);
- } else {
- reject();
- }
- });
- })
- .then(async (cachedNote) => {
- document.removeEventListener(`keydown`, firstTime);
- state.isMainEvtListenerConsumed = true;
- await player.initialize();
- deck.metadata = { title: apropos.VID_TITLE, vidId: apropos.VID_ID };
- const savedNotes = strNodesToHTMLNodes(cachedNote?.content);
- makeClickableNodes(savedNotes);
-
- deck.appendChild(savedNotes);
- handelUIRender();
- })
- .catch(() => {
- if (state.isMainEvtListenerConsumed) {
- document.addEventListener(`keydown`, firstTime);
- state.isMainEvtListenerConsumed = false;
- }
- });
-}
-
-async function firstTime(e) {
- if (isProvoked(e)) {
- console.log(`First time: I got provoked`);
- await player.initialize();
- deck.metadata = { title: apropos.VID_TITLE, vidId: apropos.VID_ID };
- const intro = format(userSettings.tmplts.deck);
- deck.appendChild(intro);
- handelUIRender();
- this.removeEventListener(`keydown`, firstTime);
- state.isMainEvtListenerConsumed = true;
- }
-}
-
-document.addEventListener(`yt-navigate-start`, async () => {
- deck.sync();
-});
-
-window.addEventListener(`beforeunload`, () => {
- deck.sync();
-});
-
-// TODO : Can be improved!!
-function isProvoked(e) {
- return (
- getVidId() &&
- (matchKey(e, userSettings.kybndg.promptCont) ||
- matchKey(e, userSettings.kybndg.promptToggle) ||
- matchKey(e, userSettings.kybndg.promptScreenSh) ||
- matchKey(e, userSettings.kybndg.promptToggleScreenSh))
- );
-}
-
-// TODO : Can be improved!!
-async function handelKeyPress(e) {
- console.log(`handelKeyPress: `, e.code);
- if (matchKey(e, userSettings.kybndg.deckFocus)) {
- deck.root.scrollIntoView({ block: `center` });
- setTimeout(() => {
- deck.current.focus();
- goToEOL(deck.current);
- deck._scrollTillEnd();
- }, 0);
- }
-
- if (isProvoked(e)) {
- console.log(`time to wake up`);
- apropos.takeTimestamp();
- if (
- matchKey(e, userSettings.kybndg.promptToggle) ||
- matchKey(e, userSettings.kybndg.promptToggleScreenSh)
- ) {
- player.pause();
- state.shouldPlayAfterPrompt = true;
- }
-
- if (
- matchKey(e, userSettings.kybndg.promptScreenSh) ||
- matchKey(e, userSettings.kybndg.promptToggleScreenSh)
- ) {
- await apropos.takeScreenshot();
- prompt.showThumbnail(apropos.SCREENSHOT_SRC);
- }
-
- prompt.updateHint(player.getCurrentCaption());
- prompt.show();
- }
-}
-
-document.addEventListener(`keydown`, (e) => {
- handelKeyPress(e);
-});
-
-function postCleaning() {
- if (state.shouldPlayAfterPrompt) {
- player.play();
- state.shouldPlayAfterPrompt = false;
- }
- apropos.clear();
- if (player.video) player.video.focus();
-}
-
-// TODO: settings - should clear terminal after exit?
-document.addEventListener(`nn-prompt-exit`, () => {
- postCleaning();
-});
-
-function makeClickableTS(node) {
- console.log(`node`, node, typeof node);
- let VID_TS = node?.dataset?.nnSeek;
- if (!VID_TS) {
- VID_TS = apropos.TS_RAW;
- node.setAttribute(`data-nn-seek`, VID_TS);
- }
- node.addEventListener(`click`, (e) => {
- e.preventDefault();
- player.goTo(VID_TS);
- player.video.focus();
- });
- node.contentEditable = false;
-}
-
-function strNodesToHTMLNodes(stringNode) {
- const concreteTemplate = document.createElement(`template`);
- concreteTemplate.innerHTML = stringNode;
- return concreteTemplate.content.children;
-}
-
-function makeClickableNodes(nodeList) {
- Array.from(nodeList).map((el) => {
- const selector = `[data-nn-seek]`;
- if (el.matches(selector)) makeClickableTS(el);
- else [...el.querySelectorAll(selector)].map(makeClickableTS);
- });
-}
-
-document.addEventListener(`nn-add-note`, (e) => {
- const note = e.detail.note;
- apropos.note = note;
- const template = userSettings.tmplts.note;
- const formattedNote = strNodesToHTMLNodes(format(template));
- makeClickableNodes(formattedNote);
- deck.appendChild(formattedNote);
- postCleaning();
-});
-
-function format(template) {
- let formattedString = template;
- [...template.matchAll(/\(%([A-Z|_]+)%\)/g)].map(
- (el) => (formattedString = formattedString.replace(el[0], apropos[el[1]]))
- );
- return formattedString;
-}
-
-function getVidId() {
- const vidID = state.currentURL;
- return (
- vidID.searchParams.get(`v`) ||
- [...vidID.pathname.matchAll(/\/embed\/(.+)\/?/g)]?.[0]?.[1]
- );
-}
+ import userSettings from "./settings";
+ import { getCurrentURL, goToEOL, matchKey, formatTime } from "./utils";
+ import player from "./player";
+ import Prompt from "./Prompt";
+ import { Deck } from "./Deck";
+
+ const state = {
+ shouldPlayAfterPrompt: false,
+ currentURL: null,
+ isMainEvtListenerConsumed: true,
+ updateURL() {
+ this.currentURL = new URL(getCurrentURL());
+ },
+ };
+
+ // JIT placeholder calculator
+ const apropos = {
+ get VID_URL() {
+ return state.currentURL;
+ },
+ get VID_ID() {
+ return (
+ this.VID_URL.searchParams.get(`v`) ||
+ [...this.VID_URL.pathname.matchAll(/\/embed\/(.+)\/?/g)]?.[0]?.[1]
+ );
+ },
+ TS_RAW: null,
+ NOTE: null,
+ SCREENSHOT_SRC: null,
+ set note(note) {
+ this.NOTE = note;
+ },
+ get NOW() {
+ return new Date().toLocaleString();
+ },
+ get TS_FORMATTED() {
+ return this.TS_RAW ? formatTime(this.TS_RAW) : ``;
+ },
+ get SCREENSHOT_FORMATTED() {
+ return this.SCREENSHOT_SRC ? format(userSettings.tmplts.screenshot) : ``;
+ },
+ get VID_TITLE() {
+ return player.title;
+ },
+ get CH_NAME() {
+ return player.channelName;
+ },
+
+ takeTimestamp() {
+ this.TS_RAW = player.currentTime();
+ },
+ async takeScreenshot() {
+ this.SCREENSHOT_SRC = await player.screenshot();
+ },
+ clear() {
+ this.SCREENSHOT_SRC = null;
+ this.NOTE = null;
+ this.TS_RAW = null;
+ },
+ };
+
+ const prompt = new Prompt();
+ const deck = new Deck();
+
+ /* Video changed --> cleanup */
+ state.observer = new MutationObserver(() => {
+ const currentURL = getCurrentURL();
+
+ if (currentURL !== state.currentURL?.toString()) {
+ console.log(`Video is changing!`);
+ deck.sync();
+ state.updateURL();
+ prompt._escape();
+ deck.hide();
+ deck.clear();
+ init();
+ }
+ });
+
+ state.observer.observe(document, {
+ attributes: false,
+ childList: true,
+ subtree: true,
+ });
+
+ function handelUIRender() {
+ if (!prompt.root.isConnected) {
+ prompt.render(document.body);
+ }
+
+ if (!deck.root.isConnected) {
+ if (apropos.VID_URL.pathname.match(/\/embed\/(.+)\/?/g)) {
+ deck.render(document.body);
+ document.body.style.overflowY = `auto`;
+ } else {
+ deck.render(userSettings.cu.sidebarView ? document.getElementById("secondary") : document.querySelector(`#page-manager div#info`), userSettings.cu.sidebarView);
+ }
+ }
+
+ deck.show();
+ }
+
+ async function init() {
+ //TODO: replace with a promise-based `local.get` as soon as Firefox supports Manifest V3
+ console.log(`Init: called!`);
+ await new Promise(function (resolve, reject) {
+ if (!getVidId()) {
+ reject();
+ }
+
+ const vidId = getVidId();
+ chrome.storage.local.get(vidId, function (store) {
+ if (store && store[vidId]) {
+ resolve(store[vidId]);
+ } else {
+ reject();
+ }
+ });
+ })
+ .then(async (cachedNote) => {
+ document.removeEventListener(`keydown`, firstTime);
+ state.isMainEvtListenerConsumed = true;
+ await player.initialize();
+ deck.metadata = { title: apropos.VID_TITLE, vidId: apropos.VID_ID };
+ const savedNotes = strNodesToHTMLNodes(cachedNote?.content);
+ makeClickableNodes(savedNotes);
+
+ deck.appendChild(savedNotes);
+ handelUIRender();
+ })
+ .catch(() => {
+ if (state.isMainEvtListenerConsumed) {
+ document.addEventListener(`keydown`, firstTime);
+ state.isMainEvtListenerConsumed = false;
+ }
+ });
+ }
+
+ async function firstTime(e) {
+ if (isProvoked(e)) {
+ console.log(`First time: I got provoked`);
+ await player.initialize();
+ deck.metadata = { title: apropos.VID_TITLE, vidId: apropos.VID_ID };
+ const intro = format(userSettings.tmplts.deck);
+ deck.appendChild(intro);
+ handelUIRender();
+ this.removeEventListener(`keydown`, firstTime);
+ state.isMainEvtListenerConsumed = true;
+ }
+ }
+
+ document.addEventListener(`yt-navigate-start`, async () => {
+ deck.sync();
+ });
+
+ window.addEventListener(`beforeunload`, () => {
+ deck.sync();
+ });
+
+ // TODO : Can be improved!!
+ function isProvoked(e) {
+ return (
+ getVidId() &&
+ (matchKey(e, userSettings.kybndg.promptCont) ||
+ matchKey(e, userSettings.kybndg.promptToggle) ||
+ matchKey(e, userSettings.kybndg.promptScreenSh) ||
+ matchKey(e, userSettings.kybndg.promptToggleScreenSh))
+ );
+ }
+
+ // TODO : Can be improved!!
+ async function handelKeyPress(e) {
+ console.log(`handelKeyPress: `, e.code);
+ if (matchKey(e, userSettings.kybndg.deckFocus)) {
+ deck.root.scrollIntoView({ block: `center` });
+ setTimeout(() => {
+ deck.current.focus();
+ goToEOL(deck.current);
+ deck._scrollTillEnd();
+ }, 0);
+ }
+
+ if (isProvoked(e)) {
+ console.log(`time to wake up`);
+ apropos.takeTimestamp();
+ if (
+ matchKey(e, userSettings.kybndg.promptToggle) ||
+ matchKey(e, userSettings.kybndg.promptToggleScreenSh)
+ ) {
+ player.pause();
+ state.shouldPlayAfterPrompt = true;
+ }
+
+ if (
+ matchKey(e, userSettings.kybndg.promptScreenSh) ||
+ matchKey(e, userSettings.kybndg.promptToggleScreenSh)
+ ) {
+ await apropos.takeScreenshot();
+ prompt.showThumbnail(apropos.SCREENSHOT_SRC);
+ }
+
+ prompt.updateHint(player.getCurrentCaption());
+ prompt.show();
+ }
+ }
+
+ document.addEventListener(`keydown`, (e) => {
+ handelKeyPress(e);
+ });
+
+ function postCleaning() {
+ if (state.shouldPlayAfterPrompt) {
+ player.play();
+ state.shouldPlayAfterPrompt = false;
+ }
+ apropos.clear();
+ if (player.video) player.video.focus();
+ }
+
+ // TODO: settings - should clear terminal after exit?
+ document.addEventListener(`nn-prompt-exit`, () => {
+ postCleaning();
+ });
+
+ function makeClickableTS(node) {
+ console.log(`node`, node, typeof node);
+ let VID_TS = node?.dataset?.nnSeek;
+ if (!VID_TS) {
+ VID_TS = apropos.TS_RAW;
+ node.setAttribute(`data-nn-seek`, VID_TS);
+ }
+ node.addEventListener(`click`, (e) => {
+ e.preventDefault();
+ player.goTo(VID_TS);
+ player.video.focus();
+ });
+ node.contentEditable = false;
+ }
+
+ function strNodesToHTMLNodes(stringNode) {
+ const concreteTemplate = document.createElement(`template`);
+ concreteTemplate.innerHTML = stringNode;
+ return concreteTemplate.content.children;
+ }
+
+ function makeClickableNodes(nodeList) {
+ Array.from(nodeList).map((el) => {
+ const selector = `[data-nn-seek]`;
+ if (el.matches(selector)) makeClickableTS(el);
+ else [...el.querySelectorAll(selector)].map(makeClickableTS);
+ });
+ }
+
+ document.addEventListener(`nn-add-note`, (e) => {
+ const note = e.detail.note;
+ apropos.note = note;
+ const template = userSettings.tmplts.note;
+ const formattedNote = strNodesToHTMLNodes(format(template));
+ makeClickableNodes(formattedNote);
+ deck.appendChild(formattedNote);
+ postCleaning();
+ });
+
+ function format(template) {
+ let formattedString = template;
+ [...template.matchAll(/\(%([A-Z|_]+)%\)/g)].map(
+ (el) => (formattedString = formattedString.replace(el[0], apropos[el[1]]))
+ );
+ return formattedString;
+ }
+
+ function getVidId() {
+ const vidID = state.currentURL;
+ return (
+ vidID.searchParams.get(`v`) ||
+ [...vidID.pathname.matchAll(/\/embed\/(.+)\/?/g)]?.[0]?.[1]
+ );
+ }
+
\ No newline at end of file
diff --git a/src/src/player.js b/src/src/player.js
index 8a0a035..7ceed2e 100644
--- a/src/src/player.js
+++ b/src/src/player.js
@@ -12,90 +12,91 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see
. */
-import {asyncLoad} from "./utils";
-import userSettings from "./settings";
-
-class Player {
- constructor() {
- this.video = document.querySelector(`#movie_player video`);
- this.title = document.querySelector(`#container h1`)?.innerText;
- this.channelName = document.querySelector(
- `#upload-info #channel-name`
- )?.innerText;
-
- this.initialize();
- }
-
- async initialize() {
- this.video =
- (await asyncLoad(`#movie_player video`)) || (await asyncLoad(`video`));
-
- let titleEl = await asyncLoad(`#container h1`);
-
- this.title =
- titleEl?.innerText || document.title.replace(` - YouTube`, ``) || ``;
-
- let channelNameEl =
- (await asyncLoad(`#upload-info #channel-name`)) ||
- (await asyncLoad(`.iv-branding-context-name`));
- this.channelName = channelNameEl?.innerText || ``;
- }
- play() {
- this.video.play();
- }
-
- async screenshot() {
- //Ref https://stackoverflow.com/a/13765373
- let canvas = document.createElement(`canvas`);
- let h = userSettings?.ss?.height;
- let w = userSettings?.ss?.width;
- if (userSettings?.ss?.automaticDims) {
- h = this.video.videoHeight || this.video.offsetHeight || 720;
- w = this.video.videoWidth || this.video.offsetWidth || 1280;
- }
- canvas.width = w;
- canvas.height = h;
-
- canvas.getContext(`2d`).drawImage(this.video, 0, 0, w, h);
-
- return canvas.toDataURL(
- `image/${userSettings?.ss?.format || `jpeg`}`,
- parseFloat(userSettings?.ss?.quality) || 0.75
- );
- }
-
- getCurrentCaption() {
- const captionEl =
- document.querySelector(`[id^="caption-window"]`) ||
- document.querySelector(`span.captions-text`) ||
- document.querySelector(`div.caption-window`);
-
- return captionEl?.innerText || ``;
- }
-
- pause() {
- this.video.pause();
- }
-
- duration() {
- //TODO: add option to format
- return this.video.duration;
- }
-
- currentTime() {
- //TODO: options to format
- return this.video.currentTime;
- }
-
- goTo(seconds) {
- if (seconds) this.video.currentTime = seconds
- }
-
- toggle() {
- if (this.video.paused) this.play();
- else this.pause();
- }
-}
-
-const player = new Player();
-export default player;
+ import {asyncLoad} from "./utils";
+ import userSettings from "./settings";
+
+ class Player {
+ constructor() {
+ this.video = document.querySelector(`#movie_player video`);
+ this.title = document.querySelector(`#container h1`)?.innerText;
+ this.channelName = document.querySelector(
+ `#upload-info #channel-name`
+ )?.innerText;
+
+ this.initialize();
+ }
+
+ async initialize() {
+ this.video =
+ (await asyncLoad(`#movie_player video`)) || (await asyncLoad(`video`));
+
+ let titleEl = await asyncLoad(`#container h1`);
+
+ this.title =
+ titleEl?.innerText || document.title.replace(` - YouTube`, ``) || ``;
+
+ let channelNameEl =
+ (await asyncLoad(`#upload-info #channel-name`)) ||
+ (await asyncLoad(`.iv-branding-context-name`));
+ this.channelName = channelNameEl?.innerText || ``;
+ }
+ play() {
+ this.video.play();
+ }
+
+ async screenshot() {
+ //Ref https://stackoverflow.com/a/13765373
+ let canvas = document.createElement(`canvas`);
+ let h = userSettings?.ss?.height;
+ let w = userSettings?.ss?.width;
+ if (userSettings?.ss?.automaticDims) {
+ h = this.video.videoHeight || this.video.offsetHeight || 720;
+ w = this.video.videoWidth || this.video.offsetWidth || 1280;
+ }
+ canvas.width = w;
+ canvas.height = h;
+
+ canvas.getContext(`2d`).drawImage(this.video, 0, 0, w, h);
+
+ return canvas.toDataURL(
+ `image/${userSettings?.ss?.format || `jpeg`}`,
+ parseFloat(userSettings?.ss?.quality) || 0.75
+ );
+ }
+
+ getCurrentCaption() {
+ const captionEl =
+ document.querySelector(`[id^="caption-window"]`) ||
+ document.querySelector(`span.captions-text`) ||
+ document.querySelector(`div.caption-window`);
+
+ return captionEl?.innerText || ``;
+ }
+
+ pause() {
+ this.video.pause();
+ }
+
+ duration() {
+ //TODO: add option to format
+ return this.video.duration;
+ }
+
+ currentTime() {
+ //TODO: options to format
+ return this.video.currentTime;
+ }
+
+ goTo(seconds) {
+ if (seconds) this.video.currentTime = seconds
+ }
+
+ toggle() {
+ if (this.video.paused) this.play();
+ else this.pause();
+ }
+ }
+
+ const player = new Player();
+ export default player;
+
\ No newline at end of file
diff --git a/src/src/scripts/nattybox.js b/src/src/scripts/nattybox.js
index b8936db..6b6111d 100644
--- a/src/src/scripts/nattybox.js
+++ b/src/src/scripts/nattybox.js
@@ -12,406 +12,514 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see
. */
-const shortcutsMetadata = {
- promptCont: {
- label: `Prompt`,
- description: `Shows the note prompt without toggling the player.`,
- mods: [`altKey`],
- key: `KeyU`,
- printableKey: `U`,
- },
- promptToggle: {
- label: `Prompt+toggle`,
- description: `Shows the note prompt and toggles the player; stops it if it is playing and starts it if it is stopped.`,
- mods: [`altKey`],
- key: `KeyP`,
- printableKey: `P`,
- },
- promptScreenSh: {
- label: `Prompt+Screenshot`,
- description: `Same as Prompt but takes a screenshot of the current video frame.`,
- mods: [`altKey`, `shiftKey`],
- key: `KeyU`,
- printableKey: `U`,
- },
- promptToggleScreenSh: {
- label: `Prompt+Toggle+Screenshot`,
- description: `Same as Prompt+Toggle, but takes a screenshot of the current video frame.`,
- mods: [`altKey`, `shiftKey`],
- key: `KeyP`,
- printableKey: `P`,
- },
- exitPrompt: {
- label: `Close prompt`,
- description: `Close the prompt, discarding current note. Optional since it can always be called by \`Escape\`.`,
- mods: [],
- key: ``,
- printableKey: ``,
- optional: true,
- },
- deckFocus: {
- label: `Deck focus`,
- description: `Focus on the notes deck.`,
- mods: [`altKey`],
- key: `KeyK`,
- printableKey: `K`,
- },
- deckBlur: {
- label: `Deck blur`,
- description: `Removes focus from the notes deck and places it at the video player. It's optional since it can always be called by \`Escape\``,
- mods: [],
- key: ``,
- printableKey: ``,
- optional: true,
- },
-};
-console.log(shortcutsMetadata);
-const defaultShortcuts = {
- promptCont: {
- label: `Prompt`,
- description: `Shows the note prompt without toggling the player.`,
- mods: [`altKey`],
- key: `KeyU`,
- printableKey: `U`,
- },
- promptToggle: {
- label: `Prompt+toggle`,
- description: `Shows the note prompt and toggles the player; stops it if it is playing and starts it if it is stopped.`,
- mods: [`altKey`],
- key: `KeyP`,
- printableKey: `P`,
- },
- commitNote: {
- label: `Commit note`,
- description: `Inserts the written note in the prompt into the deck`,
- mods: [`altKey`],
- key: `Enter`,
- printableKey: `Enter`,
- },
- promptScreenSh: {
- label: `Prompt+Screenshot`,
- description: `Same as Prompt but takes a screenshot of the current video frame.`,
- mods: [`altKey`, `shiftKey`],
- key: `KeyU`,
- printableKey: `U`,
- },
- promptToggleScreenSh: {
- label: `Prompt+Toggle+Screenshot`,
- description: `Same as Prompt+Toggle, but takes a screenshot of the current video frame.`,
- mods: [`altKey`, `shiftKey`],
- key: `KeyP`,
- printableKey: `P`,
- },
- exitPrompt: {
- label: `Close prompt`,
- description: `Close the prompt, discarding current note. Optional since it can always be called by \`Escape\`.`,
- mods: [],
- key: ``,
- printableKey: ``,
- optional: true,
- },
- deckFocus: {
- label: `Deck focus`,
- description: `Focus on the notes deck.`,
- mods: [`altKey`],
- key: `KeyK`,
- printableKey: `K`,
- },
- deckBlur: {
- label: `Deck blur`,
- description: `Removes focus from the notes deck and places it at the video player. It's optional since it can always be called by \`Escape\``,
- mods: [],
- key: ``,
- printableKey: ``,
- optional: true,
- },
-};
-
-const templates = {
- note: `
(%TS_FORMATTED%)(%NOTE%)
(%SCREENSHOT_FORMATTED%)`,
- screenshot: `
)
`,
- deck: `(%NOW%)
(%VID_TITLE%) (%CH_NAME%)`,
-};
-
-const screenshotDefaults = {
- automaticDims: true,
- width: 1280,
- height: 720,
- format: `jpeg`,
- quality: 0.75,
-};
-
-const templateDescription = {
- note: {
- label: `Note template`,
- description: `When a note written in the prompt is committed, it will be formatted using this template before being inserted into the deck.`,
- },
- screenshot: {
- label: `Screenshot template`,
- description: `Specifies how a screenshot (if any) should be displayed. Used by SCREENSHOT_FORMATTED`,
- },
- deck: {
- label: `Deck initialization template`,
- description: `This template is inserted upon the first initialization of the deck.`,
- },
-};
-
-let userShortcuts = defaultShortcuts;
-const userTemplates = templates;
-const userScreenshot = screenshotDefaults;
-const templateEls = [];
-const screenShotEls = {
- automaticDims: {id: `screenshotUseDefaults`},
- width: {id: `screenshotWidth`},
- height: {id: `screenshotHeight`},
- format: {id: `screenshotFileType`},
- quality: {id: `screenshotQuality`},
-};
-const modifiedShortcuts = {};
-
-// Temporary function until Firefox support manifest V3.
-const load = async (keys) =>
- new Promise((res) => chrome.storage.sync.get(keys, (vals) => res(vals)));
-
-function blurTextarea() {
- // Overcome issues related to `change` evt listener in chrome.
-
- templateEls.map((el) => el.blur());
-}
-
-window.onunload = blurTextarea;
-window.onblur = blurTextarea;
-window.addEventListener(`pagehide`, blurTextarea);
-
-function initTemplates() {
- const templatesEl = document.getElementById(`templates`);
-
- for (const template in templates) {
- const div = document.createElement(`div`);
- const textarea = document.createElement(`textarea`);
- const label = document.createElement(`label`);
- textarea.innerText = userTemplates[template];
- textarea.id = template;
- textarea.spellcheck = false;
- label.for = template;
- label.classList.add(`help`);
- label.innerText = templateDescription[template].label || ``;
- label.title = templateDescription[template].description || ``;
- textarea.addEventListener(`change`, function () {
- chrome.storage.sync.set({[template]: this.value});
- });
- div.appendChild(label);
- div.appendChild(textarea);
- templateEls.push(textarea);
- templatesEl.appendChild(div);
+ const shortcutsMetadata = {
+ promptCont: {
+ label: `Prompt`,
+ description: `Shows the note prompt without toggling the player.`,
+ mods: [`altKey`],
+ key: `KeyU`,
+ printableKey: `U`,
+ },
+ promptToggle: {
+ label: `Prompt+toggle`,
+ description: `Shows the note prompt and toggles the player; stops it if it is playing and starts it if it is stopped.`,
+ mods: [`altKey`],
+ key: `KeyP`,
+ printableKey: `P`,
+ },
+ promptScreenSh: {
+ label: `Prompt+Screenshot`,
+ description: `Same as Prompt but takes a screenshot of the current video frame.`,
+ mods: [`altKey`, `shiftKey`],
+ key: `KeyU`,
+ printableKey: `U`,
+ },
+ promptToggleScreenSh: {
+ label: `Prompt+Toggle+Screenshot`,
+ description: `Same as Prompt+Toggle, but takes a screenshot of the current video frame.`,
+ mods: [`altKey`, `shiftKey`],
+ key: `KeyP`,
+ printableKey: `P`,
+ },
+ exitPrompt: {
+ label: `Close prompt`,
+ description: `Close the prompt, discarding current note. Optional since it can always be called by \`Escape\`.`,
+ mods: [],
+ key: ``,
+ printableKey: ``,
+ optional: true,
+ },
+ deckFocus: {
+ label: `Deck focus`,
+ description: `Focus on the notes deck.`,
+ mods: [`altKey`],
+ key: `KeyK`,
+ printableKey: `K`,
+ },
+ deckBlur: {
+ label: `Deck blur`,
+ description: `Removes focus from the notes deck and places it at the video player. It's optional since it can always be called by \`Escape\``,
+ mods: [],
+ key: ``,
+ printableKey: ``,
+ optional: true,
+ },
+ };
+ console.log(shortcutsMetadata);
+ const defaultShortcuts = {
+ promptCont: {
+ label: `Prompt`,
+ description: `Shows the note prompt without toggling the player.`,
+ mods: [`altKey`],
+ key: `KeyU`,
+ printableKey: `U`,
+ },
+ promptToggle: {
+ label: `Prompt+toggle`,
+ description: `Shows the note prompt and toggles the player; stops it if it is playing and starts it if it is stopped.`,
+ mods: [`altKey`],
+ key: `KeyP`,
+ printableKey: `P`,
+ },
+ commitNote: {
+ label: `Commit note`,
+ description: `Inserts the written note in the prompt into the deck`,
+ mods: [`altKey`],
+ key: `Enter`,
+ printableKey: `Enter`,
+ },
+ promptScreenSh: {
+ label: `Prompt+Screenshot`,
+ description: `Same as Prompt but takes a screenshot of the current video frame.`,
+ mods: [`altKey`, `shiftKey`],
+ key: `KeyU`,
+ printableKey: `U`,
+ },
+ promptToggleScreenSh: {
+ label: `Prompt+Toggle+Screenshot`,
+ description: `Same as Prompt+Toggle, but takes a screenshot of the current video frame.`,
+ mods: [`altKey`, `shiftKey`],
+ key: `KeyP`,
+ printableKey: `P`,
+ },
+ exitPrompt: {
+ label: `Close prompt`,
+ description: `Close the prompt, discarding current note. Optional since it can always be called by \`Escape\`.`,
+ mods: [],
+ key: ``,
+ printableKey: ``,
+ optional: true,
+ },
+ deckFocus: {
+ label: `Deck focus`,
+ description: `Focus on the notes deck.`,
+ mods: [`altKey`],
+ key: `KeyK`,
+ printableKey: `K`,
+ },
+ deckBlur: {
+ label: `Deck blur`,
+ description: `Removes focus from the notes deck and places it at the video player. It's optional since it can always be called by \`Escape\``,
+ mods: [],
+ key: ``,
+ printableKey: ``,
+ optional: true,
+ },
+ };
+
+ const templates = {
+ note: `
(%TS_FORMATTED%)(%NOTE%)
(%SCREENSHOT_FORMATTED%)`,
+ screenshot: `
)
`,
+ deck: `(%NOW%)
(%VID_TITLE%) (%CH_NAME%)`,
+ };
+
+ const screenshotDefaults = {
+ automaticDims: true,
+ width: 1280,
+ height: 720,
+ format: `jpeg`,
+ quality: 0.75,
+ };
+
+ const templateDescription = {
+ note: {
+ label: `Note template`,
+ description: `When a note written in the prompt is committed, it will be formatted using this template before being inserted into the deck.`,
+ },
+ screenshot: {
+ label: `Screenshot template`,
+ description: `Specifies how a screenshot (if any) should be displayed. Used by SCREENSHOT_FORMATTED`,
+ },
+ deck: {
+ label: `Deck initialization template`,
+ description: `This template is inserted upon the first initialization of the deck.`,
+ },
+ };
+
+ const customizeuiDefaults = {
+ useBorder: false,
+ sidebarView: false,
+ backgroundColor: '#f4ecd8',
+ fontColor: '#5b4636',
+ borderColor: '#000',
+ linkColor: '#000',
+ fontSize: '16',
+ borderSize: '1'
}
-}
-
-function initScreenshotSettings() {
- Object.keys(screenShotEls).map((key) => {
- screenShotEls[key].el = document.getElementById(screenShotEls[key].id);
- });
-
- screenShotEls.automaticDims.el.checked = screenshotDefaults.automaticDims;
- screenShotEls.width.el.disabled = screenshotDefaults.automaticDims;
- screenShotEls.height.el.disabled = screenshotDefaults.automaticDims;
- screenShotEls.quality.el.disabled = screenshotDefaults.format === `png`;
-
- screenShotEls.automaticDims.el.addEventListener(`change`, function () {
- screenShotEls.width.el.disabled = this.checked;
- screenShotEls.height.el.disabled = this.checked;
- });
-
- screenShotEls.format.el.addEventListener(`change`, function () {
- screenShotEls.quality.el.disabled = this.value === `png`;
- });
-
- Object.keys(screenShotEls).map((key) => {
- const {el} = screenShotEls[key];
- if (el.type === `checkbox`) {
- el.checked = screenshotDefaults[key];
- el.addEventListener(`change`, function () {
- chrome.storage.sync.set({[key]: this.checked}, () =>
- console.log(`setting ${key}:${this.checked}`)
- );
- });
- } else {
- el.value = screenshotDefaults[key];
- el.addEventListener(`change`, function () {
- chrome.storage.sync.set({[key]: this.value});
- });
- }
- });
-}
-
-async function loadUserSettings() {
- const allSavedSettings =
- (await load([
- `shortcuts`,
- ...Object.keys(userScreenshot),
- ...Object.keys(userTemplates),
- ])) || {};
-
- console.log(allSavedSettings);
- const updateMyProps = (obj) =>
- Object.keys(obj).map(
- (key) =>
- (obj[key] =
- typeof allSavedSettings[key] === `undefined`
- ? obj[key]
- : allSavedSettings[key])
- );
- updateMyProps(userScreenshot);
- updateMyProps(userTemplates);
-}
-
-window.onload = async () => {
- await loadUserSettings();
- let loadedShortcuts = (await load(`shortcuts`))?.shortcuts || {};
-
- initTemplates();
- initScreenshotSettings();
- userShortcuts = {...userShortcuts, ...loadedShortcuts};
- const shortcutsContainer = document.getElementById(`shortcuts`);
- for (const shortcut in userShortcuts) {
- const div = document.createElement(`div`);
- const label = document.createElement(`label`);
- label.for = shortcut;
- label.title = userShortcuts[shortcut]?.description || ``;
- label.innerText = userShortcuts[shortcut]?.label || ``;
- label.classList.add(`shortcutLabel`);
- div.appendChild(label);
-
- const kbdInput = document.createElement(`input`);
- kbdInput.type = `text`;
- kbdInput.dataset.kbdAction = shortcut;
- kbdInput.required = !userShortcuts[shortcut]?.optional;
- kbdInput.addEventListener(`keydown`, myFunction);
- kbdInput.addEventListener(`blur`, saveShortcut);
- kbdInput.value = renderKBDShortcut(userShortcuts[shortcut]);
- div.appendChild(kbdInput);
-
- shortcutsContainer.appendChild(div);
+ const lightThemeDefualts = {
+ useBorder: true,
+ sidebarView: false,
+ backgroundColor: '#F4ECD8',
+ fontColor: '#5B4636',
+ borderColor: '#5B4636',
+ linkColor: '#0011FF',
+ fontSize: '16',
+ borderSize: '2'
}
-};
-
-function map(event) {
- const mods = [`ctrlKey`, `altKey`, `shiftKey`];
- const exclude = [`Meta`, `Control`, `Shift`, `Alt`];
- const finalKey = exclude.includes(event.key) ? `` : event.key || event.code;
-
- return {
- mods: mods.filter((m) => event[m]),
- key: finalKey ? event.code : ``,
- printableKey: finalKey,
- };
-}
-
-const areKbdEqual = (kbd1, kbd2) =>
- kbd1.key === kbd2.key &&
- kbd1.mods.length === kbd2.mods.length &&
- kbd1.mods.every((el) => kbd2.mods.includes(el));
-
-const isKbdTaken = (kbd) =>
- Object.keys(userShortcuts)
- .map((action) =>
- areKbdEqual(kbd, userShortcuts[action]) ? userShortcuts[action].label : ``
- )
- .filter((e) => e)
- .pop();
-
-function commitShortcut(action, newKbd, target) {
- const newShortcuts = {
- ...userShortcuts,
- [action]: {...userShortcuts[action], ...newKbd},
+ const darkThemeDefualts = {
+ useBorder: true,
+ sidebarView: false,
+ backgroundColor: '#202020',
+ fontColor: '#DEDEDE',
+ borderColor: '#404040',
+ linkColor: '#3EA6FF',
+ fontSize: '16',
+ borderSize: '2'
+ }
+
+ let userShortcuts = defaultShortcuts;
+ const userTemplates = templates;
+ const userScreenshot = screenshotDefaults;
+ const userCustomizeui = customizeuiDefaults;
+ const templateEls = [];
+ const screenShotEls = {
+ automaticDims: {id: `screenshotUseDefaults`},
+ width: {id: `screenshotWidth`},
+ height: {id: `screenshotHeight`},
+ format: {id: `screenshotFileType`},
+ quality: {id: `screenshotQuality`},
};
- userShortcuts = newShortcuts;
- chrome.storage.sync.set({shortcuts: newShortcuts}, () => {
- target.value = renderKBDShortcut(newKbd);
- });
-}
-
-function saveShortcut(e) {
- const {kbdAction} = e.target.dataset;
- const kbd = modifiedShortcuts[kbdAction];
- const oldKbd = userShortcuts[kbdAction];
-
- if (!kbd || (!kbd.key && !userShortcuts[kbdAction].optional)) {
- e.target.value = renderKBDShortcut(oldKbd);
- return;
+ const customizeuiEls = {
+ useBorder: {id: `borderCheckbox`},
+ sidebarView: {id: `sidebarCheckbox`},
+ backgroundColor: {id: `backgroundColor`},
+ fontColor: {id: `fontColor`},
+ borderColor: {id: `border`},
+ linkColor: {id: `linkColor`},
+ fontSize: {id: `fontSize`},
+ borderSize: {id: `borderSize`},
}
-
- if (!areKbdEqual(kbd, oldKbd)) {
- // Difference --> save
-
- const duplicateAction = isKbdTaken(kbd);
-
- if ((oldKbd.optional && !kbd.key) || !duplicateAction) {
- commitShortcut(kbdAction, kbd, e.target);
- e.target.value = renderKBDShortcut(kbd);
- } else {
- const p = document.createElement(`p`);
- p.innerText = `${renderKBDShortcut(
- kbd
- )} is already used by '${duplicateAction}' action.`;
- p.style.display = `inline`;
- e.target.parentElement.append(p);
- e.target.style.borderColor = `red`;
- e.target.timeout = setTimeout(() => {
- e.target.value = renderKBDShortcut(oldKbd);
- e.target.style.borderColor = ``;
- p.remove();
- }, 2000);
+ const modifiedShortcuts = {};
+
+ // Temporary function until Firefox support manifest V3.
+ const load = async (keys) =>
+ new Promise((res) => chrome.storage.sync.get(keys, (vals) => res(vals)));
+
+ function blurTextarea() {
+ // Overcome issues related to `change` evt listener in chrome.
+
+ templateEls.map((el) => el.blur());
+ }
+
+ window.onunload = blurTextarea;
+ window.onblur = blurTextarea;
+ window.addEventListener(`pagehide`, blurTextarea);
+
+ function initTemplates() {
+ const templatesEl = document.getElementById(`templates`);
+
+ for (const template in templates) {
+ const div = document.createElement(`div`);
+ const textarea = document.createElement(`textarea`);
+ const label = document.createElement(`label`);
+ textarea.innerText = userTemplates[template];
+ textarea.id = template;
+ textarea.spellcheck = false;
+ label.for = template;
+ label.classList.add(`help`);
+ label.innerText = templateDescription[template].label || ``;
+ label.title = templateDescription[template].description || ``;
+ textarea.addEventListener(`change`, function () {
+ chrome.storage.sync.set({[template]: this.value});
+ });
+ div.appendChild(label);
+ div.appendChild(textarea);
+ templateEls.push(textarea);
+ templatesEl.appendChild(div);
}
}
-
- e.target.value = renderKBDShortcut(kbd);
- delete modifiedShortcuts[kbdAction];
-}
-
-function renderKBDShortcut(kbd) {
- const to = {ctrlKey: `Ctrl`, altKey: `Alt`, shiftKey: `Shift`};
- const mods = kbd.mods.map((m) => to[m]);
- return `${mods.join(`+`)}${mods.length ? `+` : ``}${
- kbd.printableKey
- }`.toUpperCase();
-}
-
-function myFunction(e) {
- const {kbdAction} = e.target.dataset;
- if (e.target.timeout) {
- window.clearTimeout(e.target.timeout);
- e.target.style.borderColor = ``;
- if (e.target.nextElementSibling) {
- e.target.nextElementSibling.remove();
+
+ function changeTheme(theme){
+ Object.keys(customizeuiEls).map((key) => {
+ customizeuiEls[key].el = document.getElementById(customizeuiEls[key].id);
+ });
+ Object.keys(customizeuiEls).map((key) => {
+ if (customizeuiEls[key].el.type === `checkbox`) {
+ customizeuiEls[key].el.checked = theme[key]
+ chrome.storage.sync.set({[key]: theme[key]}, () =>
+ console.log(`setting ${key}:${theme[key]}`)
+ );
+ }else {
+ customizeuiEls[key].el.value = theme[key]
+ chrome.storage.sync.set({[key]: theme[key]});
+ }
+ });
+ }
+
+
+ function initCutomizeUi() {
+ Object.keys(customizeuiEls).map((key) => {
+ customizeuiEls[key].el = document.getElementById(customizeuiEls[key].id);
+ });
+
+ customizeuiEls.useBorder.el.checked = customizeuiDefaults.useBorder;
+ customizeuiEls.sidebarView.el.checked = customizeuiDefaults.sidebarView;
+ customizeuiEls.backgroundColor.el.value = customizeuiDefaults.backgroundColor;
+ customizeuiEls.fontColor.el.value = customizeuiDefaults.fontColor;
+ customizeuiEls.borderColor.el.value = customizeuiDefaults.borderColor;
+ customizeuiEls.linkColor.el.value = customizeuiDefaults.linkColor;
+ customizeuiEls.fontSize.el.value = customizeuiDefaults.fontSize;
+ customizeuiEls.borderSize.el.value = customizeuiDefaults.borderSize;
+
+ // customizeuiEls.automaticDims.el.addEventListener(`change`, function () {
+ // customizeuiEls.width.el.disabled = this.checked;
+ // customizeuiEls.height.el.disabled = this.checked;
+ // });
+
+ // customizeuiEls.format.el.addEventListener(`change`, function () {
+ // customizeuiEls.quality.el.disabled = this.value === `png`;
+ // });
+
+ Object.keys(customizeuiEls).map((key) => {
+ const {el} = customizeuiEls[key];
+ if (el.type === `checkbox`) {
+ el.checked = customizeuiDefaults[key];
+ el.addEventListener(`change`, function () {
+ chrome.storage.sync.set({[key]: this.checked}, () =>
+ console.log(`setting ${key}:${this.checked}`)
+ );
+ });
+ } else {
+ el.value = customizeuiDefaults[key];
+ el.addEventListener(`change`, function () {
+ chrome.storage.sync.set({[key]: this.value});
+ });
+ }
+ });
+ }
+
+ function initScreenshotSettings() {
+ Object.keys(screenShotEls).map((key) => {
+ screenShotEls[key].el = document.getElementById(screenShotEls[key].id);
+ });
+
+ screenShotEls.automaticDims.el.checked = screenshotDefaults.automaticDims;
+ screenShotEls.width.el.disabled = screenshotDefaults.automaticDims;
+ screenShotEls.height.el.disabled = screenshotDefaults.automaticDims;
+ screenShotEls.quality.el.disabled = screenshotDefaults.format === `png`;
+
+ screenShotEls.automaticDims.el.addEventListener(`change`, function () {
+ screenShotEls.width.el.disabled = this.checked;
+ screenShotEls.height.el.disabled = this.checked;
+ });
+
+ screenShotEls.format.el.addEventListener(`change`, function () {
+ screenShotEls.quality.el.disabled = this.value === `png`;
+ });
+
+ Object.keys(screenShotEls).map((key) => {
+ const {el} = screenShotEls[key];
+ if (el.type === `checkbox`) {
+ el.checked = screenshotDefaults[key];
+ el.addEventListener(`change`, function () {
+ chrome.storage.sync.set({[key]: this.checked}, () =>
+ console.log(`setting ${key}:${this.checked}`)
+ );
+ });
+ } else {
+ el.value = screenshotDefaults[key];
+ el.addEventListener(`change`, function () {
+ chrome.storage.sync.set({[key]: this.value});
+ });
+ }
+ });
+ }
+
+ async function loadUserSettings() {
+ const allSavedSettings =
+ (await load([
+ `shortcuts`,
+ ...Object.keys(userScreenshot),
+ ...Object.keys(userTemplates),
+ ...Object.keys(userCustomizeui),
+ ])) || {};
+
+ console.log(allSavedSettings);
+ const updateMyProps = (obj) =>
+ Object.keys(obj).map(
+ (key) =>
+ (obj[key] =
+ typeof allSavedSettings[key] === `undefined`
+ ? obj[key]
+ : allSavedSettings[key])
+ );
+ updateMyProps(userScreenshot);
+ updateMyProps(userTemplates);
+ updateMyProps(userCustomizeui);
+ }
+
+ window.onload = async () => {
+ await loadUserSettings();
+ let loadedShortcuts = (await load(`shortcuts`))?.shortcuts || {};
+
+ document.getElementById("ligthTheme").addEventListener("click", function() {changeTheme(lightThemeDefualts)});
+ document.getElementById("darkTheme").addEventListener("click", function() {changeTheme(darkThemeDefualts)});
+
+ initTemplates();
+ initScreenshotSettings();
+ initCutomizeUi();
+ userShortcuts = {...userShortcuts, ...loadedShortcuts};
+ const shortcutsContainer = document.getElementById(`shortcuts`);
+ for (const shortcut in userShortcuts) {
+ const div = document.createElement(`div`);
+ const label = document.createElement(`label`);
+ label.for = shortcut;
+ label.title = userShortcuts[shortcut]?.description || ``;
+ label.innerText = userShortcuts[shortcut]?.label || ``;
+ label.classList.add(`shortcutLabel`);
+ div.appendChild(label);
+
+ const kbdInput = document.createElement(`input`);
+ kbdInput.type = `text`;
+ kbdInput.dataset.kbdAction = shortcut;
+ kbdInput.required = !userShortcuts[shortcut]?.optional;
+ kbdInput.addEventListener(`keydown`, myFunction);
+ kbdInput.addEventListener(`blur`, saveShortcut);
+ kbdInput.value = renderKBDShortcut(userShortcuts[shortcut]);
+ div.appendChild(kbdInput);
+
+ shortcutsContainer.appendChild(div);
}
-
- delete e.target.timeout;
+ };
+
+ function map(event) {
+ const mods = [`ctrlKey`, `altKey`, `shiftKey`];
+ const exclude = [`Meta`, `Control`, `Shift`, `Alt`];
+ const finalKey = exclude.includes(event.key) ? `` : event.key || event.code;
+
+ return {
+ mods: mods.filter((m) => event[m]),
+ key: finalKey ? event.code : ``,
+ printableKey: finalKey,
+ };
}
-
- if (e.code === `Tab`) {
- return;
+
+ const areKbdEqual = (kbd1, kbd2) =>
+ kbd1.key === kbd2.key &&
+ kbd1.mods.length === kbd2.mods.length &&
+ kbd1.mods.every((el) => kbd2.mods.includes(el));
+
+ const isKbdTaken = (kbd) =>
+ Object.keys(userShortcuts)
+ .map((action) =>
+ areKbdEqual(kbd, userShortcuts[action]) ? userShortcuts[action].label : ``
+ )
+ .filter((e) => e)
+ .pop();
+
+ function commitShortcut(action, newKbd, target) {
+ const newShortcuts = {
+ ...userShortcuts,
+ [action]: {...userShortcuts[action], ...newKbd},
+ };
+ userShortcuts = newShortcuts;
+ chrome.storage.sync.set({shortcuts: newShortcuts}, () => {
+ target.value = renderKBDShortcut(newKbd);
+ });
}
-
- if (e.code === `Backspace`) {
- if (userShortcuts[kbdAction].optional) {
- modifiedShortcuts[kbdAction] = {
- mods: [],
- key: ``,
- printableKey: ``,
- };
+
+ function saveShortcut(e) {
+ const {kbdAction} = e.target.dataset;
+ const kbd = modifiedShortcuts[kbdAction];
+ const oldKbd = userShortcuts[kbdAction];
+
+ if (!kbd || (!kbd.key && !userShortcuts[kbdAction].optional)) {
+ e.target.value = renderKBDShortcut(oldKbd);
+ return;
}
-
- return (e.target.value = ``);
+
+ if (!areKbdEqual(kbd, oldKbd)) {
+ // Difference --> save
+
+ const duplicateAction = isKbdTaken(kbd);
+
+ if ((oldKbd.optional && !kbd.key) || !duplicateAction) {
+ commitShortcut(kbdAction, kbd, e.target);
+ e.target.value = renderKBDShortcut(kbd);
+ } else {
+ const p = document.createElement(`p`);
+ p.innerText = `${renderKBDShortcut(
+ kbd
+ )} is already used by '${duplicateAction}' action.`;
+ p.style.display = `inline`;
+ e.target.parentElement.append(p);
+ e.target.style.borderColor = `red`;
+ e.target.timeout = setTimeout(() => {
+ e.target.value = renderKBDShortcut(oldKbd);
+ e.target.style.borderColor = ``;
+ p.remove();
+ }, 2000);
+ }
+ }
+
+ e.target.value = renderKBDShortcut(kbd);
+ delete modifiedShortcuts[kbdAction];
}
-
- e.stopPropagation();
- e.preventDefault();
-
- // Keys.push(e.key);
- const kbd = map(e);
- e.target.value = renderKBDShortcut(kbd);
- if (kbd.key) {
- modifiedShortcuts[kbdAction] = kbd;
+
+ function renderKBDShortcut(kbd) {
+ const to = {ctrlKey: `Ctrl`, altKey: `Alt`, shiftKey: `Shift`};
+ const mods = kbd.mods.map((m) => to[m]);
+ return `${mods.join(`+`)}${mods.length ? `+` : ``}${
+ kbd.printableKey
+ }`.toUpperCase();
+ }
+
+ function myFunction(e) {
+ const {kbdAction} = e.target.dataset;
+ if (e.target.timeout) {
+ window.clearTimeout(e.target.timeout);
+ e.target.style.borderColor = ``;
+ if (e.target.nextElementSibling) {
+ e.target.nextElementSibling.remove();
+ }
+
+ delete e.target.timeout;
+ }
+
+ if (e.code === `Tab`) {
+ return;
+ }
+
+ if (e.code === `Backspace`) {
+ if (userShortcuts[kbdAction].optional) {
+ modifiedShortcuts[kbdAction] = {
+ mods: [],
+ key: ``,
+ printableKey: ``,
+ };
+ }
+
+ return (e.target.value = ``);
+ }
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ // Keys.push(e.key);
+ const kbd = map(e);
+ e.target.value = renderKBDShortcut(kbd);
+ if (kbd.key) {
+ modifiedShortcuts[kbdAction] = kbd;
+ }
}
-}
+
\ No newline at end of file
diff --git a/src/src/settings.js b/src/src/settings.js
index 7007d09..921299c 100644
--- a/src/src/settings.js
+++ b/src/src/settings.js
@@ -74,10 +74,22 @@ const ss = {
quality: 0.75,
};
-const userSettings = {};
+/* Default cutomizeui */
+const cu = {
+ useBorder: false,
+ sidebarView: false,
+ backgroundColor: '#f4ecd8',
+ fontColor: '#5b4636',
+ borderColor: '#000',
+ linkColor: '#000',
+ fontSize: '16',
+ borderSize: '1'
+}
+
+const userSettings = [];
(function () {
- const keys = [`shortcuts`, ...Object.keys(ss), ...Object.keys(tmplts)];
+ const keys = [`shortcuts`, ...Object.keys(ss), ...Object.keys(tmplts), ...Object.keys(cu)];
chrome.storage.sync.get(keys, (settings) => {
const getSubset = (obj) =>
@@ -96,6 +108,11 @@ const userSettings = {};
...ss,
...getSubset(ss),
};
+
+ userSettings.cu = {
+ ...cu,
+ ...getSubset(cu),
+ };
});
})();
diff --git a/src/src/utils.js b/src/src/utils.js
index 14649a4..19fca43 100644
--- a/src/src/utils.js
+++ b/src/src/utils.js
@@ -12,59 +12,72 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see
. */
-export async function asyncLoad(element) {
- // dirty way to wait for components to load.
- // TODO: replace with a MutationObserver
+ import userSettings from "./settings";
- let MAX_TRIALS = 10;
- let captured;
- while (!(captured = document.querySelector(element)) && MAX_TRIALS) {
- await new Promise((r) => setTimeout(r, 250));
- MAX_TRIALS--;
- }
-
- return captured;
-}
-
-export function getCurrentURL() {
- return document.URL || document.location.href || window.location.href;
-}
-export function goToEOL(element) {
- const range = document.createRange();
- range.selectNodeContents(element);
- range.collapse(false);
- const selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(range);
-}
-
-// TODO : Can be improved!!
-export function matchKey(e, {mods = [], key}) {
- if (!key) {
- return false;
- }
- const activatedModKeys = [`ctrlKey`, `altKey`, `shiftKey`].filter(
- (key) => e?.[key]
- );
- return (
- activatedModKeys.length === mods.length &&
- activatedModKeys.every((key) => mods.includes(key)) &&
- e.code === key
- );
-}
-
-export function formatTime(seconds) {
- let times = new Array(3);
- let base;
- for (let i = 0; i < times.length; i++) {
- base = 60 ** (2 - i);
- times[i] = Math.floor(seconds / base);
- seconds %= base;
- }
- const hrs = times.shift();
- times = times.map((x) => `00${x}`.slice(-2));
- if (hrs) {
- times.unshift(hrs);
- }
- return times.join(`:`);
-}
+ export async function asyncLoad(element) {
+ // dirty way to wait for components to load.
+ // TODO: replace with a MutationObserver
+
+ let MAX_TRIALS = 10;
+ let captured;
+ while (!(captured = document.querySelector(element)) && MAX_TRIALS) {
+ await new Promise((r) => setTimeout(r, 250));
+ MAX_TRIALS--;
+ }
+
+ return captured;
+ }
+
+ export function getCurrentURL() {
+ return document.URL || document.location.href || window.location.href;
+ }
+ export function goToEOL(element) {
+ const range = document.createRange();
+ range.selectNodeContents(element);
+ range.collapse(false);
+ const selection = window.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+
+ // TODO : Can be improved!!
+ export function matchKey(e, {mods = [], key}) {
+ if (!key) {
+ return false;
+ }
+ const activatedModKeys = [`ctrlKey`, `altKey`, `shiftKey`].filter(
+ (key) => e?.[key]
+ );
+ return (
+ activatedModKeys.length === mods.length &&
+ activatedModKeys.every((key) => mods.includes(key)) &&
+ e.code === key
+ );
+ }
+
+ export function formatTime(seconds) {
+ let times = new Array(3);
+ let base;
+ for (let i = 0; i < times.length; i++) {
+ base = 60 ** (2 - i);
+ times[i] = Math.floor(seconds / base);
+ seconds %= base;
+ }
+ const hrs = times.shift();
+ times = times.map((x) => `00${x}`.slice(-2));
+ if (hrs) {
+ times.unshift(hrs);
+ }
+ return times.join(`:`);
+ }
+
+ export function refreshUI() {
+ if (userSettings?.cu) {
+ Object.keys(userSettings.cu).forEach(key => {
+ if (key != "sidebarView" || key != "borderSize"){
+ console.log(typeof userSettings.cu[key])
+ document.documentElement.style.setProperty(`--${key}`, userSettings.cu[key] == true ? `${userSettings.cu.borderSize}px` : userSettings.cu[key] == false ? 0 : !isNaN(userSettings.cu[key])? `${userSettings.cu[key]}px` : userSettings.cu[key]);
+ }
+ });
+ }
+ }
\ No newline at end of file
From 23feaa4669b24d73dbeb648397729cc5708d5c70 Mon Sep 17 00:00:00 2001
From: alonemazin <10653747+alonemazin@users.noreply.github.com>
Date: Sun, 1 May 2022 20:12:17 +0300
Subject: [PATCH 2/2] Centering text buttons
---
src/public/styles/options.css | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/public/styles/options.css b/src/public/styles/options.css
index dd09fa2..5271770 100644
--- a/src/public/styles/options.css
+++ b/src/public/styles/options.css
@@ -72,6 +72,7 @@ fieldset legend {
fieldset .button {
cursor: pointer;
+ text-align: center;
border-radius: 3px;
border: 1px solid var(--secondary);
padding: 5px;