This commit is contained in:
Ryan VanderMeulen 2013-11-06 14:49:41 -05:00
Родитель 438d08b2de b39e616813
Коммит 57c88ce89f
27 изменённых файлов: 1271 добавлений и 240 удалений

Просмотреть файл

@ -104,7 +104,12 @@ Selection.prototype = {
this.emit("pseudoclass");
}
if (detached) {
this.emit("detached", parentNode ? parentNode.rawNode() : null);
let rawNode = null;
if (parentNode && parentNode.isLocal_toBeDeprecated()) {
rawNode = parentNode.rawNode();
}
this.emit("detached", rawNode, null);
this.emit("detached-front", parentNode);
}
},
@ -156,7 +161,10 @@ Selection.prototype = {
setNodeFront: function(value, reason="unknown") {
this.reason = reason;
if (value !== this._nodeFront) {
let rawValue = value ? value.rawNode() : value;
let rawValue = null;
if (value && value.isLocal_toBeDeprecated()) {
rawValue = value.rawNode();
}
this.emit("before-new-node", rawValue, reason);
this.emit("before-new-node-front", value, reason);
let previousNode = this._node;
@ -208,7 +216,10 @@ Selection.prototype = {
// As long as there are still tools going around
// accessing node.rawNode, this needs to stay.
let rawNode = node.rawNode();
let rawNode = null;
if (node.isLocal_toBeDeprecated()) {
rawNode = node.rawNode();
}
if (rawNode) {
try {
let doc = this.document;

Просмотреть файл

@ -35,6 +35,7 @@ browser.jar:
content/browser/devtools/codemirror/xml.js (sourceeditor/codemirror/xml.js)
content/browser/devtools/codemirror/css.js (sourceeditor/codemirror/css.js)
content/browser/devtools/codemirror/htmlmixed.js (sourceeditor/codemirror/htmlmixed.js)
content/browser/devtools/codemirror/clike.js (sourceeditor/codemirror/clike.js)
content/browser/devtools/codemirror/activeline.js (sourceeditor/codemirror/activeline.js)
content/browser/devtools/codemirror/matchbrackets.js (sourceeditor/codemirror/matchbrackets.js)
content/browser/devtools/codemirror/closebrackets.js (sourceeditor/codemirror/closebrackets.js)

Просмотреть файл

@ -1570,7 +1570,9 @@ function ElementEditor(aContainer, aNode) {
// Create the main editor
this.template("element", this);
this.rawNode = aNode.rawNode();
if (aNode.isLocal_toBeDeprecated()) {
this.rawNode = aNode.rawNode();
}
// Make the tag name editable (unless this is a remote node or
// a document element)

Просмотреть файл

@ -38,7 +38,6 @@ const SHADERS_AUTOGROW_ITEMS = 4;
const GUTTER_ERROR_PANEL_OFFSET_X = 7; // px
const GUTTER_ERROR_PANEL_DELAY = 100; // ms
const DEFAULT_EDITOR_CONFIG = {
mode: Editor.modes.text,
gutters: ["errors"],
lineNumbers: true,
showAnnotationRuler: true
@ -389,6 +388,7 @@ let ShadersEditorsView = {
// in the ether of a resolved promise's value.
let parent = $("#" + type +"-editor");
let editor = new Editor(DEFAULT_EDITOR_CONFIG);
editor.config.mode = Editor.modes[type];
editor.appendTo(parent).then(() => deferred.resolve(editor));
return deferred.promise;

Просмотреть файл

@ -15,6 +15,7 @@ To confirm the functionality run mochitests for the following components:
* scratchpad
* debugger
* styleditor
* netmonitor
The sourceeditor component contains imported CodeMirror tests [3]. Some
tests were commented out because we don't use that functionality within
@ -38,7 +39,10 @@ in the LICENSE file:
* comment.js
* dialog/dialog.css
* dialog/dialog.js
* xml.js
* css.js
* javascript.js
* clike.js
* matchbrackets.js
* closebrackets.js
* search/match-highlighter.js

Просмотреть файл

@ -0,0 +1,362 @@
CodeMirror.defineMode("clike", function(config, parserConfig) {
var indentUnit = config.indentUnit,
statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
dontAlignCalls = parserConfig.dontAlignCalls,
keywords = parserConfig.keywords || {},
builtin = parserConfig.builtin || {},
blockKeywords = parserConfig.blockKeywords || {},
atoms = parserConfig.atoms || {},
hooks = parserConfig.hooks || {},
multiLineStrings = parserConfig.multiLineStrings;
var isOperatorChar = /[+\-*&%=<>!?|\/]/;
var curPunc;
function tokenBase(stream, state) {
var ch = stream.next();
if (hooks[ch]) {
var result = hooks[ch](stream, state);
if (result !== false) return result;
}
if (ch == '"' || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
curPunc = ch;
return null;
}
if (/\d/.test(ch)) {
stream.eatWhile(/[\w\.]/);
return "number";
}
if (ch == "/") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
}
if (stream.eat("/")) {
stream.skipToEnd();
return "comment";
}
}
if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return "operator";
}
stream.eatWhile(/[\w\$_]/);
var cur = stream.current();
if (keywords.propertyIsEnumerable(cur)) {
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
return "keyword";
}
if (builtin.propertyIsEnumerable(cur)) {
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
return "builtin";
}
if (atoms.propertyIsEnumerable(cur)) return "atom";
return "variable";
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote && !escaped) {end = true; break;}
escaped = !escaped && next == "\\";
}
if (end || !(escaped || multiLineStrings))
state.tokenize = null;
return "string";
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = null;
break;
}
maybeEnd = (ch == "*");
}
return "comment";
}
function Context(indented, column, type, align, prev) {
this.indented = indented;
this.column = column;
this.type = type;
this.align = align;
this.prev = prev;
}
function pushContext(state, col, type) {
var indent = state.indented;
if (state.context && state.context.type == "statement")
indent = state.context.indented;
return state.context = new Context(indent, col, type, null, state.context);
}
function popContext(state) {
var t = state.context.type;
if (t == ")" || t == "]" || t == "}")
state.indented = state.context.indented;
return state.context = state.context.prev;
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: null,
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
indented: 0,
startOfLine: true
};
},
token: function(stream, state) {
var ctx = state.context;
if (stream.sol()) {
if (ctx.align == null) ctx.align = false;
state.indented = stream.indentation();
state.startOfLine = true;
}
if (stream.eatSpace()) return null;
curPunc = null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style == "comment" || style == "meta") return style;
if (ctx.align == null) ctx.align = true;
if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state);
else if (curPunc == "{") pushContext(state, stream.column(), "}");
else if (curPunc == "[") pushContext(state, stream.column(), "]");
else if (curPunc == "(") pushContext(state, stream.column(), ")");
else if (curPunc == "}") {
while (ctx.type == "statement") ctx = popContext(state);
if (ctx.type == "}") ctx = popContext(state);
while (ctx.type == "statement") ctx = popContext(state);
}
else if (curPunc == ctx.type) popContext(state);
else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement"))
pushContext(state, stream.column(), "statement");
state.startOfLine = false;
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
var closing = firstChar == ctx.type;
if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
else if (ctx.align && (!dontAlignCalls || ctx.type != ")")) return ctx.column + (closing ? 0 : 1);
else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit;
else return ctx.indented + (closing ? 0 : indentUnit);
},
electricChars: "{}",
blockCommentStart: "/*",
blockCommentEnd: "*/",
lineComment: "//",
fold: "brace"
};
});
(function() {
function words(str) {
var obj = {}, words = str.split(" ");
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}
var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
"double static else struct entry switch extern typedef float union for unsigned " +
"goto while enum void const signed volatile";
function cppHook(stream, state) {
if (!state.startOfLine) return false;
for (;;) {
if (stream.skipTo("\\")) {
stream.next();
if (stream.eol()) {
state.tokenize = cppHook;
break;
}
} else {
stream.skipToEnd();
state.tokenize = null;
break;
}
}
return "meta";
}
// C#-style strings where "" escapes a quote.
function tokenAtString(stream, state) {
var next;
while ((next = stream.next()) != null) {
if (next == '"' && !stream.eat('"')) {
state.tokenize = null;
break;
}
}
return "string";
}
function mimes(ms, mode) {
for (var i = 0; i < ms.length; ++i) CodeMirror.defineMIME(ms[i], mode);
}
mimes(["text/x-csrc", "text/x-c", "text/x-chdr"], {
name: "clike",
keywords: words(cKeywords),
blockKeywords: words("case do else for if switch while struct"),
atoms: words("null"),
hooks: {"#": cppHook}
});
mimes(["text/x-c++src", "text/x-c++hdr"], {
name: "clike",
keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
"static_cast typeid catch operator template typename class friend private " +
"this using const_cast inline public throw virtual delete mutable protected " +
"wchar_t"),
blockKeywords: words("catch class do else finally for if struct switch try while"),
atoms: words("true false null"),
hooks: {"#": cppHook}
});
CodeMirror.defineMIME("text/x-java", {
name: "clike",
keywords: words("abstract assert boolean break byte case catch char class const continue default " +
"do double else enum extends final finally float for goto if implements import " +
"instanceof int interface long native new package private protected public " +
"return short static strictfp super switch synchronized this throw throws transient " +
"try void volatile while"),
blockKeywords: words("catch class do else finally for if switch try while"),
atoms: words("true false null"),
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
return "meta";
}
}
});
CodeMirror.defineMIME("text/x-csharp", {
name: "clike",
keywords: words("abstract as base break case catch checked class const continue" +
" default delegate do else enum event explicit extern finally fixed for" +
" foreach goto if implicit in interface internal is lock namespace new" +
" operator out override params private protected public readonly ref return sealed" +
" sizeof stackalloc static struct switch this throw try typeof unchecked" +
" unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
" global group into join let orderby partial remove select set value var yield"),
blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
" Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" +
" UInt64 bool byte char decimal double short int long object" +
" sbyte float string ushort uint ulong"),
atoms: words("true false null"),
hooks: {
"@": function(stream, state) {
if (stream.eat('"')) {
state.tokenize = tokenAtString;
return tokenAtString(stream, state);
}
stream.eatWhile(/[\w\$_]/);
return "meta";
}
}
});
CodeMirror.defineMIME("text/x-scala", {
name: "clike",
keywords: words(
/* scala */
"abstract case catch class def do else extends false final finally for forSome if " +
"implicit import lazy match new null object override package private protected return " +
"sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
"<% >: # @ " +
/* package scala */
"assert assume require print println printf readLine readBoolean readByte readShort " +
"readChar readInt readLong readFloat readDouble " +
"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
"Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
/* package java.lang */
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
),
blockKeywords: words("catch class do else finally for forSome if match switch try while"),
atoms: words("true false null"),
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
return "meta";
}
}
});
mimes(["x-shader/x-vertex", "x-shader/x-fragment"], {
name: "clike",
keywords: words("float int bool void " +
"vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
"mat2 mat3 mat4 " +
"sampler1D sampler2D sampler3D samplerCube " +
"sampler1DShadow sampler2DShadow" +
"const attribute uniform varying " +
"break continue discard return " +
"for while do if else struct " +
"in out inout"),
blockKeywords: words("for while do if else struct"),
builtin: words("radians degrees sin cos tan asin acos atan " +
"pow exp log exp2 sqrt inversesqrt " +
"abs sign floor ceil fract mod min max clamp mix step smootstep " +
"length distance dot cross normalize ftransform faceforward " +
"reflect refract matrixCompMult " +
"lessThan lessThanEqual greaterThan greaterThanEqual " +
"equal notEqual any all not " +
"texture1D texture1DProj texture1DLod texture1DProjLod " +
"texture2D texture2DProj texture2DLod texture2DProjLod " +
"texture3D texture3DProj texture3DLod texture3DProjLod " +
"textureCube textureCubeLod " +
"shadow1D shadow2D shadow1DProj shadow2DProj " +
"shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
"dFdx dFdy fwidth " +
"noise1 noise2 noise3 noise4"),
atoms: words("true false " +
"gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
"gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
"gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
"gl_FogCoord " +
"gl_Position gl_PointSize gl_ClipVertex " +
"gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
"gl_TexCoord gl_FogFragCoord " +
"gl_FragCoord gl_FrontFacing " +
"gl_FragColor gl_FragData gl_FragDepth " +
"gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
"gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
"gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
"gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
"gl_ProjectionMatrixInverseTranspose " +
"gl_ModelViewProjectionMatrixInverseTranspose " +
"gl_TextureMatrixInverseTranspose " +
"gl_NormalScale gl_DepthRange gl_ClipPlane " +
"gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
"gl_FrontLightModelProduct gl_BackLightModelProduct " +
"gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
"gl_FogParameters " +
"gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
"gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
"gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
"gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
"gl_MaxDrawBuffers"),
hooks: {"#": cppHook}
});
}());

