Merge pull request #103 from tophf/editor-theme
Editor: option to select CodeMirror CSS theme
This commit is contained in:
commit
b6444c86ec
|
@ -96,10 +96,18 @@
|
||||||
"message": "Tab size",
|
"message": "Tab size",
|
||||||
"description": "Label for the text box controlling tab size option for the style editor."
|
"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": {
|
"dbError": {
|
||||||
"message": "An error has occurred using the Stylish database. Would you like to visit a web page with possible solutions?",
|
"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"
|
"description": "Prompt when a DB error is encountered"
|
||||||
},
|
},
|
||||||
|
"defaultTheme": {
|
||||||
|
"message": "default",
|
||||||
|
"description": "Default CodeMirror CSS theme option on the edit style page"
|
||||||
|
},
|
||||||
"deleteStyleLabel": {
|
"deleteStyleLabel": {
|
||||||
"message": "Delete",
|
"message": "Delete",
|
||||||
"description": "Label for the button to delete a style"
|
"description": "Label for the button to delete a style"
|
||||||
|
|
19
apply.js
19
apply.js
|
@ -1,7 +1,18 @@
|
||||||
|
requestStyles();
|
||||||
|
|
||||||
|
function requestStyles() {
|
||||||
|
// If this is a Stylish page (Edit Style or Manage Styles),
|
||||||
|
// we'll request the styles directly to minimize delay and flicker,
|
||||||
|
// unless Chrome still starts up and the background page isn't fully loaded.
|
||||||
|
// (Note: in this case the function may be invoked again from applyStyles.)
|
||||||
var request = {method: "getStyles", matchUrl: location.href, enabled: true, asHash: true};
|
var request = {method: "getStyles", matchUrl: location.href, enabled: true, asHash: true};
|
||||||
if (location.href.indexOf(chrome.extension.getURL("")) == 0) {
|
if (location.href.indexOf(chrome.extension.getURL("")) == 0) {
|
||||||
chrome.extension.getBackgroundPage().getStyles(request, applyStyles);
|
var bg = chrome.extension.getBackgroundPage();
|
||||||
} else {
|
if (bg && bg.getStyles) {
|
||||||
|
bg.getStyles(request, applyStyles);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
chrome.extension.sendMessage(request, applyStyles);
|
chrome.extension.sendMessage(request, applyStyles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +74,10 @@ function removeStyle(id, doc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyStyles(styleHash) {
|
function applyStyles(styleHash) {
|
||||||
|
if (!styleHash) { // Chrome is starting up
|
||||||
|
requestStyles();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ("disableAll" in styleHash) {
|
if ("disableAll" in styleHash) {
|
||||||
disableAll(styleHash.disableAll);
|
disableAll(styleHash.disableAll);
|
||||||
delete styleHash.disableAll;
|
delete styleHash.disableAll;
|
||||||
|
|
|
@ -392,3 +392,8 @@ function openURL(options) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var codeMirrorThemes;
|
||||||
|
getCodeMirrorThemes(function(themes) {
|
||||||
|
codeMirrorThemes = themes;
|
||||||
|
});
|
||||||
|
|
18
edit.html
18
edit.html
|
@ -276,12 +276,25 @@
|
||||||
#sections > *:not(h2) {
|
#sections > *:not(h2) {
|
||||||
padding-left: 0.4rem;
|
padding-left: 0.4rem;
|
||||||
}
|
}
|
||||||
|
.applies-type {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media(max-width:500px) {
|
||||||
|
#options {
|
||||||
|
-webkit-column-count: 1;
|
||||||
|
}
|
||||||
|
#options #tabSize-label {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link id="cm-theme" rel="stylesheet">
|
||||||
<script src="storage.js"></script>
|
<script src="storage.js"></script>
|
||||||
<script src="messaging.js"></script>
|
<script src="messaging.js"></script>
|
||||||
<script src="localization.js"></script>
|
<script src="localization.js"></script>
|
||||||
<script src="apply.js"></script>
|
<script src="apply.js"></script>
|
||||||
|
<script src="edit.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body id="stylish-edit">
|
<body id="stylish-edit">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
|
@ -322,11 +335,14 @@
|
||||||
<label id="keyMap-label" for="editor.keyMap" i18n-text="cm_keyMap"></label>
|
<label id="keyMap-label" for="editor.keyMap" i18n-text="cm_keyMap"></label>
|
||||||
<select data-option="keyMap" id="editor.keyMap"></select>
|
<select data-option="keyMap" id="editor.keyMap"></select>
|
||||||
</div>
|
</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>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<section id="sections">
|
<section id="sections">
|
||||||
<h2><span id="sections-heading" i18n-text="styleSectionsTitle"></span><img id="sections-help" src="help.png" i18n-alt="helpAlt"></h2>
|
<h2><span id="sections-heading" i18n-text="styleSectionsTitle"></span><img id="sections-help" src="help.png" i18n-alt="helpAlt"></h2>
|
||||||
</section>
|
</section>
|
||||||
<script src="edit.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
105
edit.js
105
edit.js
|
@ -128,6 +128,7 @@ function initCodeMirror() {
|
||||||
matchBrackets: true,
|
matchBrackets: true,
|
||||||
lint: CodeMirror.lint.css,
|
lint: CodeMirror.lint.css,
|
||||||
keyMap: "sublime",
|
keyMap: "sublime",
|
||||||
|
theme: "default",
|
||||||
extraKeys: {"Ctrl-Space": "autocomplete"}
|
extraKeys: {"Ctrl-Space": "autocomplete"}
|
||||||
}
|
}
|
||||||
mergeOptions(stylishOptions, CM.defaults);
|
mergeOptions(stylishOptions, CM.defaults);
|
||||||
|
@ -169,31 +170,80 @@ function initCodeMirror() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// preload the theme so that CodeMirror can calculate its metrics in DOMContentLoaded->loadPrefs()
|
||||||
|
var theme = prefs.getPref("editor.theme");
|
||||||
|
document.getElementById("cm-theme").href = theme == "default" ? "" : "codemirror/theme/" + theme + ".css";
|
||||||
|
|
||||||
// initialize global editor controls
|
// initialize global editor controls
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
function optionsHtmlFromArray(options) {
|
||||||
|
return options.map(function(opt) { return "<option>" + opt + "</option>"; }).join("");
|
||||||
|
}
|
||||||
|
var themeControl = document.getElementById("editor.theme");
|
||||||
|
var bg = chrome.extension.getBackgroundPage();
|
||||||
|
if (bg && bg.codeMirrorThemes) {
|
||||||
|
themeControl.innerHTML = optionsHtmlFromArray(bg.codeMirrorThemes);
|
||||||
|
} else {
|
||||||
|
// Chrome is starting up and shows our edit.html, but the background page isn't loaded yet
|
||||||
|
themeControl.innerHTML = optionsHtmlFromArray([theme == "default" ? t("defaultTheme") : theme]);
|
||||||
|
getCodeMirrorThemes(function(themes) {
|
||||||
|
themeControl.innerHTML = optionsHtmlFromArray(themes);
|
||||||
|
themeControl.selectedIndex = Math.max(0, themes.indexOf(theme));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
document.getElementById("editor.keyMap").innerHTML = optionsHtmlFromArray(Object.keys(CM.keyMap).sort());
|
||||||
|
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);
|
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;
|
|
||||||
});
|
|
||||||
|
|
||||||
var controlPrefs = {},
|
|
||||||
controlOptions = ["smartIndent", "indentWithTabs", "tabSize", "keyMap", "lineWrapping"];
|
|
||||||
controlOptions.forEach(function(option) {
|
|
||||||
controlPrefs["editor." + option] = CM.defaults[option];
|
|
||||||
});
|
|
||||||
loadPrefs(controlPrefs);
|
loadPrefs(controlPrefs);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
initCodeMirror();
|
initCodeMirror();
|
||||||
|
|
||||||
function acmeEventListener(event) {
|
function acmeEventListener(event) {
|
||||||
var option = event.target.dataset.option;
|
var el = event.target;
|
||||||
console.log("acmeEventListener heard %s on %s", event.type, event.target.id);
|
var option = el.dataset.option;
|
||||||
if (!option) console.error("acmeEventListener: no 'cm_option' %O", event.target);
|
//console.log("acmeEventListener heard %s on %s", event.type, el.id);
|
||||||
else CodeMirror.setOption(option, event.target[isCheckbox(event.target) ? "checked" : "value"]);
|
if (!option) {
|
||||||
|
console.error("acmeEventListener: no 'cm_option' %O", el);
|
||||||
if ("tabSize" === option) CodeMirror.setOption("indentUnit", CodeMirror.getOption("tabSize"));
|
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 || value == "default" || value == t("defaultTheme")) {
|
||||||
|
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
|
// replace given textarea with the CodeMirror editor
|
||||||
|
@ -598,12 +648,19 @@ function init() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// This is an edit
|
// This is an edit
|
||||||
chrome.extension.sendMessage({method: "getStyles", id: params.id}, function(styles) {
|
requestStyle();
|
||||||
|
function requestStyle() {
|
||||||
|
chrome.extension.sendMessage({method: "getStyles", id: params.id}, function callback(styles) {
|
||||||
|
if (!styles) { // Chrome is starting up and shows edit.html
|
||||||
|
requestStyle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
var style = styles[0];
|
var style = styles[0];
|
||||||
styleId = style.id;
|
styleId = style.id;
|
||||||
initWithStyle(style);
|
initWithStyle(style);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initWithStyle(style) {
|
function initWithStyle(style) {
|
||||||
document.getElementById("name").value = style.name;
|
document.getElementById("name").value = style.name;
|
||||||
|
@ -626,6 +683,10 @@ function initHooks() {
|
||||||
node.addEventListener("change", onChange);
|
node.addEventListener("change", onChange);
|
||||||
node.addEventListener("input", 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();
|
setupGlobalSearch();
|
||||||
setCleanGlobal();
|
setCleanGlobal();
|
||||||
|
@ -787,7 +848,6 @@ function getParams() {
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
|
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
|
||||||
var installed = document.getElementById("installed");
|
|
||||||
switch (request.method) {
|
switch (request.method) {
|
||||||
case "styleUpdated":
|
case "styleUpdated":
|
||||||
if (styleId == request.id) {
|
if (styleId == request.id) {
|
||||||
|
@ -806,8 +866,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);
|
|
||||||
|
|
10
health.js
10
health.js
|
@ -1,7 +1,11 @@
|
||||||
|
healthCheck();
|
||||||
|
|
||||||
|
function healthCheck() {
|
||||||
chrome.extension.sendMessage({method: "healthCheck"}, function(ok) {
|
chrome.extension.sendMessage({method: "healthCheck"}, function(ok) {
|
||||||
if (!ok) {
|
if (ok === undefined) { // Chrome is starting up
|
||||||
if (confirm(t("dbError"))) {
|
healthCheck();
|
||||||
|
} else if (!ok && confirm(t("dbError"))) {
|
||||||
window.open("http://userstyles.org/dberror");
|
window.open("http://userstyles.org/dberror");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,10 @@ loadPrefs({
|
||||||
});
|
});
|
||||||
|
|
||||||
function showStyles(styles) {
|
function showStyles(styles) {
|
||||||
|
if (!styles) { // Chrome is starting up
|
||||||
|
chrome.extension.sendMessage({method: "getStyles"}, showStyles);
|
||||||
|
return;
|
||||||
|
}
|
||||||
styles.sort(function(a, b) { return a.name.localeCompare(b.name)});
|
styles.sort(function(a, b) { return a.name.localeCompare(b.name)});
|
||||||
var installed = document.getElementById("installed");
|
var installed = document.getElementById("installed");
|
||||||
styles.map(createStyleElement).forEach(function(e) {
|
styles.map(createStyleElement).forEach(function(e) {
|
||||||
|
|
20
storage.js
20
storage.js
|
@ -178,6 +178,7 @@ var prefs = {
|
||||||
"editor.indentWithTabs": false,// smart indent with tabs
|
"editor.indentWithTabs": false,// smart indent with tabs
|
||||||
"editor.tabSize": 4, // tab width, in spaces
|
"editor.tabSize": 4, // tab width, in spaces
|
||||||
"editor.keyMap": "sublime", // keymap
|
"editor.keyMap": "sublime", // keymap
|
||||||
|
"editor.theme": "default", // CSS theme
|
||||||
|
|
||||||
NO_DEFAULT_PREFERENCE: "No default preference for '%s'",
|
NO_DEFAULT_PREFERENCE: "No default preference for '%s'",
|
||||||
UNHANDLED_DATA_TYPE: "Default '%s' is of type '%s' - what should be done with it?",
|
UNHANDLED_DATA_TYPE: "Default '%s' is of type '%s' - what should be done with it?",
|
||||||
|
@ -222,3 +223,22 @@ var prefs = {
|
||||||
},
|
},
|
||||||
removePref: function(key) { setPref(key, undefined) }
|
removePref: function(key) { setPref(key, undefined) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getCodeMirrorThemes(callback) {
|
||||||
|
chrome.runtime.getPackageDirectoryEntry(function(rootDir) {
|
||||||
|
rootDir.getDirectory("codemirror/theme", {create: false}, function(themeDir) {
|
||||||
|
themeDir.createReader().readEntries(function(entries) {
|
||||||
|
var themes = [chrome.i18n.getMessage("defaultTheme")];
|
||||||
|
entries
|
||||||
|
.filter(function(entry) { return entry.isFile })
|
||||||
|
.sort(function(a, b) { return a.name < b.name ? -1 : 1 })
|
||||||
|
.forEach(function(entry) {
|
||||||
|
themes.push(entry.name.replace(/\.css$/, ""));
|
||||||
|
});
|
||||||
|
if (callback) {
|
||||||
|
callback(themes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user