From bc6476bc523496d87326e2d79c2cb28c26485521 Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 11 Apr 2015 13:28:25 +0300 Subject: [PATCH] Editor: option to select CodeMirror CSS theme --- _locales/en/messages.json | 8 ++++ background.js | 14 +++++++ edit.html | 18 +++++++- edit.js | 87 ++++++++++++++++++++++++++++----------- storage.js | 1 + 5 files changed, 103 insertions(+), 25 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index bf57d82a..4ea59264 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -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" diff --git a/background.js b/background.js index fe199f13..2044a0d6 100644 --- a/background.js +++ b/background.js @@ -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$/, "")); + }); + }); + }); +}); diff --git a/edit.html b/edit.html index 60f6100f..f26b2521 100644 --- a/edit.html +++ b/edit.html @@ -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; + } } + + +
+ + +

- diff --git a/edit.js b/edit.js index 469213f6..83198ca5 100644 --- a/edit.js +++ b/edit.js @@ -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 + ""; + } + 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", + ''); + (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); diff --git a/storage.js b/storage.js index a60254d6..b44767ae 100644 --- a/storage.js +++ b/storage.js @@ -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?",