Просмотреть файл

@ -46,6 +46,7 @@ const CM_SCRIPTS = [
"chrome://browser/content/devtools/codemirror/xml.js",
"chrome://browser/content/devtools/codemirror/css.js",
"chrome://browser/content/devtools/codemirror/htmlmixed.js",
"chrome://browser/content/devtools/codemirror/clike.js",
"chrome://browser/content/devtools/codemirror/activeline.js"
];
@ -66,8 +67,9 @@ const CM_IFRAME =
const CM_MAPPING = [
"focus",
"hasFocus",
"getCursor",
"lineCount",
"somethingSelected",
"getCursor",
"setSelection",
"getSelection",
"replaceSelection",
@ -76,7 +78,6 @@ const CM_MAPPING = [
"clearHistory",
"openDialog",
"cursorCoords",
"lineCount",
"refresh"
];
@ -91,9 +92,11 @@ const editors = new WeakMap();
Editor.modes = {
text: { name: "text" },
js: { name: "javascript" },
html: { name: "htmlmixed" },
css: { name: "css" }
css: { name: "css" },
js: { name: "javascript" },
vs: { name: "x-shader/x-vertex" },
fs: { name: "x-shader/x-fragment" }
};
function ctrl(k) {
@ -250,63 +253,12 @@ Editor.prototype = {
},
/**
* Returns true if there's something to undo and false otherwise.
* Returns the currently active highlighting mode.
* See Editor.modes for the list of all suppoert modes.
*/
canUndo: function () {
getMode: function () {
let cm = editors.get(this);
return cm.historySize().undo > 0;
},
/**
* Returns true if there's something to redo and false otherwise.
*/
canRedo: function () {
let cm = editors.get(this);
return cm.historySize().redo > 0;
},
/**
* Calculates and returns one or more {line, ch} objects for
* a zero-based index who's value is relative to the start of
* the editor's text.
*
* If only one argument is given, this method returns a single
* {line,ch} object. Otherwise it returns an array.
*/
getPosition: function (...args) {
let cm = editors.get(this);
let res = args.map((ind) => cm.posFromIndex(ind));
return args.length === 1 ? res[0] : res;
},
/**
* The reverse of getPosition. Similarly to getPosition this
* method returns a single value if only one argument was given
* and an array otherwise.
*/
getOffset: function (...args) {
let cm = editors.get(this);
let res = args.map((pos) => cm.indexFromPos(pos));
return args.length > 1 ? res : res[0];
},
/**
* Returns text from the text area. If line argument is provided
* the method returns only that line.
*/
getText: function (line) {
let cm = editors.get(this);
return line == null ?
cm.getValue() : (cm.lineInfo(line) ? cm.lineInfo(line).text : "");
},
/**
* Replaces whatever is in the text area with the contents of
* the 'value' argument.
*/
setText: function (value) {
let cm = editors.get(this);
cm.setValue(value);
return cm.getOption("mode");
},
/**
@ -319,20 +271,26 @@ Editor.prototype = {
},
/**
* Returns the currently active highlighting mode.
* See Editor.modes for the list of all suppoert modes.
* Returns text from the text area. If line argument is provided
* the method returns only that line.
*/
getMode: function () {
getText: function (line) {
let cm = editors.get(this);
return cm.getOption("mode");
if (line == null)
return cm.getValue();
let info = cm.lineInfo(line);
return info ? cm.lineInfo(line).text : "";
},
/**
* True if the editor is in the read-only mode, false otherwise.
* Replaces whatever is in the text area with the contents of
* the 'value' argument.
*/
isReadOnly: function () {
setText: function (value) {
let cm = editors.get(this);
return cm.getOption("readOnly");
cm.setValue(value);
},
/**
@ -374,57 +332,6 @@ Editor.prototype = {
this.setCursor(this.getCursor());
},
/**
* Marks the contents as clean and returns the current
* version number.
*/
setClean: function () {
let cm = editors.get(this);
this.version = cm.changeGeneration();
return this.version;
},
/**
* Returns true if contents of the text area are
* clean i.e. no changes were made since the last version.
*/
isClean: function () {
let cm = editors.get(this);
return cm.isClean(this.version);
},
/**
* Displays a context menu at the point x:y. The first
* argument, container, should be a DOM node that contains
* a context menu element specified by the ID from
* config.contextMenu.
*/
showContextMenu: function (container, x, y) {
if (this.config.contextMenu == null)
return;
let popup = container.getElementById(this.config.contextMenu);
popup.openPopupAtScreen(x, y, true);
},
/**
* This method opens an in-editor dialog asking for a line to
* jump to. Once given, it changes cursor to that line.
*/
jumpToLine: function () {
this.openDialog(CM_JUMP_DIALOG, (line) =>
this.setCursor({ line: line - 1, ch: 0 }));
},
/**
* Returns a {line, ch} object that corresponds to the
* left, top coordinates.
*/
getPositionFromCoords: function (left, top) {
let cm = editors.get(this);
return cm.coordsChar({ left: left, top: top });
},
/**
* Extends the current selection to the position specified
* by the provided {line, ch} object.
@ -437,35 +344,6 @@ Editor.prototype = {
cm.setSelection(anchor, head);
},
/**
* Extends an instance of the Editor object with additional
* functions. Each function will be called with context as
* the first argument. Context is a {ed, cm} object where
* 'ed' is an instance of the Editor object and 'cm' is an
* instance of the CodeMirror object. Example:
*
* function hello(ctx, name) {
* let { cm, ed } = ctx;
* cm; // CodeMirror instance
* ed; // Editor instance
* name; // 'Mozilla'
* }
*
* editor.extend({ hello: hello });
* editor.hello('Mozilla');
*/
extend: function (funcs) {
Object.keys(funcs).forEach((name) => {
let cm = editors.get(this);
let ctx = { ed: this, cm: cm };
if (name === "initialize")
return void funcs[name](ctx);
this[name] = funcs[name].bind(null, ctx);
});
},
/**
* Gets the first visible line number in the editor.
*/
@ -641,6 +519,135 @@ Editor.prototype = {
cm.removeLineClass(line, "wrap", className);
},
/**
* Calculates and returns one or more {line, ch} objects for
* a zero-based index who's value is relative to the start of
* the editor's text.
*
* If only one argument is given, this method returns a single
* {line,ch} object. Otherwise it returns an array.
*/
getPosition: function (...args) {
let cm = editors.get(this);
let res = args.map((ind) => cm.posFromIndex(ind));
return args.length === 1 ? res[0] : res;
},
/**
* The reverse of getPosition. Similarly to getPosition this
* method returns a single value if only one argument was given
* and an array otherwise.
*/
getOffset: function (...args) {
let cm = editors.get(this);
let res = args.map((pos) => cm.indexFromPos(pos));
return args.length > 1 ? res : res[0];
},
/**
* Returns a {line, ch} object that corresponds to the
* left, top coordinates.
*/
getPositionFromCoords: function (left, top) {
let cm = editors.get(this);
return cm.coordsChar({ left: left, top: top });
},
/**
* Returns true if there's something to undo and false otherwise.
*/
canUndo: function () {
let cm = editors.get(this);
return cm.historySize().undo > 0;
},
/**
* Returns true if there's something to redo and false otherwise.
*/
canRedo: function () {
let cm = editors.get(this);
return cm.historySize().redo > 0;
},
/**
* Marks the contents as clean and returns the current
* version number.
*/
setClean: function () {
let cm = editors.get(this);
this.version = cm.changeGeneration();
return this.version;
},
/**
* Returns true if contents of the text area are
* clean i.e. no changes were made since the last version.
*/
isClean: function () {
let cm = editors.get(this);
return cm.isClean(this.version);
},
/**
* True if the editor is in the read-only mode, false otherwise.
*/
isReadOnly: function () {
let cm = editors.get(this);
return cm.getOption("readOnly");
},
/**
* Displays a context menu at the point x:y. The first
* argument, container, should be a DOM node that contains
* a context menu element specified by the ID from
* config.contextMenu.
*/
showContextMenu: function (container, x, y) {
if (this.config.contextMenu == null)
return;
let popup = container.getElementById(this.config.contextMenu);
popup.openPopupAtScreen(x, y, true);
},
/**
* This method opens an in-editor dialog asking for a line to
* jump to. Once given, it changes cursor to that line.
*/
jumpToLine: function () {
this.openDialog(CM_JUMP_DIALOG, (line) =>
this.setCursor({ line: line - 1, ch: 0 }));
},
/**
* Extends an instance of the Editor object with additional
* functions. Each function will be called with context as
* the first argument. Context is a {ed, cm} object where
* 'ed' is an instance of the Editor object and 'cm' is an
* instance of the CodeMirror object. Example:
*
* function hello(ctx, name) {
* let { cm, ed } = ctx;
* cm; // CodeMirror instance
* ed; // Editor instance
* name; // 'Mozilla'
* }
*
* editor.extend({ hello: hello });
* editor.hello('Mozilla');
*/
extend: function (funcs) {
Object.keys(funcs).forEach((name) => {
let cm = editors.get(this);
let ctx = { ed: this, cm: cm };
if (name === "initialize")
return void funcs[name](ctx);
this[name] = funcs[name].bind(null, ctx);
});
},
destroy: function () {
this.container = null;
this.config = null;

Просмотреть файл

@ -1217,9 +1217,11 @@ SelectorView.prototype = {
}
let contentDoc = null;
let rawNode = this.tree.viewedElement.rawNode();
if (rawNode) {
contentDoc = rawNode.ownerDocument;
if (this.tree.viewedElement.isLocal_toBeDeprecated()) {
let rawNode = this.tree.viewedElement.rawNode();
if (rawNode) {
contentDoc = rawNode.ownerDocument;
}
}
let viewSourceUtils = inspector.viewSourceUtils;

Просмотреть файл

@ -223,6 +223,7 @@ skip-if = os == "linux"
[browser_webconsole_execution_scope.js]
[browser_webconsole_for_of.js]
[browser_webconsole_history.js]
[browser_webconsole_input_field_focus_on_panel_select.js]
[browser_webconsole_js_input_expansion.js]
[browser_webconsole_jsterm.js]
[browser_webconsole_live_filtering_of_message_types.js]

Просмотреть файл

@ -0,0 +1,46 @@
/* Any copyright is dedicated to the Public Domain
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test that the JS input field is focused when the user switches back to the
// web console from other tools, see bug 891581.
const TEST_URI = "data:text/html;charset=utf8,<p>hello";
function test()
{
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, consoleOpened);
}, true);
}
function consoleOpened(hud)
{
is(hud.jsterm.inputNode.hasAttribute("focused"), true,
"inputNode should be focused");
hud.ui.filterBox.focus();
is(hud.ui.filterBox.hasAttribute("focused"), true,
"filterBox should be focused");
is(hud.jsterm.inputNode.hasAttribute("focused"), false,
"inputNode shouldn't be focused");
openDebugger().then(debuggerOpened);
}
function debuggerOpened()
{
openConsole(null, consoleReopened);
}
function consoleReopened(hud)
{
is(hud.jsterm.inputNode.hasAttribute("focused"), true,
"inputNode should be focused");
finishTest();
}

Просмотреть файл

@ -31,6 +31,7 @@ loader.lazyImporter(this, "ObjectClient", "resource://gre/modules/devtools/dbg-c
loader.lazyImporter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm");
loader.lazyImporter(this, "VariablesViewController", "resource:///modules/devtools/VariablesViewController.jsm");
loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
@ -198,6 +199,7 @@ function WebConsoleFrame(aWebConsoleOwner)
this.output = new ConsoleOutput(this);
this._toggleFilter = this._toggleFilter.bind(this);
this._onPanelSelected = this._onPanelSelected.bind(this);
this._flushMessageQueue = this._flushMessageQueue.bind(this);
this._outputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
@ -555,6 +557,21 @@ WebConsoleFrame.prototype = {
this.jsterm = new JSTerm(this);
this.jsterm.init();
this.jsterm.inputNode.focus();
let toolbox = gDevTools.getToolbox(this.owner.target);
if (toolbox) {
toolbox.on("webconsole-selected", this._onPanelSelected);
}
},
/**
* Sets the focus to JavaScript input field when the web console tab is
* selected.
* @private
*/
_onPanelSelected: function WCF__onPanelSelected()
{
this.jsterm.inputNode.focus();
},
/**
@ -2826,6 +2843,11 @@ WebConsoleFrame.prototype = {
this._destroyer = promise.defer();
let toolbox = gDevTools.getToolbox(this.owner.target);
if (toolbox) {
toolbox.off("webconsole-selected", this._onPanelSelected);
}
this._repeatNodes = {};
this._outputQueue = [];
this._pruneCategoriesQueue = {};

Просмотреть файл

@ -79,23 +79,21 @@
}
.theme-fg-color1,
.cm-s-mozilla .cm-variable-2,
.cm-s-mozilla .cm-quote { /* green */
.cm-s-mozilla .cm-number { /* green */
color: #5c9966;
}
.theme-fg-color2,
.cm-s-mozilla .cm-attribute,
.cm-s-mozilla .cm-builtin,
.cm-s-mozilla .cm-variable,
.cm-s-mozilla .cm-def,
.cm-s-mozilla .cm-variable-3,
.cm-s-mozilla .cm-property,
.cm-s-mozilla .cm-qualifier { /* blue */
color: #3689b2;
}
.theme-fg-color3,
.cm-s-mozilla .cm-builtin,
.cm-s-mozilla .cm-tag,
.cm-s-mozilla .cm-header { /* pink/lavender */
color: #a673bf;
@ -107,18 +105,19 @@
.theme-fg-color5,
.cm-s-mozilla .cm-bracket,
.cm-s-mozilla .cm-atom,
.cm-s-mozilla .cm-keyword { /* Yellow */
color: #a18650;
}
.theme-fg-color6,
.cm-s-mozilla .cm-string { /* Orange */
.cm-s-mozilla .cm-string,
.cm-s-mozilla .cm-string-2 { /* Orange */
color: #b26b47;
}
.theme-fg-color7,
.cm-s-mozilla .cm-string-2,
.cm-s-mozilla .cm-atom,
.cm-s-mozilla .cm-quote,
.cm-s-mozilla .cm-error { /* Red */
color: #bf5656;
}
@ -144,9 +143,10 @@
}
.CodeMirror pre,
.cm-s-mozilla .cm-variable-2,
.cm-s-mozilla .cm-variable-3,
.cm-s-mozilla .cm-operator,
.cm-s-mozilla .cm-special,
.cm-s-mozilla .cm-number { /* theme-body color */
.cm-s-mozilla .cm-special { /* theme-body color */
color: #8fa1b2;
}
@ -162,10 +162,15 @@
background: rgb(176, 176, 176);
}
.CodeMirror-activeline-background { /* selected color with alpha */
.cm-s-mozilla .CodeMirror-activeline-background { /* selected color with alpha */
background: rgba(185, 215, 253, .15);
}
div.cm-s-mozilla span.CodeMirror-matchingbracket { /* highlight brackets */
outline: solid 1px rgba(255, 255, 255, .25);
color: white;
}
.cm-s-mozilla .CodeMirror-linenumber { /* line number text */
color: #5f7387;
}

Просмотреть файл

@ -79,23 +79,21 @@
}
.theme-fg-color1,
.cm-s-mozilla .cm-variable-2,
.cm-s-mozilla .cm-quote { /* green */
.cm-s-mozilla .cm-number { /* green */
color: hsl(72,100%,27%);
}
.theme-fg-color2,
.cm-s-mozilla .cm-attribute,
.cm-s-mozilla .cm-builtin,
.cm-s-mozilla .cm-variable,
.cm-s-mozilla .cm-def,
.cm-s-mozilla .cm-variable-3,
.cm-s-mozilla .cm-property,
.cm-s-mozilla .cm-qualifier { /* blue */
color: hsl(208,56%,40%);
}
.theme-fg-color3,
.cm-s-mozilla .cm-variable,
.cm-s-mozilla .cm-tag,
.cm-s-mozilla .cm-header { /* dark blue */
color: hsl(208,81%,21%)
@ -107,18 +105,19 @@
.theme-fg-color5,
.cm-s-mozilla .cm-bracket,
.cm-s-mozilla .cm-keyword,
.cm-s-mozilla .cm-atom { /* Yellow */
.cm-s-mozilla .cm-keyword { /* Yellow */
color: #a18650;
}
.theme-fg-color6,
.cm-s-mozilla .cm-string { /* Orange */
.cm-s-mozilla .cm-string,
.cm-s-mozilla .cm-string-2 { /* Orange */
color: hsl(24,85%,39%);
}
.theme-fg-color7,
.cm-s-mozilla .cm-string-2,
.cm-s-mozilla .cm-atom,
.cm-s-mozilla .cm-quote,
.cm-s-mozilla .cm-error { /* Red */
color: #bf5656;
}
@ -144,9 +143,10 @@
}
.CodeMirror pre,
.cm-s-mozilla .cm-variable-2,
.cm-s-mozilla .cm-variable-3,
.cm-s-mozilla .cm-operator,
.cm-s-mozilla .cm-special,
.cm-s-mozilla .cm-number { /* theme-body color */
.cm-s-mozilla .cm-special { /* theme-body color */
color: black;
}
@ -162,7 +162,7 @@
background: rgb(176, 176, 176);
}
.CodeMirror-activeline-background { /* selected color with alpha */
.cm-s-mozilla .CodeMirror-activeline-background { /* selected color with alpha */
background: rgba(185, 215, 253, .35);
}

Просмотреть файл

@ -1717,6 +1717,10 @@ var NativeWindow = {
* the checked state as an argument.
*/
show: function(aMessage, aValue, aButtons, aTabID, aOptions) {
if (aButtons == null) {
aButtons = [];
}
aButtons.forEach((function(aButton) {
this._callbacks[this._callbacksId] = { cb: aButton.callback, prompt: this._promptId };
aButton.callback = this._callbacksId;

Просмотреть файл

@ -520,11 +520,11 @@ ImportCertsIntoPermanentStorage(const ScopedCERTCertList &certChain, const SECCe
chainNode = CERT_LIST_NEXT(chainNode), i++) {
rawArray[i] = &chainNode->cert->derCert;
}
CERT_ImportCerts(certdb, usage, chainLen,
rawArray, nullptr, true, caOnly, nullptr);
SECStatus srv = CERT_ImportCerts(certdb, usage, chainLen, rawArray,
nullptr, true, caOnly, nullptr);
PORT_Free(rawArray);
return SECSuccess;
PORT_Free(rawArray);
return srv;
}
@ -800,7 +800,10 @@ nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfac
continue;
}
ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true);
rv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true);
if (rv != SECSuccess) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;

Просмотреть файл

@ -1209,19 +1209,18 @@ Engine.prototype = {
fileInStream.init(this._file, MODE_RDONLY, PERMS_FILE, false);
switch (this._dataType) {
case SEARCH_DATA_XML:
var domParser = Cc["@mozilla.org/xmlextras/domparser;1"].
createInstance(Ci.nsIDOMParser);
var doc = domParser.parseFromStream(fileInStream, "UTF-8",
this._file.fileSize,
"text/xml");
if (this._dataType == SEARCH_DATA_XML) {
var domParser = Cc["@mozilla.org/xmlextras/domparser;1"].
createInstance(Ci.nsIDOMParser);
var doc = domParser.parseFromStream(fileInStream, "UTF-8",
this._file.fileSize,
"text/xml");
this._data = doc.documentElement;
break;
default:
ERROR("Unsuppored engine _dataType in _initFromFile: \"" + this._dataType + "\"",
Cr.NS_ERROR_UNEXPECTED);
this._data = doc.documentElement;
} else {
ERROR("Unsuppored engine _dataType in _initFromFile: \"" +
this._dataType + "\"",
Cr.NS_ERROR_UNEXPECTED);
}
fileInStream.close();
@ -1230,14 +1229,41 @@ Engine.prototype = {
},
/**
* Retrieves the engine data from a URI.
* Retrieves the data from the engine's file asynchronously. If the engine's
* dataType is XML, the document element is placed in the engine's data field.
*
* @returns {Promise} A promise, resolved successfully if initializing from
* data succeeds, rejected if it fails.
*/
_initFromURI: function SRCH_ENG_initFromURI() {
_asyncInitFromFile: function SRCH_ENG__asyncInitFromFile() {
return TaskUtils.spawn(function() {
if (!this._file || !(yield OS.File.exists(this._file.path)))
FAIL("File must exist before calling initFromFile!", Cr.NS_ERROR_UNEXPECTED);
if (this._dataType == SEARCH_DATA_XML) {
let fileURI = NetUtil.ioService.newFileURI(this._file);
yield this._retrieveSearchXMLData(fileURI.spec);
} else {
ERROR("Unsuppored engine _dataType in _initFromFile: \"" +
this._dataType + "\"",
Cr.NS_ERROR_UNEXPECTED);
}
// Now that the data is loaded, initialize the engine object
this._initFromData();
}.bind(this));
},
/**
* Retrieves the engine data from a URI. Initializes the engine, flushes to
* disk, and notifies the search service once initialization is complete.
*/
_initFromURIAndLoad: function SRCH_ENG_initFromURIAndLoad() {
ENSURE_WARN(this._uri instanceof Ci.nsIURI,
"Must have URI when calling _initFromURI!",
"Must have URI when calling _initFromURIAndLoad!",
Cr.NS_ERROR_UNEXPECTED);
LOG("_initFromURI: Downloading engine from: \"" + this._uri.spec + "\".");
LOG("_initFromURIAndLoad: Downloading engine from: \"" + this._uri.spec + "\".");
var chan = NetUtil.ioService.newChannelFromURI(this._uri);
@ -1251,7 +1277,47 @@ Engine.prototype = {
chan.notificationCallbacks = listener;
chan.asyncOpen(listener, null);
},
/**
* Retrieves the engine data from a URI asynchronously and initializes it.
*
* @returns {Promise} A promise, resolved successfully if retrieveing data
* succeeds.
*/
_asyncInitFromURI: function SRCH_ENG__asyncInitFromURI() {
return TaskUtils.spawn(function() {
LOG("_asyncInitFromURI: Loading engine from: \"" + this._uri.spec + "\".");
yield this._retrieveSearchXMLData(this._uri.spec);
// Now that the data is loaded, initialize the engine object
this._initFromData();
}.bind(this));
},
/**
* Retrieves the engine data for a given URI asynchronously.
*
* @returns {Promise} A promise, resolved successfully if retrieveing data
* succeeds.
*/
_retrieveSearchXMLData: function SRCH_ENG__retrieveSearchXMLData(aURL) {
let deferred = Promise.defer();
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsIXMLHttpRequest);
request.overrideMimeType("text/xml");
request.onload = (aEvent) => {
let responseXML = aEvent.target.responseXML;
this._data = responseXML.documentElement;
deferred.resolve();
};
request.onerror = function(aEvent) {
deferred.resolve();
};
request.open("GET", aURL, true);
request.send();
return deferred.promise;
},
_initFromURISync: function SRCH_ENG_initFromURISync() {
ENSURE_WARN(this._uri instanceof Ci.nsIURI,
"Must have URI when calling _initFromURISync!",
@ -1575,7 +1641,6 @@ Engine.prototype = {
* Initialize this Engine object from the collected data.
*/
_initFromData: function SRCH_ENG_initFromData() {
ENSURE_WARN(this._data, "Can't init an engine with no data!",
Cr.NS_ERROR_UNEXPECTED);
@ -2642,6 +2707,26 @@ function executeSoon(func) {
Services.tm.mainThread.dispatch(func, Ci.nsIThread.DISPATCH_NORMAL);
}
/**
* Check for sync initialization has completed or not.
*
* @param {aPromise} A promise.
*
* @returns the value returned by the invoked method.
* @throws NS_ERROR_ALREADY_INITIALIZED if sync initialization has completed.
*/
function checkForSyncCompletion(aPromise) {
return aPromise.then(function(aValue) {
if (gInitialized) {
throw Components.Exception("Synchronous fallback was called and has " +
"finished so no need to pursue asynchronous " +
"initialization",
Cr.NS_ERROR_ALREADY_INITIALIZED);
}
return aValue;
});
}
// nsIBrowserSearchService
function SearchService() {
// Replace empty LOG function with the useful one if the log pref is set.
@ -2658,6 +2743,9 @@ SearchService.prototype = {
// initialization is complete, only if an error has been encountered so far.
_initRV: Cr.NS_OK,
// The boolean indicates that the initialization has started or not.
_initStarted: null,
// If initialization has not been completed yet, perform synchronous
// initialization.
// Throws in case of initialization error.
@ -2687,9 +2775,10 @@ SearchService.prototype = {
// Synchronous implementation of the initializer.
// Used by |_ensureInitialized| as a fallback if initialization is not
// complete. In this implementation, it is also used by |init|.
// complete.
_syncInit: function SRCH_SVC__syncInit() {
LOG("_syncInit start");
this._initStarted = true;
try {
this._syncLoadEngines();
} catch (ex) {
@ -2707,6 +2796,30 @@ SearchService.prototype = {
LOG("_syncInit end");
},
/**
* Asynchronous implementation of the initializer.
*
* @returns {Promise} A promise, resolved successfully if the initialization
* succeeds.
*/
_asyncInit: function SRCH_SVC__asyncInit() {
return TaskUtils.spawn(function() {
LOG("_asyncInit start");
try {
yield checkForSyncCompletion(this._asyncLoadEngines());
} catch (ex if ex.result != Cr.NS_ERROR_ALREADY_INITIALIZED) {
this._initRV = Cr.NS_ERROR_FAILURE;
LOG("_asyncInit: failure loading engines: " + ex);
}
this._addObservers();
gInitialized = true;
this._initObservers.resolve(this._initRV);
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
LOG("_asyncInit: Completed _asyncInit");
}.bind(this));
},
_engines: { },
__sortedEngines: null,
get _sortedEngines() {
@ -2880,6 +2993,115 @@ SearchService.prototype = {
LOG("_loadEngines: done");
},
/**
* Loads engines asynchronously.
*
* @returns {Promise} A promise, resolved successfully if loading data
* succeeds.
*/
_asyncLoadEngines: function SRCH_SVC__asyncLoadEngines() {
return TaskUtils.spawn(function() {
LOG("_asyncLoadEngines: start");
// See if we have a cache file so we don't have to parse a bunch of XML.
let cache = {};
let cacheEnabled = getBoolPref(BROWSER_SEARCH_PREF + "cache.enabled", true);
if (cacheEnabled) {
let cacheFilePath = OS.Path.join(OS.Constants.Path.profileDir, "search.json");
cache = yield checkForSyncCompletion(this._asyncReadCacheFile(cacheFilePath));
}
// Add all the non-empty directories of NS_APP_SEARCH_DIR_LIST to
// loadDirs.
let loadDirs = [];
let locations = getDir(NS_APP_SEARCH_DIR_LIST, Ci.nsISimpleEnumerator);
while (locations.hasMoreElements()) {
let dir = locations.getNext().QueryInterface(Ci.nsIFile);
let iterator = new OS.File.DirectoryIterator(dir.path,
{ winPattern: "*.xml" });
try {
// Add dir to loadDirs if it contains any files.
yield checkForSyncCompletion(iterator.next());
loadDirs.push(dir);
} catch (ex if ex.result != Cr.NS_ERROR_ALREADY_INITIALIZED) {
// Catch for StopIteration exception.
} finally {
iterator.close();
}
}
let loadFromJARs = getBoolPref(BROWSER_SEARCH_PREF + "loadFromJars", false);
let chromeURIs = [];
let chromeFiles = [];
if (loadFromJARs) {
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "find-jar-engines");
[chromeFiles, chromeURIs] =
yield checkForSyncCompletion(this._asyncFindJAREngines());
}
let toLoad = chromeFiles.concat(loadDirs);
function hasModifiedDir(aList) {
return TaskUtils.spawn(function() {
let modifiedDir = false;
for (let dir of aList) {
if (!cache.directories || !cache.directories[dir.path]) {
modifiedDir = true;
break;
}
let info = yield OS.File.stat(dir.path);
if (cache.directories[dir.path].lastModifiedTime !=
info.lastModificationDate.getTime()) {
modifiedDir = true;
break;
}
}
throw new Task.Result(modifiedDir);
});
}
function notInCachePath(aPathToLoad)
cachePaths.indexOf(aPathToLoad.path) == -1;
let buildID = Services.appinfo.platformBuildID;
let cachePaths = [path for (path in cache.directories)];
let rebuildCache = !cache.directories ||
cache.version != CACHE_VERSION ||
cache.locale != getLocale() ||
cache.buildID != buildID ||
cachePaths.length != toLoad.length ||
toLoad.some(notInCachePath) ||
(yield checkForSyncCompletion(hasModifiedDir(toLoad)));
if (!cacheEnabled || rebuildCache) {
LOG("_asyncLoadEngines: Absent or outdated cache. Loading engines from disk.");
let engines = [];
for (let loadDir of loadDirs) {
let enginesFromDir =
yield checkForSyncCompletion(this._asyncLoadEnginesFromDir(loadDir));
engines = engines.concat(enginesFromDir);
}
let enginesFromURLs =
yield checkForSyncCompletion(this._asyncLoadFromChromeURLs(chromeURIs));
engines = engines.concat(enginesFromURLs);
for (let engine of engines) {
this._addEngineToStore(engine);
}
if (cacheEnabled)
this._buildCache();
return;
}
LOG("_asyncLoadEngines: loading from cache directories");
for each (let dir in cache.directories)
this._loadEnginesFromCache(dir);
LOG("_asyncLoadEngines: done");
}.bind(this));
},
_readCacheFile: function SRCH_SVC__readCacheFile(aFile) {
let stream = Cc["@mozilla.org/network/file-input-stream;1"].
createInstance(Ci.nsIFileInputStream);
@ -2896,6 +3118,28 @@ SearchService.prototype = {
return false;
},
/**
* Read from a given cache file asynchronously.
*
* @param aPath the file path.
*
* @returns {Promise} A promise, resolved successfully if retrieveing data
* succeeds.
*/
_asyncReadCacheFile: function SRCH_SVC__asyncReadCacheFile(aPath) {
return TaskUtils.spawn(function() {
let json;
try {
let bytes = yield OS.File.read(aPath);
json = JSON.parse(new TextDecoder().decode(bytes));
} catch (ex) {
LOG("_asyncReadCacheFile: Error reading cache file: " + ex);
json = {};
}
throw new Task.Result(json);
});
},
_batchTimer: null,
_batchCacheInvalidation: function SRCH_SVC__batchCacheInvalidation() {
let callback = {
@ -3042,15 +3286,64 @@ SearchService.prototype = {
}
},
/**
* Loads engines from a given directory asynchronously.
*
* @param aDir the directory.
*
* @returns {Promise} A promise, resolved successfully if retrieveing data
* succeeds.
*/
_asyncLoadEnginesFromDir: function SRCH_SVC__asyncLoadEnginesFromDir(aDir) {
LOG("_asyncLoadEnginesFromDir: Searching in " + aDir.path + " for search engines.");
// Check whether aDir is the user profile dir
let isInProfile = aDir.equals(getDir(NS_APP_USER_SEARCH_DIR));
let iterator = new OS.File.DirectoryIterator(aDir.path);
return TaskUtils.spawn(function() {
let osfiles = yield iterator.nextBatch();
iterator.close();
let engines = [];
for (let osfile of osfiles) {
if (osfile.isDir || osfile.isSymLink)
continue;
let fileInfo = yield OS.File.stat(osfile.path);
if (fileInfo.size == 0)
continue;
let parts = osfile.path.split(".");
if (parts.length <= 1 || (parts.pop()).toLowerCase() != "xml") {
// Not an engine
continue;
}
let addedEngine = null;
try {
let file = new FileUtils.File(osfile.path);
let isWritable = isInProfile;
addedEngine = new Engine(file, SEARCH_DATA_XML, !isWritable);
yield checkForSyncCompletion(addedEngine._asyncInitFromFile());
} catch (ex if ex.result != Cr.NS_ERROR_ALREADY_INITIALIZED) {
LOG("_asyncLoadEnginesFromDir: Failed to load " + file.path + "!\n" + ex);
continue;
}
engines.push(addedEngine);
}
throw new Task.Result(engines);
}.bind(this));
},
_loadFromChromeURLs: function SRCH_SVC_loadFromChromeURLs(aURLs) {
aURLs.forEach(function (url) {
try {
LOG("_loadFromChromeURLs: loading engine from chrome url: " + url);
let engine = new Engine(makeURI(url), SEARCH_DATA_XML, true);
engine._initFromURISync();
this._addEngineToStore(engine);
} catch (ex) {
LOG("_loadFromChromeURLs: failed to load engine: " + ex);
@ -3058,6 +3351,31 @@ SearchService.prototype = {
}, this);
},
/**
* Loads engines from Chrome URLs asynchronously.
*
* @param aURLs a list of URLs.
*
* @returns {Promise} A promise, resolved successfully if loading data
* succeeds.
*/
_asyncLoadFromChromeURLs: function SRCH_SVC__asyncLoadFromChromeURLs(aURLs) {
return TaskUtils.spawn(function() {
let engines = [];
for (let url of aURLs) {
try {
LOG("_asyncLoadFromChromeURLs: loading engine from chrome url: " + url);
let engine = new Engine(NetUtil.newURI(url), SEARCH_DATA_XML, true);
yield checkForSyncCompletion(engine._asyncInitFromURI());
engines.push(engine);
} catch (ex if ex.result != Cr.NS_ERROR_ALREADY_INITIALIZED) {
LOG("_asyncLoadFromChromeURLs: failed to load engine: " + ex);
}
}
throw new Task.Result(engines);
}.bind(this));
},
_findJAREngines: function SRCH_SVC_findJAREngines() {
LOG("_findJAREngines: looking for engines in JARs")
@ -3119,6 +3437,77 @@ SearchService.prototype = {
return [chromeFiles, uris];
},
/**
* Loads jar engines asynchronously.
*
* @returns {Promise} A promise, resolved successfully if finding jar engines
* succeeds.
*/
_asyncFindJAREngines: function SRCH_SVC__asyncFindJAREngines() {
return TaskUtils.spawn(function() {
LOG("_asyncFindJAREngines: looking for engines in JARs")
let rootURIPref = "";
try {
rootURIPref = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + "jarURIs");
} catch (ex) {}
if (!rootURIPref) {
LOG("_asyncFindJAREngines: no JAR URIs were specified");
throw new Task.Result([[], []]);
}
let rootURIs = rootURIPref.split(",");
let uris = [];
let chromeFiles = [];
for (let root of rootURIs) {
// Find the underlying JAR file for this chrome package (_loadEngines uses
// it to determine whether it needs to invalidate the cache)
let chromeFile;
try {
let chromeURI = gChromeReg.convertChromeURL(makeURI(root));
let fileURI = chromeURI; // flat packaging
while (fileURI instanceof Ci.nsIJARURI)
fileURI = fileURI.JARFile; // JAR packaging
fileURI.QueryInterface(Ci.nsIFileURL);
chromeFile = fileURI.file;
} catch (ex) {
LOG("_asyncFindJAREngines: failed to get chromeFile for " + root + ": " + ex);
}
if (!chromeFile) {
return;
}
chromeFiles.push(chromeFile);
// Read list.txt from the chrome package to find the engines we need to
// load
let listURL = root + "list.txt";
let deferred = Promise.defer();
let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsIXMLHttpRequest);
request.onload = function(aEvent) {
deferred.resolve(aEvent.target.responseText);
};
request.onerror = function(aEvent) {
LOG("_asyncFindJAREngines: failed to retrieve list.txt from " + listURL);
deferred.resolve("");
};
request.open("GET", NetUtil.newURI(listURL).spec, true);
request.send();
let list = yield deferred.promise;
let names = [];
names = list.split("\n").filter(function (n) !!n);
names.forEach(function (n) uris.push(root + n + ".xml"));
}
throw new Task.Result([chromeFiles, uris]);
});
},
_saveSortedEngineList: function SRCH_SVC_saveSortedEngineList() {
LOG("SRCH_SVC_saveSortedEngineList: starting");
@ -3262,17 +3651,13 @@ SearchService.prototype = {
this._initStarted = true;
TaskUtils.spawn(function task() {
try {
yield engineMetadataService.init();
if (gInitialized) {
// No need to pursue asynchronous initialization,
// synchronous fallback had to be called and has finished.
return;
}
// Complete initialization. In the current implementation,
// this is done by calling the synchronous initializer.
// Future versions might introduce an actually synchronous
// implementation.
self._syncInit();
yield checkForSyncCompletion(engineMetadataService.init());
// Complete initialization by calling asynchronous initializer.
yield self._asyncInit();
TelemetryStopwatch.finish("SEARCH_SERVICE_INIT_MS");
} catch (ex if ex.result == Cr.NS_ERROR_ALREADY_INITIALIZED) {
// No need to pursue asynchronous because synchronous fallback was
// called and has finished.
TelemetryStopwatch.finish("SEARCH_SERVICE_INIT_MS");
} catch (ex) {
self._initObservers.reject(ex);
@ -3428,7 +3813,7 @@ SearchService.prototype = {
engine._installCallback = null;
};
}
engine._initFromURI();
engine._initFromURIAndLoad();
} catch (ex) {
// Drop the reference to the callback, if set
if (engine)
@ -3855,6 +4240,9 @@ var engineMetadataService = {
*/
syncInit: function epsSyncInit() {
LOG("metadata syncInit start");
if (this._initState == engineMetadataService._InitStates.FINISHED_SUCCESS) {
return;
}
switch (this._initState) {
case engineMetadataService._InitStates.NOT_STARTED:
let jsonFile = new FileUtils.File(this._jsonFile);
@ -4065,7 +4453,7 @@ var engineUpdateService = {
ULOG("updating " + engine.name + " from " + updateURI.spec);
testEngine = new Engine(updateURI, dataType, false);
testEngine._engineToUpdate = engine;
testEngine._initFromURI();
testEngine._initFromURIAndLoad();
} else
ULOG("invalid updateURI");

Просмотреть файл

@ -315,7 +315,13 @@ SuggestAutoComplete.prototype = {
this._clearServerErrors();
var serverResults = JSON.parse(responseText);
try {
var serverResults = JSON.parse(responseText);
} catch(ex) {
Components.utils.reportError("Failed to parse JSON from " + this._suggestURI.spec + ": " + ex);
return;
}
var searchString = serverResults[0] || "";
var results = serverResults[1] || [];

Просмотреть файл

@ -0,0 +1,36 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
do_test_pending();
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
let url = "chrome://testsearchplugin/locale/searchplugins/";
Services.prefs.setCharPref("browser.search.jarURIs", url);
Services.prefs.setBoolPref("browser.search.loadFromJars", true);
do_check_false(Services.search.isInitialized);
Services.search.init(function search_initialized(aStatus) {
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(Services.search.isInitialized);
// test engines from dir are loaded.
let engines = Services.search.getEngines();
do_check_true(engines.length > 1);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
Services.prefs.clearUserPref("browser.search.jarURIs");
Services.prefs.clearUserPref("browser.search.loadFromJars");
do_test_finished();
});
}

Просмотреть файл

@ -0,0 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
let url = "chrome://testsearchplugin/locale/searchplugins/";
Services.prefs.setCharPref("browser.search.jarURIs", url);
Services.prefs.setBoolPref("browser.search.loadFromJars", true);
do_check_false(Services.search.isInitialized);
// test engines from dir are loaded.
let engines = Services.search.getEngines();
do_check_true(engines.length > 1);
do_check_true(Services.search.isInitialized);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
Services.prefs.clearUserPref("browser.search.jarURIs");
Services.prefs.clearUserPref("browser.search.loadFromJars");
}

Просмотреть файл

@ -0,0 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
do_test_pending();
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
let url = "chrome://testsearchplugin/locale/searchplugins/";
Services.prefs.setCharPref("browser.search.jarURIs", url);
Services.prefs.setBoolPref("browser.search.loadFromJars", true);
do_check_false(Services.search.isInitialized);
let fallback = false;
Services.search.init(function search_initialized(aStatus) {
do_check_true(fallback);
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(Services.search.isInitialized);
// test engines from dir are loaded.
let engines = Services.search.getEngines();
do_check_true(engines.length > 1);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
Services.prefs.clearUserPref("browser.search.jarURIs");
Services.prefs.clearUserPref("browser.search.loadFromJars");
do_test_finished();
});
// Execute test for the sync fallback while the async code is being executed.
Services.obs.addObserver(function searchServiceObserver(aResult, aTopic, aVerb) {
if (aVerb == "find-jar-engines") {
Services.obs.removeObserver(searchServiceObserver, aTopic);
fallback = true;
do_check_false(Services.search.isInitialized);
// test engines from dir are loaded.
let engines = Services.search.getEngines();
do_check_true(engines.length > 1);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
do_check_true(Services.search.isInitialized);
}
}, "browser-search-service", false);
}

Просмотреть файл

@ -0,0 +1,48 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function run_test() {
do_test_pending();
removeMetadata();
removeCacheFile();
do_load_manifest("data/chrome.manifest");
let url = "chrome://testsearchplugin/locale/searchplugins/";
Services.prefs.setCharPref("browser.search.jarURIs", url);
Services.prefs.setBoolPref("browser.search.loadFromJars", true);
do_check_false(Services.search.isInitialized);
Services.search.init(function search_initialized(aStatus) {
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(Services.search.isInitialized);
// test engines from dir are loaded.
let engines = Services.search.getEngines();
do_check_true(engines.length > 1);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
Services.prefs.clearUserPref("browser.search.jarURIs");
Services.prefs.clearUserPref("browser.search.loadFromJars");
do_test_finished();
});
do_check_false(Services.search.isInitialized);
// test engines from dir are loaded.
let engines = Services.search.getEngines();
do_check_true(engines.length > 1);
do_check_true(Services.search.isInitialized);
// test jar engine is loaded ok.
let engine = Services.search.getEngineByName("bug645970");
do_check_neq(engine, null);
}

Просмотреть файл

@ -27,3 +27,7 @@ support-files =
[test_prefSync.js]
[test_notifications.js]
[test_addEngine_callback.js]
[test_async.js]
[test_sync.js]
[test_sync_fallback.js]
[test_sync_delay_fallback.js]

Просмотреть файл

@ -386,8 +386,8 @@ struct TelemetryHistogram {
uint32_t max;
uint32_t bucketCount;
uint32_t histogramType;
uint16_t id_offset;
uint16_t comment_offset;
uint32_t id_offset;
uint32_t comment_offset;
bool extendedStatisticsOK;
const char *id() const;

Просмотреть файл

@ -76,7 +76,7 @@ def write_histogram_table(histograms):
strtab_name = "gHistogramStringTable"
table.writeDefinition(sys.stdout, strtab_name)
static_assert("sizeof(%s) <= UINT16_MAX" % strtab_name,
static_assert("sizeof(%s) <= UINT32_MAX" % strtab_name,
"index overflow")
# Write out static asserts for histogram data. We'd prefer to perform

Просмотреть файл

@ -583,6 +583,17 @@ let NodeFront = protocol.FrontClass(NodeActor, {
return ret;
},
/**
* Do we use a local target?
* Useful to know if a rawNode is available or not.
*
* This will, one day, be removed. External code should
* not need to know if the target is remote or not.
*/
isLocal_toBeDeprecated: function() {
return !!this.conn._transport._serverConnection;
},
/**
* Get an nsIDOMNode for the given node front. This only works locally,
* and is only intended as a stopgap during the transition to the remote

Просмотреть файл

@ -492,7 +492,6 @@ MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
// tracking flags.
mContentConsumingTouch = false;
mRecognizerWantsEvents = true;
mIsFirstTouchMove = true;
mCancelable = true;
mCanceledIds.Clear();
}
@ -560,24 +559,15 @@ MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
return S_OK;
}
AddPointerMoveDataToRecognizer(aArgs);
// If the point hasn't moved, filter it out per the spec. Pres shell does
// this as well, but we need to know when our first touchmove is going to
// get delivered so we can check the result.
if (!HasPointMoved(touch, currentPoint.Get())) {
// The recognizer needs the intermediate data otherwise it acts flaky
AddPointerMoveDataToRecognizer(aArgs);
return S_OK;
}
// If we've accumulated a batch of pointer moves and we're now on a new batch
// at a new position send the previous batch. (perf opt)
if (!mIsFirstTouchMove && touch->mChanged) {
WidgetTouchEvent* touchEvent =
new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
InitTouchEventTouchList(touchEvent);
DispatchAsyncTouchEvent(touchEvent);
}
touch = CreateDOMTouch(currentPoint.Get());
touch->mChanged = true;
// replacing old touch point in mTouches map
@ -585,15 +575,8 @@ MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
WidgetTouchEvent* touchEvent =
new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
// If this is the first touch move of our session, dispatch it now.
if (mIsFirstTouchMove) {
InitTouchEventTouchList(touchEvent);
DispatchAsyncTouchEvent(touchEvent);
mIsFirstTouchMove = false;
}
AddPointerMoveDataToRecognizer(aArgs);
InitTouchEventTouchList(touchEvent);
DispatchAsyncTouchEvent(touchEvent);
return S_OK;
}

Просмотреть файл

@ -203,7 +203,6 @@ private:
// For example, a set of mousemove, mousedown, and mouseup events might
// be sent if a tap is detected.
bool mContentConsumingTouch;
bool mIsFirstTouchMove;
bool mCancelable;
bool mRecognizerWantsEvents;
nsTArray<uint32_t> mCanceledIds;