Merge fx-team to central, a=merge

--HG--
extra : commitid : 3fYHYStKxoc
This commit is contained in:
Wes Kocher 2015-12-15 15:40:48 -08:00
Родитель 6a769445fb ad7fe1de80
Коммит 3a7310f16a
54 изменённых файлов: 877 добавлений и 983 удалений

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

@ -13,7 +13,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/LoginHelper.jsm");
Cu.importGlobalProperties(['FileReader']);
@ -275,9 +274,9 @@ CtypesVaultHelpers.prototype = {
function hostIsIPAddress(aHost) {
try {
Services.eTLD.getBaseDomainFromHost(aHost);
} catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
return true;
} catch (e) {}
} catch (e) {
return e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS;
}
return false;
}
@ -514,7 +513,7 @@ Cookies.prototype = {
migrate(aCallback) {
this.ctypesKernelHelpers = new CtypesKernelHelpers();
let cookiesGenerator = (function genCookie() {
let cookiesGenerator = (function* genCookie() {
let success = false;
let folders = this._migrationType == MSMigrationUtils.MIGRATION_TYPE_EDGE ?
this.__cookiesFolders : [this.__cookiesFolder];
@ -792,12 +791,21 @@ WindowsVaultFormPasswords.prototype = {
if (!_isIEOrEdgePassword(item.contents.schemaId.id)) {
continue;
}
let url = item.contents.pResourceElement.contents.itemValue.readString();
let realURL;
try {
realURL = Services.io.newURI(url, null, null);
} catch (ex) { /* leave realURL as null */ }
if (!realURL || ["http", "https", "ftp"].indexOf(realURL.scheme) == -1) {
// Ignore items for non-URLs or URLs that aren't HTTP(S)/FTP
continue;
}
// if aOnlyCheckExists is set to true, the purpose of the call is to return true if there is at
// least a password which is true in this case because a password was by now already found
if (aOnlyCheckExists) {
return true;
}
let url = item.contents.pResourceElement.contents.itemValue.readString();
let username = item.contents.pIdentityElement.contents.itemValue.readString();
// the current login credential object
let credential = new ctypesVaultHelpers._structs.VAULT_ELEMENT.ptr;
@ -824,7 +832,7 @@ WindowsVaultFormPasswords.prototype = {
// create a new login
let login = {
username, password,
hostname: NetUtil.newURI(url).prePath,
hostname: realURL.prePath,
timeCreated: creation,
};
LoginHelper.maybeImportLogin(login);

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

@ -76,6 +76,8 @@ this.TabGroupsMigrator = {
);
}
// We always write this back to ensure that any spurious tab groups data is
// removed:
stateAsSupportsString.data = JSON.stringify(state);
},
@ -99,15 +101,39 @@ this.TabGroupsMigrator = {
}
let windowGroupData = new Map();
let activeGroupID = null;
let tabsWithoutGroup = [];
for (let tab of win.tabs) {
let group;
// Get a string group ID:
try {
group = tab.extData && tab.extData["tabview-tab"] &&
(JSON.parse(tab.extData["tabview-tab"]).groupID + "");
let tabViewData = tab.extData && tab.extData["tabview-tab"] &&
JSON.parse(tab.extData["tabview-tab"]);
if (tabViewData && ("groupID" in tabViewData)) {
group = tabViewData.groupID + "";
}
} catch (ex) {
// Ignore tabs with no group info
continue;
// Ignore errors reading group info, treat as active group
}
if (!group) {
// We didn't find group info. If we already have an active group,
// pretend this is part of that group:
if (activeGroupID) {
group = activeGroupID;
} else {
if (!tabsWithoutGroup) {
Cu.reportError("ERROR: the list of tabs without groups was " +
"nulled out, but there's no active group ID? " +
"This should never happen!");
tabsWithoutGroup = [];
}
// Otherwise, add to the list of tabs with no group and move to
// the next tab immediately. We'll add all these tabs at the
// beginning of the active group as soon as we find a tab in it,
// so as to preserve their order.
tabsWithoutGroup.push(tab);
continue;
}
}
let groupData = windowGroupData.get(group);
if (!groupData) {
@ -119,11 +145,26 @@ this.TabGroupsMigrator = {
if (!title) {
groupData.anonGroupID = ++globalAnonGroupID;
}
// If this is the active group, set the active group ID and add
// all the already-known tabs (that didn't list a group ID), if any.
if (!activeGroupID && !tab.hidden) {
activeGroupID = group;
groupData.tabs = tabsWithoutGroup;
tabsWithoutGroup = null;
}
windowGroupData.set(group, groupData);
}
groupData.tabs.push(tab);
}
// If we found tabs but no active group, assume there's just 1 group:
if (tabsWithoutGroup && tabsWithoutGroup.length) {
windowGroupData.set("active group", {
tabs: tabsWithoutGroup,
anonGroupID: ++globalAnonGroupID,
});
}
allGroupData.set(win, windowGroupData);
}
}

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

@ -80,6 +80,91 @@ const TEST_STATES = {
}
],
},
TAB_WITHOUT_GROUP: {
selectedWindow: 1,
windows: [
{
tabs: [
{
entries: [{
url: "about:robots",
title: "Robots 1",
}],
index: 1,
hidden: false,
},
{
entries: [{
url: "about:robots",
title: "Robots 2",
}],
index: 1,
hidden: false,
extData: {
"tabview-tab": "{\"groupID\":2}",
},
},
{
entries: [{
url: "about:robots",
title: "Robots 3",
}],
index: 1,
hidden: true,
extData: {
"tabview-tab": "{\"groupID\":1}",
},
}
],
extData: {
"tabview-group": "{\"2\":{}, \"1\": {}}",
"tabview-groups": "{\"nextID\":20,\"activeGroupId\":2,\"totalNumber\":2}",
"tabview-visibility": "false"
},
}
],
},
ONLY_UNGROUPED_TABS: {
selectedWindow: 1,
windows: [
{
tabs: [
{
entries: [{
url: "about:robots",
title: "Robots 1",
}],
index: 1,
hidden: false,
},
{
entries: [{
url: "about:robots",
title: "Robots 2",
}],
index: 1,
hidden: false,
extData: {
"tabview-tab": "{}",
},
},
{
entries: [{
url: "about:robots",
title: "Robots 3",
}],
index: 1,
hidden: true,
extData: {
},
}
],
extData: {
"tabview-group": "{\"2\":{}}",
},
}
],
},
};
add_task(function* gatherGroupDataTest() {
@ -89,17 +174,14 @@ add_task(function* gatherGroupDataTest() {
Assert.equal(singleWinGroups.size, 2, "2 groups");
let group2 = singleWinGroups.get("2");
Assert.ok(!!group2, "group 2 should exist");
if (group2) {
Assert.equal(group2.tabs.length, 2, "2 tabs in group 2");
Assert.equal(group2.tabGroupsMigrationTitle, "", "We don't assign titles to untitled groups");
Assert.equal(group2.anonGroupID, "1", "We mark an untitled group with an anonymous id");
}
Assert.equal(group2.tabs.length, 2, "2 tabs in group 2");
Assert.equal(group2.tabGroupsMigrationTitle, "", "We don't assign titles to untitled groups");
Assert.equal(group2.anonGroupID, "1", "We mark an untitled group with an anonymous id");
let group13 = singleWinGroups.get("13");
if (group13) {
Assert.equal(group13.tabs.length, 1, "1 tabs in group 13");
Assert.equal(group13.tabGroupsMigrationTitle, "Foopy", "Group with title has correct title");
Assert.ok(!("anonGroupID" in group13), "We don't mark a titled group with an anonymous id");
}
Assert.ok(!!group13, "group 13 should exist");
Assert.equal(group13.tabs.length, 1, "1 tabs in group 13");
Assert.equal(group13.tabGroupsMigrationTitle, "Foopy", "Group with title has correct title");
Assert.ok(!("anonGroupID" in group13), "We don't mark a titled group with an anonymous id");
});
add_task(function* bookmarkingTest() {
@ -202,3 +284,27 @@ add_task(function* migrationPageDataTest() {
},
"Should have added expected tab at the end of the tab list.");
});
add_task(function* correctMissingTabGroupInfo() {
let stateClone = JSON.parse(JSON.stringify(TEST_STATES.TAB_WITHOUT_GROUP));
let groupInfo = TabGroupsMigrator._gatherGroupData(stateClone);
Assert.equal(groupInfo.size, 1, "Should have 1 window");
let windowGroups = [...groupInfo][0][1];
Assert.equal(windowGroups.size, 2, "Window should have 2 groups");
let group2 = windowGroups.get("2");
Assert.ok(group2, "Group 2 should exist");
Assert.equal(group2.tabs.length, 2, "There should be 2 tabs in group 2");
Assert.equal(group2.tabs[0].entries[0].title, "Robots 1", "The first tab of group 2 should be the tab with no group info.");
});
add_task(function* dealWithNoGroupInfo() {
let stateClone = JSON.parse(JSON.stringify(TEST_STATES.ONLY_UNGROUPED_TABS));
let groupInfo = TabGroupsMigrator._gatherGroupData(stateClone);
Assert.equal(groupInfo.size, 1, "Should have 1 window");
let windowGroups = [...groupInfo][0][1];
Assert.equal(windowGroups.size, 1, "Window should have 1 group");
let fallbackActiveGroup = windowGroups.get("active group");
Assert.ok(fallbackActiveGroup, "Fallback group should exist");
Assert.equal(fallbackActiveGroup.tabs.length, 3, "There should be 3 tabs in the fallback group");
});

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

@ -41,7 +41,10 @@ exports.TargetComponent = React.createClass({
let workerActor = this.props.target.actorID;
client.attachWorker(workerActor, (response, workerClient) => {
gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
"jsdebugger", Toolbox.HostType.WINDOW);
"jsdebugger", Toolbox.HostType.WINDOW)
.then(toolbox => {
toolbox.once("destroy", () => workerClient.detach());
});
});
break;
default:

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

@ -10,3 +10,4 @@ support-files =
[browser_addons_install.js]
[browser_service_workers.js]
[browser_service_workers_timeout.js]

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

@ -0,0 +1,112 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Service workers can't be loaded from chrome://,
// but http:// is ok with dom.serviceWorkers.testing.enabled turned on.
const HTTP_ROOT = CHROME_ROOT.replace("chrome://mochitests/content/",
"http://mochi.test:8888/");
const SERVICE_WORKER = HTTP_ROOT + "service-workers/empty-sw.js";
const TAB_URL = HTTP_ROOT + "service-workers/empty-sw.html";
const SW_TIMEOUT = 1000;
function waitForWorkersUpdate(document) {
return new Promise(done => {
var observer = new MutationObserver(function(mutations) {
observer.disconnect();
done();
});
var target = document.getElementById("service-workers");
observer.observe(target, { childList: true });
});
}
function assertHasWorker(expected, document, type, name) {
let names = [...document.querySelectorAll("#" + type + " .target-name")];
names = names.map(element => element.textContent);
is(names.includes(name), expected, "The " + type + " url appears in the list: " + names);
}
add_task(function *() {
yield new Promise(done => {
let options = {"set": [
// Accept workers from mochitest's http
["dom.serviceWorkers.testing.enabled", true],
// Reduce the timeout to expose issues when service worker
// freezing is broken
["dom.serviceWorkers.idle_timeout", SW_TIMEOUT],
["dom.serviceWorkers.idle_extended_timeout", SW_TIMEOUT],
]};
SpecialPowers.pushPrefEnv(options, done);
});
let { tab, document } = yield openAboutDebugging("workers");
let swTab = yield addTab(TAB_URL);
yield waitForWorkersUpdate(document);
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
// XXX: race, the WorkerDebugger is ready whereas ServiceWorkerInfo
// doesn't has the worker registered yet on its side
yield new Promise(done => {
require("sdk/timers").setTimeout(done, 250);
});
// Retrieve the DEBUG button for the worker
let names = [...document.querySelectorAll("#service-workers .target-name")];
let name = names.filter(element => element.textContent === SERVICE_WORKER)[0];
ok(name, "Found the service worker in the list");
let debugBtn = name.parentNode.parentNode.querySelector("button");
ok(debugBtn, "Found its debug button");
// Click on it and wait for the toolbox to be ready
let onToolboxReady = new Promise(done => {
gDevTools.once("toolbox-ready", function (e, toolbox) {
done(toolbox);
});
});
debugBtn.click();
let toolbox = yield onToolboxReady;
// Wait for more than the regular timeout,
// so that if the worker freezing doesn't work,
// it will be destroyed and removed from the list
yield new Promise(done => {
setTimeout(done, SW_TIMEOUT * 2);
});
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
yield toolbox.destroy();
toolbox = null;
// Now ensure that the worker is correctly destroyed
// after we destroy the toolbox.
// The list should update once it get destroyed.
yield waitForWorkersUpdate(document);
assertHasWorker(false, document, "service-workers", SERVICE_WORKER);
// Finally, unregister the service worker itself
// Use message manager to work with e10s
let frameScript = function () {
// Retrieve the `sw` promise created in the html page
let { sw } = content.wrappedJSObject;
sw.then(function (registration) {
registration.unregister().then(function (success) {
dump("SW unregistered: " + success + "\n");
},
function (e) {
dump("SW not unregistered; " + e + "\n");
});
});
};
swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
yield removeTab(swTab);
yield closeAboutDebugging(tab);
});

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

@ -5,7 +5,7 @@ code, and optionally help with indentation.
# Upgrade
Currently used version is 5.7.0. To upgrade, download a new version of
Currently used version is 5.9.0. To upgrade, download a new version of
CodeMirror from the project's page [1] and replace all JavaScript and
CSS files inside the codemirror directory [2].

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

@ -21,22 +21,28 @@
}
CodeMirror.commands.toggleComment = function(cm) {
var minLine = Infinity, ranges = cm.listSelections(), mode = null;
cm.toggleComment();
};
CodeMirror.defineExtension("toggleComment", function(options) {
if (!options) options = noOptions;
var cm = this;
var minLine = Infinity, ranges = this.listSelections(), mode = null;
for (var i = ranges.length - 1; i >= 0; i--) {
var from = ranges[i].from(), to = ranges[i].to();
if (from.line >= minLine) continue;
if (to.line >= minLine) to = Pos(minLine, 0);
minLine = from.line;
if (mode == null) {
if (cm.uncomment(from, to)) mode = "un";
else { cm.lineComment(from, to); mode = "line"; }
if (cm.uncomment(from, to, options)) mode = "un";
else { cm.lineComment(from, to, options); mode = "line"; }
} else if (mode == "un") {
cm.uncomment(from, to);
cm.uncomment(from, to, options);
} else {
cm.lineComment(from, to);
cm.lineComment(from, to, options);
}
}
};
});
CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions;
@ -57,7 +63,14 @@
self.operation(function() {
if (options.indent) {
var baseString = firstLine.slice(0, firstNonWS(firstLine));
var baseString = null;
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i);
var whitespace = line.slice(0, firstNonWS(line));
if (baseString == null || baseString.length > whitespace.length) {
baseString = whitespace;
}
}
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i), cut = baseString.length;
if (!blankLines && !nonWS.test(line)) continue;

0
devtools/client/sourceeditor/codemirror/addon/comment/continuecomment.js поставляемый Normal file → Executable file
Просмотреть файл

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

@ -25,8 +25,18 @@
};
CodeMirror.defineExtension("showHint", function(options) {
// We want a single cursor position.
if (this.listSelections().length > 1 || this.somethingSelected()) return;
options = parseOptions(this, this.getCursor("start"), options);
var selections = this.listSelections()
if (selections.length > 1) return;
// By default, don't allow completion when something is selected.
// A hint function can have a `supportsSelection` property to
// indicate that it can handle selections.
if (this.somethingSelected()) {
if (!options.hint.supportsSelection) return;
// Don't try with cross-line selections
for (var i = 0; i < selections.length; i++)
if (selections[i].head.line != selections[i].anchor.line) return;
}
if (this.state.completionActive) this.state.completionActive.close();
var completion = this.state.completionActive = new Completion(this, options);
@ -38,12 +48,12 @@
function Completion(cm, options) {
this.cm = cm;
this.options = this.buildOptions(options);
this.options = options;
this.widget = null;
this.debounce = 0;
this.tick = 0;
this.startPos = this.cm.getCursor();
this.startLen = this.cm.getLine(this.startPos.line).length;
this.startPos = this.cm.getCursor("start");
this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
var self = this;
cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
@ -124,20 +134,21 @@
CodeMirror.signal(data, "shown");
}
}
},
buildOptions: function(options) {
var editor = this.cm.options.hintOptions;
var out = {};
for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
if (editor) for (var prop in editor)
if (editor[prop] !== undefined) out[prop] = editor[prop];
if (options) for (var prop in options)
if (options[prop] !== undefined) out[prop] = options[prop];
return out;
}
};
function parseOptions(cm, pos, options) {
var editor = cm.options.hintOptions;
var out = {};
for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
if (editor) for (var prop in editor)
if (editor[prop] !== undefined) out[prop] = editor[prop];
if (options) for (var prop in options)
if (options[prop] !== undefined) out[prop] = options[prop];
if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
return out;
}
function getText(completion) {
if (typeof completion == "string") return completion;
else return completion.text;
@ -284,6 +295,13 @@
setTimeout(function(){cm.focus();}, 20);
});
if (completion.options.completeOnSingleClick)
CodeMirror.on(hints, "mousemove", function(e) {
var elt = getHintElement(hints, e.target || e.srcElement);
if (elt && elt.hintId != null)
widget.changeActive(elt.hintId);
});
CodeMirror.signal(data, "select", completions[0], hints.firstChild);
return true;
}
@ -336,18 +354,61 @@
}
};
CodeMirror.registerHelper("hint", "auto", function(cm, options) {
var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
function applicableHelpers(cm, helpers) {
if (!cm.somethingSelected()) return helpers
var result = []
for (var i = 0; i < helpers.length; i++)
if (helpers[i].supportsSelection) result.push(helpers[i])
return result
}
function resolveAutoHints(cm, pos) {
var helpers = cm.getHelpers(pos, "hint"), words
if (helpers.length) {
for (var i = 0; i < helpers.length; i++) {
var cur = helpers[i](cm, options);
if (cur && cur.list.length) return cur;
var async = false, resolved
for (var i = 0; i < helpers.length; i++) if (helpers[i].async) async = true
if (async) {
resolved = function(cm, callback, options) {
var app = applicableHelpers(cm, helpers)
function run(i, result) {
if (i == app.length) return callback(null)
var helper = app[i]
if (helper.async) {
helper(cm, function(result) {
if (result) callback(result)
else run(i + 1)
}, options)
} else {
var result = helper(cm, options)
if (result) callback(result)
else run(i + 1)
}
}
run(0)
}
resolved.async = true
} else {
resolved = function(cm, options) {
var app = applicableHelpers(cm, helpers)
for (var i = 0; i < app.length; i++) {
var cur = app[i](cm, options)
if (cur && cur.list.length) return cur
}
}
}
resolved.supportsSelection = true
return resolved
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
if (words) return CodeMirror.hint.fromList(cm, {words: words});
return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
} else if (CodeMirror.hint.anyword) {
return CodeMirror.hint.anyword(cm, options);
return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
} else {
return function() {}
}
}
CodeMirror.registerHelper("hint", "auto", {
resolve: resolveAutoHints
});
CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
@ -376,7 +437,7 @@
alignWithWord: true,
closeCharacters: /[\s()\[\]{};:>,]/,
closeOnUnfocus: true,
completeOnSingleClick: false,
completeOnSingleClick: true,
container: null,
customKeys: null,
extraKeys: null

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

@ -29,7 +29,7 @@
query.lastIndex = stream.pos;
var match = query.exec(stream.string);
if (match && match.index == stream.pos) {
stream.pos += match[0].length;
stream.pos += match[0].length || 1;
return "searching";
} else if (match) {
stream.pos = match.index;

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

@ -135,6 +135,7 @@
},
destroy: function () {
closeArgHints(this)
if (this.worker) {
this.worker.terminate();
this.worker = null;

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

@ -240,7 +240,9 @@
});
};
map[ctrl + "/"] = "toggleComment";
map[ctrl + "/"] = function(cm) {
cm.toggleComment({ indent: true });
}
cmds[map[ctrl + "J"] = "joinLines"] = function(cm) {
var ranges = cm.listSelections(), joined = [];

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

@ -3208,7 +3208,7 @@
return cur;
}
/*
/**
* Returns the boundaries of the next word. If the cursor in the middle of
* the word, then returns the boundaries of the current word, starting at
* the cursor. If the cursor is at the start/end of a word, and we are going

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

@ -21,27 +21,29 @@
// Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing.
var userAgent = navigator.userAgent;
var platform = navigator.platform;
var gecko = /gecko\/\d/i.test(navigator.userAgent);
var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
var gecko = /gecko\/\d/i.test(userAgent);
var ie_upto10 = /MSIE \d/.test(userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
var ie = ie_upto10 || ie_11up;
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
var webkit = /WebKit\//.test(navigator.userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
var chrome = /Chrome\//.test(navigator.userAgent);
var presto = /Opera\//.test(navigator.userAgent);
var webkit = /WebKit\//.test(userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
var chrome = /Chrome\//.test(userAgent);
var presto = /Opera\//.test(userAgent);
var safari = /Apple Computer/.test(navigator.vendor);
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
var phantom = /PhantomJS/.test(navigator.userAgent);
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
var phantom = /PhantomJS/.test(userAgent);
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
// This is woefully incomplete. Suggestions for alternative methods welcome.
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
var mac = ios || /Mac/.test(navigator.platform);
var windows = /win/i.test(navigator.platform);
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
var mac = ios || /Mac/.test(platform);
var windows = /win/i.test(platform);
var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
if (presto_version) presto_version = Number(presto_version[1]);
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
@ -408,7 +410,7 @@
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
});
this.checkedOverlay = false;
this.checkedZeroWidth = false;
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
}
@ -443,29 +445,43 @@
this.horiz.firstChild.style.width = "0";
}
if (!this.checkedOverlay && measure.clientHeight > 0) {
if (sWidth == 0) this.overlayHack();
this.checkedOverlay = true;
if (!this.checkedZeroWidth && measure.clientHeight > 0) {
if (sWidth == 0) this.zeroWidthHack();
this.checkedZeroWidth = true;
}
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
},
setScrollLeft: function(pos) {
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
},
setScrollTop: function(pos) {
if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
},
overlayHack: function() {
zeroWidthHack: function() {
var w = mac && !mac_geMountainLion ? "12px" : "18px";
this.horiz.style.minHeight = this.vert.style.minWidth = w;
var self = this;
var barMouseDown = function(e) {
if (e_target(e) != self.vert && e_target(e) != self.horiz)
operation(self.cm, onMouseDown)(e);
};
on(this.vert, "mousedown", barMouseDown);
on(this.horiz, "mousedown", barMouseDown);
this.horiz.style.height = this.vert.style.width = w;
this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
this.disableHoriz = new Delayed;
this.disableVert = new Delayed;
},
enableZeroWidthBar: function(bar, delay) {
bar.style.pointerEvents = "auto";
function maybeDisable() {
// To find out whether the scrollbar is still visible, we
// check whether the element under the pixel in the bottom
// left corner of the scrollbar box is the scrollbar box
// itself (when the bar is still visible) or its filler child
// (when the bar is hidden). If it is still visible, we keep
// it enabled, if it's hidden, we disable pointer events.
var box = bar.getBoundingClientRect();
var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
if (elt != bar) bar.style.pointerEvents = "none";
else delay.set(1000, maybeDisable);
}
delay.set(1000, maybeDisable);
},
clear: function() {
var parent = this.horiz.parentNode;
@ -3777,7 +3793,7 @@
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
function gutterEvent(cm, e, type, prevent, signalfn) {
function gutterEvent(cm, e, type, prevent) {
try { var mX = e.clientX, mY = e.clientY; }
catch(e) { return false; }
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
@ -3794,14 +3810,14 @@
if (g && g.getBoundingClientRect().right >= mX) {
var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i];
signalfn(cm, type, cm, line, gutter, e);
signal(cm, type, cm, line, gutter, e);
return e_defaultPrevented(e);
}
}
}
function clickInGutter(cm, e) {
return gutterEvent(cm, e, "gutterClick", true, signalLater);
return gutterEvent(cm, e, "gutterClick", true);
}
// Kludge to work around strange IE behavior where it'll sometimes
@ -3822,9 +3838,15 @@
if (files && files.length && window.FileReader && window.File) {
var n = files.length, text = Array(n), read = 0;
var loadFile = function(file, i) {
if (cm.options.allowDropFileTypes &&
indexOf(cm.options.allowDropFileTypes, file.type) == -1)
return;
var reader = new FileReader;
reader.onload = operation(cm, function() {
text[i] = reader.result;
var content = reader.result;
if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
text[i] = content;
if (++read == n) {
pos = clipPos(cm.doc, pos);
var change = {from: pos, to: pos,
@ -3966,8 +3988,9 @@
var display = cm.display, scroll = display.scroller;
// Quit if there's nothing to scroll here
if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
dy && scroll.scrollHeight > scroll.clientHeight)) return;
var canScrollX = scroll.scrollWidth > scroll.clientWidth;
var canScrollY = scroll.scrollHeight > scroll.clientHeight;
if (!(dx && canScrollX || dy && canScrollY)) return;
// Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element.
@ -3991,10 +4014,15 @@
// scrolling entirely here. It'll be slightly off from native, but
// better than glitching out.
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
if (dy)
if (dy && canScrollY)
setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
e_preventDefault(e);
// Only prevent default scrolling if vertical scrolling is
// actually possible. Otherwise, it causes vertical scroll
// jitter on OSX trackpads when deltaX is small and deltaY
// is large (issue #3579)
if (!dy || (dy && canScrollY))
e_preventDefault(e);
display.wheelStartX = null; // Abort measurement, if in progress
return;
}
@ -4222,12 +4250,13 @@
// right-click take effect on it.
function onContextMenu(cm, e) {
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
if (signalDOMEvent(cm, e, "contextmenu")) return;
cm.display.input.onContextMenu(e);
}
function contextMenuInGutter(cm, e) {
if (!hasHandler(cm, "gutterContextMenu")) return false;
return gutterEvent(cm, e, "gutterContextMenu", false, signal);
return gutterEvent(cm, e, "gutterContextMenu", false);
}
// UPDATING
@ -5405,6 +5434,7 @@
});
option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
option("dragDrop", true, dragDropChanged);
option("allowDropFileTypes", null);
option("cursorBlinkRate", 530);
option("cursorScrollMargin", 0);
@ -5709,8 +5739,8 @@
var range = cm.listSelections()[i];
cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
cm.indentLine(range.from().line + 1, null, true);
ensureCursorVisible(cm);
}
ensureCursorVisible(cm);
});
},
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
@ -7059,7 +7089,7 @@
spanEndStyle = "";
}
if (m.className) spanStyle += " " + m.className;
if (m.css) css = m.css;
if (m.css) css = (css ? css + ";" : "") + m.css;
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
if (m.title && !title) title = m.title;
@ -7328,6 +7358,7 @@
this.id = ++nextDocId;
this.modeOption = mode;
this.lineSep = lineSep;
this.extend = false;
if (typeof text == "string") text = this.splitLines(text);
updateDoc(this, {from: start, to: start, text: text});
@ -7543,7 +7574,7 @@
removeLineWidget: function(widget) { widget.clear(); },
markText: function(from, to, options) {
return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
@ -8104,24 +8135,30 @@
}
};
var noHandlers = []
function getHandlers(emitter, type, copy) {
var arr = emitter._handlers && emitter._handlers[type]
if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
else return arr || noHandlers
}
var off = CodeMirror.off = function(emitter, type, f) {
if (emitter.removeEventListener)
emitter.removeEventListener(type, f, false);
else if (emitter.detachEvent)
emitter.detachEvent("on" + type, f);
else {
var arr = emitter._handlers && emitter._handlers[type];
if (!arr) return;
for (var i = 0; i < arr.length; ++i)
if (arr[i] == f) { arr.splice(i, 1); break; }
var handlers = getHandlers(emitter, type, false)
for (var i = 0; i < handlers.length; ++i)
if (handlers[i] == f) { handlers.splice(i, 1); break; }
}
};
var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
var arr = emitter._handlers && emitter._handlers[type];
if (!arr) return;
var handlers = getHandlers(emitter, type, true)
if (!handlers.length) return;
var args = Array.prototype.slice.call(arguments, 2);
for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
};
var orphanDelayedCallbacks = null;
@ -8134,8 +8171,8 @@
// them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires.
function signalLater(emitter, type /*, values...*/) {
var arr = emitter._handlers && emitter._handlers[type];
if (!arr) return;
var arr = getHandlers(emitter, type, false)
if (!arr.length) return;
var args = Array.prototype.slice.call(arguments, 2), list;
if (operationGroup) {
list = operationGroup.delayedCallbacks;
@ -8175,8 +8212,7 @@
}
function hasHandler(emitter, type) {
var arr = emitter._handlers && emitter._handlers[type];
return arr && arr.length > 0;
return getHandlers(emitter, type).length > 0
}
// Add on and off methods to a constructor's prototype, to make
@ -8830,7 +8866,7 @@
// THE END
CodeMirror.version = "5.7.0";
CodeMirror.version = "5.9.0";
return CodeMirror;
});

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

