Editor: option to select CodeMirror CSS theme

This commit is contained in:
tophf 2015-04-11 13:28:25 +03:00
parent 38d8903f8d
commit bc6476bc52
5 changed files with 103 additions and 25 deletions

View File

@ -96,10 +96,18 @@
"message": "Tab size",
"description": "Label for the text box controlling tab size option for the style editor."
},
"cm_theme": {
"message": "Theme",
"description": "Label for the style editor's CSS theme."
},
"dbError": {
"message": "An error has occurred using the Stylish database. Would you like to visit a web page with possible solutions?",
"description": "Prompt when a DB error is encountered"
},
"default": {
"message": "default",
"description": "Default item in various lists"
},
"deleteStyleLabel": {
"message": "Delete",
"description": "Label for the button to delete a style"

View File

@ -392,3 +392,17 @@ function openURL(options) {
}
});
}
var codeMirrorThemes = [chrome.i18n.getMessage("default")];
chrome.runtime.getPackageDirectoryEntry(function(rootDir) {
rootDir.getDirectory("codemirror/theme", {create: false}, function(themeDir) {
themeDir.createReader().readEntries(function(entries) {
entries
.filter(function(entry) { return entry.isFile })
.sort(function(a, b) { return a.name < b.name ? -1 : 1 })
.forEach(function(entry) {
codeMirrorThemes.push(entry.name.replace(/\.css$/, ""));
});
});
});
});

View File

@ -276,12 +276,25 @@
#sections > *:not(h2) {
padding-left: 0.4rem;
}
.applies-type {
width: 30%;
}
}
@media(max-width:500px) {
#options {
-webkit-column-count: 1;
}
#options #tabSize-label {
position: static;
}
}
</style>
<link id="cm-theme" rel="stylesheet">
<script src="storage.js"></script>
<script src="messaging.js"></script>
<script src="localization.js"></script>
<script src="apply.js"></script>
<script src="edit.js"></script>
</head>
<body id="stylish-edit">
<div id="header">
@ -322,11 +335,14 @@
<label id="keyMap-label" for="editor.keyMap" i18n-text="cm_keyMap"></label>
<select data-option="keyMap" id="editor.keyMap"></select>
</div>
<div class="option aligned">
<label id="theme-label" for="editor.theme" i18n-text="cm_theme"></label>
<select data-option="theme" id="editor.theme"></select>
</div>
</section>
</div>
<section id="sections">
<h2><span id="sections-heading" i18n-text="styleSectionsTitle"></span><img id="sections-help" src="help.png" i18n-alt="helpAlt"></h2>
</section>
<script src="edit.js"></script>
</body>
</html>

87
edit.js
View File

