Bug 919978 - Make StyleEditor use CodeMirror, r=anton, msucan
This commit is contained in:
@@ -12,6 +12,10 @@ const EXPAND_TAB = "devtools.editor.expandtab";
|
||||
const L10N_BUNDLE = "chrome://browser/locale/devtools/sourceeditor.properties";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
// Maximum allowed margin (in number of lines) from top or bottom of the editor
|
||||
// while shifting to a line which was initially out of view.
|
||||
const MAX_VERTICAL_OFFSET = 3;
|
||||
|
||||
const promise = require("sdk/core/promise");
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
|
||||
@@ -34,6 +38,7 @@ const CM_SCRIPTS = [
|
||||
"chrome://browser/content/devtools/codemirror/searchcursor.js",
|
||||
"chrome://browser/content/devtools/codemirror/search.js",
|
||||
"chrome://browser/content/devtools/codemirror/matchbrackets.js",
|
||||
"chrome://browser/content/devtools/codemirror/closebrackets.js",
|
||||
"chrome://browser/content/devtools/codemirror/comment.js",
|
||||
"chrome://browser/content/devtools/codemirror/javascript.js",
|
||||
"chrome://browser/content/devtools/codemirror/xml.js",
|
||||
@@ -59,7 +64,6 @@ const CM_IFRAME =
|
||||
const CM_MAPPING = [
|
||||
"focus",
|
||||
"hasFocus",
|
||||
"setCursor",
|
||||
"getCursor",
|
||||
"somethingSelected",
|
||||
"setSelection",
|
||||
@@ -78,6 +82,8 @@ const CM_JUMP_DIALOG = [
|
||||
+ " <input type=text style='width: 10em'/>"
|
||||
];
|
||||
|
||||
const { cssProperties, cssValues, cssColors } = getCSSKeywords();
|
||||
|
||||
const editors = new WeakMap();
|
||||
|
||||
Editor.modes = {
|
||||
@@ -192,7 +198,21 @@ Editor.prototype = {
|
||||
CM_SCRIPTS.forEach((url) =>
|
||||
Services.scriptloader.loadSubScript(url, win, "utf8"));
|
||||
|
||||
// Create a CodeMirror instance add support for context menus and
|
||||
// Replace the propertyKeywords, colorKeywords and valueKeywords
|
||||
// properties of the CSS MIME type with the values provided by Gecko.
|
||||
let cssSpec = win.CodeMirror.resolveMode("text/css");
|
||||
cssSpec.propertyKeywords = cssProperties;
|
||||
cssSpec.colorKeywords = cssColors;
|
||||
cssSpec.valueKeywords = cssValues;
|
||||
win.CodeMirror.defineMIME("text/css", cssSpec);
|
||||
|
||||
let scssSpec = win.CodeMirror.resolveMode("text/x-scss");
|
||||
scssSpec.propertyKeywords = cssProperties;
|
||||
scssSpec.colorKeywords = cssColors;
|
||||
scssSpec.valueKeywords = cssValues;
|
||||
win.CodeMirror.defineMIME("text/x-scss", scssSpec);
|
||||
|
||||
// Create a CodeMirror instance add support for context menus,
|
||||
// overwrite the default controller (otherwise items in the top and
|
||||
// context menus won't work).
|
||||
|
||||
@@ -434,6 +454,67 @@ Editor.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the first visible line number in the editor.
|
||||
*/
|
||||
getFirstVisibleLine: function () {
|
||||
let cm = editors.get(this);
|
||||
return cm.lineAtHeight(0, "local");
|
||||
},
|
||||
|
||||
/**
|
||||
* Scrolls the view such that the given line number is the first visible line.
|
||||
*/
|
||||
setFirstVisibleLine: function (line) {
|
||||
let cm = editors.get(this);
|
||||
let { top } = cm.charCoords({line: line, ch: 0}, "local");
|
||||
cm.scrollTo(0, top);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the cursor to the specified {line, ch} position with an additional
|
||||
* option to align the line at the "top", "center" or "bottom" of the editor
|
||||
* with "top" being default value.
|
||||
*/
|
||||
setCursor: function ({line, ch}, align) {
|
||||
let cm = editors.get(this);
|
||||
this.alignLine(line, align);
|
||||
cm.setCursor({line: line, ch: ch});
|
||||
},
|
||||
|
||||
/**
|
||||
* Aligns the provided line to either "top", "center" or "bottom" of the
|
||||
* editor view with a maximum margin of MAX_VERTICAL_OFFSET lines from top or
|
||||
* bottom.
|
||||
*/
|
||||
alignLine: function(line, align) {
|
||||
let cm = editors.get(this);
|
||||
let from = cm.lineAtHeight(0, "page");
|
||||
let to = cm.lineAtHeight(cm.getWrapperElement().clientHeight, "page");
|
||||
let linesVisible = to - from;
|
||||
let halfVisible = Math.round(linesVisible/2);
|
||||
|
||||
// If the target line is in view, skip the vertical alignment part.
|
||||
if (line <= to && line >= from) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Setting the offset so that the line always falls in the upper half
|
||||
// of visible lines (lower half for bottom aligned).
|
||||
// MAX_VERTICAL_OFFSET is the maximum allowed value.
|
||||
let offset = Math.min(halfVisible, MAX_VERTICAL_OFFSET);
|
||||
|
||||
let topLine = {
|
||||
"center": Math.max(line - halfVisible, 0),
|
||||
"bottom": Math.max(line - linesVisible + offset, 0),
|
||||
"top": Math.max(line - offset, 0)
|
||||
}[align || "top"] || offset;
|
||||
|
||||
// Bringing down the topLine to total lines in the editor if exceeding.
|
||||
topLine = Math.min(topLine, this.lineCount());
|
||||
this.setFirstVisibleLine(topLine);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.container = null;
|
||||
this.config = null;
|
||||
@@ -452,6 +533,44 @@ CM_MAPPING.forEach(function (name) {
|
||||
};
|
||||
});
|
||||
|
||||
// Since Gecko already provide complete and up to date list of CSS property
|
||||
// names, values and color names, we compute them so that they can replace
|
||||
// the ones used in CodeMirror while initiating an editor object. This is done
|
||||
// here instead of the file codemirror/css.js so as to leave that file untouched
|
||||
// and easily upgradable.
|
||||
function getCSSKeywords() {
|
||||
function keySet(array) {
|
||||
var keys = {};
|
||||
for (var i = 0; i < array.length; ++i) {
|
||||
keys[array[i]] = true;
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
|
||||
.getService(Ci.inIDOMUtils);
|
||||
let cssProperties = domUtils.getCSSPropertyNames(domUtils.INCLUDE_ALIASES);
|
||||
let cssColors = {};
|
||||
let cssValues = {};
|
||||
cssProperties.forEach(property => {
|
||||
if (property.contains("color")) {
|
||||
domUtils.getCSSValuesForProperty(property).forEach(value => {
|
||||
cssColors[value] = true;
|
||||
});
|
||||
}
|
||||
else {
|
||||
domUtils.getCSSValuesForProperty(property).forEach(value => {
|
||||
cssValues[value] = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
return {
|
||||
cssProperties: keySet(cssProperties),
|
||||
cssValues: cssValues,
|
||||
cssColors: cssColors
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a controller object that can be used for
|
||||
* editor-specific commands such as find, jump to line,
|
||||
@@ -530,4 +649,4 @@ function controller(ed, view) {
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Editor;
|
||||
module.exports = Editor;
|
||||
|
||||
Reference in New Issue
Block a user