diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 70b3753d..7f33807f 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -72,6 +72,26 @@ "message": "Checking...", "description": "Text to display when checking a style for an update" }, + "cm_indentWithTabs": { + "message": "Use tabs with smart indentation", + "description": "Label for the checkbox controlling tabs with smart indentation option for the style editor." + }, + "cm_keyMap": { + "message": "Keymap", + "description": "Label for the drop-down list controlling the keymap for the style editor." + }, + "cm_lineWrapping": { + "message": "Word wrap", + "description": "Label for the checkbox controlling word wrap option for the style editor." + }, + "cm_smartIndent": { + "message": "Use smart indentation", + "description": "Label for the checkbox controlling smart indentation option for the style editor." + }, + "cm_tabSize": { + "message": "Tab size", + "description": "Label for the text box controlling tab size option for the style editor." + }, "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" @@ -169,10 +189,6 @@ "message": "Show number of styles active for the current site on the toolbar button", "description": "Label for the checkbox controlling toolbar badge text." }, - "prefSmartIndent": { - "message": "Use smart indentation", - "description": "Label for the checkbox controlling smart indentation option for the style editor." - }, "sectionAdd": { "message": "Add another section", "description": "Label for the button to add a section" diff --git a/edit.html b/edit.html index 24841df8..6be58b2e 100644 --- a/edit.html +++ b/edit.html @@ -173,6 +173,16 @@ } } + + /* editor options */ + [type="number"] { + max-width: 2.8em; + text-align: right; + } + table, input, select { + font-size: inherit; + } + table td:first-child {min-width: 60px} @@ -191,7 +201,34 @@

- + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + +
diff --git a/edit.js b/edit.js index a0570dca..90c55157 100644 --- a/edit.js +++ b/edit.js @@ -12,11 +12,13 @@ appliesToEverythingTemplate.innerHTML = t("appliesToEverything") + ' '; +var editors = []; // array of all CodeMirror instances +function initCodeMirror() { + var CM = CodeMirror; -var editors = [] // array of all CodeMirror instances -// replace given textarea with the CodeMirror editor -function setupCodeMirror(textarea) { - var cm = CodeMirror.fromTextArea(textarea, { + // default option values + var userOptions = prefs.getPref("editor.options"); + var stylishOptions = { mode: 'css', lineNumbers: true, lineWrapping: true, @@ -24,26 +26,70 @@ function setupCodeMirror(textarea) { gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"], matchBrackets: true, lint: CodeMirror.lint.css, - smartIndent: prefs.getPref("smart-indent"), keyMap: "sublime", extraKeys: {"Ctrl-Space": "autocomplete"} + }; + mergeOptions(stylishOptions, CM.defaults); + mergeOptions(userOptions, CM.defaults); + + function mergeOptions(source, target) { + for (var key in source) target[key] = source[key]; + return target; + } + + // additional commands + var cc = CM.commands; + cc.jumpToLine = jumpToLine; + cc.nextBuffer = nextBuffer; + cc.prevBuffer = prevBuffer; + // cc.save = save; + + // user option values + CM.getOption = function (o) { + return CodeMirror.defaults[o]; + } + CM.setOption = function (o, v) { + CodeMirror.defaults[o] = v; + editors.forEach(function(editor) { + editor.setOption(o, v); + }); + } + + // 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; }); + + var controlPrefs = {}, + controlOptions = ["smartIndent", "indentWithTabs", "tabSize", "keyMap", "lineWrapping"]; + controlOptions.forEach(function(option) { + controlPrefs["editor." + option] = CM.defaults[option]; + tE(option + "-label", "cm_" + 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")); +} + +// replace given textarea with the CodeMirror editor +function setupCodeMirror(textarea) { + var cm = CodeMirror.fromTextArea(textarea); cm.addKeyMap({ - "Ctrl-G": function(cm) { - var cur = cm.getCursor(); - cm.openDialog(t('editGotoLine') + ': ', function(str) { - var m = str.match(/^\s*(\d+)(?:\s*:\s*(\d+))?\s*$/); - if (m) { - cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch); - } - }, {value: cur.line+1}); - }, - "Alt-PageDown": function(cm) { - editors[(editors.indexOf(cm) + 1) % editors.length].focus(); - }, - "Alt-PageUp": function(cm) { - editors[(editors.indexOf(cm) - 1 + editors.length) % editors.length].focus(); - } + "Ctrl-G": "jumpToLine", + "Alt-PageDown": "nextBuffer", + "Alt-PageUp": "prevBuffer" }); cm.lastChange = cm.changeGeneration(); cm.on("change", indicateCodeChange); @@ -325,11 +371,27 @@ function setupGlobalSearch() { CodeMirror.commands.findPrev = function(cm) { findNext(cm, true) } } +function jumpToLine(cm) { + var cur = cm.getCursor(); + cm.openDialog(t('editGotoLine') + ': ', function(str) { + var m = str.match(/^\s*(\d+)(?:\s*:\s*(\d+))?\s*$/); + if (m) { + cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch); + } + }, {value: cur.line+1}); +} + +function nextBuffer(cm) { + editors[(editors.indexOf(cm) + 1) % editors.length].focus(); +} +function prevBuffer(cm) { + editors[(editors.indexOf(cm) - 1 + editors.length) % editors.length].focus(); +} + window.addEventListener("load", init, false); function init() { tE("sections-help", "helpAlt", "alt"); - loadPrefs({"smart-indent": true}); var params = getParams(); if (!params.id) { // match should be 2 - one for the whole thing, one for the parentheses // This is an add @@ -554,10 +616,8 @@ chrome.extension.onMessage.addListener(function(request, sender, sendResponse) { } break; case "prefChanged": - if (request.prefName == "smart-indent") { - editors.forEach(function(editor) { - editor.setOption("smartIndent", request.value); - }); + if (request.prefName == "editor.smartIndent") { + CodeMirror.setOption("smartIndent", request.value); } } }); @@ -569,7 +629,6 @@ tE("save-button", "styleSaveLabel"); tE("cancel-button", "styleCancelEditLabel"); tE("sections-heading", "styleSectionsTitle"); tE("options-heading", "optionsHeading"); -tE("smart-indent-label", "prefSmartIndent"); document.getElementById("name").addEventListener("change", makeDirty, false); document.getElementById("enabled").addEventListener("change", makeDirty, false); diff --git a/storage.js b/storage.js index 29651754..cb9b8004 100644 --- a/storage.js +++ b/storage.js @@ -162,14 +162,20 @@ var prefs = { // defaults "openEditInWindow": false, // new editor opens in a own browser window "show-badge": true, // display text on popup menu icon - "smart-indent": true, // CodeMirror smart indent "popup.breadcrumbs": true, // display "New style" links as URL breadcrumbs "popup.breadcrumbs.usePath": false, // use URL path for "this URL" "popup.enabledFirst": true, // display enabled styles before disabled styles "manage.onlyEnabled": false, // display only enabled styles - "manage.onlyEdited": false,// display only styles created locally + "manage.onlyEdited": false, // display only styles created locally + + "editor.options": null, // CodeMirror.defaults.* + "editor.lineWrapping": true, // word wrap + "editor.smartIndent": true, // "smart" indent + "editor.indentWithTabs": false,// smart indent with tabs + "editor.tabSize": 4, // tab width, in spaces + "editor.keyMap": "sublime", // keymap NO_DEFAULT_PREFERENCE: "No default preference for '%s'", UNHANDLED_DATA_TYPE: "Default '%s' is of type '%s' - what should be done with it?",