@ -128,6 +128,7 @@ function initCodeMirror() {
matchBrackets: true,
lint: CodeMirror.lint.css,
keyMap: "sublime",
theme: "default",
extraKeys: {"Ctrl-Space": "autocomplete"}
}
mergeOptions(stylishOptions, CM.defaults);
@ -169,31 +170,70 @@ function initCodeMirror() {
});
}
// preload the theme so that CodeMirror can calculate its metrics in DOMContentLoaded->loadPrefs()
var theme = prefs.getPref("editor.theme");
var themes = chrome.extension.getBackgroundPage().codeMirrorThemes;
document.getElementById("cm-theme").href = themes.indexOf(theme) <= 0 ? "" : "codemirror/theme/" + theme + ".css";
// initialize global editor controls
document.getElementById("options").addEventListener("change", acmeEventListener, false);
var keymapControl = document.getElementById("editor.keyMap");
Object.keys(CodeMirror.keyMap).sort().forEach(function(map) {
keymapControl.appendChild(document.createElement("option")).textContent = map;
document.addEventListener("DOMContentLoaded", function() {
function concatOption(html, option) {
return html + "<option>" + option + "</option>";
}
document.getElementById("editor.theme").innerHTML = themes.reduce(concatOption, "");
document.getElementById("editor.keyMap").innerHTML = Object.keys(CM.keyMap).sort().reduce(concatOption, "");
var controlPrefs = {};
document.querySelectorAll("#options *[data-option][id^='editor.']").forEach(function(option) {
controlPrefs[option.id] = CM.defaults[option.dataset.option];
});
document.getElementById("options").addEventListener("change", acmeEventListener, false);
loadPrefs(controlPrefs);
});
var controlPrefs = {},
controlOptions = ["smartIndent", "indentWithTabs", "tabSize", "keyMap", "lineWrapping"];
controlOptions.forEach(function(option) {
controlPrefs["editor." + option] = CM.defaults[option];
});
loadPrefs(controlPrefs);
}
initCodeMirror();
function acmeEventListener(event) {
var option = event.target.dataset.option;
console.log("acmeEventListener heard %s on %s", event.type, event.target.id);
if (!option) console.error("acmeEventListener: no 'cm_option' %O", event.target);
else CodeMirror.setOption(option, event.target[isCheckbox(event.target) ? "checked" : "value"]);
if ("tabSize" === option) CodeMirror.setOption("indentUnit", CodeMirror.getOption("tabSize"));
var el = event.target;
var option = el.dataset.option;
//console.log("acmeEventListener heard %s on %s", event.type, el.id);
if (!option) {
console.error("acmeEventListener: no 'cm_option' %O", el);
return;
}
var value = el.type == "checkbox" ? el.checked : el.value;
switch (option) {
case "tabSize":
CodeMirror.setOption("indentUnit", value);
break;
case "theme":
var themeLink = document.getElementById("cm-theme");
// use non-localized "default" internally
if (!value || el.selectedIndex <= 0) {
value = "default";
if (prefs.getPref(el.id) != value) {
prefs.setPref(el.id, value);
}
themeLink.href = "";
el.selectedIndex = 0;
break;
}
var url = chrome.extension.getURL("codemirror/theme/" + value + ".css");
if (themeLink.href == url) { // preloaded in initCodeMirror()
break;
}
// avoid flicker: wait for the second stylesheet to load, then apply the theme
document.head.insertAdjacentHTML("beforeend",
'<link id="cm-theme2" rel="stylesheet" href="' + url + '">');
(function() {
setTimeout(function() {
CodeMirror.setOption(option, value);
themeLink.remove();
document.getElementById("cm-theme2").id = "cm-theme";
}, 100);
})();
return;
}
CodeMirror.setOption(option, value);
}
// replace given textarea with the CodeMirror editor
@ -626,6 +666,10 @@ function initHooks() {
node.addEventListener("change", onChange);
node.addEventListener("input", onChange);
});
document.getElementById("to-mozilla").addEventListener("click", showMozillaFormat, false);
document.getElementById("to-mozilla-help").addEventListener("click", showToMozillaHelp, false);
document.getElementById("save-button").addEventListener("click", save, false);
document.getElementById("sections-help").addEventListener("click", showSectionHelp, false);
setupGlobalSearch();
setCleanGlobal();
@ -806,8 +850,3 @@ chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
}
}
});
document.getElementById("to-mozilla").addEventListener("click", showMozillaFormat, false);
document.getElementById("to-mozilla-help").addEventListener("click", showToMozillaHelp, false);
document.getElementById("save-button").addEventListener("click", save, false);
document.getElementById("sections-help").addEventListener("click", showSectionHelp, false);

View File

@ -178,6 +178,7 @@ var prefs = {
"editor.indentWithTabs": false,// smart indent with tabs
"editor.tabSize": 4, // tab width, in spaces
"editor.keyMap": "sublime", // keymap
"editor.theme": "default", // CSS theme
NO_DEFAULT_PREFERENCE: "No default preference for '%s'",
UNHANDLED_DATA_TYPE: "Default '%s' is of type '%s' - what should be done with it?",