extract stuff from edit.js and load on demand
This commit is contained in:
parent
8d639b6140
commit
e74a349a88
141
edit/edit.js
141
edit/edit.js
|
@ -3,19 +3,14 @@
|
|||
define(require => {
|
||||
const {API, msg} = require('/js/msg');
|
||||
const {
|
||||
FIREFOX,
|
||||
closeCurrentTab,
|
||||
debounce,
|
||||
getOwnTab,
|
||||
sessionStore,
|
||||
} = require('/js/toolbox');
|
||||
const {
|
||||
$,
|
||||
$$,
|
||||
$create,
|
||||
$remove,
|
||||
getEventKeyName,
|
||||
onDOMready,
|
||||
setupLivePrefs,
|
||||
} = require('/js/dom');
|
||||
const t = require('/js/localization');
|
||||
|
@ -26,14 +21,10 @@ define(require => {
|
|||
const {CodeMirror, initBeautifyButton} = require('./codemirror-factory');
|
||||
|
||||
let headerHeight;
|
||||
let isSimpleWindow;
|
||||
let isWindowed;
|
||||
|
||||
window.on('beforeunload', beforeUnload);
|
||||
msg.onExtension(onRuntimeMessage);
|
||||
|
||||
lazyInit();
|
||||
|
||||
(async function init() {
|
||||
await preinit;
|
||||
buildThemeElement();
|
||||
|
@ -205,77 +196,6 @@ define(require => {
|
|||
}
|
||||
}
|
||||
|
||||
/* Stuff not needed for the main init so we can let it run at its own tempo */
|
||||
function lazyInit() {
|
||||
let ownTabId;
|
||||
// not using `await` so we don't block the subsequent code
|
||||
getOwnTab().then(patchHistoryBack);
|
||||
// no windows on android
|
||||
if (chrome.windows) {
|
||||
detectWindowedState();
|
||||
chrome.tabs.onAttached.addListener(onAttached);
|
||||
}
|
||||
async function patchHistoryBack(tab) {
|
||||
ownTabId = tab.id;
|
||||
// use browser history back when 'back to manage' is clicked
|
||||
if (sessionStore['manageStylesHistory' + ownTabId] === location.href) {
|
||||
await onDOMready();
|
||||
$('#cancel-button').onclick = event => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
history.back();
|
||||
};
|
||||
}
|
||||
}
|
||||
async function detectWindowedState() {
|
||||
isSimpleWindow =
|
||||
(await browser.windows.getCurrent()).type === 'popup';
|
||||
isWindowed = isSimpleWindow || (
|
||||
prefs.get('openEditInWindow') &&
|
||||
history.length === 1 &&
|
||||
(await browser.windows.getAll()).length > 1 &&
|
||||
(await browser.tabs.query({currentWindow: true})).length === 1
|
||||
);
|
||||
if (isSimpleWindow) {
|
||||
await onDOMready();
|
||||
initPopupButton();
|
||||
}
|
||||
}
|
||||
function initPopupButton() {
|
||||
const POPUP_HOTKEY = 'Shift-Ctrl-Alt-S';
|
||||
const btn = $create('img', {
|
||||
id: 'popup-button',
|
||||
title: t('optionsCustomizePopup') + '\n' + POPUP_HOTKEY,
|
||||
onclick: embedPopup,
|
||||
});
|
||||
const onIconsetChanged = (_, val) => {
|
||||
const prefix = `images/icon/${val ? 'light/' : ''}`;
|
||||
btn.srcset = `${prefix}16.png 1x,${prefix}32.png 2x`;
|
||||
};
|
||||
prefs.subscribe('iconset', onIconsetChanged, {runNow: true});
|
||||
document.body.appendChild(btn);
|
||||
window.on('keydown', e => getEventKeyName(e) === POPUP_HOTKEY && embedPopup());
|
||||
CodeMirror.defaults.extraKeys[POPUP_HOTKEY] = 'openStylusPopup'; // adds to keymap help
|
||||
}
|
||||
async function onAttached(tabId, info) {
|
||||
if (tabId !== ownTabId) {
|
||||
return;
|
||||
}
|
||||
if (info.newPosition !== 0) {
|
||||
prefs.set('openEditInWindow', false);
|
||||
return;
|
||||
}
|
||||
const win = await browser.windows.get(info.newWindowId, {populate: true});
|
||||
// If there's only one tab in this window, it's been dragged to new window
|
||||
const openEditInWindow = win.tabs.length === 1;
|
||||
// FF-only because Chrome retardedly resets the size during dragging
|
||||
if (openEditInWindow && FIREFOX) {
|
||||
chrome.windows.update(info.newWindowId, prefs.get('windowPosition'));
|
||||
}
|
||||
prefs.set('openEditInWindow', openEditInWindow);
|
||||
}
|
||||
}
|
||||
|
||||
function onRuntimeMessage(request) {
|
||||
const {style} = request;
|
||||
switch (request.method) {
|
||||
|
@ -322,7 +242,7 @@ define(require => {
|
|||
}
|
||||
|
||||
function canSaveWindowPos() {
|
||||
return isWindowed &&
|
||||
return editor.isWindowed &&
|
||||
document.visibilityState === 'visible' &&
|
||||
prefs.get('openEditInWindow') &&
|
||||
!isWindowMaximized();
|
||||
|
@ -383,63 +303,4 @@ define(require => {
|
|||
window.outerHeight < screen.availHeight + 10
|
||||
);
|
||||
}
|
||||
|
||||
function embedPopup() {
|
||||
const ID = 'popup-iframe';
|
||||
const SEL = '#' + ID;
|
||||
if ($(SEL)) return;
|
||||
const frame = $create('iframe', {
|
||||
id: ID,
|
||||
src: chrome.runtime.getManifest().browser_action.default_popup,
|
||||
height: 600,
|
||||
width: prefs.get('popupWidth'),
|
||||
onload() {
|
||||
frame.onload = null;
|
||||
frame.focus();
|
||||
const pw = frame.contentWindow;
|
||||
const body = pw.document.body;
|
||||
pw.on('keydown', e => getEventKeyName(e) === 'Escape' && embedPopup._close());
|
||||
pw.close = embedPopup._close;
|
||||
if (pw.IntersectionObserver) {
|
||||
let loaded;
|
||||
new pw.IntersectionObserver(([e]) => {
|
||||
const el = pw.document.scrollingElement;
|
||||
const h = e.isIntersecting && !pw.scrollY ? el.offsetHeight : el.scrollHeight;
|
||||
const hasSB = h > el.offsetHeight;
|
||||
const {width} = e.boundingClientRect;
|
||||
frame.height = h;
|
||||
if (!hasSB !== !frame._scrollbarWidth || frame.width - width) {
|
||||
frame._scrollbarWidth = hasSB ? width - el.offsetWidth : 0;
|
||||
frame.width = width + frame._scrollbarWidth;
|
||||
}
|
||||
if (!loaded) {
|
||||
loaded = true;
|
||||
frame.dataset.loaded = '';
|
||||
}
|
||||
}).observe(body.appendChild(
|
||||
$create('div', {style: {height: '1px', marginTop: '-1px'}})
|
||||
));
|
||||
} else {
|
||||
frame.dataset.loaded = '';
|
||||
frame.height = body.scrollHeight;
|
||||
}
|
||||
new pw.MutationObserver(() => {
|
||||
const bs = body.style;
|
||||
const w = parseFloat(bs.minWidth || bs.width) + (frame._scrollbarWidth || 0);
|
||||
const h = parseFloat(bs.minHeight || body.offsetHeight);
|
||||
if (frame.width - w) frame.width = w;
|
||||
if (frame.height - h) frame.height = h;
|
||||
}).observe(body, {attributes: true, attributeFilter: ['style']});
|
||||
},
|
||||
});
|
||||
// saving the listener here so it's the same function reference for window.off
|
||||
if (!embedPopup._close) {
|
||||
embedPopup._close = () => {
|
||||
$remove(SEL);
|
||||
window.off('mousedown', embedPopup._close);
|
||||
};
|
||||
}
|
||||
window.on('mousedown', embedPopup._close);
|
||||
document.body.appendChild(frame);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -22,6 +22,8 @@ define(require => {
|
|||
const editor = {
|
||||
dirty,
|
||||
isUsercss: false,
|
||||
isWindowed: false,
|
||||
isWindowSimple: false,
|
||||
/** @type {'customName'|'name'} */
|
||||
nameTarget: 'name',
|
||||
previewDelay: 200, // Chrome devtools uses 200
|
||||
|
|
114
edit/embedded-popup.js
Normal file
114
edit/embedded-popup.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
'use strict';
|
||||
|
||||
define(require => {
|
||||
const {
|
||||
$,
|
||||
$create,
|
||||
$remove,
|
||||
getEventKeyName,
|
||||
} = require('/js/dom');
|
||||
const t = require('/js/localization');
|
||||
const prefs = require('/js/prefs');
|
||||
const {CodeMirror} = require('./codemirror-factory');
|
||||
|
||||
const ID = 'popup-iframe';
|
||||
const SEL = '#' + ID;
|
||||
const URL = chrome.runtime.getManifest().browser_action.default_popup;
|
||||
/** @type {HTMLIFrameElement} */
|
||||
let frame;
|
||||
let isLoaded;
|
||||
let scrollbarWidth;
|
||||
|
||||
return {
|
||||
initPopupButton() {
|
||||
const POPUP_HOTKEY = 'Shift-Ctrl-Alt-S';
|
||||
const btn = $create('img', {
|
||||
id: 'popup-button',
|
||||
title: t('optionsCustomizePopup') + '\n' + POPUP_HOTKEY,
|
||||
onclick: embedPopup,
|
||||
});
|
||||
const onIconsetChanged = (_, val) => {
|
||||
const prefix = `images/icon/${val ? 'light/' : ''}`;
|
||||
btn.srcset = `${prefix}16.png 1x,${prefix}32.png 2x`;
|
||||
};
|
||||
prefs.subscribe('iconset', onIconsetChanged, {runNow: true});
|
||||
document.body.appendChild(btn);
|
||||
window.on('keydown', e => getEventKeyName(e) === POPUP_HOTKEY && embedPopup());
|
||||
CodeMirror.defaults.extraKeys[POPUP_HOTKEY] = 'openStylusPopup'; // adds to keymap help
|
||||
},
|
||||
};
|
||||
|
||||
function embedPopup() {
|
||||
if ($(SEL)) return;
|
||||
isLoaded = false;
|
||||
scrollbarWidth = 0;
|
||||
frame = $create('iframe', {
|
||||
id: ID,
|
||||
src: URL,
|
||||
height: 600,
|
||||
width: prefs.get('popupWidth'),
|
||||
onload: initFrame,
|
||||
});
|
||||
window.on('mousedown', removePopup);
|
||||
document.body.appendChild(frame);
|
||||
}
|
||||
|
||||
function initFrame() {
|
||||
frame = this;
|
||||
frame.focus();
|
||||
const pw = frame.contentWindow;
|
||||
const body = pw.document.body;
|
||||
pw.on('keydown', removePopupOnEsc);
|
||||
pw.close = removePopup;
|
||||
if (pw.IntersectionObserver) {
|
||||
new pw.IntersectionObserver(onIntersect).observe(body.appendChild(
|
||||
$create('div', {style: {height: '1px', marginTop: '-1px'}})
|
||||
));
|
||||
} else {
|
||||
frame.dataset.loaded = '';
|
||||
frame.height = body.scrollHeight;
|
||||
}
|
||||
new pw.MutationObserver(onMutation).observe(body, {
|
||||
attributes: true,
|
||||
attributeFilter: ['style'],
|
||||
});
|
||||
}
|
||||
|
||||
function onMutation() {
|
||||
const body = frame.contentDocument.body;
|
||||
const bs = body.style;
|
||||
const w = parseFloat(bs.minWidth || bs.width) + (scrollbarWidth || 0);
|
||||
const h = parseFloat(bs.minHeight || body.offsetHeight);
|
||||
if (frame.width - w) frame.width = w;
|
||||
if (frame.height - h) frame.height = h;
|
||||
}
|
||||
|
||||
function onIntersect([e]) {
|
||||
const pw = frame.contentWindow;
|
||||
const el = pw.document.scrollingElement;
|
||||
const h = e.isIntersecting && !pw.scrollY ? el.offsetHeight : el.scrollHeight;
|
||||
const hasSB = h > el.offsetHeight;
|
||||
const {width} = e.boundingClientRect;
|
||||
frame.height = h;
|
||||
if (!hasSB !== !scrollbarWidth || frame.width - width) {
|
||||
scrollbarWidth = hasSB ? width - el.offsetWidth : 0;
|
||||
frame.width = width + scrollbarWidth;
|
||||
}
|
||||
if (!isLoaded) {
|
||||
isLoaded = true;
|
||||
frame.dataset.loaded = '';
|
||||
}
|
||||
}
|
||||
|
||||
function removePopup() {
|
||||
frame = null;
|
||||
$remove(SEL);
|
||||
window.off('mousedown', removePopup);
|
||||
}
|
||||
|
||||
function removePopupOnEsc(e) {
|
||||
if (getEventKeyName(e) === 'Escape') {
|
||||
removePopup();
|
||||
}
|
||||
}
|
||||
});
|
106
edit/preinit.js
106
edit/preinit.js
|
@ -2,8 +2,14 @@
|
|||
|
||||
define(require => {
|
||||
const {API} = require('/js/msg');
|
||||
const {sessionStore, tryCatch, tryJSONparse} = require('/js/toolbox');
|
||||
const {waitForSelector} = require('/js/dom');
|
||||
const {
|
||||
FIREFOX,
|
||||
getOwnTab,
|
||||
sessionStore,
|
||||
tryCatch,
|
||||
tryJSONparse,
|
||||
} = require('/js/toolbox');
|
||||
const {$, waitForSelector} = require('/js/dom');
|
||||
const prefs = require('/js/prefs');
|
||||
const editor = require('./editor');
|
||||
const util = require('./util');
|
||||
|
@ -12,9 +18,12 @@ define(require => {
|
|||
emacs: '/vendor/codemirror/keymap/emacs',
|
||||
vim: '/vendor/codemirror/keymap/vim',
|
||||
};
|
||||
const domReady = waitForSelector('#sections');
|
||||
let ownTabId;
|
||||
|
||||
// resize the window on 'undo close'
|
||||
if (chrome.windows) {
|
||||
initWindowedMode();
|
||||
const pos = tryJSONparse(sessionStore.windowPos);
|
||||
delete sessionStore.windowPos;
|
||||
if (pos && pos.left != null && chrome.windows) {
|
||||
|
@ -22,27 +31,35 @@ define(require => {
|
|||
}
|
||||
}
|
||||
|
||||
async function preinit() {
|
||||
const params = new URLSearchParams(location.search);
|
||||
const id = Number(params.get('id'));
|
||||
const style = id && await API.styles.get(id) || {
|
||||
name: params.get('domain') ||
|
||||
tryCatch(() => new URL(params.get('url-prefix')).hostname) ||
|
||||
'',
|
||||
enabled: true,
|
||||
sections: [
|
||||
util.DocFuncMapper.toSection([...params], {code: ''}),
|
||||
],
|
||||
};
|
||||
// switching the mode here to show the correct page ASAP, usually before DOMContentLoaded
|
||||
editor.isUsercss = Boolean(style.usercssData || !style.id && prefs.get('newStyleAsUsercss'));
|
||||
editor.lazyKeymaps = lazyKeymaps;
|
||||
editor.style = style;
|
||||
editor.updateTitle(false);
|
||||
document.documentElement.classList.toggle('usercss', editor.isUsercss);
|
||||
sessionStore.justEditedStyleId = style.id || '';
|
||||
// no such style so let's clear the invalid URL parameters
|
||||
if (!style.id) history.replaceState({}, '', location.pathname);
|
||||
getOwnTab().then(async tab => {
|
||||
ownTabId = tab.id;
|
||||
// use browser history back when 'back to manage' is clicked
|
||||
if (sessionStore['manageStylesHistory' + ownTabId] === location.href) {
|
||||
await domReady;
|
||||
$('#cancel-button').onclick = event => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
history.back();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
async function initWindowedMode() {
|
||||
chrome.tabs.onAttached.addListener(onTabAttached);
|
||||
editor.isWindowSimple =
|
||||
(await browser.windows.getCurrent()).type === 'popup';
|
||||
if (editor.isWindowSimple) {
|
||||
Promise.all([
|
||||
require(['./embedded-popup']),
|
||||
domReady,
|
||||
]).then(([_]) => _.initPopupButton());
|
||||
}
|
||||
editor.isWindowed = editor.isWindowSimple || (
|
||||
history.length === 1 &&
|
||||
await prefs.initializing && prefs.get('openEditInWindow') &&
|
||||
(await browser.windows.getAll()).length > 1 &&
|
||||
(await browser.tabs.query({currentWindow: true})).length === 1
|
||||
);
|
||||
}
|
||||
|
||||
/** Preloads the theme so CodeMirror can use the correct metrics in its first render */
|
||||
|
@ -70,6 +87,47 @@ define(require => {
|
|||
/vim/i.test(km) && require([lazyKeymaps.vim]);
|
||||
}
|
||||
|
||||
async function onTabAttached(tabId, info) {
|
||||
if (tabId !== ownTabId) {
|
||||
return;
|
||||
}
|
||||
if (info.newPosition !== 0) {
|
||||
prefs.set('openEditInWindow', false);
|
||||
return;
|
||||
}
|
||||
const win = await browser.windows.get(info.newWindowId, {populate: true});
|
||||
// If there's only one tab in this window, it's been dragged to new window
|
||||
const openEditInWindow = win.tabs.length === 1;
|
||||
// FF-only because Chrome retardedly resets the size during dragging
|
||||
if (openEditInWindow && FIREFOX) {
|
||||
chrome.windows.update(info.newWindowId, prefs.get('windowPosition'));
|
||||
}
|
||||
prefs.set('openEditInWindow', openEditInWindow);
|
||||
}
|
||||
|
||||
async function preinit() {
|
||||
const params = new URLSearchParams(location.search);
|
||||
const id = Number(params.get('id'));
|
||||
const style = id && await API.styles.get(id) || {
|
||||
name: params.get('domain') ||
|
||||
tryCatch(() => new URL(params.get('url-prefix')).hostname) ||
|
||||
'',
|
||||
enabled: true,
|
||||
sections: [
|
||||
util.DocFuncMapper.toSection([...params], {code: ''}),
|
||||
],
|
||||
};
|
||||
// switching the mode here to show the correct page ASAP, usually before DOMContentLoaded
|
||||
editor.isUsercss = Boolean(style.usercssData || !style.id && prefs.get('newStyleAsUsercss'));
|
||||
editor.lazyKeymaps = lazyKeymaps;
|
||||
editor.style = style;
|
||||
editor.updateTitle(false);
|
||||
document.documentElement.classList.toggle('usercss', editor.isUsercss);
|
||||
sessionStore.justEditedStyleId = style.id || '';
|
||||
// no such style so let's clear the invalid URL parameters
|
||||
if (!style.id) history.replaceState({}, '', location.pathname);
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
preinit(),
|
||||
prefs.initializing.then(() =>
|
||||
|
@ -77,6 +135,6 @@ define(require => {
|
|||
loadTheme(),
|
||||
loadKeymaps(),
|
||||
])),
|
||||
waitForSelector('#sections'),
|
||||
domReady,
|
||||
]);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user