WIP: install page + editor

This commit is contained in:
eight 2017-09-24 16:54:21 +08:00
parent 18fd15317e
commit 24cd85688f
10 changed files with 222 additions and 146 deletions

View File

@ -415,8 +415,13 @@
}
},
"installUpdateFromLabel": {
"message": "Install update from this URL",
"description": "Label for the checkbox to save current URL for update check"
"message": "Install update from $url$",
"description": "Label for the checkbox to save current URL for update check",
"placeholders": {
"url": {
"content": "$1"
}
}
},
"license": {
"message": "License",

View File

@ -59,6 +59,9 @@
<script src="vendor/codemirror/keymap/sublime.js"></script>
<script src="vendor/codemirror/keymap/emacs.js"></script>
<script src="vendor/codemirror/keymap/vim.js"></script>
<script src="/vendor-overwrites/codemirror/codemirror-default.js"></script>
<link rel="stylesheet" href="/vendor-overwrites/codemirror/codemirror-default.css">
<link id="cm-theme" rel="stylesheet">
<template data-id="appliesTo">

View File

@ -167,20 +167,10 @@ h2 .svg-icon, label .svg-icon {
margin-left: 0.25rem;
}
/* code */
.CodeMirror-hint:hover {
color: white;
background: #08f;
}
.code {
height: 10rem;
width: 40rem;
}
.CodeMirror {
border: solid #CCC 1px;
}
.CodeMirror-lint-mark-warning {
background: none;
}
.resize-grip-enabled .CodeMirror-scroll {
height: auto !important;;
position: absolute !important;
@ -198,22 +188,6 @@ h2 .svg-icon, label .svg-icon {
.resize-grip-enabled .CodeMirror-scrollbar-filler {
bottom: 7px; /* make space for resize-grip */
}
.CodeMirror-dialog {
-webkit-animation: highlight 3s ease-out;
}
.CodeMirror-focused {
outline: -webkit-focus-ring-color auto 5px;
outline-offset: -2px;
}
.CodeMirror-search-field {
width: 10em;
}
.CodeMirror-jump-field {
width: 5em;
}
.CodeMirror-search-hint {
color: #888;
}
body[data-match-highlight="token"] .cm-matchhighlight-approved .cm-matchhighlight,
body[data-match-highlight="token"] .CodeMirror-selection-highlight-scrollbar {
animation: fadein-match-highlighter 1s cubic-bezier(.97,.01,.42,.98);

View File

@ -164,111 +164,16 @@ function setCleanSection(section) {
function initCodeMirror() {
const CM = CodeMirror;
const isWindowsOS = navigator.appVersion.indexOf('Windows') > 0;
// lint.js is not loaded initially
// CodeMirror miserably fails on keyMap='' so let's ensure it's not
if (!prefs.get('editor.keyMap')) {
prefs.reset('editor.keyMap');
}
// default option values
Object.assign(CM.defaults, {
mode: 'css',
lineNumbers: true,
lineWrapping: true,
foldGutter: true,
gutters: [
'CodeMirror-linenumbers',
'CodeMirror-foldgutter',
...(prefs.get('editor.linter') ? ['CodeMirror-lint-markers'] : []),
],
matchBrackets: true,
highlightSelectionMatches: {showToken: /[#.\-\w]/, annotateScrollbar: true},
hintOptions: {},
lint: linterConfig.getForCodeMirror(),
lintReportDelay: prefs.get('editor.lintReportDelay'),
styleActiveLine: true,
theme: 'default',
keyMap: prefs.get('editor.keyMap'),
extraKeys: {
// independent of current keyMap
'Alt-Enter': 'toggleStyle',
'Alt-PageDown': 'nextEditor',
'Alt-PageUp': 'prevEditor'
}
}, prefs.get('editor.options'));
CM.defaults.lint = linterConfig.getForCodeMirror();
// additional commands
CM.commands.jumpToLine = jumpToLine;
CM.commands.nextEditor = cm => nextPrevEditor(cm, 1);
CM.commands.prevEditor = cm => nextPrevEditor(cm, -1);
CM.commands.save = save;
CM.commands.blockComment = cm => {
cm.blockComment(cm.getCursor('from'), cm.getCursor('to'), {fullLines: false});
};
CM.commands.toggleStyle = toggleStyle;
// 'basic' keymap only has basic keys by design, so we skip it
const extraKeysCommands = {};
Object.keys(CM.defaults.extraKeys).forEach(key => {
extraKeysCommands[CM.defaults.extraKeys[key]] = true;
});
if (!extraKeysCommands.jumpToLine) {
CM.keyMap.sublime['Ctrl-G'] = 'jumpToLine';
CM.keyMap.emacsy['Ctrl-G'] = 'jumpToLine';
CM.keyMap.pcDefault['Ctrl-J'] = 'jumpToLine';
CM.keyMap.macDefault['Cmd-J'] = 'jumpToLine';
}
if (!extraKeysCommands.autocomplete) {
// will be used by 'sublime' on PC via fallthrough
CM.keyMap.pcDefault['Ctrl-Space'] = 'autocomplete';
// OSX uses Ctrl-Space and Cmd-Space for something else
CM.keyMap.macDefault['Alt-Space'] = 'autocomplete';
// copied from 'emacs' keymap
CM.keyMap.emacsy['Alt-/'] = 'autocomplete';
// 'vim' and 'emacs' define their own autocomplete hotkeys
}
if (!extraKeysCommands.blockComment) {
CM.keyMap.sublime['Shift-Ctrl-/'] = 'blockComment';
}
if (isWindowsOS) {
// 'pcDefault' keymap on Windows should have F3/Shift-F3
if (!extraKeysCommands.findNext) {
CM.keyMap.pcDefault['F3'] = 'findNext';
}
if (!extraKeysCommands.findPrev) {
CM.keyMap.pcDefault['Shift-F3'] = 'findPrev';
}
// try to remap non-interceptable Ctrl-(Shift-)N/T/W hotkeys
['N', 'T', 'W'].forEach(char => {
[
{from: 'Ctrl-', to: ['Alt-', 'Ctrl-Alt-']},
// Note: modifier order in CM is S-C-A
{from: 'Shift-Ctrl-', to: ['Ctrl-Alt-', 'Shift-Ctrl-Alt-']}
].forEach(remap => {
const oldKey = remap.from + char;
Object.keys(CM.keyMap).forEach(keyMapName => {
const keyMap = CM.keyMap[keyMapName];
const command = keyMap[oldKey];
if (!command) {
return;
}
remap.to.some(newMod => {
const newKey = newMod + char;
if (!(newKey in keyMap)) {
delete keyMap[oldKey];
keyMap[newKey] = command;
return true;
}
});
});
});
});
}
// user option values
CM.getOption = o => CodeMirror.defaults[o];
CM.setOption = (o, v) => {
@ -278,8 +183,6 @@ function initCodeMirror() {
});
};
CM.modeURL = '/vendor/codemirror/mode/%N/%N.js';
CM.prototype.getSection = function () {
return this.display.wrapper.parentNode;
};

View File

@ -6,11 +6,6 @@
'use strict';
function createSourceEditor(style) {
const MODE = {
stylus: 'stylus',
uso: 'css'
};
// style might be an object reference to background page
style = deepCopy(style);
@ -403,10 +398,9 @@ function createSourceEditor(style) {
$('#enabled').checked = style.enabled;
$('#url').href = style.url;
const {usercssData: {preprocessor}} = style;
cm.setOption('mode', MODE[preprocessor] || 'css');
CodeMirror.autoLoadMode(cm, MODE[preprocessor] || 'css');
cm.setPreprocessor(preprocessor);
// beautify only works with regular CSS
$('#beautify').disabled = MODE[preprocessor] && MODE[preprocessor] !== 'css';
$('#beautify').disabled = cm.getOption('mode') !== 'css';
updateTitle();
}

View File

@ -10,16 +10,17 @@ body {
.container {
display: flex;
min-height: 100vh;
height: 100vh;
align-items: stretch;
}
.header {
width: 280px;
flex: 0 0 280px;
padding: 15px;
border-right: 1px dashed #aaa;
box-shadow: 0 0 50px -18px black;
overflow-wrap: break-word;
overflow: auto;
}
.header > :first-child {
@ -51,8 +52,8 @@ h1 small {
}
.actions label {
width: fit-content;
width: -moz-fit-content;
max-width: fit-content;
max-width: -moz-fit-content;
display: flex;
align-items: center;
margin: 0.5em 0;
@ -60,6 +61,11 @@ h1 small {
.actions label input {
margin: 0 0.5em 0 0;
flex: 0 0 auto;
}
.actions label span {
min-width: 0;
}
.external {
@ -75,7 +81,13 @@ h1 small {
}
.main {
flex-grow: 1;
flex: 1 1 auto;
overflow: hidden;
overflow-wrap: break-word;
min-width: 0;
}
.main .code,
.main .CodeMirror {
height: 100%;
}

View File

@ -6,13 +6,44 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Loading...</title>
<link rel="stylesheet" href="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="/vendor/node-semver/semver.js"></script>
<!-- FIXME: do we need all of these? -->
<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>
<script src="/vendor-overwrites/codemirror/codemirror-default.js"></script>
<link rel="stylesheet" href="/vendor-overwrites/codemirror/codemirror-default.css">
<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-overwrites/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/addon/mode/loadmode.js"></script>
</head>
<body>
<div class="container">
@ -21,7 +52,7 @@
<button class="install" i18n-text="installButton"></button>
<label class="set-update-url">
<input type="checkbox">
<span i18n-text="installUpdateFromLabel"></span>
<span></span>
</label>
</div>
<h1>

View File

@ -13,10 +13,18 @@
port.onMessage.addListener(msg => {
switch (msg.method) {
case 'getSourceCodeResponse':
if (msg.error) {
alert(msg.error);
} else {
initSourceCode(msg.sourceCode);
}
break;
}
});
port.onDisconnect.addListener(() => {
// FIXME: Firefox: 1) window.close doesn't work. 2) onDisconnect is fired only if the tab is closed.
window.close();
});
const cm = CodeMirror.fromTextArea($('.code textarea'), {readOnly: true});
@ -38,11 +46,11 @@
.then(result => {
$$('.warning')
.forEach(el => el.remove());
$('button.install').textContent = 'Installed';
$('button.install').disabled = true;
$('button.install').classList.add('installed');
$('.set-update-url').disabled = true;
$('.set-update-url-label').title = result.updateUrl ?
$('.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}));
})
@ -76,6 +84,7 @@
const dupData = dup && dup.usercssData;
const versionTest = dup && semverCompare(data.version, dupData.version);
// update UI
if (versionTest < 0) {
$('.actions').parentNode.insertBefore(
$element({className: 'warning', textContent: t('versionInvalidOlder')}),
@ -94,8 +103,10 @@
}
};
// set updateUrl
const setUpdate = $('.set-update-url input[type=checkbox]');
const updateUrl = new URL(params.updateUrl);
$('.set-update-url > span').textContent = t('installUpdateFromLabel', updateUrl.href);
if (dup && dup.updateUrl === updateUrl.href) {
setUpdate.checked = true;
// there is no way to "unset" updateUrl, you can only overwrite it.
@ -112,6 +123,9 @@
}
};
// update editor
cm.setPreprocessor(data.preprocessor);
// update metas
document.title = data.name;

View File

@ -0,0 +1,26 @@
.CodeMirror-hint:hover {
color: white;
background: #08f;
}
.CodeMirror {
border: solid #CCC 1px;
}
.CodeMirror-lint-mark-warning {
background: none;
}
.CodeMirror-dialog {
-webkit-animation: highlight 3s ease-out;
}
.CodeMirror-focused {
outline: -webkit-focus-ring-color auto 5px;
outline-offset: -2px;
}
.CodeMirror-search-field {
width: 10em;
}
.CodeMirror-jump-field {
width: 5em;
}
.CodeMirror-search-hint {
color: #888;
}

View File

@ -0,0 +1,114 @@
/* global CodeMirror prefs */
'use strict';
(function () {
// CodeMirror miserably fails on keyMap='' so let's ensure it's not
if (!prefs.get('editor.keyMap')) {
prefs.reset('editor.keyMap');
}
const defaults = {
mode: 'css',
lineNumbers: true,
lineWrapping: true,
foldGutter: true,
gutters: [
'CodeMirror-linenumbers',
'CodeMirror-foldgutter',
...(prefs.get('editor.linter') ? ['CodeMirror-lint-markers'] : []),
],
matchBrackets: true,
highlightSelectionMatches: {showToken: /[#.\-\w]/, annotateScrollbar: true},
hintOptions: {},
lintReportDelay: prefs.get('editor.lintReportDelay'),
styleActiveLine: true,
theme: 'default',
keyMap: prefs.get('editor.keyMap'),
extraKeys: {
// independent of current keyMap
'Alt-Enter': 'toggleStyle',
'Alt-PageDown': 'nextEditor',
'Alt-PageUp': 'prevEditor'
}
};
Object.assign(CodeMirror.defaults, defaults, prefs.get('editor.options'));
CodeMirror.commands.blockComment = cm => {
cm.blockComment(cm.getCursor('from'), cm.getCursor('to'), {fullLines: false});
};
// 'basic' keymap only has basic keys by design, so we skip it
const extraKeysCommands = {};
Object.keys(CodeMirror.defaults.extraKeys).forEach(key => {
extraKeysCommands[CodeMirror.defaults.extraKeys[key]] = true;
});
if (!extraKeysCommands.jumpToLine) {
CodeMirror.keyMap.sublime['Ctrl-G'] = 'jumpToLine';
CodeMirror.keyMap.emacsy['Ctrl-G'] = 'jumpToLine';
CodeMirror.keyMap.pcDefault['Ctrl-J'] = 'jumpToLine';
CodeMirror.keyMap.macDefault['Cmd-J'] = 'jumpToLine';
}
if (!extraKeysCommands.autocomplete) {
// will be used by 'sublime' on PC via fallthrough
CodeMirror.keyMap.pcDefault['Ctrl-Space'] = 'autocomplete';
// OSX uses Ctrl-Space and Cmd-Space for something else
CodeMirror.keyMap.macDefault['Alt-Space'] = 'autocomplete';
// copied from 'emacs' keymap
CodeMirror.keyMap.emacsy['Alt-/'] = 'autocomplete';
// 'vim' and 'emacs' define their own autocomplete hotkeys
}
if (!extraKeysCommands.blockComment) {
CodeMirror.keyMap.sublime['Shift-Ctrl-/'] = 'blockComment';
}
if (navigator.appVersion.includes('Windows')) {
// 'pcDefault' keymap on Windows should have F3/Shift-F3
if (!extraKeysCommands.findNext) {
CodeMirror.keyMap.pcDefault['F3'] = 'findNext';
}
if (!extraKeysCommands.findPrev) {
CodeMirror.keyMap.pcDefault['Shift-F3'] = 'findPrev';
}
// try to remap non-interceptable Ctrl-(Shift-)N/T/W hotkeys
['N', 'T', 'W'].forEach(char => {
[
{from: 'Ctrl-', to: ['Alt-', 'Ctrl-Alt-']},
// Note: modifier order in CodeMirror is S-C-A
{from: 'Shift-Ctrl-', to: ['Ctrl-Alt-', 'Shift-Ctrl-Alt-']}
].forEach(remap => {
const oldKey = remap.from + char;
Object.keys(CodeMirror.keyMap).forEach(keyMapName => {
const keyMap = CodeMirror.keyMap[keyMapName];
const command = keyMap[oldKey];
if (!command) {
return;
}
remap.to.some(newMod => {
const newKey = newMod + char;
if (!(newKey in keyMap)) {
delete keyMap[oldKey];
keyMap[newKey] = command;
return true;
}
});
});
});
});
}
CodeMirror.modeURL = '/vendor/codemirror/mode/%N/%N.js';
const MODE = {
stylus: 'stylus',
uso: 'css'
};
CodeMirror.prototype.setPreprocessor = function(preprocessor) {
this.setOption('mode', MODE[preprocessor] || 'css');
CodeMirror.autoLoadMode(this, MODE[preprocessor] || 'css');
};
})();