mirror of
https://github.com/NohamR/Pocket-Bird.git
synced 2026-05-25 12:17:22 +00:00
Add separate entry points
This commit is contained in:
309
build.js
309
build.js
@@ -14,7 +14,7 @@ const DIST_DIR = "./dist";
|
|||||||
|
|
||||||
const BROWSER_MANIFEST = "./platform-specific/extension/manifest.json";
|
const BROWSER_MANIFEST = "./platform-specific/extension/manifest.json";
|
||||||
const OBSIDIAN_MANIFEST = "./platform-specific/obsidian/manifest.json";
|
const OBSIDIAN_MANIFEST = "./platform-specific/obsidian/manifest.json";
|
||||||
const USERSCRIPT_HEADER = "./platform-specific/userscript/header.txt";
|
const USERSCRIPT_HEADER = "./platform-specific/userscript/header.txt";
|
||||||
const OBSIDIAN_WRAPPER = "./platform-specific/obsidian/wrapper.js";
|
const OBSIDIAN_WRAPPER = "./platform-specific/obsidian/wrapper.js";
|
||||||
const VENCORD_WRAPPER = "./platform-specific/vencord/wrapper.js";
|
const VENCORD_WRAPPER = "./platform-specific/vencord/wrapper.js";
|
||||||
|
|
||||||
@@ -24,8 +24,13 @@ const OBSIDIAN_DIR = DIST_DIR + "/obsidian";
|
|||||||
const VENCORD_DIR = DIST_DIR + "/vencord";
|
const VENCORD_DIR = DIST_DIR + "/vencord";
|
||||||
|
|
||||||
const STYLESHEET_PATH = SRC_DIR + "/stylesheet.css";
|
const STYLESHEET_PATH = SRC_DIR + "/stylesheet.css";
|
||||||
// const APPLICATION_ENTRY = SRC_DIR + "/application.js";
|
|
||||||
const APPLICATION_ENTRY = SRC_DIR + "/platforms/browser.js";
|
const WEB_ENTRY = SRC_DIR + "/platforms/web.js";
|
||||||
|
const USERSCRIPT_ENTRY = SRC_DIR + "/platforms/userscript.js";
|
||||||
|
const BROWSER_EXTENSION_ENTRY = SRC_DIR + "/platforms/extension.js";
|
||||||
|
const OBSIDIAN_ENTRY = SRC_DIR + "/platforms/obsidian.js";
|
||||||
|
const VENCORD_ENTRY = SRC_DIR + "/platforms/vencord.js";
|
||||||
|
|
||||||
const BUNDLED_OUTPUT = DIST_DIR + "/birb.bundled.js";
|
const BUNDLED_OUTPUT = DIST_DIR + "/birb.bundled.js";
|
||||||
const BIRB_OUTPUT = DIST_DIR + "/birb.js";
|
const BIRB_OUTPUT = DIST_DIR + "/birb.js";
|
||||||
|
|
||||||
@@ -78,128 +83,268 @@ const version = `${versionDate}`; // Disable build number for now
|
|||||||
buildCache.version = version;
|
buildCache.version = version;
|
||||||
writeFileSync(BUILD_CACHE_PATH, JSON.stringify(buildCache), 'utf8');
|
writeFileSync(BUILD_CACHE_PATH, JSON.stringify(buildCache), 'utf8');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} entryPoint
|
||||||
|
* @param {boolean} [embedFont]
|
||||||
|
* @returns {Promise<string>}
|
||||||
|
*/
|
||||||
|
async function generateCode(entryPoint, embedFont = false) {
|
||||||
|
// Bundle with rollup
|
||||||
|
const bundle = await rollup({
|
||||||
|
input: entryPoint,
|
||||||
|
});
|
||||||
|
|
||||||
|
await bundle.write({
|
||||||
|
file: BUNDLED_OUTPUT,
|
||||||
|
format: 'iife',
|
||||||
|
});
|
||||||
|
|
||||||
|
await bundle.close();
|
||||||
|
|
||||||
|
let birbJs = readFileSync(BUNDLED_OUTPUT, 'utf8');
|
||||||
|
|
||||||
|
// Delete bundled file
|
||||||
|
unlinkSync(BUNDLED_OUTPUT);
|
||||||
|
|
||||||
|
// Replace version placeholder
|
||||||
|
birbJs = birbJs.replaceAll(VERSION_KEY, version);
|
||||||
|
|
||||||
|
// Compile and insert sprite sheets
|
||||||
|
for (const spriteSheet of spriteSheets) {
|
||||||
|
const dataUri = readFileSync(spriteSheet.path, 'base64');
|
||||||
|
birbJs = birbJs.replaceAll(spriteSheet.key, `data:image/png;base64,${dataUri}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert stylesheet
|
||||||
|
const stylesheetContent = readFileSync(STYLESHEET_PATH, 'utf8');
|
||||||
|
birbJs = birbJs.replace(STYLESHEET_KEY, stylesheetContent);
|
||||||
|
|
||||||
|
if (embedFont) {
|
||||||
|
// Encode font to data URI
|
||||||
|
const monocraftFontData = readFileSync(FONTS_DIR + '/Monocraft.otf', 'base64');
|
||||||
|
const monocraftDataUri = `data:font/otf;base64,${monocraftFontData}`;
|
||||||
|
birbJs = birbJs.replaceAll(MONOCRAFT_SRC_KEY, monocraftDataUri);
|
||||||
|
} else {
|
||||||
|
birbJs = birbJs.replaceAll(MONOCRAFT_SRC_KEY, MONOCRAFT_URL);
|
||||||
|
}
|
||||||
|
return birbJs;
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
// Build JavaScript function
|
// Build JavaScript function
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
// Bundle with rollup
|
async function buildWeb() {
|
||||||
const bundle = await rollup({
|
const birbJs = await generateCode(WEB_ENTRY);
|
||||||
input: APPLICATION_ENTRY,
|
writeFileSync(BIRB_OUTPUT, birbJs);
|
||||||
});
|
|
||||||
|
|
||||||
await bundle.write({
|
|
||||||
file: BUNDLED_OUTPUT,
|
|
||||||
format: 'iife',
|
|
||||||
});
|
|
||||||
|
|
||||||
await bundle.close();
|
|
||||||
|
|
||||||
let birbJs = readFileSync(BUNDLED_OUTPUT, 'utf8');
|
|
||||||
|
|
||||||
// Delete bundled file
|
|
||||||
unlinkSync(BUNDLED_OUTPUT);
|
|
||||||
|
|
||||||
// Replace version placeholder
|
|
||||||
birbJs = birbJs.replaceAll(VERSION_KEY, version);
|
|
||||||
|
|
||||||
// Compile and insert sprite sheets
|
|
||||||
for (const spriteSheet of spriteSheets) {
|
|
||||||
const dataUri = readFileSync(spriteSheet.path, 'base64');
|
|
||||||
birbJs = birbJs.replaceAll(spriteSheet.key, `data:image/png;base64,${dataUri}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert stylesheet
|
// Bundle with rollup
|
||||||
const stylesheetContent = readFileSync(STYLESHEET_PATH, 'utf8');
|
// const bundle = await rollup({
|
||||||
birbJs = birbJs.replace(STYLESHEET_KEY, stylesheetContent).replace(MONOCRAFT_SRC_KEY, MONOCRAFT_URL);
|
// input: APPLICATION_ENTRY,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// await bundle.write({
|
||||||
|
// file: BUNDLED_OUTPUT,
|
||||||
|
// format: 'iife',
|
||||||
|
// });
|
||||||
|
|
||||||
|
// await bundle.close();
|
||||||
|
|
||||||
|
// let birbJs = readFileSync(BUNDLED_OUTPUT, 'utf8');
|
||||||
|
|
||||||
|
// // Delete bundled file
|
||||||
|
// unlinkSync(BUNDLED_OUTPUT);
|
||||||
|
|
||||||
|
// // Replace version placeholder
|
||||||
|
// birbJs = birbJs.replaceAll(VERSION_KEY, version);
|
||||||
|
|
||||||
|
// // Compile and insert sprite sheets
|
||||||
|
// for (const spriteSheet of spriteSheets) {
|
||||||
|
// const dataUri = readFileSync(spriteSheet.path, 'base64');
|
||||||
|
// birbJs = birbJs.replaceAll(spriteSheet.key, `data:image/png;base64,${dataUri}`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Insert stylesheet
|
||||||
|
// const stylesheetContent = readFileSync(STYLESHEET_PATH, 'utf8');
|
||||||
|
// birbJs = birbJs.replace(STYLESHEET_KEY, stylesheetContent).replace(MONOCRAFT_SRC_KEY, MONOCRAFT_URL);
|
||||||
|
|
||||||
|
|
||||||
// Write bundled JavaScript function
|
// // Write bundled JavaScript function
|
||||||
writeFileSync(BIRB_OUTPUT, birbJs);
|
// writeFileSync(BIRB_OUTPUT, birbJs);
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
// Build userscript
|
// Build userscript
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
// Get userscript header
|
// Get userscript header
|
||||||
const userScriptHeader = readFileSync(USERSCRIPT_HEADER, 'utf8').replaceAll(VERSION_KEY, version);
|
// const userScriptHeader = readFileSync(USERSCRIPT_HEADER, 'utf8').replaceAll(VERSION_KEY, version);
|
||||||
|
|
||||||
mkdirSync(USERSCRIPT_DIR, { recursive: true });
|
// mkdirSync(USERSCRIPT_DIR, { recursive: true });
|
||||||
const userScript = userScriptHeader + "\n" + birbJs;
|
// const userScript = userScriptHeader + "\n" + birbJs;
|
||||||
writeFileSync(USERSCRIPT_DIR + '/birb.user.js', userScript);
|
// writeFileSync(USERSCRIPT_DIR + '/birb.user.js', userScript);
|
||||||
|
|
||||||
|
async function buildUserscript() {
|
||||||
|
const birbJs = await generateCode(USERSCRIPT_ENTRY);
|
||||||
|
// Get userscript header
|
||||||
|
const userScriptHeader = readFileSync(USERSCRIPT_HEADER, 'utf8').replaceAll(VERSION_KEY, version);
|
||||||
|
|
||||||
|
mkdirSync(USERSCRIPT_DIR, { recursive: true });
|
||||||
|
const userScript = userScriptHeader + "\n" + birbJs;
|
||||||
|
writeFileSync(USERSCRIPT_DIR + '/birb.user.js', userScript);
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
// Build browser extension
|
// Build browser extension
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
mkdirSync(EXTENSION_DIR, { recursive: true });
|
// mkdirSync(EXTENSION_DIR, { recursive: true });
|
||||||
|
|
||||||
// Copy birb.js
|
// // Copy birb.js
|
||||||
writeFileSync(EXTENSION_DIR + '/birb.js', birbJs);
|
// writeFileSync(EXTENSION_DIR + '/birb.js', birbJs);
|
||||||
|
|
||||||
// Copy manifest.json
|
// // Copy manifest.json
|
||||||
let browserManifest = readFileSync(BROWSER_MANIFEST, 'utf8');
|
// let browserManifest = readFileSync(BROWSER_MANIFEST, 'utf8');
|
||||||
browserManifest = browserManifest.replace(VERSION_KEY, version);
|
// browserManifest = browserManifest.replace(VERSION_KEY, version);
|
||||||
writeFileSync(EXTENSION_DIR + '/manifest.json', browserManifest);
|
// writeFileSync(EXTENSION_DIR + '/manifest.json', browserManifest);
|
||||||
|
|
||||||
// Copy icons folder
|
// // Copy icons folder
|
||||||
mkdirSync(EXTENSION_DIR + '/images/icons', { recursive: true });
|
// mkdirSync(EXTENSION_DIR + '/images/icons', { recursive: true });
|
||||||
cpSync(IMAGES_DIR + '/icons/transparent', EXTENSION_DIR + '/images/icons/transparent', { recursive: true });
|
// cpSync(IMAGES_DIR + '/icons/transparent', EXTENSION_DIR + '/images/icons/transparent', { recursive: true });
|
||||||
|
|
||||||
// Copy fonts folder
|
// // Copy fonts folder
|
||||||
mkdirSync(EXTENSION_DIR + '/fonts', { recursive: true });
|
// mkdirSync(EXTENSION_DIR + '/fonts', { recursive: true });
|
||||||
cpSync(FONTS_DIR, EXTENSION_DIR + '/fonts', { recursive: true });
|
// cpSync(FONTS_DIR, EXTENSION_DIR + '/fonts', { recursive: true });
|
||||||
|
|
||||||
// Compress extension folder into zip
|
// // Compress extension folder into zip
|
||||||
const output = createWriteStream(DIST_DIR + "/extension.zip");
|
// const output = createWriteStream(DIST_DIR + "/extension.zip");
|
||||||
const archive = archiver('zip');
|
// const archive = archiver('zip');
|
||||||
|
|
||||||
output.on('close', () => {
|
// output.on('close', () => {
|
||||||
console.log(`Created zip file: ${archive.pointer()} total bytes`);
|
// console.log(`Created zip file: ${archive.pointer()} total bytes`);
|
||||||
});
|
// });
|
||||||
|
|
||||||
archive.on('error', (err) => {
|
// archive.on('error', (err) => {
|
||||||
throw err;
|
// throw err;
|
||||||
});
|
// });
|
||||||
|
|
||||||
archive.pipe(output);
|
// archive.pipe(output);
|
||||||
archive.directory(EXTENSION_DIR + '/', false);
|
// archive.directory(EXTENSION_DIR + '/', false);
|
||||||
archive.finalize();
|
// archive.finalize();
|
||||||
|
|
||||||
|
async function buildExtension() {
|
||||||
|
const birbJs = await generateCode(BROWSER_EXTENSION_ENTRY);
|
||||||
|
|
||||||
|
mkdirSync(EXTENSION_DIR, { recursive: true });
|
||||||
|
|
||||||
|
// Copy birb.js
|
||||||
|
writeFileSync(EXTENSION_DIR + '/birb.js', birbJs);
|
||||||
|
|
||||||
|
// Copy manifest.json
|
||||||
|
let browserManifest = readFileSync(BROWSER_MANIFEST, 'utf8');
|
||||||
|
browserManifest = browserManifest.replace(VERSION_KEY, version);
|
||||||
|
writeFileSync(EXTENSION_DIR + '/manifest.json', browserManifest);
|
||||||
|
|
||||||
|
// Copy icons folder
|
||||||
|
mkdirSync(EXTENSION_DIR + '/images/icons', { recursive: true });
|
||||||
|
cpSync(IMAGES_DIR + '/icons/transparent', EXTENSION_DIR + '/images/icons/transparent', { recursive: true });
|
||||||
|
|
||||||
|
// Copy fonts folder
|
||||||
|
mkdirSync(EXTENSION_DIR + '/fonts', { recursive: true });
|
||||||
|
cpSync(FONTS_DIR, EXTENSION_DIR + '/fonts', { recursive: true });
|
||||||
|
|
||||||
|
// Compress extension folder into zip
|
||||||
|
const output = createWriteStream(DIST_DIR + "/extension.zip");
|
||||||
|
const archive = archiver('zip');
|
||||||
|
|
||||||
|
output.on('close', () => {
|
||||||
|
console.log(`Created zip file: ${archive.pointer()} total bytes`);
|
||||||
|
});
|
||||||
|
|
||||||
|
archive.on('error', (err) => {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
archive.pipe(output);
|
||||||
|
archive.directory(EXTENSION_DIR + '/', false);
|
||||||
|
archive.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
// Build Obsidian plugin
|
// Build Obsidian plugin
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
mkdirSync(OBSIDIAN_DIR, { recursive: true });
|
// mkdirSync(OBSIDIAN_DIR, { recursive: true });
|
||||||
|
|
||||||
// Wrap birb.js with plugin boilerplate
|
// // Wrap birb.js with plugin boilerplate
|
||||||
let obsidianPlugin = readFileSync(OBSIDIAN_WRAPPER, 'utf8').replace(VERSION_KEY, version).replace(CODE_KEY, birbJs);
|
// let obsidianPlugin = readFileSync(OBSIDIAN_WRAPPER, 'utf8').replace(VERSION_KEY, version).replace(CODE_KEY, birbJs);
|
||||||
|
|
||||||
// Encode font to data URI since Obsidian plugins can't have external font files
|
// // Encode font to data URI since Obsidian plugins can't have external font files
|
||||||
const monocraftFontData = readFileSync(FONTS_DIR + '/Monocraft.otf', 'base64');
|
// const monocraftFontData = readFileSync(FONTS_DIR + '/Monocraft.otf', 'base64');
|
||||||
const monocraftDataUri = `data:font/otf;base64,${monocraftFontData}`;
|
// const monocraftDataUri = `data:font/otf;base64,${monocraftFontData}`;
|
||||||
obsidianPlugin = obsidianPlugin.replace(MONOCRAFT_URL, monocraftDataUri);
|
// obsidianPlugin = obsidianPlugin.replace(MONOCRAFT_URL, monocraftDataUri);
|
||||||
|
|
||||||
// Create main.js with plugin code
|
// // Create main.js with plugin code
|
||||||
writeFileSync(OBSIDIAN_DIR + '/main.js', obsidianPlugin);
|
// writeFileSync(OBSIDIAN_DIR + '/main.js', obsidianPlugin);
|
||||||
|
|
||||||
// Copy manifest.json
|
// // Copy manifest.json
|
||||||
let obsidianManifest = readFileSync(OBSIDIAN_MANIFEST, 'utf8');
|
// let obsidianManifest = readFileSync(OBSIDIAN_MANIFEST, 'utf8');
|
||||||
obsidianManifest = obsidianManifest.replace(/"version":\s*".*"/, `"version": "${version}"`);
|
// obsidianManifest = obsidianManifest.replace(/"version":\s*".*"/, `"version": "${version}"`);
|
||||||
writeFileSync(OBSIDIAN_DIR + '/manifest.json', obsidianManifest);
|
// writeFileSync(OBSIDIAN_DIR + '/manifest.json', obsidianManifest);
|
||||||
|
|
||||||
|
async function buildObsidian() {
|
||||||
|
const birbJs = await generateCode(OBSIDIAN_ENTRY, true);
|
||||||
|
|
||||||
|
mkdirSync(OBSIDIAN_DIR, { recursive: true });
|
||||||
|
|
||||||
|
// Wrap birb.js with plugin boilerplate
|
||||||
|
let obsidianPlugin = readFileSync(OBSIDIAN_WRAPPER, 'utf8').replace(VERSION_KEY, version).replace(CODE_KEY, birbJs);
|
||||||
|
|
||||||
|
// Create main.js with plugin code
|
||||||
|
writeFileSync(OBSIDIAN_DIR + '/main.js', obsidianPlugin);
|
||||||
|
|
||||||
|
// Copy manifest.json
|
||||||
|
let obsidianManifest = readFileSync(OBSIDIAN_MANIFEST, 'utf8');
|
||||||
|
obsidianManifest = obsidianManifest.replace(/"version":\s*".*"/, `"version": "${version}"`);
|
||||||
|
writeFileSync(OBSIDIAN_DIR + '/manifest.json', obsidianManifest);
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
// Build Vencord plugin
|
// Build Vencord plugin
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
mkdirSync(VENCORD_DIR, { recursive: true });
|
// mkdirSync(VENCORD_DIR, { recursive: true });
|
||||||
|
|
||||||
// Wrap birb.js with plugin boilerplate
|
// // Wrap birb.js with plugin boilerplate
|
||||||
let vencordPlugin = readFileSync(VENCORD_WRAPPER, 'utf8').replace(CODE_KEY, birbJs);
|
// let vencordPlugin = readFileSync(VENCORD_WRAPPER, 'utf8').replace(CODE_KEY, birbJs);
|
||||||
|
|
||||||
// Set context to "local"
|
// // Set context to "local"
|
||||||
vencordPlugin = vencordPlugin.replace(CONTEXT_KEY, "local");
|
// vencordPlugin = vencordPlugin.replace(CONTEXT_KEY, "local");
|
||||||
|
|
||||||
// Create exported birb function
|
// // Create exported birb function
|
||||||
writeFileSync(VENCORD_DIR + '/birb.export.js', vencordPlugin);
|
// writeFileSync(VENCORD_DIR + '/birb.export.js', vencordPlugin);
|
||||||
|
|
||||||
console.log(`Build complete: ${version}`);
|
// console.log(`Build complete: ${version}`);
|
||||||
|
|
||||||
|
async function buildVencord() {
|
||||||
|
const birbJs = await generateCode(VENCORD_ENTRY);
|
||||||
|
|
||||||
|
mkdirSync(VENCORD_DIR, { recursive: true });
|
||||||
|
|
||||||
|
// Wrap birb.js with plugin boilerplate
|
||||||
|
let vencordPlugin = readFileSync(VENCORD_WRAPPER, 'utf8').replace(CODE_KEY, birbJs);
|
||||||
|
|
||||||
|
// Set context to "local"
|
||||||
|
vencordPlugin = vencordPlugin.replace(CONTEXT_KEY, "local");
|
||||||
|
|
||||||
|
// Create exported birb function
|
||||||
|
writeFileSync(VENCORD_DIR + '/birb.export.js', vencordPlugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Starting build...");
|
||||||
|
|
||||||
|
await buildWeb();
|
||||||
|
await buildUserscript();
|
||||||
|
await buildExtension();
|
||||||
|
await buildObsidian();
|
||||||
|
await buildVencord();
|
||||||
306
dist/birb.js
vendored
306
dist/birb.js
vendored
@@ -1,4 +1,4 @@
|
|||||||
(function (exports) {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Directions = {
|
const Directions = {
|
||||||
@@ -226,139 +226,6 @@
|
|||||||
return document.documentElement.clientHeight;
|
return document.documentElement.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVE_KEY = "birbSaveData";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
class Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {boolean} Whether this context is applicable
|
|
||||||
*/
|
|
||||||
// isContextActive() {
|
|
||||||
// throw new Error("Method not implemented");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
resetSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string[]} A list of CSS selectors for focusable elements
|
|
||||||
*/
|
|
||||||
getFocusableElements() {
|
|
||||||
return ["img", "video", ".birb-sticky-note"];
|
|
||||||
}
|
|
||||||
|
|
||||||
getFocusElementTopMargin() {
|
|
||||||
return 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string} The current path of the active page in this context
|
|
||||||
*/
|
|
||||||
getPath() {
|
|
||||||
// Default to website URL
|
|
||||||
return window.location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
|
||||||
*/
|
|
||||||
getActivePage() {
|
|
||||||
// Default to root element
|
|
||||||
return document.documentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a path is applicable given the context
|
|
||||||
* @param {string} path Can be a site URL or another context-specific path
|
|
||||||
* @returns {boolean} Whether the path matches the current context state
|
|
||||||
*/
|
|
||||||
isPathApplicable(path) {
|
|
||||||
// Default to website URL matching
|
|
||||||
const currentUrl = window.location.href;
|
|
||||||
const stickyNoteWebsite = path.split("?")[0];
|
|
||||||
const currentWebsite = currentUrl.split("?")[0];
|
|
||||||
|
|
||||||
if (stickyNoteWebsite !== currentWebsite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathParams = parseUrlParams(path);
|
|
||||||
const currentParams = parseUrlParams(currentUrl);
|
|
||||||
|
|
||||||
if (window.location.hostname === "www.youtube.com") {
|
|
||||||
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
areStickyNotesEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines and returns the current context
|
|
||||||
* @returns {Context}
|
|
||||||
*/
|
|
||||||
// export function getContext() {
|
|
||||||
// if (CONTEXTS_BY_KEY[SET_CONTEXT]) {
|
|
||||||
// return new CONTEXTS_BY_KEY[SET_CONTEXT]();
|
|
||||||
// }
|
|
||||||
// for (const context of contextProcessingOrder) {
|
|
||||||
// if (context.isContextActive()) {
|
|
||||||
// return context;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// error("No applicable context found");
|
|
||||||
// // return new LocalContext();
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URL parameters into a key-value map
|
|
||||||
* @param {string} url
|
|
||||||
* @returns {Record<string, string>}
|
|
||||||
*/
|
|
||||||
function parseUrlParams(url) {
|
|
||||||
const queryString = url.split("?")[1];
|
|
||||||
if (!queryString) return {};
|
|
||||||
|
|
||||||
return queryString.split("&").reduce((params, param) => {
|
|
||||||
const [key, value] = param.split("=");
|
|
||||||
return { ...params, [key]: value };
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Indicators for parts of the base bird sprite sheet */
|
/** Indicators for parts of the base bird sprite sheet */
|
||||||
const Sprite = {
|
const Sprite = {
|
||||||
THEME_HIGHLIGHT: "theme-highlight",
|
THEME_HIGHLIGHT: "theme-highlight",
|
||||||
@@ -990,6 +857,140 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SAVE_KEY = "birbSaveData";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
class Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
resetSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string[]} A list of CSS selectors for focusable elements
|
||||||
|
*/
|
||||||
|
getFocusableElements() {
|
||||||
|
return ["img", "video", ".birb-sticky-note"];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFocusElementTopMargin() {
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The current path of the active page in this context
|
||||||
|
*/
|
||||||
|
getPath() {
|
||||||
|
// Default to website URL
|
||||||
|
return window.location.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
||||||
|
*/
|
||||||
|
getActivePage() {
|
||||||
|
// Default to root element
|
||||||
|
return document.documentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a path is applicable given the context
|
||||||
|
* @param {string} path Can be a site URL or another context-specific path
|
||||||
|
* @returns {boolean} Whether the path matches the current context state
|
||||||
|
*/
|
||||||
|
isPathApplicable(path) {
|
||||||
|
// Default to website URL matching
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
const stickyNoteWebsite = path.split("?")[0];
|
||||||
|
const currentWebsite = currentUrl.split("?")[0];
|
||||||
|
|
||||||
|
if (stickyNoteWebsite !== currentWebsite) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathParams = parseUrlParams(path);
|
||||||
|
const currentParams = parseUrlParams(currentUrl);
|
||||||
|
|
||||||
|
if (window.location.hostname === "www.youtube.com") {
|
||||||
|
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
areStickyNotesEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalContext extends Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
log("Loading save data from localStorage");
|
||||||
|
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
log("Saving data to localStorage");
|
||||||
|
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
resetSaveData() {
|
||||||
|
log("Resetting save data in localStorage");
|
||||||
|
localStorage.removeItem(SAVE_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse URL parameters into a key-value map
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Record<string, string>}
|
||||||
|
*/
|
||||||
|
function parseUrlParams(url) {
|
||||||
|
const queryString = url.split("?")[1];
|
||||||
|
if (!queryString) return {};
|
||||||
|
|
||||||
|
return queryString.split("&").reduce((params, param) => {
|
||||||
|
const [key, value] = param.split("=");
|
||||||
|
return { ...params, [key]: value };
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} SavedStickyNote
|
* @typedef {Object} SavedStickyNote
|
||||||
* @property {string} id
|
* @property {string} id
|
||||||
@@ -2614,41 +2615,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('../application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
class LocalContext extends Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
log("Loading save data from localStorage");
|
|
||||||
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
log("Saving data to localStorage");
|
|
||||||
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
resetSaveData() {
|
|
||||||
log("Resetting save data in localStorage");
|
|
||||||
localStorage.removeItem(SAVE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeApplication(new LocalContext());
|
initializeApplication(new LocalContext());
|
||||||
|
|
||||||
exports.LocalContext = LocalContext;
|
})();
|
||||||
|
|
||||||
return exports;
|
|
||||||
|
|
||||||
})({});
|
|
||||||
|
|||||||
BIN
dist/extension.zip
vendored
BIN
dist/extension.zip
vendored
Binary file not shown.
323
dist/extension/birb.js
vendored
323
dist/extension/birb.js
vendored
@@ -1,4 +1,4 @@
|
|||||||
(function (exports) {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Directions = {
|
const Directions = {
|
||||||
@@ -226,139 +226,6 @@
|
|||||||
return document.documentElement.clientHeight;
|
return document.documentElement.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVE_KEY = "birbSaveData";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
class Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {boolean} Whether this context is applicable
|
|
||||||
*/
|
|
||||||
// isContextActive() {
|
|
||||||
// throw new Error("Method not implemented");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
resetSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string[]} A list of CSS selectors for focusable elements
|
|
||||||
*/
|
|
||||||
getFocusableElements() {
|
|
||||||
return ["img", "video", ".birb-sticky-note"];
|
|
||||||
}
|
|
||||||
|
|
||||||
getFocusElementTopMargin() {
|
|
||||||
return 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string} The current path of the active page in this context
|
|
||||||
*/
|
|
||||||
getPath() {
|
|
||||||
// Default to website URL
|
|
||||||
return window.location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
|
||||||
*/
|
|
||||||
getActivePage() {
|
|
||||||
// Default to root element
|
|
||||||
return document.documentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a path is applicable given the context
|
|
||||||
* @param {string} path Can be a site URL or another context-specific path
|
|
||||||
* @returns {boolean} Whether the path matches the current context state
|
|
||||||
*/
|
|
||||||
isPathApplicable(path) {
|
|
||||||
// Default to website URL matching
|
|
||||||
const currentUrl = window.location.href;
|
|
||||||
const stickyNoteWebsite = path.split("?")[0];
|
|
||||||
const currentWebsite = currentUrl.split("?")[0];
|
|
||||||
|
|
||||||
if (stickyNoteWebsite !== currentWebsite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathParams = parseUrlParams(path);
|
|
||||||
const currentParams = parseUrlParams(currentUrl);
|
|
||||||
|
|
||||||
if (window.location.hostname === "www.youtube.com") {
|
|
||||||
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
areStickyNotesEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines and returns the current context
|
|
||||||
* @returns {Context}
|
|
||||||
*/
|
|
||||||
// export function getContext() {
|
|
||||||
// if (CONTEXTS_BY_KEY[SET_CONTEXT]) {
|
|
||||||
// return new CONTEXTS_BY_KEY[SET_CONTEXT]();
|
|
||||||
// }
|
|
||||||
// for (const context of contextProcessingOrder) {
|
|
||||||
// if (context.isContextActive()) {
|
|
||||||
// return context;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// error("No applicable context found");
|
|
||||||
// // return new LocalContext();
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URL parameters into a key-value map
|
|
||||||
* @param {string} url
|
|
||||||
* @returns {Record<string, string>}
|
|
||||||
*/
|
|
||||||
function parseUrlParams(url) {
|
|
||||||
const queryString = url.split("?")[1];
|
|
||||||
if (!queryString) return {};
|
|
||||||
|
|
||||||
return queryString.split("&").reduce((params, param) => {
|
|
||||||
const [key, value] = param.split("=");
|
|
||||||
return { ...params, [key]: value };
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Indicators for parts of the base bird sprite sheet */
|
/** Indicators for parts of the base bird sprite sheet */
|
||||||
const Sprite = {
|
const Sprite = {
|
||||||
THEME_HIGHLIGHT: "theme-highlight",
|
THEME_HIGHLIGHT: "theme-highlight",
|
||||||
@@ -990,6 +857,155 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SAVE_KEY = "birbSaveData";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
class Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
resetSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string[]} A list of CSS selectors for focusable elements
|
||||||
|
*/
|
||||||
|
getFocusableElements() {
|
||||||
|
return ["img", "video", ".birb-sticky-note"];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFocusElementTopMargin() {
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The current path of the active page in this context
|
||||||
|
*/
|
||||||
|
getPath() {
|
||||||
|
// Default to website URL
|
||||||
|
return window.location.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
||||||
|
*/
|
||||||
|
getActivePage() {
|
||||||
|
// Default to root element
|
||||||
|
return document.documentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a path is applicable given the context
|
||||||
|
* @param {string} path Can be a site URL or another context-specific path
|
||||||
|
* @returns {boolean} Whether the path matches the current context state
|
||||||
|
*/
|
||||||
|
isPathApplicable(path) {
|
||||||
|
// Default to website URL matching
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
const stickyNoteWebsite = path.split("?")[0];
|
||||||
|
const currentWebsite = currentUrl.split("?")[0];
|
||||||
|
|
||||||
|
if (stickyNoteWebsite !== currentWebsite) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathParams = parseUrlParams(path);
|
||||||
|
const currentParams = parseUrlParams(currentUrl);
|
||||||
|
|
||||||
|
if (window.location.hostname === "www.youtube.com") {
|
||||||
|
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
areStickyNotesEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BrowserExtensionContext extends Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
log("Loading save data from browser extension storage");
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// @ts-expect-error
|
||||||
|
chrome.storage.sync.get([SAVE_KEY], (result) => {
|
||||||
|
resolve(result[SAVE_KEY] ?? {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
log("Saving data to browser extension storage");
|
||||||
|
// @ts-expect-error
|
||||||
|
chrome.storage.sync.set({ [SAVE_KEY]: saveData }, function () {
|
||||||
|
// @ts-expect-error
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
// @ts-expect-error
|
||||||
|
console.error(chrome.runtime.lastError);
|
||||||
|
} else {
|
||||||
|
console.log("Settings saved successfully");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
resetSaveData() {
|
||||||
|
log("Resetting save data in browser extension storage");
|
||||||
|
// @ts-expect-error
|
||||||
|
chrome.storage.sync.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse URL parameters into a key-value map
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Record<string, string>}
|
||||||
|
*/
|
||||||
|
function parseUrlParams(url) {
|
||||||
|
const queryString = url.split("?")[1];
|
||||||
|
if (!queryString) return {};
|
||||||
|
|
||||||
|
return queryString.split("&").reduce((params, param) => {
|
||||||
|
const [key, value] = param.split("=");
|
||||||
|
return { ...params, [key]: value };
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} SavedStickyNote
|
* @typedef {Object} SavedStickyNote
|
||||||
* @property {string} id
|
* @property {string} id
|
||||||
@@ -2614,41 +2630,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
initializeApplication(new BrowserExtensionContext());
|
||||||
* @typedef {import('../application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
class LocalContext extends Context {
|
})();
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
log("Loading save data from localStorage");
|
|
||||||
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
log("Saving data to localStorage");
|
|
||||||
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
resetSaveData() {
|
|
||||||
log("Resetting save data in localStorage");
|
|
||||||
localStorage.removeItem(SAVE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeApplication(new LocalContext());
|
|
||||||
|
|
||||||
exports.LocalContext = LocalContext;
|
|
||||||
|
|
||||||
return exports;
|
|
||||||
|
|
||||||
})({});
|
|
||||||
|
|||||||
361
dist/obsidian/main.js
vendored
361
dist/obsidian/main.js
vendored
@@ -3,7 +3,7 @@ module.exports = class PocketBird extends Plugin {
|
|||||||
onload() {
|
onload() {
|
||||||
console.log("Loading Pocket Bird version 2025.11.16...");
|
console.log("Loading Pocket Bird version 2025.11.16...");
|
||||||
const OBSIDIAN_PLUGIN = this;
|
const OBSIDIAN_PLUGIN = this;
|
||||||
(function (exports) {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Directions = {
|
const Directions = {
|
||||||
@@ -231,139 +231,6 @@ module.exports = class PocketBird extends Plugin {
|
|||||||
return document.documentElement.clientHeight;
|
return document.documentElement.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVE_KEY = "birbSaveData";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
class Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {boolean} Whether this context is applicable
|
|
||||||
*/
|
|
||||||
// isContextActive() {
|
|
||||||
// throw new Error("Method not implemented");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
resetSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string[]} A list of CSS selectors for focusable elements
|
|
||||||
*/
|
|
||||||
getFocusableElements() {
|
|
||||||
return ["img", "video", ".birb-sticky-note"];
|
|
||||||
}
|
|
||||||
|
|
||||||
getFocusElementTopMargin() {
|
|
||||||
return 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string} The current path of the active page in this context
|
|
||||||
*/
|
|
||||||
getPath() {
|
|
||||||
// Default to website URL
|
|
||||||
return window.location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
|
||||||
*/
|
|
||||||
getActivePage() {
|
|
||||||
// Default to root element
|
|
||||||
return document.documentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a path is applicable given the context
|
|
||||||
* @param {string} path Can be a site URL or another context-specific path
|
|
||||||
* @returns {boolean} Whether the path matches the current context state
|
|
||||||
*/
|
|
||||||
isPathApplicable(path) {
|
|
||||||
// Default to website URL matching
|
|
||||||
const currentUrl = window.location.href;
|
|
||||||
const stickyNoteWebsite = path.split("?")[0];
|
|
||||||
const currentWebsite = currentUrl.split("?")[0];
|
|
||||||
|
|
||||||
if (stickyNoteWebsite !== currentWebsite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathParams = parseUrlParams(path);
|
|
||||||
const currentParams = parseUrlParams(currentUrl);
|
|
||||||
|
|
||||||
if (window.location.hostname === "www.youtube.com") {
|
|
||||||
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
areStickyNotesEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines and returns the current context
|
|
||||||
* @returns {Context}
|
|
||||||
*/
|
|
||||||
// export function getContext() {
|
|
||||||
// if (CONTEXTS_BY_KEY[SET_CONTEXT]) {
|
|
||||||
// return new CONTEXTS_BY_KEY[SET_CONTEXT]();
|
|
||||||
// }
|
|
||||||
// for (const context of contextProcessingOrder) {
|
|
||||||
// if (context.isContextActive()) {
|
|
||||||
// return context;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// error("No applicable context found");
|
|
||||||
// // return new LocalContext();
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URL parameters into a key-value map
|
|
||||||
* @param {string} url
|
|
||||||
* @returns {Record<string, string>}
|
|
||||||
*/
|
|
||||||
function parseUrlParams(url) {
|
|
||||||
const queryString = url.split("?")[1];
|
|
||||||
if (!queryString) return {};
|
|
||||||
|
|
||||||
return queryString.split("&").reduce((params, param) => {
|
|
||||||
const [key, value] = param.split("=");
|
|
||||||
return { ...params, [key]: value };
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Indicators for parts of the base bird sprite sheet */
|
/** Indicators for parts of the base bird sprite sheet */
|
||||||
const Sprite = {
|
const Sprite = {
|
||||||
THEME_HIGHLIGHT: "theme-highlight",
|
THEME_HIGHLIGHT: "theme-highlight",
|
||||||
@@ -995,6 +862,193 @@ module.exports = class PocketBird extends Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ROOT_PATH = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
class Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
resetSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string[]} A list of CSS selectors for focusable elements
|
||||||
|
*/
|
||||||
|
getFocusableElements() {
|
||||||
|
return ["img", "video", ".birb-sticky-note"];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFocusElementTopMargin() {
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The current path of the active page in this context
|
||||||
|
*/
|
||||||
|
getPath() {
|
||||||
|
// Default to website URL
|
||||||
|
return window.location.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
||||||
|
*/
|
||||||
|
getActivePage() {
|
||||||
|
// Default to root element
|
||||||
|
return document.documentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a path is applicable given the context
|
||||||
|
* @param {string} path Can be a site URL or another context-specific path
|
||||||
|
* @returns {boolean} Whether the path matches the current context state
|
||||||
|
*/
|
||||||
|
isPathApplicable(path) {
|
||||||
|
// Default to website URL matching
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
const stickyNoteWebsite = path.split("?")[0];
|
||||||
|
const currentWebsite = currentUrl.split("?")[0];
|
||||||
|
|
||||||
|
if (stickyNoteWebsite !== currentWebsite) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathParams = parseUrlParams(path);
|
||||||
|
const currentParams = parseUrlParams(currentUrl);
|
||||||
|
|
||||||
|
if (window.location.hostname === "www.youtube.com") {
|
||||||
|
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
areStickyNotesEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObsidianContext extends Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// @ts-expect-error
|
||||||
|
OBSIDIAN_PLUGIN.loadData().then((data) => {
|
||||||
|
resolve(data ?? {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {BirbSaveData|{}} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
// @ts-expect-error
|
||||||
|
await OBSIDIAN_PLUGIN.saveData(saveData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
resetSaveData() {
|
||||||
|
this.putSaveData({});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
getFocusableElements() {
|
||||||
|
const elements = [
|
||||||
|
".workspace-leaf",
|
||||||
|
".cm-callout",
|
||||||
|
".HyperMD-codeblock-begin",
|
||||||
|
".status-bar",
|
||||||
|
".mobile-navbar"
|
||||||
|
];
|
||||||
|
return super.getFocusableElements().concat(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
getPath() {
|
||||||
|
// @ts-expect-error
|
||||||
|
const file = app.workspace.getActiveFile();
|
||||||
|
if (file && this.getActiveEditorElement()) {
|
||||||
|
return file.path;
|
||||||
|
} else {
|
||||||
|
return ROOT_PATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
getActivePage() {
|
||||||
|
if (this.getPath() === ROOT_PATH) {
|
||||||
|
// Root page, use document element
|
||||||
|
return document.documentElement
|
||||||
|
}
|
||||||
|
return this.getActiveEditorElement() ?? document.documentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
isPathApplicable(path) {
|
||||||
|
return path === this.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
areStickyNotesEnabled() {
|
||||||
|
return this.getPath() !== ROOT_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {HTMLElement|null} */
|
||||||
|
getActiveEditorElement() {
|
||||||
|
// @ts-expect-error
|
||||||
|
const activeLeaf = app.workspace.activeLeaf;
|
||||||
|
const leafElement = activeLeaf?.view?.containerEl;
|
||||||
|
return leafElement?.querySelector(".cm-scroller") ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse URL parameters into a key-value map
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Record<string, string>}
|
||||||
|
*/
|
||||||
|
function parseUrlParams(url) {
|
||||||
|
const queryString = url.split("?")[1];
|
||||||
|
if (!queryString) return {};
|
||||||
|
|
||||||
|
return queryString.split("&").reduce((params, param) => {
|
||||||
|
const [key, value] = param.split("=");
|
||||||
|
return { ...params, [key]: value };
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} SavedStickyNote
|
* @typedef {Object} SavedStickyNote
|
||||||
* @property {string} id
|
* @property {string} id
|
||||||
@@ -2619,44 +2673,9 @@ module.exports = class PocketBird extends Plugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
initializeApplication(new ObsidianContext());
|
||||||
* @typedef {import('../application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
class LocalContext extends Context {
|
})();
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
log("Loading save data from localStorage");
|
|
||||||
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
log("Saving data to localStorage");
|
|
||||||
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
resetSaveData() {
|
|
||||||
log("Resetting save data in localStorage");
|
|
||||||
localStorage.removeItem(SAVE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeApplication(new LocalContext());
|
|
||||||
|
|
||||||
exports.LocalContext = LocalContext;
|
|
||||||
|
|
||||||
return exports;
|
|
||||||
|
|
||||||
})({});
|
|
||||||
|
|
||||||
console.log("Pocket Bird loaded!");
|
console.log("Pocket Bird loaded!");
|
||||||
}
|
}
|
||||||
|
|||||||
314
dist/userscript/birb.user.js
vendored
314
dist/userscript/birb.user.js
vendored
@@ -12,7 +12,7 @@
|
|||||||
// @grant GM_deleteValue
|
// @grant GM_deleteValue
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
(function (exports) {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Directions = {
|
const Directions = {
|
||||||
@@ -240,139 +240,6 @@
|
|||||||
return document.documentElement.clientHeight;
|
return document.documentElement.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVE_KEY = "birbSaveData";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
class Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {boolean} Whether this context is applicable
|
|
||||||
*/
|
|
||||||
// isContextActive() {
|
|
||||||
// throw new Error("Method not implemented");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
resetSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string[]} A list of CSS selectors for focusable elements
|
|
||||||
*/
|
|
||||||
getFocusableElements() {
|
|
||||||
return ["img", "video", ".birb-sticky-note"];
|
|
||||||
}
|
|
||||||
|
|
||||||
getFocusElementTopMargin() {
|
|
||||||
return 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string} The current path of the active page in this context
|
|
||||||
*/
|
|
||||||
getPath() {
|
|
||||||
// Default to website URL
|
|
||||||
return window.location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
|
||||||
*/
|
|
||||||
getActivePage() {
|
|
||||||
// Default to root element
|
|
||||||
return document.documentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a path is applicable given the context
|
|
||||||
* @param {string} path Can be a site URL or another context-specific path
|
|
||||||
* @returns {boolean} Whether the path matches the current context state
|
|
||||||
*/
|
|
||||||
isPathApplicable(path) {
|
|
||||||
// Default to website URL matching
|
|
||||||
const currentUrl = window.location.href;
|
|
||||||
const stickyNoteWebsite = path.split("?")[0];
|
|
||||||
const currentWebsite = currentUrl.split("?")[0];
|
|
||||||
|
|
||||||
if (stickyNoteWebsite !== currentWebsite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathParams = parseUrlParams(path);
|
|
||||||
const currentParams = parseUrlParams(currentUrl);
|
|
||||||
|
|
||||||
if (window.location.hostname === "www.youtube.com") {
|
|
||||||
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
areStickyNotesEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines and returns the current context
|
|
||||||
* @returns {Context}
|
|
||||||
*/
|
|
||||||
// export function getContext() {
|
|
||||||
// if (CONTEXTS_BY_KEY[SET_CONTEXT]) {
|
|
||||||
// return new CONTEXTS_BY_KEY[SET_CONTEXT]();
|
|
||||||
// }
|
|
||||||
// for (const context of contextProcessingOrder) {
|
|
||||||
// if (context.isContextActive()) {
|
|
||||||
// return context;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// error("No applicable context found");
|
|
||||||
// // return new LocalContext();
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URL parameters into a key-value map
|
|
||||||
* @param {string} url
|
|
||||||
* @returns {Record<string, string>}
|
|
||||||
*/
|
|
||||||
function parseUrlParams(url) {
|
|
||||||
const queryString = url.split("?")[1];
|
|
||||||
if (!queryString) return {};
|
|
||||||
|
|
||||||
return queryString.split("&").reduce((params, param) => {
|
|
||||||
const [key, value] = param.split("=");
|
|
||||||
return { ...params, [key]: value };
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Indicators for parts of the base bird sprite sheet */
|
/** Indicators for parts of the base bird sprite sheet */
|
||||||
const Sprite = {
|
const Sprite = {
|
||||||
THEME_HIGHLIGHT: "theme-highlight",
|
THEME_HIGHLIGHT: "theme-highlight",
|
||||||
@@ -1004,6 +871,146 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SAVE_KEY = "birbSaveData";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
class Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
resetSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string[]} A list of CSS selectors for focusable elements
|
||||||
|
*/
|
||||||
|
getFocusableElements() {
|
||||||
|
return ["img", "video", ".birb-sticky-note"];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFocusElementTopMargin() {
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The current path of the active page in this context
|
||||||
|
*/
|
||||||
|
getPath() {
|
||||||
|
// Default to website URL
|
||||||
|
return window.location.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
||||||
|
*/
|
||||||
|
getActivePage() {
|
||||||
|
// Default to root element
|
||||||
|
return document.documentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a path is applicable given the context
|
||||||
|
* @param {string} path Can be a site URL or another context-specific path
|
||||||
|
* @returns {boolean} Whether the path matches the current context state
|
||||||
|
*/
|
||||||
|
isPathApplicable(path) {
|
||||||
|
// Default to website URL matching
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
const stickyNoteWebsite = path.split("?")[0];
|
||||||
|
const currentWebsite = currentUrl.split("?")[0];
|
||||||
|
|
||||||
|
if (stickyNoteWebsite !== currentWebsite) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathParams = parseUrlParams(path);
|
||||||
|
const currentParams = parseUrlParams(currentUrl);
|
||||||
|
|
||||||
|
if (window.location.hostname === "www.youtube.com") {
|
||||||
|
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
areStickyNotesEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserScriptContext extends Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
log("Loading save data from UserScript storage");
|
||||||
|
/** @type {BirbSaveData|{}} */
|
||||||
|
let saveData = {};
|
||||||
|
// @ts-expect-error
|
||||||
|
saveData = GM_getValue(SAVE_KEY, {}) ?? {};
|
||||||
|
return saveData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
log("Saving data to UserScript storage");
|
||||||
|
// @ts-expect-error
|
||||||
|
GM_setValue(SAVE_KEY, saveData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
resetSaveData() {
|
||||||
|
log("Resetting save data in UserScript storage");
|
||||||
|
// @ts-expect-error
|
||||||
|
GM_deleteValue(SAVE_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse URL parameters into a key-value map
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Record<string, string>}
|
||||||
|
*/
|
||||||
|
function parseUrlParams(url) {
|
||||||
|
const queryString = url.split("?")[1];
|
||||||
|
if (!queryString) return {};
|
||||||
|
|
||||||
|
return queryString.split("&").reduce((params, param) => {
|
||||||
|
const [key, value] = param.split("=");
|
||||||
|
return { ...params, [key]: value };
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} SavedStickyNote
|
* @typedef {Object} SavedStickyNote
|
||||||
* @property {string} id
|
* @property {string} id
|
||||||
@@ -2628,41 +2635,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
initializeApplication(new UserScriptContext());
|
||||||
* @typedef {import('../application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
class LocalContext extends Context {
|
})();
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
log("Loading save data from localStorage");
|
|
||||||
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
log("Saving data to localStorage");
|
|
||||||
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
resetSaveData() {
|
|
||||||
log("Resetting save data in localStorage");
|
|
||||||
localStorage.removeItem(SAVE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeApplication(new LocalContext());
|
|
||||||
|
|
||||||
exports.LocalContext = LocalContext;
|
|
||||||
|
|
||||||
return exports;
|
|
||||||
|
|
||||||
})({});
|
|
||||||
|
|||||||
306
dist/vencord/birb.export.js
vendored
306
dist/vencord/birb.export.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
export const Birb = () => {
|
export const Birb = () => {
|
||||||
(function (exports) {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Directions = {
|
const Directions = {
|
||||||
@@ -227,139 +227,6 @@ export const Birb = () => {
|
|||||||
return document.documentElement.clientHeight;
|
return document.documentElement.clientHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVE_KEY = "birbSaveData";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
class Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {boolean} Whether this context is applicable
|
|
||||||
*/
|
|
||||||
// isContextActive() {
|
|
||||||
// throw new Error("Method not implemented");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
*/
|
|
||||||
resetSaveData() {
|
|
||||||
throw new Error("Method not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string[]} A list of CSS selectors for focusable elements
|
|
||||||
*/
|
|
||||||
getFocusableElements() {
|
|
||||||
return ["img", "video", ".birb-sticky-note"];
|
|
||||||
}
|
|
||||||
|
|
||||||
getFocusElementTopMargin() {
|
|
||||||
return 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string} The current path of the active page in this context
|
|
||||||
*/
|
|
||||||
getPath() {
|
|
||||||
// Default to website URL
|
|
||||||
return window.location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
|
||||||
*/
|
|
||||||
getActivePage() {
|
|
||||||
// Default to root element
|
|
||||||
return document.documentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a path is applicable given the context
|
|
||||||
* @param {string} path Can be a site URL or another context-specific path
|
|
||||||
* @returns {boolean} Whether the path matches the current context state
|
|
||||||
*/
|
|
||||||
isPathApplicable(path) {
|
|
||||||
// Default to website URL matching
|
|
||||||
const currentUrl = window.location.href;
|
|
||||||
const stickyNoteWebsite = path.split("?")[0];
|
|
||||||
const currentWebsite = currentUrl.split("?")[0];
|
|
||||||
|
|
||||||
if (stickyNoteWebsite !== currentWebsite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathParams = parseUrlParams(path);
|
|
||||||
const currentParams = parseUrlParams(currentUrl);
|
|
||||||
|
|
||||||
if (window.location.hostname === "www.youtube.com") {
|
|
||||||
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
areStickyNotesEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines and returns the current context
|
|
||||||
* @returns {Context}
|
|
||||||
*/
|
|
||||||
// export function getContext() {
|
|
||||||
// if (CONTEXTS_BY_KEY[SET_CONTEXT]) {
|
|
||||||
// return new CONTEXTS_BY_KEY[SET_CONTEXT]();
|
|
||||||
// }
|
|
||||||
// for (const context of contextProcessingOrder) {
|
|
||||||
// if (context.isContextActive()) {
|
|
||||||
// return context;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// error("No applicable context found");
|
|
||||||
// // return new LocalContext();
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URL parameters into a key-value map
|
|
||||||
* @param {string} url
|
|
||||||
* @returns {Record<string, string>}
|
|
||||||
*/
|
|
||||||
function parseUrlParams(url) {
|
|
||||||
const queryString = url.split("?")[1];
|
|
||||||
if (!queryString) return {};
|
|
||||||
|
|
||||||
return queryString.split("&").reduce((params, param) => {
|
|
||||||
const [key, value] = param.split("=");
|
|
||||||
return { ...params, [key]: value };
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Indicators for parts of the base bird sprite sheet */
|
/** Indicators for parts of the base bird sprite sheet */
|
||||||
const Sprite = {
|
const Sprite = {
|
||||||
THEME_HIGHLIGHT: "theme-highlight",
|
THEME_HIGHLIGHT: "theme-highlight",
|
||||||
@@ -991,6 +858,140 @@ export const Birb = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SAVE_KEY = "birbSaveData";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./application.js').BirbSaveData} BirbSaveData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
class Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
resetSaveData() {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string[]} A list of CSS selectors for focusable elements
|
||||||
|
*/
|
||||||
|
getFocusableElements() {
|
||||||
|
return ["img", "video", ".birb-sticky-note"];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFocusElementTopMargin() {
|
||||||
|
return 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The current path of the active page in this context
|
||||||
|
*/
|
||||||
|
getPath() {
|
||||||
|
// Default to website URL
|
||||||
|
return window.location.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HTMLElement} The current active page element where sticky notes can be applied
|
||||||
|
*/
|
||||||
|
getActivePage() {
|
||||||
|
// Default to root element
|
||||||
|
return document.documentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a path is applicable given the context
|
||||||
|
* @param {string} path Can be a site URL or another context-specific path
|
||||||
|
* @returns {boolean} Whether the path matches the current context state
|
||||||
|
*/
|
||||||
|
isPathApplicable(path) {
|
||||||
|
// Default to website URL matching
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
const stickyNoteWebsite = path.split("?")[0];
|
||||||
|
const currentWebsite = currentUrl.split("?")[0];
|
||||||
|
|
||||||
|
if (stickyNoteWebsite !== currentWebsite) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathParams = parseUrlParams(path);
|
||||||
|
const currentParams = parseUrlParams(currentUrl);
|
||||||
|
|
||||||
|
if (window.location.hostname === "www.youtube.com") {
|
||||||
|
if (currentParams.v !== undefined && currentParams.v !== pathParams.v) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
areStickyNotesEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalContext extends Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
log("Loading save data from localStorage");
|
||||||
|
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
log("Saving data to localStorage");
|
||||||
|
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
resetSaveData() {
|
||||||
|
log("Resetting save data in localStorage");
|
||||||
|
localStorage.removeItem(SAVE_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse URL parameters into a key-value map
|
||||||
|
* @param {string} url
|
||||||
|
* @returns {Record<string, string>}
|
||||||
|
*/
|
||||||
|
function parseUrlParams(url) {
|
||||||
|
const queryString = url.split("?")[1];
|
||||||
|
if (!queryString) return {};
|
||||||
|
|
||||||
|
return queryString.split("&").reduce((params, param) => {
|
||||||
|
const [key, value] = param.split("=");
|
||||||
|
return { ...params, [key]: value };
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} SavedStickyNote
|
* @typedef {Object} SavedStickyNote
|
||||||
* @property {string} id
|
* @property {string} id
|
||||||
@@ -2615,43 +2616,8 @@ export const Birb = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('../application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
class LocalContext extends Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
log("Loading save data from localStorage");
|
|
||||||
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
log("Saving data to localStorage");
|
|
||||||
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
resetSaveData() {
|
|
||||||
log("Resetting save data in localStorage");
|
|
||||||
localStorage.removeItem(SAVE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeApplication(new LocalContext());
|
initializeApplication(new LocalContext());
|
||||||
|
|
||||||
exports.LocalContext = LocalContext;
|
})();
|
||||||
|
|
||||||
return exports;
|
|
||||||
|
|
||||||
})({});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -13,14 +13,6 @@ const SET_CONTEXT = "__CONTEXT__"
|
|||||||
*/
|
*/
|
||||||
export class Context {
|
export class Context {
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract
|
|
||||||
* @returns {boolean} Whether this context is applicable
|
|
||||||
*/
|
|
||||||
// isContextActive() {
|
|
||||||
// throw new Error("Method not implemented");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
@@ -102,6 +94,33 @@ export class Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class LocalContext extends Context {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @returns {Promise<BirbSaveData|{}>}
|
||||||
|
*/
|
||||||
|
async getSaveData() {
|
||||||
|
log("Loading save data from localStorage");
|
||||||
|
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {BirbSaveData} saveData
|
||||||
|
*/
|
||||||
|
async putSaveData(saveData) {
|
||||||
|
log("Saving data to localStorage");
|
||||||
|
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
resetSaveData() {
|
||||||
|
log("Resetting save data in localStorage");
|
||||||
|
localStorage.removeItem(SAVE_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class UserScriptContext extends Context {
|
export class UserScriptContext extends Context {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,7 +154,7 @@ export class UserScriptContext extends Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrowserExtensionContext extends Context {
|
export class BrowserExtensionContext extends Context {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
@@ -257,37 +276,6 @@ export class ObsidianContext extends Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const contextProcessingOrder = [
|
|
||||||
new UserScriptContext(),
|
|
||||||
new ObsidianContext(),
|
|
||||||
new BrowserExtensionContext(),
|
|
||||||
];
|
|
||||||
|
|
||||||
const CONTEXTS_BY_KEY = {
|
|
||||||
// "local": LocalContext,
|
|
||||||
"userscript": UserScriptContext,
|
|
||||||
"browser-extension": BrowserExtensionContext,
|
|
||||||
"obsidian": ObsidianContext
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines and returns the current context
|
|
||||||
* @returns {Context}
|
|
||||||
*/
|
|
||||||
// export function getContext() {
|
|
||||||
// if (CONTEXTS_BY_KEY[SET_CONTEXT]) {
|
|
||||||
// return new CONTEXTS_BY_KEY[SET_CONTEXT]();
|
|
||||||
// }
|
|
||||||
// for (const context of contextProcessingOrder) {
|
|
||||||
// if (context.isContextActive()) {
|
|
||||||
// return context;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// error("No applicable context found");
|
|
||||||
// // return new LocalContext();
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse URL parameters into a key-value map
|
* Parse URL parameters into a key-value map
|
||||||
* @param {string} url
|
* @param {string} url
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
import { Context, SAVE_KEY } from "../context.js";
|
|
||||||
import { log } from "../shared.js";
|
|
||||||
import { initializeApplication } from "../application";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('../application.js').BirbSaveData} BirbSaveData
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class LocalContext extends Context {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @returns {Promise<BirbSaveData|{}>}
|
|
||||||
*/
|
|
||||||
async getSaveData() {
|
|
||||||
log("Loading save data from localStorage");
|
|
||||||
return JSON.parse(localStorage.getItem(SAVE_KEY) ?? "{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
* @param {BirbSaveData} saveData
|
|
||||||
*/
|
|
||||||
async putSaveData(saveData) {
|
|
||||||
log("Saving data to localStorage");
|
|
||||||
localStorage.setItem(SAVE_KEY, JSON.stringify(saveData));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
resetSaveData() {
|
|
||||||
log("Resetting save data in localStorage");
|
|
||||||
localStorage.removeItem(SAVE_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initializeApplication(new LocalContext());
|
|
||||||
4
src/platforms/extension.js
Normal file
4
src/platforms/extension.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { initializeApplication } from "../application.js";
|
||||||
|
import { BrowserExtensionContext } from "../context.js";
|
||||||
|
|
||||||
|
initializeApplication(new BrowserExtensionContext());
|
||||||
4
src/platforms/obsidian.js
Normal file
4
src/platforms/obsidian.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { initializeApplication } from "../application.js";
|
||||||
|
import { ObsidianContext } from "../context.js";
|
||||||
|
|
||||||
|
initializeApplication(new ObsidianContext());
|
||||||
4
src/platforms/userscript.js
Normal file
4
src/platforms/userscript.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { initializeApplication } from "../application.js";
|
||||||
|
import { UserScriptContext } from "../context.js";
|
||||||
|
|
||||||
|
initializeApplication(new UserScriptContext());
|
||||||
4
src/platforms/vencord.js
Normal file
4
src/platforms/vencord.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { initializeApplication } from "../application.js";
|
||||||
|
import { LocalContext } from "../context.js";
|
||||||
|
|
||||||
|
initializeApplication(new LocalContext());
|
||||||
4
src/platforms/web.js
Normal file
4
src/platforms/web.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { initializeApplication } from "../application.js";
|
||||||
|
import { LocalContext } from "../context.js";
|
||||||
|
|
||||||
|
initializeApplication(new LocalContext());
|
||||||
Reference in New Issue
Block a user