Add: live-reload

This commit is contained in:
eight 2017-09-25 20:01:50 +08:00
parent 04ebc837e2
commit c2eadda708
5 changed files with 153 additions and 55 deletions

View File

@ -393,6 +393,10 @@
"message": "Install",
"description": "Label for install button"
},
"installButtonInstalled": {
"message": "Installed",
"description": "Text displayed when the style is successfully installed"
},
"installButtonUpdate": {
"message": "Update",
"description": "Label for update button"

View File

@ -68,7 +68,10 @@ function createSourceLoader() {
}
function initUsercssInstall() {
const pendingSource = createSourceLoader().load();
const sourceLoader = createSourceLoader();
const pendingSource = sourceLoader.load();
let watcher;
chrome.runtime.onConnect.addListener(port => {
// FIXME: is this the correct way to reject a connection?
// https://developer.chrome.com/extensions/messaging#connect
@ -83,6 +86,19 @@ function initUsercssInstall() {
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;
}
});
});

View File

@ -54,6 +54,10 @@
<input type="checkbox">
<span></span>
</label>
<label class="live-reload">
<input type="checkbox">
<span i18n-text="liveReloadLabel"></span>
</label>
</div>
<h1>
<span class="meta-name"></span>

View File

@ -85,6 +85,18 @@ h1 small {
overflow: hidden;
overflow-wrap: break-word;
min-width: 0;
display: flex;
flex-direction: column;
}
.main > :first-child {
flex: 0 0 auto;
}
.main > :last-child {
flex: 1 1 auto;
min-height: 0;
}
.main .code,

View File

@ -4,6 +4,8 @@
(function () {
const params = getParams();
let liveReload = false;
let installed = false;
const port = chrome.tabs.connect(
Number(params.tabId),
@ -19,11 +21,104 @@
initSourceCode(msg.sourceCode);
}
break;
case 'sourceCodeChanged':
if (msg.error) {
alert(msg.error);
} else {
liveReloadUpdate(msg.sourceCode);
}
break;
}
});
port.onDisconnect.addListener(closeCurrentTab);
const cm = CodeMirror.fromTextArea($('.code textarea'), {readOnly: true});
let liveReloadPending = Promise.resolve();
function liveReloadUpdate(sourceCode) {
liveReloadPending = liveReloadPending.then(() => {
const scrollInfo = cm.getScrollInfo();
const cursor = cm.getCursor();
cm.setValue(sourceCode);
cm.setCursor(cursor);
cm.scrollTo(scrollInfo.left, scrollInfo.top);
return runtimeSend({
method: 'saveUsercss',
reason: 'update',
sourceCode
}).then(updateMeta).catch(showError);
});
}
function updateMeta(style, dup) {
$$('.main .warning').forEach(e => e.remove());
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}`;
$('.install').textContent = installButtonLabel();
$('.set-update-url').title = dup && dup.updateUrl && t('installUpdateFrom', dup.updateUrl) || '';
$('.meta-name').textContent = data.name;
$('.meta-version').textContent = data.version;
$('.meta-description').textContent = data.description;
$('.meta-author').parentNode.style.display = data.author ? '' : 'none';
$('.meta-author').textContent = data.author;
$('.meta-license').parentNode.style.display = data.license ? '' : 'none';
$('.meta-license').textContent = data.license;
$('.applies-to').textContent = '';
getAppliesTo(style).forEach(pattern =>
$('.applies-to').appendChild($element({tag: 'li', textContent: pattern}))
);
$('.external-link').textContent = '';
const externalLink = makeExternalLink();
if (externalLink) {
$('.external-link').appendChild(externalLink);
}
function makeExternalLink() {
const urls = [];
if (data.homepageURL) {
urls.push([data.homepageURL, t('externalHomepage')]);
}
if (data.supportURL) {
urls.push([data.supportURL, t('externalSupport')]);
}
if (urls.length) {
return $element({appendChild: [
$element({tag: 'h3', textContent: t('externalLink')}),
$element({tag: 'ul', appendChild: urls.map(args =>
$element({tag: 'li', appendChild: makeLink(...args)})
)})
]});
}
}
function installButtonLabel() {
return t(
installed ? 'installButtonInstalled' :
!dup ? 'installButton' :
versionTest > 0 ? 'installButtonUpdate' : 'installButtonReinstall'
);
}
}
function showError(err) {
$$('.main .warning').forEach(e => e.remove());
const main = $('.main');
main.insertBefore(buildWarning(err), main.firstChild);
}
function runtimeSend(request) {
return new Promise((resolve, reject) => {
@ -41,15 +136,25 @@
});
return runtimeSend(request)
.then(result => {
installed = true;
$$('.warning')
.forEach(el => el.remove());
$('.install').textContent = 'Installed';
$('.install').disabled = true;
$('.install').classList.add('installed');
$('.set-update-url input[type=checkbox]').disabled = true;
$('.set-update-url').title = result.updateUrl ?
t('installUpdateFrom', result.updateUrl) : '';
window.dispatchEvent(new CustomEvent('installed', {detail: result}));
updateMeta(result);
if (liveReload) {
port.postMessage({method: 'liveReloadStart'});
}
$('.live-reload').addEventListener('change', () => {
const method = 'liveReload' + (liveReload ? 'Start' : 'Stop');
port.postMessage({method});
});
})
.catch(err => {
alert(chrome.i18n.getMessage('styleInstallFailed', String(err)));
@ -81,6 +186,8 @@
const dupData = dup && dup.usercssData;
const versionTest = dup && semverCompare(data.version, dupData.version);
updateMeta(style, dup);
// update UI
if (versionTest < 0) {
$('.actions').parentNode.insertBefore(
@ -120,59 +227,14 @@
}
};
// update editor
cm.setPreprocessor(data.preprocessor);
// update metas
document.title = `${installButtonLabel()} ${data.name}`;
$('.install').textContent = installButtonLabel();
$('.set-update-url').title = dup && dup.updateUrl && t('installUpdateFrom', dup.updateUrl) || '';
$('.meta-name').textContent = data.name;
$('.meta-version').textContent = data.version;
$('.meta-description').textContent = data.description;
if (data.author) {
$('.meta-author').textContent = data.author;
// live reload
const setLiveReload = $('.live-reload input[type=checkbox]');
if (updateUrl.protocol !== 'file:') {
setLiveReload.parentNode.remove();
} else {
$('.meta-author').parentNode.remove();
}
if (data.license) {
$('.meta-license').textContent = data.license;
} else {
$('.meta-license').parentNode.remove();
}
getAppliesTo(style).forEach(pattern =>
$('.applies-to').appendChild($element({tag: 'li', textContent: pattern}))
);
const externalLink = makeExternalLink();
if (externalLink) {
$('.external-link').appendChild(externalLink);
}
function makeExternalLink() {
const urls = [];
if (data.homepageURL) {
urls.push([data.homepageURL, t('externalHomepage')]);
}
if (data.supportURL) {
urls.push([data.supportURL, t('externalSupport')]);
}
if (urls.length) {
return $element({appendChild: [
$element({tag: 'h3', textContent: t('externalLink')}),
$element({tag: 'ul', appendChild: urls.map(args =>
$element({tag: 'li', appendChild: makeLink(...args)})
)})
]});
}
}
function installButtonLabel() {
return t(!dup ? 'installButton' :
versionTest > 0 ? 'installButtonUpdate' : 'installButtonReinstall');
setLiveReload.addEventListener('change', () => {
liveReload = setLiveReload.checked;
});
}
}