allow live-reload without reinstalling
This commit is contained in:
parent
c9e60dc19b
commit
a339b50e27
|
@ -588,6 +588,10 @@
|
|||
"message": "Live reload",
|
||||
"description": "The label of live-reload feature"
|
||||
},
|
||||
"liveReloadInstallHint": {
|
||||
"message": "Live reload is enabled so the installed style will be auto-updated on external changes while both this tab and the source file tab are open.",
|
||||
"description": "The label of live-reload feature"
|
||||
},
|
||||
"liveReloadError": {
|
||||
"message": "An error occurred while watching the file",
|
||||
"description": "The label of live-reload error"
|
||||
|
|
|
@ -1,7 +1,64 @@
|
|||
'use strict';
|
||||
|
||||
function createSourceLoader() {
|
||||
let source;
|
||||
(() => {
|
||||
// some weird bug in new Chrome: the content script gets injected multiple times
|
||||
if (typeof window.initUsercssInstall === 'function') return;
|
||||
if (!/text\/(css|plain)/.test(document.contentType) ||
|
||||
!/==userstyle==/i.test(document.body.textContent)) {
|
||||
return;
|
||||
}
|
||||
window.initUsercssInstall = () => {};
|
||||
|
||||
orphanCheck();
|
||||
|
||||
const DELAY = 500;
|
||||
const url = location.href;
|
||||
let sourceCode, port, timer;
|
||||
|
||||
chrome.runtime.onConnect.addListener(onConnected);
|
||||
chrome.runtime.sendMessage({method: 'installUsercss', url}, r =>
|
||||
r && r.__ERROR__ && alert(r.__ERROR__));
|
||||
|
||||
function onConnected(newPort) {
|
||||
port = newPort;
|
||||
port.onDisconnect.addListener(stop);
|
||||
port.onMessage.addListener(onMessage);
|
||||
}
|
||||
|
||||
function onMessage(msg, port) {
|
||||
switch (msg.method) {
|
||||
case 'getSourceCode':
|
||||
fetchText(url)
|
||||
.then(text => {
|
||||
sourceCode = sourceCode || text;
|
||||
port.postMessage({
|
||||
method: msg.method + 'Response',
|
||||
sourceCode,
|
||||
});
|
||||
})
|
||||
.catch(err => port.postMessage({
|
||||
method: msg.method + 'Response',
|
||||
error: err.message || String(err),
|
||||
}));
|
||||
break;
|
||||
|
||||
case 'liveReloadStart':
|
||||
start();
|
||||
break;
|
||||
|
||||
case 'liveReloadStop':
|
||||
stop();
|
||||
break;
|
||||
|
||||
case 'closeTab':
|
||||
if (history.length > 1) {
|
||||
history.back();
|
||||
} else {
|
||||
chrome.runtime.sendMessage({method: 'closeTab'});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function fetchText(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -14,104 +71,40 @@ function createSourceLoader() {
|
|||
});
|
||||
}
|
||||
|
||||
function load() {
|
||||
return fetchText(location.href).then(newSource => {
|
||||
source = newSource;
|
||||
return source;
|
||||
});
|
||||
function start() {
|
||||
timer = timer || setTimeout(check, DELAY);
|
||||
}
|
||||
|
||||
function watch(cb) {
|
||||
let timer;
|
||||
const DELAY = 1000;
|
||||
|
||||
function start() {
|
||||
if (timer) {
|
||||
return;
|
||||
}
|
||||
timer = setTimeout(check, DELAY);
|
||||
}
|
||||
|
||||
function stop() {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
|
||||
function check() {
|
||||
fetchText(location.href)
|
||||
.then(newSource => {
|
||||
if (source !== newSource) {
|
||||
source = newSource;
|
||||
return cb(source);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(chrome.i18n.getMessage('liveReloadError', error));
|
||||
})
|
||||
.then(() => {
|
||||
timer = setTimeout(check, DELAY);
|
||||
});
|
||||
}
|
||||
|
||||
return {start, stop};
|
||||
function stop() {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
|
||||
return {load, watch, source: () => source};
|
||||
}
|
||||
|
||||
function initUsercssInstall() {
|
||||
const sourceLoader = createSourceLoader();
|
||||
const pendingSource = sourceLoader.load();
|
||||
let watcher;
|
||||
|
||||
chrome.runtime.onConnect.addListener(port => {
|
||||
port.onMessage.addListener(msg => {
|
||||
switch (msg.method) {
|
||||
case 'getSourceCode':
|
||||
pendingSource
|
||||
.then(sourceCode => port.postMessage({method: msg.method + 'Response', sourceCode}))
|
||||
.catch(err => port.postMessage({method: msg.method + 'Response', error: err.message || String(err)}));
|
||||
break;
|
||||
|
||||
case 'liveReloadStart':
|
||||
if (!watcher) {
|
||||
watcher = sourceLoader.watch(sourceCode => {
|
||||
port.postMessage({method: 'sourceCodeChanged', sourceCode});
|
||||
});
|
||||
}
|
||||
watcher.start();
|
||||
break;
|
||||
|
||||
case 'liveReloadStop':
|
||||
watcher.stop();
|
||||
break;
|
||||
|
||||
case 'closeTab':
|
||||
if (history.length > 1) {
|
||||
history.back();
|
||||
} else {
|
||||
chrome.runtime.sendMessage({method: 'closeTab'});
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
chrome.runtime.sendMessage({
|
||||
method: 'installUsercss',
|
||||
url: location.href,
|
||||
}, r => r && r.__ERROR__ && alert(r.__ERROR__));
|
||||
}
|
||||
|
||||
function isUsercss() {
|
||||
if (!/text\/(css|plain)/.test(document.contentType)) {
|
||||
return false;
|
||||
function check() {
|
||||
fetchText(url)
|
||||
.then(text => {
|
||||
if (sourceCode === text) return;
|
||||
sourceCode = text;
|
||||
port.postMessage({method: 'sourceCodeChanged', sourceCode});
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(chrome.i18n.getMessage('liveReloadError', error));
|
||||
})
|
||||
.then(() => {
|
||||
timer = null;
|
||||
start();
|
||||
});
|
||||
}
|
||||
if (!/==userstyle==/i.test(document.body.textContent)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isUsercss()) {
|
||||
initUsercssInstall();
|
||||
}
|
||||
function orphanCheck() {
|
||||
const eventName = chrome.runtime.id + '-install-hook-usercss';
|
||||
const orphanCheckRequest = () => {
|
||||
if (chrome.i18n && chrome.i18n.getUILanguage()) return true;
|
||||
// In Chrome content script is orphaned on an extension update/reload
|
||||
// so we need to detach event listeners
|
||||
removeEventListener(eventName, orphanCheckRequest, true);
|
||||
};
|
||||
dispatchEvent(new Event(eventName));
|
||||
addEventListener(eventName, orphanCheckRequest, true);
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -5,50 +5,37 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Loading...</title>
|
||||
<link rel="stylesheet" href="global.css">
|
||||
<link rel="stylesheet" href="/install-usercss/install-usercss.css">
|
||||
<script src="/js/messaging.js"></script>
|
||||
<script src="/js/prefs.js"></script>
|
||||
<script src="/js/dom.js"></script>
|
||||
<script src="/js/localization.js"></script>
|
||||
<script src="/content/apply.js"></script>
|
||||
<script src="/vendor/node-semver/semver.js"></script>
|
||||
|
||||
<link href="global.css" rel="stylesheet">
|
||||
<link href="install-usercss/install-usercss.css" rel="stylesheet">
|
||||
|
||||
<script src="js/messaging.js"></script>
|
||||
<script src="js/prefs.js"></script>
|
||||
<script src="js/dom.js"></script>
|
||||
<script src="js/localization.js"></script>
|
||||
<script src="js/script-loader.js"></script>
|
||||
<script src="content/apply.js"></script>
|
||||
<script src="vendor/node-semver/semver.js"></script>
|
||||
|
||||
<script src="/msgbox/msgbox.js"></script>
|
||||
<link rel="stylesheet" href="/msgbox/msgbox.css">
|
||||
<link href="msgbox/msgbox.css" rel="stylesheet">
|
||||
<script src="msgbox/msgbox.js"></script>
|
||||
|
||||
<script src="/vendor/codemirror/lib/codemirror.js"></script>
|
||||
<script src="/vendor/codemirror/keymap/sublime.js"></script>
|
||||
<script src="/vendor/codemirror/keymap/emacs.js"></script>
|
||||
<script src="/vendor/codemirror/keymap/vim.js"></script>
|
||||
<link href="vendor/codemirror/lib/codemirror.css" rel="stylesheet">
|
||||
<script src="vendor/codemirror/lib/codemirror.js"></script>
|
||||
<script src="vendor/codemirror/keymap/sublime.js"></script>
|
||||
<script src="vendor/codemirror/keymap/emacs.js"></script>
|
||||
<script src="vendor/codemirror/keymap/vim.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="/vendor/codemirror/lib/codemirror.css">
|
||||
<script src="/vendor/codemirror/mode/css/css.js"></script>
|
||||
<link rel="stylesheet" href="/vendor/codemirror/addon/dialog/dialog.css">
|
||||
<link rel="stylesheet" href="/vendor/codemirror/addon/search/matchesonscrollbar.css">
|
||||
<script src="/vendor/codemirror/addon/scroll/annotatescrollbar.js"></script>
|
||||
<script src="/vendor/codemirror/addon/search/matchesonscrollbar.js"></script>
|
||||
<script src="/vendor/codemirror/addon/search/match-highlighter.js"></script>
|
||||
<script src="/vendor/codemirror/addon/dialog/dialog.js"></script>
|
||||
<script src="/vendor/codemirror/addon/search/searchcursor.js"></script>
|
||||
<script src="/vendor/codemirror/addon/search/search.js"></script>
|
||||
<script src="/vendor/codemirror/addon/comment/comment.js"></script>
|
||||
<script src="/vendor/codemirror/addon/selection/active-line.js"></script>
|
||||
<link rel="stylesheet" href="/vendor/codemirror/addon/fold/foldgutter.css" />
|
||||
<script src="/vendor/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script src="/vendor/codemirror/addon/fold/foldgutter.js"></script>
|
||||
<script src="/vendor/codemirror/addon/fold/brace-fold.js"></script>
|
||||
<script src="/vendor/codemirror/addon/fold/comment-fold.js"></script>
|
||||
<script src="/vendor/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<link rel="stylesheet" href="/vendor/codemirror/addon/lint/lint.css" />
|
||||
<link rel="stylesheet" href="/vendor/codemirror/addon/hint/show-hint.css" />
|
||||
<script src="/vendor/codemirror/addon/hint/show-hint.js"></script>
|
||||
<script src="/vendor/codemirror/addon/hint/css-hint.js"></script>
|
||||
<script src="vendor/codemirror/mode/css/css.js"></script>
|
||||
<script src="vendor/codemirror/addon/search/searchcursor.js"></script>
|
||||
|
||||
<script src="/edit/match-highlighter-helper.js"></script>
|
||||
<script src="/edit/codemirror-default.js"></script>
|
||||
<link rel="stylesheet" href="/edit/codemirror-default.css">
|
||||
<link href="vendor/codemirror/addon/fold/foldgutter.css" rel="stylesheet" />
|
||||
<script src="vendor/codemirror/addon/fold/foldcode.js"></script>
|
||||
<script src="vendor/codemirror/addon/fold/foldgutter.js"></script>
|
||||
<script src="vendor/codemirror/addon/fold/brace-fold.js"></script>
|
||||
|
||||
<script src="edit/codemirror-default.js"></script>
|
||||
<link rel="stylesheet" href="edit/codemirror-default.css">
|
||||
</head>
|
||||
<body id="stylus-install-usercss">
|
||||
<div class="container">
|
||||
|
@ -60,6 +47,7 @@
|
|||
<div class="actions">
|
||||
<h2 class="installed" i18n-text="installButtonInstalled"></h2>
|
||||
<button class="install" i18n-text="installButton"></button>
|
||||
<p id="live-reload-install-hint" i18n-text="liveReloadInstallHint" class="hidden"></p>
|
||||
<label class="set-update-url">
|
||||
<input type="checkbox">
|
||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||
|
@ -91,7 +79,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/install-usercss/install-usercss.js"></script>
|
||||
<script src="install-usercss/install-usercss.js"></script>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none !important;">
|
||||
<symbol id="svg-icon-checked" viewBox="0 0 1000 1000">
|
||||
|
|
|
@ -156,12 +156,18 @@ h1 small {
|
|||
background-position: center center;
|
||||
}
|
||||
|
||||
.install:hover {
|
||||
.install:hover:not(:disabled) {
|
||||
filter: brightness(1.1);
|
||||
color: #eee;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.install:disabled {
|
||||
opacity: .25;
|
||||
color: white;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.install.reinstall:after {
|
||||
background-color: #333;
|
||||
filter: grayscale(100%);
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
// TODO: remove .replace(/^\?/, '') when minimum_chrome_version >= 52 (https://crbug.com/601425)
|
||||
const params = new URLSearchParams(location.search.replace(/^\?/, ''));
|
||||
let liveReload = false;
|
||||
let installed = false;
|
||||
let installed = null;
|
||||
let installedDup = null;
|
||||
|
||||
const tabId = Number(params.get('tabId'));
|
||||
let tabUrl;
|
||||
|
@ -65,7 +66,7 @@
|
|||
cm.scrollTo(scrollInfo.left, scrollInfo.top);
|
||||
|
||||
return sendMessage({
|
||||
id: installed.id,
|
||||
id: (installed || installedDup).id,
|
||||
method: 'saveUsercss',
|
||||
reason: 'update',
|
||||
sourceCode
|
||||
|
@ -74,19 +75,27 @@
|
|||
});
|
||||
}
|
||||
|
||||
function updateMeta(style, dup) {
|
||||
function updateMeta(style, dup = installedDup) {
|
||||
installedDup = dup;
|
||||
const data = style.usercssData;
|
||||
const dupData = dup && dup.usercssData;
|
||||
const versionTest = dup && semverCompare(data.version, dupData.version);
|
||||
|
||||
// update editor
|
||||
cm.setPreprocessor(data.preprocessor);
|
||||
|
||||
// update metas
|
||||
document.title = `${installButtonLabel()} ${data.name}`;
|
||||
const installButtonLabel = t(
|
||||
installed ? 'installButtonInstalled' :
|
||||
!dup ? 'installButton' :
|
||||
versionTest > 0 ? 'installButtonUpdate' : 'installButtonReinstall'
|
||||
);
|
||||
document.title = `${installButtonLabel} ${data.name}`;
|
||||
|
||||
$('.install').textContent = installButtonLabel();
|
||||
$('.install').classList.add(installButtonClass());
|
||||
$('.install').textContent = installButtonLabel;
|
||||
$('.install').classList.add(
|
||||
installed ? 'installed' :
|
||||
!dup ? 'install' :
|
||||
versionTest > 0 ? 'update' :
|
||||
'reinstall');
|
||||
$('.set-update-url').title = dup && dup.updateUrl && t('installUpdateFrom', dup.updateUrl) || '';
|
||||
$('.meta-name').textContent = data.name;
|
||||
$('.meta-version').textContent = data.version;
|
||||
|
@ -158,20 +167,6 @@
|
|||
))
|
||||
]));
|
||||
}
|
||||
|
||||
function installButtonClass() {
|
||||
return installed ? 'installed' :
|
||||
!dup ? 'install' :
|
||||
versionTest > 0 ? 'update' : 'reinstall';
|
||||
}
|
||||
|
||||
function installButtonLabel() {
|
||||
return t(
|
||||
installed ? 'installButtonInstalled' :
|
||||
!dup ? 'installButton' :
|
||||
versionTest > 0 ? 'installButtonUpdate' : 'installButtonReinstall'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function showError(err) {
|
||||
|
@ -213,7 +208,7 @@
|
|||
cm.setValue(sourceCode);
|
||||
cm.refresh();
|
||||
API.buildUsercss({sourceCode, checkDup: true})
|
||||
.then(r => init(r instanceof Object ? r : deepCopy(r)))
|
||||
.then(init)
|
||||
.catch(err => {
|
||||
$('.header').classList.add('meta-init-error');
|
||||
showError(err);
|
||||
|
@ -324,9 +319,11 @@
|
|||
} else {
|
||||
setLiveReload.addEventListener('change', () => {
|
||||
liveReload = setLiveReload.checked;
|
||||
if (installed) {
|
||||
if (installed || installedDup) {
|
||||
const method = 'liveReload' + (liveReload ? 'Start' : 'Stop');
|
||||
port.postMessage({method});
|
||||
$('.install').disabled = liveReload;
|
||||
$('#live-reload-install-hint').classList.toggle('hidden', !liveReload);
|
||||
}
|
||||
});
|
||||
window.addEventListener('installed', () => {
|
||||
|
|
Loading…
Reference in New Issue
Block a user