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", "message": "Install",
"description": "Label for install button" "description": "Label for install button"
}, },
"installButtonInstalled": {
"message": "Installed",
"description": "Text displayed when the style is successfully installed"
},
"installButtonUpdate": { "installButtonUpdate": {
"message": "Update", "message": "Update",
"description": "Label for update button" "description": "Label for update button"

View File

@ -68,7 +68,10 @@ function createSourceLoader() {
} }
function initUsercssInstall() { function initUsercssInstall() {
const pendingSource = createSourceLoader().load(); const sourceLoader = createSourceLoader();
const pendingSource = sourceLoader.load();
let watcher;
chrome.runtime.onConnect.addListener(port => { chrome.runtime.onConnect.addListener(port => {
// FIXME: is this the correct way to reject a connection? // FIXME: is this the correct way to reject a connection?
// https://developer.chrome.com/extensions/messaging#connect // https://developer.chrome.com/extensions/messaging#connect
@ -83,6 +86,19 @@ function initUsercssInstall() {
port.postMessage({method: msg.method + 'Response', error: err.message || String(err)}) port.postMessage({method: msg.method + 'Response', error: err.message || String(err)})
); );
break; 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"> <input type="checkbox">
<span></span> <span></span>
</label> </label>
<label class="live-reload">
<input type="checkbox">
<span i18n-text="liveReloadLabel"></span>
</label>
</div> </div>
<h1> <h1>
<span class="meta-name"></span> <span class="meta-name"></span>

View File

@ -85,6 +85,18 @@ h1 small {
overflow: hidden; overflow: hidden;
overflow-wrap: break-word; overflow-wrap: break-word;
min-width: 0; 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, .main .code,

View File

@ -4,6 +4,8 @@
(function () { (function () {
const params = getParams(); const params = getParams();
let liveReload = false;
let installed = false;
const port = chrome.tabs.connect( const port = chrome.tabs.connect(
Number(params.tabId), Number(params.tabId),
@ -19,11 +21,104 @@
initSourceCode(msg.sourceCode); initSourceCode(msg.sourceCode);
} }
break; break;
case 'sourceCodeChanged':
if (msg.error) {
alert(msg.error);
} else {
liveReloadUpdate(msg.sourceCode);
}
break;
} }
}); });
port.onDisconnect.addListener(closeCurrentTab); port.onDisconnect.addListener(closeCurrentTab);
const cm = CodeMirror.fromTextArea($('.code textarea'), {readOnly: true}); 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) { function runtimeSend(request) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -41,15 +136,25 @@
}); });
return runtimeSend(request) return runtimeSend(request)
.then(result => { .then(result => {
installed = true;
$$('.warning') $$('.warning')
.forEach(el => el.remove()); .forEach(el => el.remove());
$('.install').textContent = 'Installed';
$('.install').disabled = true; $('.install').disabled = true;
$('.install').classList.add('installed'); $('.install').classList.add('installed');
$('.set-update-url input[type=checkbox]').disabled = true; $('.set-update-url input[type=checkbox]').disabled = true;
$('.set-update-url').title = result.updateUrl ? $('.set-update-url').title = result.updateUrl ?
t('installUpdateFrom', 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 => { .catch(err => {
alert(chrome.i18n.getMessage('styleInstallFailed', String(err))); alert(chrome.i18n.getMessage('styleInstallFailed', String(err)));
@ -81,6 +186,8 @@
const dupData = dup && dup.usercssData; const dupData = dup && dup.usercssData;
const versionTest = dup && semverCompare(data.version, dupData.version); const versionTest = dup && semverCompare(data.version, dupData.version);
updateMeta(style, dup);
// update UI // update UI
if (versionTest < 0) { if (versionTest < 0) {
$('.actions').parentNode.insertBefore( $('.actions').parentNode.insertBefore(
@ -120,59 +227,14 @@
} }
}; };
// update editor // live reload
cm.setPreprocessor(data.preprocessor); const setLiveReload = $('.live-reload input[type=checkbox]');
if (updateUrl.protocol !== 'file:') {
// update metas setLiveReload.parentNode.remove();
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;
} else { } else {
$('.meta-author').parentNode.remove(); setLiveReload.addEventListener('change', () => {
} liveReload = setLiveReload.checked;
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');
} }
} }