@ -25,8 +25,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
multiLineStrings = parserConfig.multiLineStrings,
indentStatements = parserConfig.indentStatements !== false,
indentSwitch = parserConfig.indentSwitch !== false,
namespaceSeparator = parserConfig.namespaceSeparator;
var isOperatorChar = /[+\-*&%=<>!?|\/]/;
namespaceSeparator = parserConfig.namespaceSeparator,
isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
numberStart = parserConfig.numberStart || /[\d\.]/,
number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
endStatement = parserConfig.endStatement || /^[;:,]$/;
var curPunc, isDefKeyword;
@ -40,13 +44,14 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
if (isPunctuationChar.test(ch)) {
curPunc = ch;
return null;
}
if (/\d/.test(ch)) {
stream.eatWhile(/[\w\.]/);
return "number";
if (numberStart.test(ch)) {
stream.backUp(1)
if (stream.match(number)) return "number"
stream.next()
}
if (ch == "/") {
if (stream.eat("*")) {
@ -67,17 +72,17 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
var cur = stream.current();
if (keywords.propertyIsEnumerable(cur)) {
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
if (defKeywords.propertyIsEnumerable(cur)) isDefKeyword = true;
if (contains(keywords, cur)) {
if (contains(blockKeywords, cur)) curPunc = "newstatement";
if (contains(defKeywords, cur)) isDefKeyword = true;
return "keyword";
}
if (types.propertyIsEnumerable(cur)) return "variable-3";
if (builtin.propertyIsEnumerable(cur)) {
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
if (contains(types, cur)) return "variable-3";
if (contains(builtin, cur)) {
if (contains(blockKeywords, cur)) curPunc = "newstatement";
return "builtin";
}
if (atoms.propertyIsEnumerable(cur)) return "atom";
if (contains(atoms, cur)) return "atom";
return "variable";
}
@ -168,8 +173,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
if (style == "comment" || style == "meta") return style;
if (ctx.align == null) ctx.align = true;
if ((curPunc == ";" || curPunc == ":" || curPunc == ","))
while (isStatement(state.context.type)) popContext(state);
if (endStatement.test(curPunc)) while (isStatement(state.context.type)) popContext(state);
else if (curPunc == "{") pushContext(state, stream.column(), "}");
else if (curPunc == "[") pushContext(state, stream.column(), "]");
else if (curPunc == "(") pushContext(state, stream.column(), ")");
@ -212,8 +216,16 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
if (isStatement(ctx.type) && firstChar == "}") ctx = ctx.prev;
if (hooks.indent) {
var hook = hooks.indent(state, ctx, textAfter);
if (typeof hook == "number") return hook
}
var closing = firstChar == ctx.type;
var switchBlock = ctx.prev && ctx.prev.type == "switchstatement";
if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
return ctx.indented
}
if (isStatement(ctx.type))
return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
@ -238,9 +250,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}
function contains(words, word) {
if (typeof words === "function") {
return words(word);
} else {
return words.propertyIsEnumerable(word);
}
}
var cKeywords = "auto if break case register continue return default do sizeof " +
"static else struct switch extern typedef float union for " +
"goto while enum const volatile";
"static else struct switch extern typedef union for goto while enum const volatile";
var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t";
function cppHook(stream, state) {
@ -413,6 +431,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
defKeywords: words("class interface package enum"),
typeFirstDefinitions: true,
atoms: words("true false null"),
endStatement: /^[;:]$/,
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
@ -468,7 +487,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
keywords: words(
/* scala */
"abstract case catch class def do else extends false final finally for forSome if " +
"abstract case catch class def do else extends final finally for forSome if " +
"implicit import lazy match new null object override package private protected return " +
"sealed super this throw trait try type val var while with yield _ : = => <- <: " +
"<% >: # @ " +
@ -516,6 +535,59 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
modeProps: {closeBrackets: {triples: '"'}}
});
function tokenKotlinString(tripleString){
return function (stream, state) {
var escaped = false, next, end = false;
while (!stream.eol()) {
if (!tripleString && !escaped && stream.match('"') ) {end = true; break;}
if (tripleString && stream.match('"""')) {end = true; break;}
next = stream.next();
if(!escaped && next == "$" && stream.match('{'))
stream.skipTo("}");
escaped = !escaped && next == "\\" && !tripleString;
}
if (end || !tripleString)
state.tokenize = null;
return "string";
}
}
def("text/x-kotlin", {
name: "clike",
keywords: words(
/*keywords*/
"package as typealias class interface this super val " +
"var fun for is in This throw return " +
"break continue object if else while do try when !in !is as? " +
/*soft keywords*/
"file import where by get set abstract enum open inner override private public internal " +
"protected catch finally out final vararg reified dynamic companion constructor init " +
"sealed field property receiver param sparam lateinit data inline noinline tailrec " +
"external annotation crossinline const operator infix"
),
types: words(
/* 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"
),
intendSwitch: false,
indentStatements: false,
multiLineStrings: true,
blockKeywords: words("catch class do else finally for if where try while enum"),
defKeywords: words("class val var object package interface fun"),
atoms: words("true false null this"),
hooks: {
'"': function(stream, state) {
state.tokenize = tokenKotlinString(stream.match('""'));
return state.tokenize(stream, state);
}
},
modeProps: {closeBrackets: {triples: '"'}}
});
def(["x-shader/x-vertex", "x-shader/x-fragment"], {
name: "clike",
keywords: words("sampler1D sampler2D sampler3D samplerCube " +
@ -598,7 +670,10 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
stream.eatWhile(/[\w\$]/);
return "keyword";
},
"#": cppHook
"#": cppHook,
indent: function(_state, ctx, textAfter) {
if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented
}
},
modeProps: {fold: "brace"}
});
@ -616,4 +691,85 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
modeProps: {fold: ["brace", "include"]}
});
// Ceylon Strings need to deal with interpolation
var stringTokenizer = null;
function tokenCeylonString(type) {
return function(stream, state) {
var escaped = false, next, end = false;
while (!stream.eol()) {
if (!escaped && stream.match('"') &&
(type == "single" || stream.match('""'))) {
end = true;
break;
}
if (!escaped && stream.match('``')) {
stringTokenizer = tokenCeylonString(type);
end = true;
break;
}
next = stream.next();
escaped = type == "single" && !escaped && next == "\\";
}
if (end)
state.tokenize = null;
return "string";
}
}
def("text/x-ceylon", {
name: "clike",
keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" +
" exists extends finally for function given if import in interface is let module new" +
" nonempty object of out outer package return satisfies super switch then this throw" +
" try value void while"),
types: function(word) {
// In Ceylon all identifiers that start with an uppercase are types
var first = word.charAt(0);
return (first === first.toUpperCase() && first !== first.toLowerCase());
},
blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"),
defKeywords: words("class dynamic function interface module object package value"),
builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" +
" native optional sealed see serializable shared suppressWarnings tagged throws variable"),
isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
numberStart: /[\d#$]/,
number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
multiLineStrings: true,
typeFirstDefinitions: true,
atoms: words("true false null larger smaller equal empty finished"),
indentSwitch: false,
styleDefs: false,
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
return "meta";
},
'"': function(stream, state) {
state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single");
return state.tokenize(stream, state);
},
'`': function(stream, state) {
if (!stringTokenizer || !stream.match('`')) return false;
state.tokenize = stringTokenizer;
stringTokenizer = null;
return state.tokenize(stream, state);
},
"'": function(stream) {
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
return "atom";
},
token: function(_stream, state, style) {
if ((style == "variable" || style == "variable-3") &&
state.prevToken == ".") {
return "variable-2";
}
}
},
modeProps: {
fold: ["brace", "import"],
closeBrackets: {triples: '"'}
}
});
});

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

@ -228,7 +228,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
if (type == "}" || type == "{") return popAndPass(type, stream, state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
override += " error";
} else if (type == "word") {
wordAsValue(stream);
@ -275,6 +275,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
if (type == "}" || type == ";") return popAndPass(type, stream, state);
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") {
var word = stream.current().toLowerCase();
if (word == "only" || word == "not" || word == "and" || word == "or")

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

@ -30,14 +30,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"async": kw("async"), "function": kw("function"), "catch": kw("catch"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
"await": C, "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
@ -56,7 +56,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
"static": kw("static"),
// types
"string": type, "number": type, "bool": type, "any": type
"string": type, "number": type, "boolean": type, "any": type
};
for (var attr in tsKeywords) {
@ -121,8 +121,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
} else if (state.lastType == "operator" || state.lastType == "keyword c" ||
state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
} else if (/^(?:operator|sof|keyword c|case|new|[\[{}\(,;:])$/.test(state.lastType)) {
readRegexp(stream);
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
return ret("regexp", "string-2");
@ -281,8 +280,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return false;
}
var state = cx.state;
cx.marked = "def";
if (state.context) {
cx.marked = "def";
if (inList(state.localVars)) return;
state.localVars = {name: varname, next: state.localVars};
} else {
@ -373,14 +372,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "async") return cont(expression);
if (type == "function") return cont(functiondef, maybeop);
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
if (type == "quasi") { return pass(quasi, maybeop); }
if (type == "quasi") return pass(quasi, maybeop);
if (type == "new") return cont(maybeTarget(noComma));
return cont();
}
function maybeexpression(type) {
@ -431,6 +430,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement : expressionNoComma);
}
function maybeTarget(noComma) {
return function(type) {
if (type == ".") return cont(noComma ? targetNoComma : target);
else return pass(noComma ? expressionNoComma : expression);
};
}
function target(_, value) {
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
}
function targetNoComma(_, value) {
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperatorComma, expect(";"), poplex);
@ -439,9 +450,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "variable") {cx.marked = "property"; return cont();}
}
function objprop(type, value) {
if (type == "async") {
return cont(objprop);
} else if (type == "variable" || cx.style == "keyword") {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
return cont(afterprop);
@ -452,6 +461,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(afterprop);
} else if (type == "[") {
return cont(expression, expect("]"), afterprop);
} else if (type == "spread") {
return cont(expression);
}
}
function getterSetter(type) {
@ -501,6 +512,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
}
function pattern(type, value) {
if (type == "variable") { register(value); return cont(); }
if (type == "spread") return cont(pattern);
if (type == "[") return contCommasep(pattern, "]");
if (type == "{") return contCommasep(proppattern, "}");
}
@ -510,6 +522,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(maybeAssign);
}
if (type == "variable") cx.marked = "property";
if (type == "spread") return cont(pattern);
return cont(expect(":"), pattern, maybeAssign);
}
function maybeAssign(_type, value) {

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

@ -79,7 +79,7 @@ namespace = "comment_";
test("indented", "javascript", function(cm) {
cm.lineComment(Pos(1, 0), Pos(2), {indent: true});
}, simpleProg, "function foo() {\n // return bar;\n // }");
}, simpleProg, "function foo() {\n// return bar;\n// }");
test("singleEmptyLine", "javascript", function(cm) {
cm.setCursor(1);

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

@ -19,7 +19,7 @@
var code;
for (var c in CodeMirror.keyNames)
if (CodeMirror.keyNames[c] == key) { code = c; break; }
if (c == null) throw new Error("Unknown key: " + key);
if (code == null) throw new Error("Unknown key: " + key);
return eventCache[keyName] = {
type: "keydown", keyCode: code, ctrlKey: ctrl, shiftKey: shift, altKey: alt,

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

@ -6,7 +6,7 @@
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
MT("locals",
"[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }");
"[keyword function] [def foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }");
MT("comma-and-binop",
"[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }");
@ -18,7 +18,7 @@
"})();");
MT("class_body",
"[keyword class] [variable Foo] {",
"[keyword class] [def Foo] {",
" [property constructor]() {}",
" [property sayName]() {",
" [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];",
@ -26,7 +26,7 @@
"}");
MT("class",
"[keyword class] [variable Point] [keyword extends] [variable SuperThing] {",
"[keyword class] [def Point] [keyword extends] [variable SuperThing] {",
" [property get] [property prop]() { [keyword return] [number 24]; }",
" [property constructor]([def x], [def y]) {",
" [keyword super]([string 'something']);",
@ -35,44 +35,44 @@
"}");
MT("import",
"[keyword function] [variable foo]() {",
"[keyword function] [def foo]() {",
" [keyword import] [def $] [keyword from] [string 'jquery'];",
" [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
"}");
MT("const",
"[keyword function] [variable f]() {",
"[keyword function] [def f]() {",
" [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
"}");
MT("for/of",
"[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}");
"[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}");
MT("generator",
"[keyword function*] [variable repeat]([def n]) {",
"[keyword function*] [def repeat]([def n]) {",
" [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])",
" [keyword yield] [variable-2 i];",
"}");
MT("quotedStringAddition",
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
"[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
MT("quotedFatArrow",
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];");
"[keyword let] [def f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];");
MT("fatArrow",
"[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);",
"[variable a];", // No longer in scope
"[keyword let] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
"[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
"[variable c];");
MT("spread",
"[keyword function] [variable f]([def a], [meta ...][def b]) {",
"[keyword function] [def f]([def a], [meta ...][def b]) {",
" [variable something]([variable-2 a], [meta ...][variable-2 b]);",
"}");
MT("comprehension",
"[keyword function] [variable f]() {",
"[keyword function] [def f]() {",
" [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];",
" ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));",
"}");
@ -84,7 +84,7 @@
"[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
MT("indent_statement",
"[keyword var] [variable x] [operator =] [number 10]",
"[keyword var] [def x] [operator =] [number 10]",
"[variable x] [operator +=] [variable y] [operator +]",
" [atom Infinity]",
"[keyword debugger];");
@ -105,14 +105,14 @@
"}");
MT("indent_for",
"[keyword for] ([keyword var] [variable i] [operator =] [number 0];",
"[keyword for] ([keyword var] [def i] [operator =] [number 0];",
" [variable i] [operator <] [number 100];",
" [variable i][operator ++])",
" [variable doSomething]([variable i]);",
"[keyword debugger];");
MT("indent_c_style",
"[keyword function] [variable foo]()",
"[keyword function] [def foo]()",
"{",
" [keyword debugger];",
"}");
@ -140,24 +140,32 @@
"[number 2];");
MT("multilinestring",
"[keyword var] [variable x] [operator =] [string 'foo\\]",
"[keyword var] [def x] [operator =] [string 'foo\\]",
"[string bar'];");
MT("scary_regexp",
"[string-2 /foo[[/]]bar/];");
MT("indent_strange_array",
"[keyword var] [variable x] [operator =] [[",
"[keyword var] [def x] [operator =] [[",
" [number 1],,",
" [number 2],",
"]];",
"[number 10];");
MT("param_default",
"[keyword function] [variable foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {",
"[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {",
" [keyword return] [variable-2 x];",
"}");
MT("new_target",
"[keyword function] [def F]([def target]) {",
" [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {",
" [keyword return] [keyword new]",
" .[keyword target];",
" }",
"}");
var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2},
{name: "javascript", jsonld: true}

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

@ -11,6 +11,12 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIWorkerDebuggerManager"
);
XPCOMUtils.defineLazyServiceGetter(
this, "swm",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager"
);
function matchWorkerDebugger(dbg, options) {
if ("type" in options && dbg.type !== options.type) {
return false;
@ -54,6 +60,14 @@ WorkerActor.prototype = {
}
if (!this._isAttached) {
// Automatically disable their internal timeout that shut them down
// Should be refactored by having actors specific to service workers
if (this._dbg.type == Ci.nsIWorkerDebugger.TYPE_SERVICE) {
let worker = this._getServiceWorkerInfo();
if (worker) {
worker.attachDebugger();
}
}
this._dbg.addListener(this);
this._isAttached = true;
}
@ -115,6 +129,11 @@ WorkerActor.prototype = {
reportError("ERROR:" + filename + ":" + lineno + ":" + message + "\n");
},
_getServiceWorkerInfo: function () {
let info = swm.getRegistrationByPrincipal(this._dbg.principal, this._dbg.url);
return info.getWorkerByID(this._dbg.serviceWorkerID);
},
_detach: function () {
if (this._threadActor !== null) {
this._transport.close();
@ -122,6 +141,20 @@ WorkerActor.prototype = {
this._threadActor = null;
}
// If the worker is already destroyed, nsIWorkerDebugger.type throws
// (_dbg.closed appears to be false when it throws)
let type;
try {
type = this._dbg.type;
} catch(e) {}
if (type == Ci.nsIWorkerDebugger.TYPE_SERVICE) {
let worker = this._getServiceWorkerInfo();
if (worker) {
worker.detachDebugger();
}
}
this._dbg.removeListener(this);
this._isAttached = false;
}

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

@ -42,7 +42,7 @@ interface nsIServiceWorkerRegistrationInfoListener : nsISupports
void onChange();
};
[scriptable, builtinclass, uuid(72faba24-0a1b-4284-bad3-d44c044d6d95)]
[scriptable, builtinclass, uuid(ddbc1fd4-2f2e-4fca-a395-6e010bbedfe3)]
interface nsIServiceWorkerRegistrationInfo : nsISupports
{
readonly attribute nsIPrincipal principal;
@ -54,6 +54,12 @@ interface nsIServiceWorkerRegistrationInfo : nsISupports
readonly attribute nsIServiceWorkerInfo waitingWorker;
readonly attribute nsIServiceWorkerInfo activeWorker;
// Allows to get the related nsIServiceWorkerInfo for a given
// nsIWorkerDebugger. Over time we shouldn't need this anymore,
// and instead always control then nsIWorkerDebugger from
// nsIServiceWorkerInfo and not the other way around.
nsIServiceWorkerInfo getWorkerByID(in unsigned long long aID);
void addListener(in nsIServiceWorkerRegistrationInfoListener listener);
void removeListener(in nsIServiceWorkerRegistrationInfoListener listener);
@ -67,7 +73,7 @@ interface nsIServiceWorkerManagerListener : nsISupports
void onUnregister(in nsIServiceWorkerRegistrationInfo aInfo);
};
[scriptable, builtinclass, uuid(a03f2b64-7aaf-423a-97b0-e1f733cce0f6)]
[scriptable, builtinclass, uuid(12381ddf-9b51-4c0a-9123-9e7754393a5a)]
interface nsIServiceWorkerManager : nsISupports
{
/**
@ -100,6 +106,9 @@ interface nsIServiceWorkerManager : nsISupports
// Remove ready pending Promise
void removeReadyPromise(in nsIDOMWindow aWindow);
nsIServiceWorkerRegistrationInfo getRegistrationByPrincipal(in nsIPrincipal aPrincipal,
in DOMString aScope);
/**
* Call this to request that document `aDoc` be controlled by a ServiceWorker
* if a registration exists for it's scope.

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

@ -503,6 +503,20 @@ ServiceWorkerRegistrationInfo::GetActiveWorker(nsIServiceWorkerInfo **aResult)
return NS_OK;
}
NS_IMETHODIMP
ServiceWorkerRegistrationInfo::GetWorkerByID(uint64_t aID, nsIServiceWorkerInfo **aResult)
{
AssertIsOnMainThread();
MOZ_ASSERT(aResult);
RefPtr<ServiceWorkerInfo> info = GetServiceWorkerInfoById(aID);
if (NS_WARN_IF(!info)) {
return NS_ERROR_FAILURE;
}
info.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
ServiceWorkerRegistrationInfo::AddListener(
nsIServiceWorkerRegistrationInfoListener *aListener)
@ -4071,6 +4085,30 @@ ServiceWorkerManager::GetRegistration(nsIPrincipal* aPrincipal,
return GetRegistration(scopeKey, aScope);
}
NS_IMETHODIMP
ServiceWorkerManager::GetRegistrationByPrincipal(nsIPrincipal* aPrincipal,
const nsAString& aScope,
nsIServiceWorkerRegistrationInfo** aInfo)
{
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aInfo);
nsCOMPtr<nsIURI> scopeURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerRegistrationInfo> info =
GetServiceWorkerRegistrationInfo(aPrincipal, scopeURI);
if (!info) {
return NS_ERROR_FAILURE;
}
info.forget(aInfo);
return NS_OK;
}
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetRegistration(const nsACString& aScopeKey,
const nsACString& aScope) const

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

@ -3710,6 +3710,36 @@ WorkerDebugger::GetWindow(nsIDOMWindow** aResult)
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::GetPrincipal(nsIPrincipal** aResult)
{
AssertIsOnMainThread();
MOZ_ASSERT(aResult);
if (!mWorkerPrivate) {
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIPrincipal> prin = mWorkerPrivate->GetPrincipal();
prin.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::GetServiceWorkerID(uint32_t* aResult)
{
AssertIsOnMainThread();
MOZ_ASSERT(aResult);
if (!mWorkerPrivate || !mWorkerPrivate->IsServiceWorker()) {
return NS_ERROR_UNEXPECTED;
}
*aResult = mWorkerPrivate->ServiceWorkerID();
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::Initialize(const nsAString& aURL, JSContext* aCx)
{

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

@ -1,6 +1,7 @@
#include "nsISupports.idl"
interface nsIDOMWindow;
interface nsIPrincipal;
[scriptable, uuid(9cf3b48e-361d-486a-8917-55cf8d00bb41)]
interface nsIWorkerDebuggerListener : nsISupports
@ -13,7 +14,7 @@ interface nsIWorkerDebuggerListener : nsISupports
void onMessage(in DOMString message);
};
[scriptable, builtinclass, uuid(2b8d801c-973d-425b-a6d5-1a2505dd8b78)]
[scriptable, builtinclass, uuid(2fe71e0d-3a39-40a3-b809-8418b72328b4)]
interface nsIWorkerDebugger : nsISupports
{
const unsigned long TYPE_DEDICATED = 0;
@ -34,6 +35,10 @@ interface nsIWorkerDebugger : nsISupports
readonly attribute nsIDOMWindow window;
readonly attribute nsIPrincipal principal;
readonly attribute unsigned long serviceWorkerID;
[implicit_jscontext]
void initialize(in DOMString url);

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

@ -70,7 +70,21 @@
info("Attach a debugger to the service worker, and check that the " +
"service worker is restarted.");
activeWorker.attachDebugger();
ok(activeWorker.debugger !== null);
let workerDebugger = activeWorker.debugger;
ok(workerDebugger !== null);
// Verify debugger properties
ok(workerDebugger.principal instanceof Ci.nsIPrincipal);
is(workerDebugger.url, EXAMPLE_URL + "worker.js");
info("Verify that getRegistrationByPrincipal return the same " +
"nsIServiceWorkerRegistrationInfo");
let reg = swm.getRegistrationByPrincipal(workerDebugger.principal,
workerDebugger.url);
is(reg, registration);
info("Check that getWorkerByID returns the same nsIWorkerDebugger");
is(activeWorker, reg.getWorkerByID(workerDebugger.serviceWorkerID));
info("Detach the debugger from the service worker, and check that " +
"the service worker eventually shuts down again.");

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 544 B

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 661 B

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

@ -41,7 +41,6 @@
<item name="android:actionModeCutDrawable">@drawable/ab_cut</item>
<item name="android:actionModePasteDrawable">@drawable/ab_paste</item>
<item name="android:listViewStyle">@style/Widget.ListView</item>
<item name="android:panelBackground">@drawable/menu_panel_bg</item>
<item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>

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

@ -17,7 +17,6 @@
<item name="android:actionModeSelectAllDrawable">@drawable/ab_select_all</item>
<item name="android:actionModeStyle">@style/GeckoActionBar</item>
<item name="android:listViewStyle">@style/Widget.ListView</item>
<item name="android:panelBackground">@drawable/menu_panel_bg</item>
<item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>

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

@ -42,7 +42,6 @@
<style name="GeckoAppBase" parent="Gecko">
<item name="android:actionButtonStyle">@style/GeckoActionBar.Button</item>
<item name="android:listViewStyle">@style/Widget.ListView</item>
<item name="android:panelBackground">@drawable/menu_panel_bg</item>
<item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>

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

@ -12,13 +12,6 @@
<style name="GeckoBase" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
<!-- Gingerbread "More" menu background color; AppCompat sets this to
transparent by default: http://stackoverflow.com/a/31777488.
This color is set anecdotally to make all text colors, which change
by device, visible. Standard colors are #8D8D8D & #C8C8C8 (disabled)
and #000000 has also been seen. -->
<item name="android:panelBackground">@color/text_and_tabs_tray_grey</item>
</style>
<style name="GeckoDialogBase" parent="@android:style/Theme.Dialog">

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

@ -14,7 +14,6 @@ Contents:
localeswitching
uitelemetry
adjust
gradle
Indices and tables
==================
@ -22,4 +21,3 @@ Indices and tables
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

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

@ -1,155 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
targetSdkVersion 22
minSdkVersion 9
applicationId mozconfig.substs.ANDROID_PACKAGE_NAME
testApplicationId 'org.mozilla.roboexample.test'
testInstrumentationRunner 'org.mozilla.gecko.FennecInstrumentationTestRunner'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
buildTypes {
release {
minifyEnabled true
proguardFile "${topsrcdir}/mobile/android/config/proguard/proguard.cfg"
}
}
sourceSets {
main {
manifest.srcFile "${topobjdir}/mobile/android/base/AndroidManifest.xml"
}
androidTest {
manifest.srcFile "${topobjdir}/build/mobile/robocop/AndroidManifest.xml"
java {
srcDir "src/robocop"
srcDir "src/background"
srcDir "src/browser"
srcDir "src/javaaddons"
}
}
}
}
dependencies {
compile project(':base')
compile project(':omnijar')
// Including the Robotium JAR directly can cause issues with dexing.
androidTestCompile 'com.jayway.android.robotium:robotium-solo:4.3.1'
}
task syncOmnijarFromDistDir(type: Sync) {
into("${project.buildDir}/generated/omnijar")
from("${topobjdir}/dist/fennec/assets") {
include 'omni.ja'
}
}
task checkLibsExistInDistDir<< {
if (syncLibsFromDistDir.source.empty) {
throw new GradleException("Required JNI libraries not found in ${topobjdir}/dist/fennec/lib. Have you built and packaged?")
}
}
task syncLibsFromDistDir(type: Sync, dependsOn: checkLibsExistInDistDir) {
into("${project.buildDir}/generated/jniLibs")
from("${topobjdir}/dist/fennec/lib")
}
task checkAssetsExistInDistDir<< {
if (syncAssetsFromDistDir.source.empty) {
throw new GradleException("Required assets not found in ${topobjdir}/dist/fennec/assets. Have you built and packaged?")
}
}
task syncAssetsFromDistDir(type: Sync, dependsOn: checkAssetsExistInDistDir) {
into("${project.buildDir}/generated/assets")
from("${topobjdir}/dist/fennec/assets") {
exclude 'omni.ja'
}
}
/**
* We want to expose the JSM files and chrome content to IDEs; the omnijar
* project does this. In addition, the :omnijar:buildOmnijar task builds a new
* omni.ja (directly into the object directory).
*
* The task dependency is: :generateDebugAssets -> :omnijar:buildOmnijar.
*
* One might expect that we could do this all in the omnijar project, but there
* appears to be a bug (which I have not fully isolated) where-by debug-only
* assets in a library (.aar file) are ignored in favor of release assets. This
* means we would have to insert the omni.ja into the omnijar project's release
* assets, which is altogether confusing.
*/
android.applicationVariants.all { variant ->
// We only insert omni.ja and the .so libraries into debug builds.
def name = variant.buildType.name
if (!name.contains(com.android.builder.core.BuilderConstants.DEBUG)) {
return
}
def buildOmnijarTask = project(':omnijar').tasks.getByName('buildOmnijar')
syncOmnijarFromDistDir.dependsOn buildOmnijarTask
def generateAssetsTask = tasks.findByName("generate${name.capitalize()}Assets")
generateAssetsTask.dependsOn syncOmnijarFromDistDir
generateAssetsTask.dependsOn syncLibsFromDistDir
generateAssetsTask.dependsOn syncAssetsFromDistDir
android.sourceSets.debug.assets.srcDir syncOmnijarFromDistDir.destinationDir
android.sourceSets.debug.assets.srcDir syncAssetsFromDistDir.destinationDir
android.sourceSets.debug.jniLibs.srcDir syncLibsFromDistDir.destinationDir
}
apply plugin: 'spoon'
spoon {
// For now, let's be verbose.
debug = true
// It's not helpful to pass when we don't have a device connected.
failIfNoDeviceConnected = true
def spoonPackageName
if (gradle.startParameter.taskNames.contains('runBrowserTests')) {
spoonPackageName = 'org.mozilla.tests.browser.junit3'
}
if (gradle.startParameter.taskNames.contains('runBackgroundTests')) {
spoonPackageName = 'org.mozilla.gecko.background'
}
if (project.hasProperty('spoonPackageName')) {
// Command line overrides everything.
spoonPackageName = project.spoonPackageName
}
if (spoonPackageName) {
instrumentationArgs = ['-e', "package=${spoonPackageName}".toString()]
}
}
// See discussion at https://github.com/stanfy/spoon-gradle-plugin/issues/9.
afterEvaluate {
tasks["spoon${android.testBuildType.capitalize()}AndroidTest"].outputs.upToDateWhen { false }
// This is an awkward way to define different sets of instrumentation tests.
// The task name itself is fished at runtime and the package name configured
// in the spoon configuration.
task runBrowserTests {
dependsOn tasks["spoonDebugAndroidTest"]
}
task runBackgroundTests {
dependsOn tasks["spoonDebugAndroidTest"]
}
}

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

@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.gecko">
</manifest>

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

@ -1,132 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
targetSdkVersion 22
minSdkVersion 9
// Used by Robolectric based tests; see TestRunner.
buildConfigField 'String', 'BUILD_DIR', "\"${project.buildDir}\""
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
buildTypes {
release {
minifyEnabled false
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
sourceSets {
main {
java {
srcDir 'src/services/java'
exclude 'org/mozilla/gecko/resources/**'
if (!mozconfig.substs.MOZ_CRASHREPORTER) {
exclude 'org/mozilla/gecko/CrashReporter.java'
}
if (!mozconfig.substs.MOZ_NATIVE_DEVICES) {
exclude 'org/mozilla/gecko/ChromeCast.java'
exclude 'org/mozilla/gecko/GeckoMediaPlayer.java'
exclude 'org/mozilla/gecko/MediaPlayerManager.java'
}
if (mozconfig.substs.MOZ_WEBRTC) {
srcDir 'src/webrtc_audio_device'
srcDir 'src/webrtc_video_capture'
srcDir 'src/webrtc_video_render'
}
if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
exclude 'org/mozilla/gecko/adjust/StubAdjustHelper.java'
} else {
exclude 'org/mozilla/gecko/adjust/AdjustHelper.java'
}
srcDir "${project.buildDir}/generated/source/preprocessed_code" // See syncPreprocessedCode.
}
res {
srcDir 'src/branding/res'
srcDir 'src/services/res'
srcDir "${project.buildDir}/generated/source/preprocessed_resources" // See syncPreprocessedResources.
if (mozconfig.substs.MOZ_CRASHREPORTER) {
srcDir "src/crashreporter/res"
}
}
}
test {
java {
srcDir "src/background_junit4"
}
resources {
srcDir "resources/background_junit4"
}
}
}
}
task syncPreprocessedCode(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
into("${project.buildDir}/generated/source/preprocessed_code")
from("${topobjdir}/mobile/android/base/generated/preprocessed")
}
task syncPreprocessedResources(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
into("${project.buildDir}/generated/source/preprocessed_resources")
from("${topobjdir}/mobile/android/base/res")
}
android.libraryVariants.all { variant ->
variant.preBuild.dependsOn syncPreprocessedCode
variant.preBuild.dependsOn syncPreprocessedResources
}
dependencies {
compile 'com.android.support:support-v4:23.0.1'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
if (mozconfig.substs.MOZ_NATIVE_DEVICES) {
compile 'com.android.support:mediarouter-v7:23.0.1'
compile 'com.google.android.gms:play-services-basement:8.1.0'
compile 'com.google.android.gms:play-services-base:8.1.0'
compile 'com.google.android.gms:play-services-cast:8.1.0'
}
if (mozconfig.substs.MOZ_ANDROID_GCM) {
compile 'com.google.android.gms:play-services-basement:8.1.0'
compile 'com.google.android.gms:play-services-base:8.1.0'
compile 'com.google.android.gms:play-services-gcm:8.1.0'
}
compile project(':thirdparty')
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
testCompile 'org.simpleframework:simple-http:4.1.13'
}
apply plugin: 'idea'
idea {
module {
excludeDirs += file('org/mozilla/gecko/resources')
}
}

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

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<!-- Enable relevant checks disabled by default -->
<issue id="NegativeMargin" severity="warning" />
<!-- We have a custom menu and don't conform to the recommended styles. -->
<issue id="IconColors" severity="ignore" />
</lint>

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

@ -1,102 +0,0 @@
import java.util.regex.Pattern
allprojects {
// Expose the per-object-directory configuration to all projects.
ext {
mozconfig = gradle.mozconfig
topsrcdir = gradle.mozconfig.topsrcdir
topobjdir = gradle.mozconfig.topobjdir
}
repositories {
jcenter()
}
}
buildDir "${topobjdir}/mobile/android/gradle/build"
buildscript {
repositories {
jcenter()
// For spoon-gradle-plugin SNAPSHOT release. This needs to go before
// the snapshots repository, otherwise we find a remote 1.0.3-SNAPSHOT
// that doesn't include nalexander's local changes.
maven {
url "file://${gradle.mozconfig.topsrcdir}/mobile/android/gradle/m2repo"
}
// For spoon SNAPSHOT releases.
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots'
}
}
dependencies {
// Unit testing support was added in 1.1.0. IntelliJ 14.1.4 and Android
// Studio 1.2.1.1 appear to work fine with plugin version 1.3.0.
classpath 'com.android.tools.build:gradle:1.3.0'
classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.3-SNAPSHOT') {
// Without these, we get errors linting.
exclude module: 'guava'
}
}
}
task generateCodeAndResources(type:Exec) {
workingDir "${topobjdir}"
commandLine mozconfig.substs.GMAKE
args '-C'
args "${topobjdir}/mobile/android/base"
args 'gradle-targets'
// Only show the output if something went wrong.
ignoreExitValue = true
standardOutput = new ByteArrayOutputStream()
errorOutput = standardOutput
doLast {
if (execResult.exitValue != 0) {
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
}
}
}
// Skip unit test for all build variants, unless if it was specifically requested by user.
// The enabled property for the unit test tasks is reset based on the command line task names just before the task execution.
// I bet there is a easier/cleaner way to do this, but this gets the job done for now.
Pattern pattern = Pattern.compile('.*test(.+UnitTest)?.*')
boolean startTasksIncludeTest = gradle.startParameter.taskNames.any {
taskName ->
taskName.matches(pattern)
}
gradle.taskGraph.beforeTask {
Task task ->
if (task.name.matches(pattern)) {
task.enabled = startTasksIncludeTest
}
}
afterEvaluate {
subprojects {
if (!hasProperty('android')) {
return
}
android.applicationVariants.all {
preBuild.dependsOn rootProject.generateCodeAndResources
}
android.libraryVariants.all {
preBuild.dependsOn rootProject.generateCodeAndResources
}
}
}
apply plugin: 'idea'
idea {
project {
languageLevel = '1.7'
}
}
task wrapper(type: Wrapper) {
}

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

@ -1,2 +0,0 @@
org.gradle.parallel=true
org.gradle.daemon=true

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

@ -1,5 +0,0 @@
#filter substitution
#include gradle.properties
topsrcdir=@topsrcdir@
topobjdir=@topobjdir@

Двоичные данные
mobile/android/gradle/gradle/wrapper/gradle-wrapper.jar поставляемый

Двоичный файл не отображается.

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

@ -1,6 +0,0 @@
#Sun Oct 18 17:00:46 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip

160
mobile/android/gradle/gradlew поставляемый
Просмотреть файл

@ -1,160 +0,0 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

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

@ -1,2 +0,0 @@
#filter substitution
sdk.dir=@ANDROID_SDK_ROOT@

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

@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.gecko.omnijar">
</manifest>

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

@ -1,42 +0,0 @@
apply plugin: 'java'
/**
* This task runs when any input file is newer than the omnijar.
*/
task buildOmnijar(type:Exec) {
dependsOn rootProject.generateCodeAndResources
// Depend on all the Gecko resources.
inputs.sourceDir 'src/main/java/locales'
inputs.sourceDir 'src/main/java/chrome'
inputs.sourceDir 'src/main/java/components'
inputs.sourceDir 'src/main/java/modules'
inputs.sourceDir 'src/main/java/themes'
// Produce a single output file.
outputs.file "${topobjdir}/dist/fennec/assets/omni.ja"
workingDir "${topobjdir}"
commandLine mozconfig.substs.GMAKE
args '-C'
args "${topobjdir}/mobile/android/base"
args 'gradle-omnijar'
// Only show the output if something went wrong.
ignoreExitValue = true
standardOutput = new ByteArrayOutputStream()
errorOutput = standardOutput
doLast {
if (execResult.exitValue != 0) {
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
}
}
}
apply plugin: 'idea'
idea {
module {
}
}

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

@ -1,44 +0,0 @@
// If our root project is in the object directory, we expect to be given
// topsrcdir from our environment via gradle.properties. If we don't get it,
// our root project is in the source directory, so we extract topsrcdir relative
// to the location of this script.
if (!hasProperty('topsrcdir')) {
// In the source directory, we're not worried about links crossing directories.
binding.variables['topsrcdir'] = new File("../../..").getCanonicalPath()
logger.warn("topsrcdir is undefined: assuming source directory Gradle invocation with topsrcdir=${topsrcdir}.")
}
def commandLine = ["${topsrcdir}/mach", "environment", "--format", "json", "--verbose"]
def proc = commandLine.execute(null, new File(topsrcdir))
def standardOutput = new ByteArrayOutputStream()
proc.consumeProcessOutput(standardOutput, standardOutput)
proc.waitFor()
// Only show the output if something went wrong.
if (proc.exitValue() != 0) {
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${proc.exitValue()}:\n\n${standardOutput.toString()}")
}
import groovy.json.JsonSlurper
def slurper = new JsonSlurper()
def json = slurper.parseText(standardOutput.toString())
include ':app'
include ':base'
include ':omnijar'
include ':thirdparty'
def gradleRoot = new File("${json.topobjdir}/mobile/android/gradle")
project(':app').projectDir = new File(gradleRoot, 'app')
project(':base').projectDir = new File(gradleRoot, 'base')
project(':omnijar').projectDir = new File(gradleRoot, 'omnijar')
project(':thirdparty').projectDir = new File(gradleRoot, 'thirdparty')
// The Gradle instance is shared between settings.gradle and all the
// other build.gradle files (see
// http://forums.gradle.org/gradle/topics/define_extension_properties_from_settings_xml).
// We use this ext property to pass the per-object-directory mozconfig
// between scripts. This lets us execute set-up code before we gradle
// tries to configure the project even once, and as a side benefit
// saves invoking |mach environment| multiple times.
gradle.ext.mozconfig = json

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

@ -1,4 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.gecko.thirdparty">
</manifest>

34
mobile/android/gradle/thirdparty/build.gradle поставляемый
Просмотреть файл

@ -1,34 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
targetSdkVersion 22
minSdkVersion 9
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
lintOptions {
abortOnError false
}
sourceSets {
main {
java {
if (!mozconfig.substs.MOZ_INSTALL_TRACKING) {
exclude 'com/adjust/**'
}
}
}
}
}
dependencies {
compile 'com.android.support:support-v4:23.0.1'
}

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

@ -37,6 +37,17 @@ and in IntelliJ select File > Import project... and choose
'''
# NOTE python/mach/mach/commands/commandinfo.py references this function
# by name. If this function is renamed or removed, that file should
# be updated accordingly as well.
def REMOVED(cls):
"""Command no longer exists! Use the Gradle configuration rooted in the top source directory instead.
See https://developer.mozilla.org/en-US/docs/Simple_Firefox_for_Android_build#Developing_Firefox_for_Android_in_Android_Studio_or_IDEA_IntelliJ.
"""
return False
@CommandProvider
class MachCommands(MachCommandBase):
@Command('android', category='devenv',
@ -61,106 +72,15 @@ class MachCommands(MachCommandBase):
# Avoid logging the command
self.log_manager.terminal_handler.setLevel(logging.CRITICAL)
code = self.gradle_install(quiet=True)
if code:
return code
return self.run_process(['./gradlew'] + args,
pass_thru=True, # Allow user to run gradle interactively.
ensure_exit_code=False, # Don't throw on non-zero exit code.
cwd=mozpath.join(self.topobjdir, 'mobile', 'android', 'gradle'))
cwd=mozpath.join(self.topsrcdir))
@Command('gradle-install', category='devenv',
description='Install gradle environment.',
conditions=[conditions.is_android])
def gradle_install(self, quiet=False):
import mozpack.manifests
m = mozpack.manifests.InstallManifest()
def srcdir(dst, src):
m.add_symlink(os.path.join(self.topsrcdir, src), dst)
srcdir('build.gradle', 'mobile/android/gradle/build.gradle')
srcdir('settings.gradle', 'mobile/android/gradle/settings.gradle')
m.add_pattern_copy(os.path.join(self.topsrcdir, 'mobile/android/gradle/gradle/wrapper'), '**', 'gradle/wrapper')
m.add_copy(os.path.join(self.topsrcdir, 'mobile/android/gradle/gradlew'), 'gradlew')
defines = {
'topsrcdir': self.topsrcdir,
'topobjdir': self.topobjdir,
'ANDROID_SDK_ROOT': self.substs['ANDROID_SDK_ROOT'],
}
m.add_preprocess(os.path.join(self.topsrcdir, 'mobile/android/gradle/gradle.properties.in'),
'gradle.properties',
defines=defines,
deps=os.path.join(self.topobjdir, 'mobile/android/gradle/.deps/gradle.properties.pp'))
m.add_preprocess(os.path.join(self.topsrcdir, 'mobile/android/gradle/local.properties.in'),
'local.properties',
defines=defines,
deps=os.path.join(self.topobjdir, 'mobile/android/gradle/.deps/local.properties.pp'))
srcdir('thirdparty/build.gradle', 'mobile/android/gradle/thirdparty/build.gradle')
srcdir('thirdparty/src/main/AndroidManifest.xml', 'mobile/android/gradle/thirdparty/AndroidManifest.xml')
srcdir('thirdparty/src/main/java', 'mobile/android/thirdparty')
srcdir('omnijar/build.gradle', 'mobile/android/gradle/omnijar/build.gradle')
srcdir('omnijar/src/main/java/locales', 'mobile/android/locales')
srcdir('omnijar/src/main/java/chrome', 'mobile/android/chrome')
srcdir('omnijar/src/main/java/components', 'mobile/android/components')
srcdir('omnijar/src/main/java/modules', 'mobile/android/modules')
srcdir('omnijar/src/main/java/themes', 'mobile/android/themes')
srcdir('app/build.gradle', 'mobile/android/gradle/app/build.gradle')
srcdir('app/src/androidTest/res', 'mobile/android/tests/browser/robocop/res')
srcdir('app/src/androidTest/assets', 'mobile/android/tests/browser/robocop/assets')
# Test code.
srcdir('app/src/robocop', 'mobile/android/tests/browser/robocop/src')
srcdir('app/src/background', 'mobile/android/tests/background/junit3/src')
srcdir('app/src/browser', 'mobile/android/tests/browser/junit3/src')
srcdir('app/src/javaaddons', 'mobile/android/tests/javaaddons/src')
srcdir('base/build.gradle', 'mobile/android/gradle/base/build.gradle')
srcdir('base/lint.xml', 'mobile/android/gradle/base/lint.xml')
srcdir('base/src/main/AndroidManifest.xml', 'mobile/android/gradle/base/AndroidManifest.xml')
srcdir('base/src/main/java/org/mozilla/gecko', 'mobile/android/base/java/org/mozilla/gecko')
srcdir('base/src/main/java/org/mozilla/mozstumbler', 'mobile/android/stumbler/java/org/mozilla/mozstumbler')
srcdir('base/src/main/java/org/mozilla/search', 'mobile/android/search/java/org/mozilla/search')
srcdir('base/src/main/java/org/mozilla/javaaddons', 'mobile/android/javaaddons/java/org/mozilla/javaaddons')
srcdir('base/src/services', 'mobile/android/services/src/main')
srcdir('base/src/webrtc_audio_device/java', 'media/webrtc/trunk/webrtc/modules/audio_device/android/java/src')
srcdir('base/src/webrtc_video_capture/java', 'media/webrtc/trunk/webrtc/modules/video_capture/android/java/src')
srcdir('base/src/webrtc_video_render/java', 'media/webrtc/trunk/webrtc/modules/video_render/android/java/src')
srcdir('base/src/main/res', 'mobile/android/base/resources')
srcdir('base/src/main/assets', 'mobile/android/app/assets')
srcdir('base/src/crashreporter/res', 'mobile/android/base/crashreporter/res')
srcdir('base/src/branding/res', os.path.join(self.substs['MOZ_BRANDING_DIRECTORY'], 'res'))
# JUnit 4 test code.
srcdir('base/src/background_junit4', 'mobile/android/tests/background/junit4/src')
srcdir('base/resources/background_junit4', 'mobile/android/tests/background/junit4/resources')
manifest_path = os.path.join(self.topobjdir, 'mobile', 'android', 'gradle.manifest')
with FileAvoidWrite(manifest_path) as f:
m.write(fileobj=f)
self.virtualenv_manager.ensure()
code = self.run_process([
self.virtualenv_manager.python_path,
os.path.join(self.topsrcdir, 'python/mozbuild/mozbuild/action/process_install_manifest.py'),
'--no-remove',
'--no-remove-all-directory-symlinks',
'--no-remove-empty-directories',
os.path.join(self.topobjdir, 'mobile', 'android', 'gradle'),
manifest_path],
pass_thru=True, # Allow user to run gradle interactively.
ensure_exit_code=False, # Don't throw on non-zero exit code.
cwd=mozpath.join(self.topsrcdir, 'mobile', 'android'))
if not quiet:
if not code:
print(SUCCESS.format(topobjdir=self.topobjdir))
return code
conditions=[REMOVED])
def gradle_install(self):
pass
class ArtifactSubCommand(SubCommand):

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

@ -71,9 +71,6 @@ class MachCommands(MachCommandBase):
res = self._mach_context.commands.dispatch('package', self._mach_context)
if res != 0:
return 1
res = self._mach_context.commands.dispatch('gradle-install', self._mach_context)
if res != 0:
return 1
else:
# Generate or refresh the IDE backend.
python = self.virtualenv_manager.python_path

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

@ -32,10 +32,11 @@ ANDROID_IDE_ADVERTISEMENT = '''
=============
ADVERTISEMENT
You are building Firefox for Android. After your build completes, you
should run `mach gradle-install` to prepare Gradle and IntelliJ/Android Studio
integration. Then import the Gradle project at $OBJDIR/mobile/android/gradle
into the IDE of your choice.
You are building Firefox for Android. After your build completes, you can open
the top source directory in IntelliJ or Android Studio directly and build using
Gradle. See the documentation at
https://developer.mozilla.org/en-US/docs/Simple_Firefox_for_Android_build
PLEASE BE AWARE THAT GRADLE AND INTELLIJ/ANDROID STUDIO SUPPORT IS EXPERIMENTAL.
You should verify any changes using |mach build|.

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

@ -90,7 +90,7 @@ Contains the statistics about the hangs in main and background threads. Note tha
To avoid submitting overly large payloads, some limits are applied:
* Identical, adjacent "(chrome script)" or "(content script)" stack entries are collapsed together. If a stack is reduced, the "(reduced stack)" frame marker is added as the oldest frame.
* The depth of the reported stacks is limited to 11 entries. This value represents the 95th percentile of the thread hangs stack depths reported by Telemetry.
* The depth of the reported stacks is limited to 11 entries. This value represents the 99.9th percentile of the thread hangs stack depths reported by Telemetry.
Structure::