mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-19 11:09:03 +00:00
save options in menu
This commit is contained in:
parent
8d0ce2e777
commit
15b34ef638
@ -6,33 +6,56 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export const ERROR = Symbol();
|
export const ERROR = Symbol(),
|
||||||
|
env = {},
|
||||||
|
storage = {},
|
||||||
|
fs = {},
|
||||||
|
web = {},
|
||||||
|
fmt = {},
|
||||||
|
regexers = {},
|
||||||
|
registry = {};
|
||||||
|
|
||||||
export const env = {};
|
|
||||||
env.name = 'extension';
|
env.name = 'extension';
|
||||||
env.version = chrome.runtime.getManifest().version;
|
env.version = chrome.runtime.getManifest().version;
|
||||||
|
|
||||||
env.openEnhancerMenu = () => chrome.runtime.sendMessage({ action: 'openEnhancerMenu' });
|
env.openEnhancerMenu = () => chrome.runtime.sendMessage({ action: 'openEnhancerMenu' });
|
||||||
env.focusNotion = () => chrome.runtime.sendMessage({ action: 'focusNotion' });
|
env.focusNotion = () => chrome.runtime.sendMessage({ action: 'focusNotion' });
|
||||||
|
|
||||||
/** - */
|
storage.get = (namespace, key = undefined, fallback = undefined) =>
|
||||||
|
|
||||||
export const storage = {};
|
|
||||||
|
|
||||||
storage.set = (id, key, value) =>
|
|
||||||
new Promise((res, rej) => chrome.storage.sync.set({ [`[${id}]${key}`]: value }, res));
|
|
||||||
storage.get = (id, key, fallback = undefined) =>
|
|
||||||
new Promise((res, rej) =>
|
new Promise((res, rej) =>
|
||||||
chrome.storage.sync.get([`[${id}]${key}`], (values) =>
|
chrome.storage.sync.get([namespace], async (values) => {
|
||||||
res(values[`[${id}]${key}`] ?? fallback)
|
values =
|
||||||
)
|
values[namespace] && Object.getOwnPropertyNames(values[namespace]).length
|
||||||
|
? values[namespace]
|
||||||
|
: await registry.defaults(namespace);
|
||||||
|
res((key ? values[key] : values) ?? fallback);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
storage.set = (namespace, key, value) =>
|
||||||
|
new Promise(async (res, rej) => {
|
||||||
|
const values = await storage.get(namespace, undefined, {});
|
||||||
|
chrome.storage.sync.set({ [namespace]: { ...values, [key]: value } }, res);
|
||||||
|
});
|
||||||
|
storage.reset = (namespace) =>
|
||||||
|
new Promise((res, rej) => chrome.storage.sync.set({ [namespace]: undefined }, res));
|
||||||
|
|
||||||
/** - */
|
fs.getJSON = (path) =>
|
||||||
|
fetch(path.startsWith('https://') ? path : chrome.runtime.getURL(path)).then((res) =>
|
||||||
|
res.json()
|
||||||
|
);
|
||||||
|
fs.getText = (path) =>
|
||||||
|
fetch(path.startsWith('https://') ? path : chrome.runtime.getURL(path)).then((res) =>
|
||||||
|
res.text()
|
||||||
|
);
|
||||||
|
fs.isFile = async (path) => {
|
||||||
|
try {
|
||||||
|
await fetch(chrome.runtime.getURL(path));
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const web = {};
|
web.whenReady = (selectors = []) => {
|
||||||
|
|
||||||
web.whenReady = (selectors = [], callback = () => {}) => {
|
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
let isReadyInt;
|
let isReadyInt;
|
||||||
@ -40,7 +63,6 @@ web.whenReady = (selectors = [], callback = () => {}) => {
|
|||||||
function isReadyTest() {
|
function isReadyTest() {
|
||||||
if (selectors.every((selector) => document.querySelector(selector))) {
|
if (selectors.every((selector) => document.querySelector(selector))) {
|
||||||
clearInterval(isReadyInt);
|
clearInterval(isReadyInt);
|
||||||
callback();
|
|
||||||
res(true);
|
res(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,11 +75,12 @@ web.whenReady = (selectors = [], callback = () => {}) => {
|
|||||||
} else onLoad();
|
} else onLoad();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
web.loadStyleset = (path) => {
|
||||||
/**
|
document.head.appendChild(
|
||||||
* @param {string} html
|
web.createElement(`<link rel="stylesheet" href="${chrome.runtime.getURL(path)}">`)
|
||||||
* @returns HTMLElement
|
);
|
||||||
*/
|
return true;
|
||||||
|
};
|
||||||
web.createElement = (html) => {
|
web.createElement = (html) => {
|
||||||
const template = document.createElement('template');
|
const template = document.createElement('template');
|
||||||
template.innerHTML = html.includes('<pre')
|
template.innerHTML = html.includes('<pre')
|
||||||
@ -70,25 +93,14 @@ web.createElement = (html) => {
|
|||||||
};
|
};
|
||||||
web.escapeHtml = (str) =>
|
web.escapeHtml = (str) =>
|
||||||
str
|
str
|
||||||
.replace(/&/g, '&') // (?![^\s]+;)
|
.replace(/&/g, '&')
|
||||||
.replace(/</g, '<')
|
.replace(/</g, '<')
|
||||||
.replace(/>/g, '>')
|
.replace(/>/g, '>')
|
||||||
.replace(/'/g, ''')
|
.replace(/'/g, ''')
|
||||||
.replace(/"/g, '"');
|
.replace(/"/g, '"');
|
||||||
|
|
||||||
// why a tagged template? because it syntax highlights
|
// why a tagged template? because it syntax highlights
|
||||||
// https://marketplace.visualstudio.com/items?itemName=bierner.lit-html
|
// https://marketplace.visualstudio.com/items?itemName=bierner.lit-html
|
||||||
web.html = (html, ...templates) => html.map((str) => str + (templates.shift() || '')).join('');
|
web.html = (html, ...templates) => html.map((str) => str + (templates.shift() ?? '')).join('');
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} sheet
|
|
||||||
*/
|
|
||||||
web.loadStyleset = (sheet) => {
|
|
||||||
document.head.appendChild(
|
|
||||||
web.createElement(`<link rel="stylesheet" href="${chrome.runtime.getURL(sheet)}">`)
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {array} keys
|
* @param {array} keys
|
||||||
@ -119,10 +131,6 @@ web.hotkeyListener = (keys, callback) => {
|
|||||||
web._hotkeys.push({ keys, callback });
|
web._hotkeys.push({ keys, callback });
|
||||||
};
|
};
|
||||||
|
|
||||||
/** - */
|
|
||||||
|
|
||||||
export const fmt = {};
|
|
||||||
|
|
||||||
import './dep/prism.js';
|
import './dep/prism.js';
|
||||||
fmt.Prism = Prism;
|
fmt.Prism = Prism;
|
||||||
fmt.Prism.manual = true;
|
fmt.Prism.manual = true;
|
||||||
@ -188,70 +196,37 @@ fmt.slugger = (heading, slugs = new Set()) => {
|
|||||||
return slug;
|
return slug;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** - */
|
regexers.uuid = (str) => {
|
||||||
|
|
||||||
export const fs = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} path
|
|
||||||
*/
|
|
||||||
fs.getJSON = (path) =>
|
|
||||||
fetch(path.startsWith('https://') ? path : chrome.runtime.getURL(path)).then((res) =>
|
|
||||||
res.json()
|
|
||||||
);
|
|
||||||
fs.getText = (path) =>
|
|
||||||
fetch(path.startsWith('https://') ? path : chrome.runtime.getURL(path)).then((res) =>
|
|
||||||
res.text()
|
|
||||||
);
|
|
||||||
|
|
||||||
fs.isFile = async (path) => {
|
|
||||||
try {
|
|
||||||
await fetch(chrome.runtime.getURL(path));
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** - */
|
|
||||||
|
|
||||||
export const regexers = {
|
|
||||||
uuid(str) {
|
|
||||||
const match = str.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
|
const match = str.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
|
||||||
if (match && match.length) return true;
|
if (match && match.length) return true;
|
||||||
error(`invalid uuid ${str}`);
|
error(`invalid uuid ${str}`);
|
||||||
return false;
|
return false;
|
||||||
},
|
};
|
||||||
semver(str) {
|
regexers.semver = (str) => {
|
||||||
const match = str.match(
|
const match = str.match(
|
||||||
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/i
|
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/i
|
||||||
);
|
);
|
||||||
if (match && match.length) return true;
|
if (match && match.length) return true;
|
||||||
error(`invalid semver ${str}`);
|
error(`invalid semver ${str}`);
|
||||||
return false;
|
return false;
|
||||||
},
|
};
|
||||||
email(str) {
|
regexers.email = (str) => {
|
||||||
const match = str.match(
|
const match = str.match(
|
||||||
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i
|
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/i
|
||||||
);
|
);
|
||||||
if (match && match.length) return true;
|
if (match && match.length) return true;
|
||||||
error(`invalid email ${str}`);
|
error(`invalid email ${str}`);
|
||||||
return false;
|
return false;
|
||||||
},
|
};
|
||||||
url(str) {
|
regexers.url = (str) => {
|
||||||
const match = str.match(
|
const match = str.match(
|
||||||
/^[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/i
|
/^[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/i
|
||||||
);
|
);
|
||||||
if (match && match.length) return true;
|
if (match && match.length) return true;
|
||||||
error(`invalid url ${str}`);
|
error(`invalid url ${str}`);
|
||||||
return false;
|
return false;
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** - */
|
|
||||||
|
|
||||||
export const registry = {};
|
|
||||||
|
|
||||||
registry.validate = async (mod, err, check) => {
|
registry.validate = async (mod, err, check) => {
|
||||||
let conditions = [
|
let conditions = [
|
||||||
check('name', mod.name, typeof mod.name === 'string'),
|
check('name', mod.name, typeof mod.name === 'string'),
|
||||||
@ -444,8 +419,33 @@ registry.validate = async (mod, err, check) => {
|
|||||||
} while (conditions.some((condition) => Array.isArray(condition)));
|
} while (conditions.some((condition) => Array.isArray(condition)));
|
||||||
return conditions;
|
return conditions;
|
||||||
};
|
};
|
||||||
|
registry.defaults = async (id) => {
|
||||||
|
const mod = (await registry.get()).find((mod) => mod.id === id);
|
||||||
|
if (!mod || !mod.options) return {};
|
||||||
|
const defaults = {};
|
||||||
|
for (const opt of mod.options) {
|
||||||
|
switch (opt.type) {
|
||||||
|
case 'toggle':
|
||||||
|
defaults[opt.key] = opt.value;
|
||||||
|
break;
|
||||||
|
case 'select':
|
||||||
|
defaults[opt.key] = opt.values[0];
|
||||||
|
break;
|
||||||
|
case 'text':
|
||||||
|
defaults[opt.key] = opt.value;
|
||||||
|
break;
|
||||||
|
case 'number':
|
||||||
|
defaults[opt.key] = opt.value;
|
||||||
|
break;
|
||||||
|
case 'file':
|
||||||
|
defaults[opt.key] = undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaults;
|
||||||
|
};
|
||||||
|
|
||||||
registry.get = async (callback = () => {}) => {
|
registry.get = async () => {
|
||||||
registry._list = [];
|
registry._list = [];
|
||||||
if (!registry._errors) registry._errors = [];
|
if (!registry._errors) registry._errors = [];
|
||||||
for (const dir of await fs.getJSON('repo/registry.json')) {
|
for (const dir of await fs.getJSON('repo/registry.json')) {
|
||||||
@ -466,12 +466,9 @@ registry.get = async (callback = () => {}) => {
|
|||||||
err('invalid mod.json');
|
err('invalid mod.json');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback(registry._list);
|
|
||||||
return registry._list;
|
return registry._list;
|
||||||
};
|
};
|
||||||
|
registry.errors = async () => {
|
||||||
registry.errors = async (callback = () => {}) => {
|
|
||||||
if (!registry._errors) await registry.get();
|
if (!registry._errors) await registry.get();
|
||||||
callback(registry._errors);
|
|
||||||
return registry._errors;
|
return registry._errors;
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import(chrome.runtime.getURL('helpers.js')).then(({ web, registry }) => {
|
import(chrome.runtime.getURL('helpers.js')).then(({ web, registry }) => {
|
||||||
web.whenReady([], async () => {
|
web.whenReady().then(async () => {
|
||||||
for (let mod of await registry.get()) {
|
for (let mod of await registry.get()) {
|
||||||
for (let sheet of mod.css?.client || []) {
|
for (let sheet of mod.css?.client || []) {
|
||||||
web.loadStyleset(`repo/${mod._dir}/${sheet}`);
|
web.loadStyleset(`repo/${mod._dir}/${sheet}`);
|
||||||
|
@ -51,8 +51,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.enhancer--notifications > div > :last-child > div {
|
.enhancer--notifications > div > :last-child > div {
|
||||||
margin-left: auto;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -11,7 +11,7 @@ import { env, storage, web, fs } from '../../helpers.js';
|
|||||||
|
|
||||||
const sidebarSelector =
|
const sidebarSelector =
|
||||||
'#notion-app > div > div.notion-cursor-listener > div.notion-sidebar-container > div > div > div > div:nth-child(4)';
|
'#notion-app > div > div.notion-cursor-listener > div.notion-sidebar-container > div > div > div > div:nth-child(4)';
|
||||||
web.whenReady([sidebarSelector], async () => {
|
web.whenReady([sidebarSelector]).then(async () => {
|
||||||
const $enhancerSidebarElement = web.createElement(
|
const $enhancerSidebarElement = web.createElement(
|
||||||
web.html`<div class="enhancer--sidebarMenuTrigger" role="button" tabindex="0">
|
web.html`<div class="enhancer--sidebarMenuTrigger" role="button" tabindex="0">
|
||||||
<div>
|
<div>
|
||||||
|
@ -272,7 +272,7 @@ label > span:not([class]) {
|
|||||||
height: 0.8rem;
|
height: 0.8rem;
|
||||||
width: 0.8rem;
|
width: 0.8rem;
|
||||||
left: 0.325rem;
|
left: 0.325rem;
|
||||||
top: 0.225rem;
|
top: 0.18rem;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
background: var(--theme--toggle_dot);
|
background: var(--theme--toggle_dot);
|
||||||
|
@ -87,16 +87,22 @@ components.card = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
components.options = {
|
components.options = {
|
||||||
toggle: (id, { key, label, value }) =>
|
async toggle(id, { key, label }) {
|
||||||
web.createElement(web.html`<label
|
const state = await storage.get(id, key),
|
||||||
|
opt = web.createElement(web.html`<label
|
||||||
for="toggle--${web.escapeHtml(`${id}.${key}`)}"
|
for="toggle--${web.escapeHtml(`${id}.${key}`)}"
|
||||||
class="library--toggle_label"
|
class="library--toggle_label"
|
||||||
>
|
>
|
||||||
<input type="checkbox" id="toggle--${web.escapeHtml(`${id}.${key}`)}" />
|
<input type="checkbox" id="toggle--${web.escapeHtml(`${id}.${key}`)}"
|
||||||
|
${state ? 'checked' : ''}/>
|
||||||
<p><span>${label}</span><span class="library--toggle"></span></p
|
<p><span>${label}</span><span class="library--toggle"></span></p
|
||||||
></label>`),
|
></label>`);
|
||||||
select: async (id, { key, label, values }) =>
|
opt.addEventListener('change', (event) => storage.set(id, key, event.target.checked));
|
||||||
web.createElement(web.html`<label
|
return opt;
|
||||||
|
},
|
||||||
|
async select(id, { key, label, values }) {
|
||||||
|
const state = await storage.get(id, key),
|
||||||
|
opt = web.createElement(web.html`<label
|
||||||
for="select--${web.escapeHtml(`${id}.${key}`)}"
|
for="select--${web.escapeHtml(`${id}.${key}`)}"
|
||||||
class="library--select_label"
|
class="library--select_label"
|
||||||
>
|
>
|
||||||
@ -106,37 +112,47 @@ components.options = {
|
|||||||
<select id="select--${web.escapeHtml(`${id}.${key}`)}">
|
<select id="select--${web.escapeHtml(`${id}.${key}`)}">
|
||||||
${values.map(
|
${values.map(
|
||||||
(value) =>
|
(value) =>
|
||||||
web.html`<option value="${web.escapeHtml(value)}">${web.escapeHtml(
|
web.html`<option value="${web.escapeHtml(value)}"
|
||||||
value
|
${value === state ? 'selected' : ''}>
|
||||||
)}</option>`
|
${web.escapeHtml(value)}</option>`
|
||||||
)}
|
)}
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
</label>`),
|
</label>`);
|
||||||
text(id, { key, label, value }) {
|
opt.addEventListener('change', (event) => storage.set(id, key, event.target.value));
|
||||||
const opt = web.createElement(web.html`<label
|
return opt;
|
||||||
|
},
|
||||||
|
async text(id, { key, label }) {
|
||||||
|
const state = await storage.get(id, key),
|
||||||
|
opt = web.createElement(web.html`<label
|
||||||
for="text--${web.escapeHtml(`${id}.${key}`)}"
|
for="text--${web.escapeHtml(`${id}.${key}`)}"
|
||||||
class="library--text_label"
|
class="library--text_label"
|
||||||
>
|
>
|
||||||
<p>${label}</p>
|
<p>${label}</p>
|
||||||
<textarea id="text--${web.escapeHtml(`${id}.${key}`)}" rows="1"></textarea>
|
<textarea id="text--${web.escapeHtml(`${id}.${key}`)}" rows="1">${state}</textarea>
|
||||||
</label>`);
|
</label>`);
|
||||||
opt.querySelector('textarea').addEventListener('input', (ev) => {
|
opt.querySelector('textarea').addEventListener('input', (event) => {
|
||||||
ev.target.style.removeProperty('--txt--scroll-height');
|
event.target.style.removeProperty('--txt--scroll-height');
|
||||||
ev.target.style.setProperty('--txt--scroll-height', ev.target.scrollHeight + 'px');
|
event.target.style.setProperty('--txt--scroll-height', event.target.scrollHeight + 'px');
|
||||||
});
|
});
|
||||||
|
opt.addEventListener('change', (event) => storage.set(id, key, event.target.value));
|
||||||
return opt;
|
return opt;
|
||||||
},
|
},
|
||||||
number: (id, { key, label, value }) =>
|
async number(id, { key, label }) {
|
||||||
web.createElement(web.html`<label
|
const state = await storage.get(id, key),
|
||||||
|
opt = web.createElement(web.html`<label
|
||||||
for="number--${web.escapeHtml(`${id}.${key}`)}"
|
for="number--${web.escapeHtml(`${id}.${key}`)}"
|
||||||
class="library--number_label"
|
class="library--number_label"
|
||||||
>
|
>
|
||||||
<p>${web.escapeHtml(label)}</p>
|
<p>${web.escapeHtml(label)}</p>
|
||||||
<input id="number--${web.escapeHtml(`${id}.${key}`)}" type="number" />
|
<input id="number--${web.escapeHtml(`${id}.${key}`)}" type="number" value="${state}"/>
|
||||||
</label>`),
|
</label>`);
|
||||||
|
opt.addEventListener('change', (event) => storage.set(id, key, event.target.value));
|
||||||
|
return opt;
|
||||||
|
},
|
||||||
async file(id, { key, label, extensions }) {
|
async file(id, { key, label, extensions }) {
|
||||||
const opt = web.createElement(web.html`<label
|
const state = await storage.get(id, key),
|
||||||
|
opt = web.createElement(web.html`<label
|
||||||
for="file--${web.escapeHtml(`${id}.${key}`)}"
|
for="file--${web.escapeHtml(`${id}.${key}`)}"
|
||||||
class="library--file_label"
|
class="library--file_label"
|
||||||
>
|
>
|
||||||
@ -145,18 +161,33 @@ components.options = {
|
|||||||
id="file--${web.escapeHtml(`${id}.${key}`)}"
|
id="file--${web.escapeHtml(`${id}.${key}`)}"
|
||||||
${web.escapeHtml(
|
${web.escapeHtml(
|
||||||
extensions && extensions.length
|
extensions && extensions.length
|
||||||
? ` accept="${web.escapeHtml(extensions.join(','))}"`
|
? ` accept=${web.escapeHtml(extensions.join(','))}`
|
||||||
: ''
|
: ''
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<p>${web.escapeHtml(label)}</p>
|
<p>${web.escapeHtml(label)}</p>
|
||||||
<p class="library--file">
|
<p class="library--file">
|
||||||
<span><i data-icon="fa/file"></i></span>
|
<span><i data-icon="fa/file"></i></span>
|
||||||
<span class="library--file_path">choose file...</span>
|
<span class="library--file_path">${state || 'choose file...'}</span>
|
||||||
|
</p>
|
||||||
|
<p class="library--warning">
|
||||||
|
warning: browser extensions do not have true filesystem access,
|
||||||
|
so the content of the file is saved on selection. after editing it,
|
||||||
|
the file will need to be re-selected.
|
||||||
</p>
|
</p>
|
||||||
</label>`);
|
</label>`);
|
||||||
opt.querySelector('input').addEventListener('change', (ev) => {
|
opt.addEventListener('change', (event) => {
|
||||||
opt.querySelector('.library--file_path').innerText = ev.target.files[0].name;
|
const file = event.target.files[0],
|
||||||
|
reader = new FileReader();
|
||||||
|
opt.querySelector('.library--file_path').innerText = file.name;
|
||||||
|
storage.set(id, key, file.name);
|
||||||
|
reader.onload = (progress) => {
|
||||||
|
storage.set(id, `_file.${key}`, progress.currentTarget.result);
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
});
|
||||||
|
opt.addEventListener('click', (event) => {
|
||||||
|
document.documentElement.scrollTop = 0;
|
||||||
});
|
});
|
||||||
return opt;
|
return opt;
|
||||||
},
|
},
|
||||||
@ -278,7 +309,7 @@ const views = {
|
|||||||
}, 50);
|
}, 50);
|
||||||
document
|
document
|
||||||
.querySelectorAll('img')
|
.querySelectorAll('img')
|
||||||
.forEach((img) => (img.onerror = (ev) => ev.target.remove()));
|
.forEach((img) => (img.onerror = (event) => event.target.remove()));
|
||||||
document
|
document
|
||||||
.querySelectorAll('a[href^="?"]')
|
.querySelectorAll('a[href^="?"]')
|
||||||
.forEach((a) => a.addEventListener('click', this._router));
|
.forEach((a) => a.addEventListener('click', this._router));
|
||||||
@ -310,12 +341,12 @@ const views = {
|
|||||||
views._router = views._router.bind(views);
|
views._router = views._router.bind(views);
|
||||||
views._navigator = views._navigator.bind(views);
|
views._navigator = views._navigator.bind(views);
|
||||||
views._load();
|
views._load();
|
||||||
window.addEventListener('popstate', (ev) => {
|
window.addEventListener('popstate', (event) => {
|
||||||
if (ev.state) views._load();
|
if (event.state) views._load();
|
||||||
});
|
});
|
||||||
|
|
||||||
const notifications = {
|
const notifications = {
|
||||||
_generate({ heading, message = '', type = 'information' }, callback = () => {}) {
|
_generate({ heading, message = '', type = 'information' }, onDismiss = () => {}) {
|
||||||
let svg = '',
|
let svg = '',
|
||||||
className = 'notification';
|
className = 'notification';
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -347,7 +378,7 @@ const notifications = {
|
|||||||
$notif.offsetHeight / parseFloat(getComputedStyle(document.documentElement).fontSize)
|
$notif.offsetHeight / parseFloat(getComputedStyle(document.documentElement).fontSize)
|
||||||
}rem`;
|
}rem`;
|
||||||
setTimeout(() => $notif.remove(), 400);
|
setTimeout(() => $notif.remove(), 400);
|
||||||
callback();
|
onDismiss();
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
$notif.style.opacity = 1;
|
$notif.style.opacity = 1;
|
||||||
@ -355,7 +386,7 @@ const notifications = {
|
|||||||
return $notif;
|
return $notif;
|
||||||
},
|
},
|
||||||
async load() {
|
async load() {
|
||||||
let notifications = {
|
const notifications = {
|
||||||
list: await fs.getJSON('https://notion-enhancer.github.io/notifications.json'),
|
list: await fs.getJSON('https://notion-enhancer.github.io/notifications.json'),
|
||||||
dismissed: await storage.get(_id, 'notifications', []),
|
dismissed: await storage.get(_id, 'notifications', []),
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user