Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2016-01-27 12:10:56 +01:00
Родитель 43abe7ef49 b9e929e1a7
Коммит 92b2943e68
215 изменённых файлов: 4605 добавлений и 2165 удалений

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

@ -84,7 +84,6 @@ browser/extensions/loop/**
# devtools/ exclusions
devtools/*.js
devtools/client/*.js
devtools/client/aboutdebugging/**
devtools/client/animationinspector/**
devtools/client/canvasdebugger/**

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

@ -302,7 +302,7 @@ const load = iced(function load(loader, module) {
let sandbox;
if (loader.sharedGlobalSandbox &&
loader.sharedGlobalBlacklist.indexOf(module.id) == -1) {
loader.sharedGlobalBlocklist.indexOf(module.id) == -1) {
// Create a new object in this sandbox, that will be used as
// the scope object for this particular module
sandbox = new loader.sharedGlobalSandbox.Object();
@ -810,9 +810,12 @@ Loader.unload = unload;
// If `resolve` does not returns `uri` string exception will be thrown by
// an associated `require` call.
function Loader(options) {
if (options.sharedGlobalBlacklist && !options.sharedGlobalBlocklist) {
options.sharedGlobalBlocklist = options.sharedGlobalBlacklist;
}
let {
modules, globals, resolve, paths, rootURI, manifest, requireMap, isNative,
metadata, sharedGlobal, sharedGlobalBlacklist, checkCompatibility, waiveIntereposition
metadata, sharedGlobal, sharedGlobalBlocklist, checkCompatibility, waiveIntereposition
} = override({
paths: {},
modules: {},
@ -832,7 +835,7 @@ function Loader(options) {
// Make the returned resolve function have the same signature
(id, requirer) => Loader.nodeResolve(id, requirer, { rootURI: rootURI }) :
Loader.resolve,
sharedGlobalBlacklist: ["sdk/indexed-db"],
sharedGlobalBlocklist: ["sdk/indexed-db"],
waiveIntereposition: false
}, options);
@ -923,7 +926,8 @@ function Loader(options) {
modules: { enumerable: false, value: modules },
metadata: { enumerable: false, value: metadata },
sharedGlobalSandbox: { enumerable: false, value: sharedGlobalSandbox },
sharedGlobalBlacklist: { enumerable: false, value: sharedGlobalBlacklist },
sharedGlobalBlocklist: { enumerable: false, value: sharedGlobalBlocklist },
sharedGlobalBlacklist: { enumerable: false, value: sharedGlobalBlocklist },
// Map of module sandboxes indexed by module URIs.
sandboxes: { enumerable: false, value: {} },
resolve: { enumerable: false, value: resolve },

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

@ -349,12 +349,41 @@ exports['test console global by default'] = function (assert) {
};
exports['test shared globals'] = function(assert) {
let uri = root + '/fixtures/loader/cycles/';
let loader = Loader({ paths: { '': uri }, sharedGlobal: true,
sharedGlobalBlocklist: ['b'] });
let program = main(loader, 'main');
// As it is hard to verify what is the global of an object
// (due to wrappers) we check that we see the `foo` symbol
// being manually injected into the shared global object
loader.sharedGlobalSandbox.foo = true;
let m = loader.sandboxes[uri + 'main.js'];
let a = loader.sandboxes[uri + 'a.js'];
let b = loader.sandboxes[uri + 'b.js'];
assert.ok(Cu.getGlobalForObject(m).foo, "main is shared");
assert.ok(Cu.getGlobalForObject(a).foo, "a is shared");
assert.ok(!Cu.getGlobalForObject(b).foo, "b isn't shared");
unload(loader);
}
exports['test deprecated shared globals exception name'] = function(assert) {
let uri = root + '/fixtures/loader/cycles/';
let loader = Loader({ paths: { '': uri }, sharedGlobal: true,
sharedGlobalBlacklist: ['b'] });
let program = main(loader, 'main');
assert.ok(loader.sharedGlobalBlocklist.includes("b"), "b should be in the blocklist");
assert.equal(loader.sharedGlobalBlocklist.length, loader.sharedGlobalBlacklist.length,
"both blocklists should have the same number of items.");
assert.equal(loader.sharedGlobalBlocklist.join(","), loader.sharedGlobalBlacklist.join(","),
"both blocklists should have the same items.");
// As it is hard to verify what is the global of an object
// (due to wrappers) we check that we see the `foo` symbol
// being manually injected into the shared global object

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

@ -1589,6 +1589,9 @@ pref("browser.defaultbrowser.notificationbar", false);
// the hang monitor.
pref("dom.ipc.cpow.timeout", 500);
// Causes access on unsafe CPOWs from browser code to throw by default.
pref("dom.ipc.cpows.forbid-unsafe-from-browser", true);
// Enable e10s hang monitoring (slow script checking and plugin hang
// detection).
pref("dom.ipc.processHangMonitor", true);

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

@ -61,7 +61,7 @@
onclick="checkForMiddleClick(this, event);"
label="&helpKeyboardShortcuts.label;"
accesskey="&helpKeyboardShortcuts.accesskey;"/>
#ifdef MOZ_SERVICES_HEALTHREPORT
#ifdef MOZ_TELEMETRY_REPORTING
<menuitem id="healthReport"
label="&healthReport2.label;"
accesskey="&healthReport2.accesskey;"

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

@ -10,7 +10,7 @@
<xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected,activity" align="baseline">
<xul:hbox flex="1" onclick="document.getBindingParent(this).onTitlebarClick(event);">
<xul:image class="chat-status-icon" xbl:inherits="src=image"/>
<xul:label class="chat-title" flex="1" xbl:inherits="value=label" crop="center"/>
<xul:label class="chat-title" flex="1" xbl:inherits="crop=titlecrop,value=label" crop="end"/>
</xul:hbox>
<xul:toolbarbutton anonid="webRTC-shareScreen-icon"
class="notification-anchor-icon chat-toolbarbutton"

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

@ -157,7 +157,9 @@ skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due
[browser_bug321000.js]
skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
[browser_bug329212.js]
skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
[browser_bug331772_xul_tooltiptext_in_html.js]
skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
[browser_bug356571.js]
[browser_bug380960.js]
[browser_bug386835.js]
@ -210,6 +212,7 @@ skip-if = buildapp == 'mulet' # Bug 1066070 - I don't think either popup notific
[browser_bug556061.js]
[browser_bug559991.js]
[browser_bug561623.js]
skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
[browser_bug561636.js]
[browser_bug562649.js]
[browser_bug563588.js]
@ -227,6 +230,7 @@ skip-if = toolkit != "cocoa"
[browser_bug581242.js]
[browser_bug581253.js]
[browser_bug581947.js]
skip-if = e10s # Bug 1236991 - Update or remove tests that use fillInPageTooltip
[browser_bug585558.js]
[browser_bug585785.js]
[browser_bug585830.js]

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

@ -1,26 +1,34 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test()
{
waitForExplicitFinish();
const PAGE = "data:text/html;charset=utf-8,<a href='%23xxx'><span>word1 <span> word2 </span></span><span> word3</span></a>";
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(performTest, content);
}, true);
/**
* Tests that we correctly compute the text for context menu
* selection of some content.
*/
add_task(function*() {
yield BrowserTestUtils.withNewTab({
gBrowser,
url: PAGE,
}, function*(browser) {
let contextMenu = document.getElementById("contentAreaContextMenu");
let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu,
"popupshown");
let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu,
"popuphidden");
content.location = "data:text/html;charset=utf-8,<a href='%23xxx'><span>word1 <span> word2 </span></span><span> word3</span></a>";
yield BrowserTestUtils.synthesizeMouseAtCenter("a", {
type: "contextmenu",
button: 2,
}, browser);
function performTest()
{
let doc = content.document;
let link = doc.querySelector("a");;
let text = gatherTextUnder(link);
is(text, "word1 word2 word3", "Text under link is correctly computed.");
gBrowser.removeCurrentTab();
finish();
}
}
yield awaitPopupShown;
is(gContextMenu.linkTextStr, "word1 word2 word3",
"Text under link is correctly computed.");
contextMenu.hidePopup();
yield awaitPopupHidden;
});
});

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

@ -2,23 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const kObservedTopics = [
"getUserMedia:response:allow",
"getUserMedia:revoke",
"getUserMedia:response:deny",
"getUserMedia:request",
"recording-device-events",
"recording-window-ended"
];
const PREF_PERMISSION_FAKE = "media.navigator.permission.fake";
const PREF_LOOP_CSP = "loop.CSP";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService",
"@mozilla.org/mediaManagerService;1",
"nsIMediaManagerService");
const CONTENT_SCRIPT_HELPER = getRootDirectory(gTestPath) + "get_user_media_content_script.js";
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript(getRootDirectory(gTestPath) + "get_user_media_helpers.js",
this);
var gTab;
@ -53,135 +43,6 @@ function isLinux() {
return navigator.platform.indexOf("Linux") != -1;
}
var gObservedTopics = {};
function observer(aSubject, aTopic, aData) {
if (!(aTopic in gObservedTopics))
gObservedTopics[aTopic] = 1;
else
++gObservedTopics[aTopic];
}
function promiseObserverCalled(aTopic, aAction) {
let deferred = Promise.defer();
info("Waiting for " + aTopic);
Services.obs.addObserver(function observer(aSubject, topic, aData) {
ok(true, "got " + aTopic + " notification");
info("Message: " + aData);
Services.obs.removeObserver(observer, aTopic);
if (kObservedTopics.indexOf(aTopic) != -1) {
if (!(aTopic in gObservedTopics))
gObservedTopics[aTopic] = -1;
else
--gObservedTopics[aTopic];
}
deferred.resolve();
}, aTopic, false);
if (aAction)
aAction();
return deferred.promise;
}
function promisePopupNotification(aName) {
let deferred = Promise.defer();
waitForCondition(() => PopupNotifications.getNotification(aName),
() => {
ok(!!PopupNotifications.getNotification(aName),
aName + " notification appeared");
deferred.resolve();
}, "timeout waiting for popup notification " + aName);
return deferred.promise;
}
function promiseNoPopupNotification(aName) {
let deferred = Promise.defer();
info("Waiting for " + aName + " to be removed");
waitForCondition(() => !PopupNotifications.getNotification(aName),
() => {
ok(!PopupNotifications.getNotification(aName),
aName + " notification removed");
deferred.resolve();
}, "timeout waiting for popup notification " + aName + " to disappear");
return deferred.promise;
}
function expectObserverCalled(aTopic) {
is(gObservedTopics[aTopic], 1, "expected notification " + aTopic);
if (aTopic in gObservedTopics)
--gObservedTopics[aTopic];
}
function expectNoObserverCalled() {
for (let topic in gObservedTopics) {
if (gObservedTopics[topic])
is(gObservedTopics[topic], 0, topic + " notification unexpected");
}
gObservedTopics = {};
}
function promiseMessage(aMessage, aAction) {
let deferred = Promise.defer();
content.addEventListener("message", function messageListener(event) {
content.removeEventListener("message", messageListener);
is(event.data, aMessage, "received " + aMessage);
if (event.data == aMessage)
deferred.resolve();
else
deferred.reject();
});
if (aAction)
aAction();
return deferred.promise;
}
function getMediaCaptureState() {
let hasVideo = {};
let hasAudio = {};
let hasScreenShare = {};
let hasWindowShare = {};
MediaManagerService.mediaCaptureWindowState(content, hasVideo, hasAudio,
hasScreenShare, hasWindowShare);
if (hasVideo.value && hasAudio.value)
return "CameraAndMicrophone";
if (hasVideo.value)
return "Camera";
if (hasAudio.value)
return "Microphone";
if (hasScreenShare)
return "Screen";
if (hasWindowShare)
return "Window";
return "none";
}
function* closeStream(aAlreadyClosed) {
expectNoObserverCalled();
info("closing the stream");
content.wrappedJSObject.closeStream();
if (!aAlreadyClosed)
yield promiseObserverCalled("recording-device-events");
yield promiseNoPopupNotification("webRTC-sharingDevices");
if (!aAlreadyClosed)
expectObserverCalled("recording-window-ended");
yield* assertWebRTCIndicatorStatus(null);
}
function loadPage(aUrl) {
let deferred = Promise.defer();
@ -214,6 +75,7 @@ fakeLoopAboutModule.prototype = {
getURIFlags: function (aURI) {
return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
Ci.nsIAboutModule.ALLOW_SCRIPT |
Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD |
Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
}
};
@ -221,14 +83,12 @@ fakeLoopAboutModule.prototype = {
var factory = XPCOMUtils._getFactory(fakeLoopAboutModule);
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
var originalLoopCsp = Services.prefs.getCharPref(PREF_LOOP_CSP);
var classIDLoopconversation, classIDEvil;
registerCleanupFunction(function() {
gBrowser.removeCurrentTab();
kObservedTopics.forEach(topic => {
Services.obs.removeObserver(observer, topic);
});
Services.prefs.clearUserPref(PREF_PERMISSION_FAKE);
Services.prefs.setCharPref(PREF_LOOP_CSP, originalLoopCsp);
registrar.unregisterFactory(classIDLoopconversation, factory);
registrar.unregisterFactory(classIDEvil, factory);
});
const permissionError = "error: SecurityError: The operation is insecure.";
@ -238,31 +98,27 @@ var gTests = [
{
desc: "getUserMedia about:loopconversation shouldn't prompt",
run: function checkAudioVideoLoop() {
Services.prefs.setCharPref(PREF_LOOP_CSP, "default-src 'unsafe-inline'");
let classID = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID();
registrar.registerFactory(classID, "",
"@mozilla.org/network/protocol/about;1?what=loopconversation",
factory);
yield new Promise(resolve => SpecialPowers.pushPrefEnv({
"set": [[PREF_LOOP_CSP, "default-src 'unsafe-inline'"]],
}, resolve));
yield loadPage("about:loopconversation");
yield promiseObserverCalled("recording-device-events", () => {
info("requesting devices");
content.wrappedJSObject.requestDevice(true, true);
});
info("requesting devices");
let promise = promiseObserverCalled("recording-device-events");
yield promiseRequestDevice(true, true);
yield promise;
// Wait for the devices to actually be captured and running before
// proceeding.
yield promisePopupNotification("webRTC-sharingDevices");
is(getMediaCaptureState(), "CameraAndMicrophone",
is((yield getMediaCaptureState()), "CameraAndMicrophone",
"expected camera and microphone to be shared");
yield closeStream();
registrar.unregisterFactory(classID, factory);
Services.prefs.setCharPref(PREF_LOOP_CSP, originalLoopCsp);
yield new Promise((resolve) => SpecialPowers.popPrefEnv(resolve));
}
},
@ -273,59 +129,45 @@ var gTests = [
return;
}
Services.prefs.setCharPref(PREF_LOOP_CSP, "default-src 'unsafe-inline'");
let classID = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID();
registrar.registerFactory(classID, "",
"@mozilla.org/network/protocol/about;1?what=loopconversation",
factory);
yield new Promise(resolve => SpecialPowers.pushPrefEnv({
"set": [[PREF_LOOP_CSP, "default-src 'unsafe-inline'"]],
}, resolve));
yield loadPage("about:loopconversation");
yield promiseObserverCalled("getUserMedia:request", () => {
info("requesting screen");
content.wrappedJSObject.requestDevice(false, true, "window");
});
info("requesting screen");
let promise = promiseObserverCalled("getUserMedia:request");
yield promiseRequestDevice(false, true, null, "window");
// Wait for the devices to actually be captured and running before
// proceeding.
yield promisePopupNotification("webRTC-shareDevices");
isnot(getMediaCaptureState(), "Window",
is((yield getMediaCaptureState()), "none",
"expected camera and microphone not to be shared");
yield promiseMessage(permissionError, () => {
PopupNotifications.panel.firstChild.button.click();
});
expectObserverCalled("getUserMedia:response:deny");
expectObserverCalled("recording-window-ended");
yield expectObserverCalled("getUserMedia:response:deny");
yield expectObserverCalled("recording-window-ended");
registrar.unregisterFactory(classID, factory);
Services.prefs.setCharPref(PREF_LOOP_CSP, originalLoopCsp);
yield new Promise((resolve) => SpecialPowers.popPrefEnv(resolve));
}
},
{
desc: "getUserMedia about:evil should prompt",
run: function checkAudioVideoNonLoop() {
let classID = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID();
registrar.registerFactory(classID, "",
"@mozilla.org/network/protocol/about;1?what=evil",
factory);
yield loadPage("about:evil");
yield promiseObserverCalled("getUserMedia:request", () => {
info("requesting devices");
content.wrappedJSObject.requestDevice(true, true);
});
let promise = promiseObserverCalled("getUserMedia:request");
yield promiseRequestDevice(true, true);
yield promise;
isnot(getMediaCaptureState(), "CameraAndMicrophone",
is((yield getMediaCaptureState()), "none",
"expected camera and microphone not to be shared");
registrar.unregisterFactory(classID, factory);
}
},
@ -334,18 +176,29 @@ var gTests = [
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref(PREF_PERMISSION_FAKE, true);
// Ensure this is always true
Services.prefs.setBoolPref("media.getusermedia.screensharing.enabled", true);
gTab = gBrowser.addTab();
gBrowser.selectedTab = gTab;
kObservedTopics.forEach(topic => {
Services.obs.addObserver(observer, topic, false);
});
gTab.linkedBrowser.messageManager.loadFrameScript(CONTENT_SCRIPT_HELPER, true);
classIDLoopconversation = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID();
registrar.registerFactory(classIDLoopconversation, "",
"@mozilla.org/network/protocol/about;1?what=loopconversation",
factory);
classIDEvil = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID();
registrar.registerFactory(classIDEvil, "",
"@mozilla.org/network/protocol/about;1?what=evil",
factory);
Task.spawn(function () {
yield new Promise(resolve => SpecialPowers.pushPrefEnv({
"set": [[PREF_PERMISSION_FAKE, true],
["media.getusermedia.screensharing.enabled", true]],
}, resolve));
for (let test of gTests) {
info(test.desc);
yield test.run();
@ -358,9 +211,3 @@ function test() {
finish();
});
}
function wait(time) {
let deferred = Promise.defer();
setTimeout(deferred.resolve, time);
return deferred.promise;
}

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

@ -49,13 +49,20 @@ addMessageListener("Test:ExpectNoObserverCalled", data => {
function _getMediaCaptureState() {
let hasVideo = {};
let hasAudio = {};
MediaManagerService.mediaCaptureWindowState(content, hasVideo, hasAudio);
let hasScreenShare = {};
let hasWindowShare = {};
MediaManagerService.mediaCaptureWindowState(content, hasVideo, hasAudio,
hasScreenShare, hasWindowShare);
if (hasVideo.value && hasAudio.value)
return "CameraAndMicrophone";
if (hasVideo.value)
return "Camera";
if (hasAudio.value)
return "Microphone";
if (hasScreenShare.value)
return "Screen";
if (hasWindowShare.value)
return "Window";
return "none";
}

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

@ -161,15 +161,15 @@ function getMediaCaptureState() {
});
}
function promiseRequestDevice(aRequestAudio, aRequestVideo, aFrameId) {
function promiseRequestDevice(aRequestAudio, aRequestVideo, aFrameId, aType) {
info("requesting devices");
return ContentTask.spawn(gBrowser.selectedBrowser,
{aRequestAudio, aRequestVideo, aFrameId},
{aRequestAudio, aRequestVideo, aFrameId, aType},
function*(args) {
let global = content.wrappedJSObject;
if (args.aFrameId)
global = global.document.getElementById(args.aFrameId).contentWindow;
global.requestDevice(args.aRequestAudio, args.aRequestVideo);
global.requestDevice(args.aRequestAudio, args.aRequestVideo, args.aType);
});
}

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

@ -535,7 +535,7 @@ BrowserGlue.prototype = {
this._isPlacesShutdownObserver = true;
os.addObserver(this, "handle-xul-text-link", false);
os.addObserver(this, "profile-before-change", false);
if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
os.addObserver(this, "keyword-search", false);
}
os.addObserver(this, "browser-search-engine-modified", false);
@ -594,7 +594,7 @@ BrowserGlue.prototype = {
os.removeObserver(this, "places-shutdown");
os.removeObserver(this, "handle-xul-text-link");
os.removeObserver(this, "profile-before-change");
if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
if (AppConstants.MOZ_TELEMETRY_REPORTING) {
os.removeObserver(this, "keyword-search");
}
os.removeObserver(this, "browser-search-engine-modified");
@ -1141,19 +1141,24 @@ BrowserGlue.prototype = {
// For any add-ons that were installed disabled and can be enabled offer
// them to the user.
let changedIDs = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED);
if (changedIDs.length > 0) {
let win = RecentWindow.getMostRecentBrowserWindow();
AddonManager.getAddonsByIDs(changedIDs, function(aAddons) {
aAddons.forEach(function(aAddon) {
// If the add-on isn't user disabled or can't be enabled then skip it.
if (!aAddon.userDisabled || !(aAddon.permissions & AddonManager.PERM_CAN_ENABLE))
return;
let win = RecentWindow.getMostRecentBrowserWindow();
AddonManager.getAllAddons(addons => {
for (let addon of addons) {
// If this add-on has already seen (or seen is undefined for non-XPI
// add-ons) then skip it.
if (addon.seen !== false) {
continue;
}
win.openUILinkIn("about:newaddon?id=" + aAddon.id, "tab");
})
});
}
// If this add-on cannot be enabled (either already enabled or
// appDisabled) then skip it.
if (!(addon.permissions & AddonManager.PERM_CAN_ENABLE)) {
continue;
}
win.openUILinkIn("about:newaddon?id=" + addon.id, "tab");
}
});
let signingRequired;
if (AppConstants.MOZ_REQUIRE_SIGNING) {

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

@ -350,7 +350,9 @@ var withBookmarksDialog = Task.async(function* (autoCancel, openFn, taskFn) {
*
* @param selector
* Valid selector syntax
* @return the target DOM node.
* @return Promise
* Returns a Promise that resolves once the context menu has been
* opened.
*/
var openContextMenuForContentSelector = Task.async(function* (browser, selector) {
info("wait for the context menu");
@ -372,8 +374,6 @@ var openContextMenuForContentSelector = Task.async(function* (browser, selector)
1, 0, false, 0, 0, true);
});
yield contextPromise;
return gContextMenuContentData.popupNode;
});
/**

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

@ -44,7 +44,7 @@ var gAdvancedPane = {
this.initSubmitCrashes();
#endif
this.initTelemetry();
#ifdef MOZ_SERVICES_HEALTHREPORT
#ifdef MOZ_TELEMETRY_REPORTING
this.initSubmitHealthReport();
#endif
this.updateOnScreenKeyboardVisibility();
@ -56,7 +56,7 @@ var gAdvancedPane = {
gAdvancedPane.updateHardwareAcceleration);
setEventListener("advancedPrefs", "select",
gAdvancedPane.tabSelectionChanged);
#ifdef MOZ_SERVICES_HEALTHREPORT
#ifdef MOZ_TELEMETRY_REPORTING
setEventListener("submitHealthReportBox", "command",
gAdvancedPane.updateSubmitHealthReport);
#endif
@ -289,7 +289,7 @@ var gAdvancedPane = {
#endif
},
#ifdef MOZ_SERVICES_HEALTHREPORT
#ifdef MOZ_TELEMETRY_REPORTING
/**
* Initialize the health report service reference and checkbox.
*/

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

@ -199,7 +199,7 @@
#ifdef MOZ_DATA_REPORTING
<!-- Data Choices -->
<tabpanel id="dataChoicesPanel" orient="vertical">
#ifdef MOZ_SERVICES_HEALTHREPORT
#ifdef MOZ_TELEMETRY_REPORTING
<groupbox>
<caption>
<checkbox id="submitHealthReportBox" label="&enableHealthReport.label;"
@ -212,7 +212,6 @@
<label id="FHRLearnMore"
class="text-link">&healthReportLearnMore.label;</label>
</hbox>
#ifdef MOZ_TELEMETRY_REPORTING
<hbox class="indent">
<groupbox flex="1">
<caption>
@ -228,7 +227,6 @@
</hbox>
</groupbox>
</hbox>
#endif
</vbox>
</groupbox>
#endif

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

@ -74,7 +74,7 @@ add_task(function flush_on_settabstate() {
// Flush all data contained in the content script but send it using
// asynchronous messages.
TabState.flushAsync(browser);
TabStateFlusher.flush(browser);
yield promiseTabState(tab, state);
@ -101,7 +101,7 @@ add_task(function flush_on_tabclose_racy() {
// Flush all data contained in the content script but send it using
// asynchronous messages.
TabState.flushAsync(browser);
TabStateFlusher.flush(browser);
yield promiseRemoveTab(tab);
let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));

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

@ -38,12 +38,18 @@ add_task(function* test_bing_translation() {
// Translating the contents of the loaded tab.
gBrowser.selectedTab = tab;
let browser = tab.linkedBrowser;
let client = new BingTranslator(
new TranslationDocument(browser.contentDocument), "fr", "en");
let result = yield client.translate();
// XXXmikedeboer; here you would continue the test/ content inspection.
Assert.ok(result, "There should be a result.");
yield ContentTask.spawn(browser, null, function*() {
Cu.import("resource:///modules/translation/BingTranslator.jsm");
Cu.import("resource:///modules/translation/TranslationDocument.jsm");
let client = new BingTranslator(
new TranslationDocument(content.document), "fr", "en");
let result = yield client.translate();
// XXXmikedeboer; here you would continue the test/ content inspection.
ok(result, "There should be a result");
});
gBrowser.removeTab(tab);
});
@ -67,18 +73,24 @@ add_task(function* test_handling_out_of_valid_key_error() {
// Translating the contents of the loaded tab.
gBrowser.selectedTab = tab;
let browser = tab.linkedBrowser;
let client = new BingTranslator(
new TranslationDocument(browser.contentDocument), "fr", "en");
client._resetToken();
try {
yield client.translate();
} catch (ex) {
// It is alright that the translation fails.
}
client._resetToken();
// Checking if the client detected service and unavailable.
Assert.ok(client._serviceUnavailable, "Service should be detected unavailable.");
yield ContentTask.spawn(browser, null, function*() {
Cu.import("resource:///modules/translation/BingTranslator.jsm");
Cu.import("resource:///modules/translation/TranslationDocument.jsm");
let client = new BingTranslator(
new TranslationDocument(content.document), "fr", "en");
client._resetToken();
try {
yield client.translate();
} catch (ex) {
// It is alright that the translation fails.
}
client._resetToken();
// Checking if the client detected service and unavailable.
ok(client._serviceUnavailable, "Service should be detected unavailable.");
});
// Cleaning up.
Services.prefs.setCharPref(kClientIdPref, "testClient");

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

@ -10,8 +10,6 @@ const kEnginePref = "browser.translation.engine";
const kApiKeyPref = "browser.translation.yandex.apiKeyOverride";
const kShowUIPref = "browser.translation.ui.show";
const {YandexTranslator} = Cu.import("resource:///modules/translation/YandexTranslator.jsm", {});
const {TranslationDocument} = Cu.import("resource:///modules/translation/TranslationDocument.jsm", {});
const {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const {Translation} = Cu.import("resource:///modules/translation/Translation.jsm", {});
@ -40,11 +38,17 @@ add_task(function* test_yandex_translation() {
// Translating the contents of the loaded tab.
gBrowser.selectedTab = tab;
let browser = tab.linkedBrowser;
let client = new YandexTranslator(
new TranslationDocument(browser.contentDocument), "fr", "en");
let result = yield client.translate();
Assert.ok(result, "There should be a result.");
yield ContentTask.spawn(browser, null, function*() {
Cu.import("resource:///modules/translation/TranslationDocument.jsm");
Cu.import("resource:///modules/translation/YandexTranslator.jsm");
let client = new YandexTranslator(
new TranslationDocument(content.document), "fr", "en");
let result = yield client.translate();
ok(result, "There should be a result.");
});
gBrowser.removeTab(tab);
});

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

@ -18,5 +18,4 @@ browser = true
qemu = false
[chrome/content/shared/test/test_shared_all.py]
skip-if = os == "win" # Bug 1149955
[chrome/content/panels/test/test_desktop_all.py]

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

@ -8402,12 +8402,6 @@ if test -n "$MOZ_SERVICES_HEALTHREPORT"; then
AC_DEFINE(MOZ_SERVICES_HEALTHREPORT)
fi
dnl Build Services metrics component
AC_SUBST(MOZ_SERVICES_METRICS)
if test -n "$MOZ_SERVICES_METRICS"; then
AC_DEFINE(MOZ_SERVICES_METRICS)
fi
dnl Build Notifications if required
AC_SUBST(MOZ_SERVICES_NOTIFICATIONS)
if test -n "$MOZ_SERVICES_NOTIFICATIONS"; then

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

@ -136,11 +136,11 @@ function test() {
is(gEditor.getText().search(/debugger/), -1,
"The second source is not displayed.");
ok(isCaretPos(gPanel, 6),
ok(isCaretPos(gPanel, 5),
"Editor caret location is correct.");
is(gEditor.getDebugLocation(), 5,
is(gEditor.getDebugLocation(), 4,
"Editor debugger location is correct.");
ok(gEditor.hasLineClass(5, "debug-line"),
ok(gEditor.hasLineClass(4, "debug-line"),
"The debugged line is highlighted appropriately (3).");
}

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

@ -131,11 +131,11 @@ function test() {
"The second source is not displayed.");
// The editor's debug location takes a tick to update.
ok(isCaretPos(gPanel, 6),
ok(isCaretPos(gPanel, 5),
"Editor caret location is correct.");
is(gEditor.getDebugLocation(), 5,
is(gEditor.getDebugLocation(), 4,
"Editor debugger location is correct.");
ok(gEditor.hasLineClass(5, "debug-line"),
ok(gEditor.hasLineClass(4, "debug-line"),
"The debugged line is highlighted appropriately.");
deferred.resolve();

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

@ -36,13 +36,13 @@ function test() {
let stepTests = [
{key: 'VK_F11', keyRepeat: 1, caretLine: 16},
{key: 'VK_F11', keyRepeat: 2, caretLine: 18},
{key: 'VK_F11', keyRepeat: 2, caretLine: 27},
{key: 'VK_F10', keyRepeat: 1, caretLine: 27},
{key: 'VK_F11', keyRepeat: 1, caretLine: 18},
{key: 'VK_F11', keyRepeat: 5, caretLine: 32},
{key: 'VK_F11', modifier:'Shift', keyRepeat: 1, caretLine: 29},
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 34},
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 34}
{key: 'VK_F11', keyRepeat: 2, caretLine: 26},
{key: 'VK_F10', keyRepeat: 1, caretLine: 18},
{key: 'VK_F11', keyRepeat: 1, caretLine: 19},
{key: 'VK_F11', keyRepeat: 5, caretLine: 29},
{key: 'VK_F11', modifier:'Shift', keyRepeat: 1, caretLine: 32},
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 32},
{key: 'VK_F11', modifier:'Shift', keyRepeat: 2, caretLine: 20}
];
// Trigger script that stops at debugger statement
executeSoon(() => generateMouseClickInTab(gTab,

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

@ -23,7 +23,7 @@ function test() {
function testNormalReturn() {
waitForSourceAndCaretAndScopes(gPanel, ".html", 17).then(() => {
waitForCaretAndScopes(gPanel, 20).then(() => {
waitForCaretAndScopes(gPanel, 19).then(() => {
let innerScope = gVars.getScopeAtIndex(0);
let returnVar = innerScope.get("<return>");

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

@ -4,7 +4,7 @@
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const {Cc, Ci} = require("chrome");
const { Services } = require("resource://gre/modules/Services.jsm");
@ -41,7 +41,7 @@ const scratchpadProps = "chrome://devtools/locale/scratchpad.properties";
const memoryProps = "chrome://devtools/locale/memory.properties";
loader.lazyGetter(this, "toolboxStrings", () => Services.strings.createBundle(toolboxProps));
loader.lazyGetter(this, "performanceStrings",() => Services.strings.createBundle(performanceProps));
loader.lazyGetter(this, "performanceStrings", () => Services.strings.createBundle(performanceProps));
loader.lazyGetter(this, "webConsoleStrings", () => Services.strings.createBundle(webConsoleProps));
loader.lazyGetter(this, "debuggerStrings", () => Services.strings.createBundle(debuggerProps));
loader.lazyGetter(this, "styleEditorStrings", () => Services.strings.createBundle(styleEditorProps));
@ -71,14 +71,14 @@ Tools.options = {
tooltip: l10n("optionsButton.tooltip", toolboxStrings),
inMenu: false,
isTargetSupported: function(target) {
isTargetSupported: function() {
return true;
},
build: function(iframeWindow, toolbox) {
return new OptionsPanel(iframeWindow, toolbox);
}
}
};
Tools.inspector = {
id: "inspector",
@ -93,7 +93,7 @@ Tools.inspector = {
panelLabel: l10n("inspector.panelLabel", inspectorStrings),
get tooltip() {
return l10n("inspector.tooltip2", inspectorStrings,
( osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+" ) + this.key);
(osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") + this.key);
},
inMenu: true,
commands: [
@ -127,20 +127,21 @@ Tools.webConsole = {
panelLabel: l10n("ToolboxWebConsole.panelLabel", webConsoleStrings),
get tooltip() {
return l10n("ToolboxWebconsole.tooltip2", webConsoleStrings,
( osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+" ) + this.key);
(osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") + this.key);
},
inMenu: true,
commands: "devtools/client/webconsole/console-commands",
preventClosingOnKey: true,
onkey: function(panel, toolbox) {
if (toolbox.splitConsole)
if (toolbox.splitConsole) {
return toolbox.focusConsoleInput();
}
panel.focusInput();
},
isTargetSupported: function(target) {
isTargetSupported: function() {
return true;
},
@ -163,12 +164,12 @@ Tools.jsdebugger = {
panelLabel: l10n("ToolboxDebugger.panelLabel", debuggerStrings),
get tooltip() {
return l10n("ToolboxDebugger.tooltip2", debuggerStrings,
( osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+" ) + this.key);
(osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") + this.key);
},
inMenu: true,
commands: "devtools/client/debugger/debugger-commands",
isTargetSupported: function(target) {
isTargetSupported: function() {
return true;
},
@ -241,7 +242,7 @@ Tools.canvasDebugger = {
return target.hasActor("canvas") && !target.chrome;
},
build: function (iframeWindow, toolbox) {
build: function(iframeWindow, toolbox) {
return new CanvasDebuggerPanel(iframeWindow, toolbox);
}
};
@ -265,11 +266,11 @@ Tools.performance = {
modifiers: "shift",
inMenu: true,
isTargetSupported: function (target) {
isTargetSupported: function(target) {
return target.hasActor("profiler");
},
build: function (frame, target) {
build: function(frame, target) {
return new PerformancePanel(frame, target);
}
};
@ -286,11 +287,11 @@ Tools.memory = {
panelLabel: l10n("memory.panelLabel", memoryStrings),
tooltip: l10n("memory.tooltip", memoryStrings),
isTargetSupported: function (target) {
isTargetSupported: function(target) {
return target.getTrait("heapSnapshots");
},
build: function (frame, target) {
build: function(frame, target) {
return new MemoryPanel(frame, target);
}
};
@ -309,7 +310,7 @@ Tools.netMonitor = {
panelLabel: l10n("netmonitor.panelLabel", netMonitorStrings),
get tooltip() {
return l10n("netmonitor.tooltip2", netMonitorStrings,
( osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+" ) + this.key);
(osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") + this.key);
},
inMenu: true,
@ -343,8 +344,7 @@ Tools.storage = {
isTargetSupported: function(target) {
return target.isLocalTab ||
( target.hasActor("storage") &&
target.getTrait("storageInspector") );
(target.hasActor("storage") && target.getTrait("storageInspector"));
},
build: function(iframeWindow, toolbox) {
@ -442,8 +442,7 @@ exports.defaultThemes = [
* The key to lookup.
* @returns A localized version of the given key.
*/
function l10n(name, bundle, arg)
{
function l10n(name, bundle, arg) {
try {
return arg ? bundle.formatStringFromName(name, [arg], 1)
: bundle.GetStringFromName(name);
@ -453,7 +452,6 @@ function l10n(name, bundle, arg)
}
}
function functionkey(shortkey)
{
function functionkey(shortkey) {
return shortkey.split("_")[1];
}

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

@ -2,7 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
/* FIXME: remove this globals comment and replace with import-globals-from when
bug 1242893 is fixed */
/* globals BrowserToolboxProcess */
"use strict";
const { interfaces: Ci, utils: Cu } = Components;
const kDebuggerPrefs = [
"devtools.debugger.remote-enabled",
"devtools.chrome.enabled"
@ -10,8 +16,8 @@ const kDebuggerPrefs = [
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
function devtoolsCommandlineHandler() {
}
function devtoolsCommandlineHandler() {}
devtoolsCommandlineHandler.prototype = {
handle: function(cmdLine) {
let consoleFlag = cmdLine.handleFlag("jsconsole", false);
@ -31,7 +37,7 @@ devtoolsCommandlineHandler.prototype = {
try {
debuggerServerFlag =
cmdLine.handleFlagWithParam("start-debugger-server", false);
} catch(e) {
} catch (e) {
// We get an error if the option is given but not followed by a value.
// By catching and trying again, the value is effectively optional.
debuggerServerFlag = cmdLine.handleFlag("start-debugger-server", false);
@ -51,7 +57,8 @@ devtoolsCommandlineHandler.prototype = {
let { console } = Cu.import("resource://gre/modules/Console.jsm", {});
hudservice.toggleBrowserConsole().then(null, console.error);
} else {
window.focus(); // the Browser Console was already open
// the Browser Console was already open
window.focus();
}
if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
@ -62,7 +69,8 @@ devtoolsCommandlineHandler.prototype = {
// Open the toolbox on the selected tab once the browser starts up.
handleDevToolsFlag: function() {
Services.obs.addObserver(function onStartup(window) {
Services.obs.removeObserver(onStartup, "browser-delayed-startup-finished");
Services.obs.removeObserver(onStartup,
"browser-delayed-startup-finished");
const {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
const {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let target = devtools.TargetFactory.forTab(window.gBrowser.selectedTab);
@ -73,14 +81,16 @@ devtoolsCommandlineHandler.prototype = {
_isRemoteDebuggingEnabled() {
let remoteDebuggingEnabled = false;
try {
remoteDebuggingEnabled = kDebuggerPrefs.every((pref) => Services.prefs.getBoolPref(pref));
remoteDebuggingEnabled = kDebuggerPrefs.every(pref => {
return Services.prefs.getBoolPref(pref);
});
} catch (ex) {
Cu.reportError(ex);
return false;
}
if (!remoteDebuggingEnabled) {
let errorMsg = "Could not run chrome debugger! You need the following prefs " +
"to be set to true: " + kDebuggerPrefs.join(", ");
let errorMsg = "Could not run chrome debugger! You need the following " +
"prefs to be set to true: " + kDebuggerPrefs.join(", ");
Cu.reportError(errorMsg);
// Dump as well, as we're doing this from a commandline, make sure people
// don't miss it:
@ -131,7 +141,7 @@ devtoolsCommandlineHandler.prototype = {
listener.portOrPath = portOrPath;
listener.open();
dump("Started debugger server on " + portOrPath + "\n");
} catch(e) {
} catch (e) {
dump("Unable to start debugger server on " + portOrPath + ": " + e);
}
@ -140,15 +150,16 @@ devtoolsCommandlineHandler.prototype = {
}
},
helpInfo : " --jsconsole Open the Browser Console.\n" +
" --jsdebugger Open the Browser Toolbox.\n" +
" --devtools Open DevTools on initial load.\n" +
" --start-debugger-server [port|path] " +
"Start the debugger server on a TCP port or " +
"Unix domain socket path. Defaults to TCP port 6000.\n",
helpInfo: " --jsconsole Open the Browser Console.\n" +
" --jsdebugger Open the Browser Toolbox.\n" +
" --devtools Open DevTools on initial load.\n" +
" --start-debugger-server [port|path] " +
"Start the debugger server on a TCP port or " +
"Unix domain socket path. Defaults to TCP port 6000.\n",
classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([devtoolsCommandlineHandler]);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
[devtoolsCommandlineHandler]);

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

@ -264,12 +264,7 @@ ToolSidebar.prototype = {
this._tabs.set(id, tab);
if (selected) {
// For some reason I don't understand, if we call this.select in this
// event loop (after inserting the tab), the tab will never get the
// the "selected" attribute set to true.
this._panelDoc.defaultView.setTimeout(() => {
this.select(id);
}, 10);
this._selectTabSoon(id);
}
this.emit("new-tab-registered", id);
@ -291,6 +286,12 @@ ToolSidebar.prototype = {
// Find an ID for this unknown tab
let id = tab.getAttribute("id") || "untitled-tab-" + (this.untitledTabsIndex++);
// If the existing tab contains the tab ID prefix, extract the ID of the
// tab
if (id.startsWith(this.TAB_ID_PREFIX)) {
id = id.split(this.TAB_ID_PREFIX).pop();
}
// Register the tab
this._tabs.set(id, tab);
this.emit("new-tab-registered", id);
@ -357,6 +358,18 @@ ToolSidebar.prototype = {
}
},
/**
* Hack required to select a tab right after it was created.
*
* @param {String} id
* The sidebar tab id to select.
*/
_selectTabSoon: function(id) {
this._panelDoc.defaultView.setTimeout(() => {
this.select(id);
}, 0);
},
/**
* Return the id of the selected tab.
*/
@ -450,13 +463,28 @@ ToolSidebar.prototype = {
/**
* Show the sidebar.
*
* @param {String} id
* The sidebar tab id to select.
*/
show: function() {
show: function(id) {
if (this._width) {
this._tabbox.width = this._width;
}
this._tabbox.removeAttribute("hidden");
// If an id is given, select the corresponding sidebar tab and record the
// tool opened.
if (id) {
this._currentTool = id;
if (this._telemetry) {
this._telemetry.toolOpened(this._currentTool);
}
this._selectTabSoon(id);
}
this.emit("show");
},

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

@ -8,6 +8,7 @@ const {Cu, Cc, Ci} = require("chrome");
const Services = require("Services");
const promise = require("promise");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools", "resource://devtools/client/framework/gDevTools.jsm");
exports.OptionsPanel = OptionsPanel;
@ -94,32 +95,21 @@ OptionsPanel.prototype = {
return this.toolbox.target;
},
open: function() {
let targetPromise;
open: Task.async(function*() {
// For local debugging we need to make the target remote.
if (!this.target.isRemote) {
targetPromise = this.target.makeRemote();
} else {
targetPromise = promise.resolve(this.target);
yield this.target.makeRemote();
}
return targetPromise.then(() => {
this.setupToolsList();
this.setupToolbarButtonsList();
this.setupThemeList();
this.updateDefaultTheme();
}).then(() => {
return this.populatePreferences();
}).then(() => {
this.isReady = true;
this.emit("ready");
return this;
}).then(null, function onError(aReason) {
Cu.reportError("OptionsPanel open failed. " +
aReason.error + ": " + aReason.message);
});
},
this.setupToolsList();
this.setupToolbarButtonsList();
this.setupThemeList();
this.updateDefaultTheme();
yield this.populatePreferences();
this.isReady = true;
this.emit("ready");
return this;
}),
_addListeners: function() {
gDevTools.on("pref-changed", this._prefChanged);

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

@ -963,13 +963,15 @@ PropertyView.prototype = {
};
this.element.addEventListener("keydown", this.onKeyDown, false);
let nameContainer = doc.createElementNS(HTML_NS, "div");
nameContainer.className = "property-name-container";
this.element.appendChild(nameContainer);
// Build the twisty expand/collapse
this.matchedExpander = doc.createElementNS(HTML_NS, "div");
this.matchedExpander.className = "expander theme-twisty";
this.matchedExpander.addEventListener("click", this.onMatchedToggle, false);
this.element.appendChild(this.matchedExpander);
this.focusElement = () => this.element.focus();
nameContainer.appendChild(this.matchedExpander);
// Build the style name element
this.nameNode = doc.createElementNS(HTML_NS, "div");
@ -981,7 +983,11 @@ PropertyView.prototype = {
// Make it hand over the focus to the container
this.onFocus = () => this.element.focus();
this.nameNode.addEventListener("click", this.onFocus, false);
this.element.appendChild(this.nameNode);
nameContainer.appendChild(this.nameNode);
let valueContainer = doc.createElementNS(HTML_NS, "div");
valueContainer.className = "property-value-container";
this.element.appendChild(valueContainer);
// Build the style value element
this.valueNode = doc.createElementNS(HTML_NS, "div");
@ -992,7 +998,7 @@ PropertyView.prototype = {
this.valueNode.setAttribute("dir", "ltr");
// Make it hand over the focus to the container
this.valueNode.addEventListener("click", this.onFocus, false);
this.element.appendChild(this.valueNode);
valueContainer.appendChild(this.valueNode);
return this.element;
},

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

@ -1,78 +0,0 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE window [
<!ENTITY % inspectorDTD SYSTEM "chrome://devtools/locale/styleinspector.dtd">
%inspectorDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
<!ELEMENT loop ANY>
<!ATTLIST li foreach CDATA #IMPLIED>
<!ATTLIST div foreach CDATA #IMPLIED>
<!ATTLIST loop foreach CDATA #IMPLIED>
<!ATTLIST a target CDATA #IMPLIED>
<!ATTLIST a __pathElement CDATA #IMPLIED>
<!ATTLIST div _id CDATA #IMPLIED>
<!ATTLIST div save CDATA #IMPLIED>
<!ATTLIST table save CDATA #IMPLIED>
<!ATTLIST loop if CDATA #IMPLIED>
<!ATTLIST tr if CDATA #IMPLIED>
]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
class="theme-sidebar">
<head>
<title>&computedViewTitle;</title>
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
<link rel="stylesheet" href="chrome://devtools/skin/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://devtools/skin/computed.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
<script type="application/javascript;version=1.8">
window.setPanel = function(panel, iframe) {
let {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
let {ComputedViewTool} = require("devtools/client/inspector/computed/computed");
this.computedview = new ComputedViewTool(panel, window);
}
window.onunload = function() {
if (this.computedview) {
this.computedview.destroy();
}
}
</script>
</head>
<body dir="&locale.dir;">
<div id="root" class="devtools-monospace">
<div class="devtools-toolbar">
<div class="devtools-searchbox">
<input id="computedview-searchbox"
class="devtools-searchinput devtools-rule-searchbox"
type="search" placeholder="&filterStylesPlaceholder;"/>
<button id="computedview-searchinput-clear" class="devtools-searchinput-clear"></button>
</div>
<xul:checkbox id="browser-style-checkbox"
class="includebrowserstyles"
checked="false" label="&browserStylesLabel;"/>
</div>
</div>
<!-- The output from #templateProperty (below) is appended here. -->
<div id="propertyContainer" class="devtools-monospace">
</div>
<!-- When no properties are found the following block is displayed. -->
<div id="noResults" hidden="">
&noPropertiesFound;
</div>
</body>
</html>

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

@ -22,17 +22,17 @@ add_task(function*() {
info("Checking the property itself");
let container = getComputedViewPropertyView(view, "color").valueNode;
checkColorCycling(container, inspector);
checkColorCycling(container, view);
info("Checking matched selectors");
container = yield getComputedViewMatchedRules(view, "color");
checkColorCycling(container, inspector);
checkColorCycling(container, view);
});
function checkColorCycling(container, inspector) {
function checkColorCycling(container, view) {
let swatch = container.querySelector(".computedview-colorswatch");
let valueNode = container.querySelector(".computedview-color");
let win = inspector.sidebar.getWindowForTab("computedview");
let win = view.styleWindow;
// "Authored" (default; currently the computed value)
is(valueNode.textContent, "rgb(255, 0, 0)",

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

@ -37,8 +37,8 @@ add_task(function*() {
is(cmdUndo.getAttribute("disabled"), "true", "cmdUndo is disabled");
is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled");
is(cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled");
is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled");
is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled");
is(cmdCut.getAttribute("disabled"), "true", "cmdCut is disabled");
is(cmdCopy.getAttribute("disabled"), "true", "cmdCopy is disabled");
is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled");
info("Closing context menu");

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

@ -53,7 +53,7 @@ function* checkCopySelection(view) {
let range = contentDocument.createRange();
range.setStart(props[1], 0);
range.setEnd(props[3], 3);
range.setEnd(props[3], 2);
contentDocument.defaultView.getSelection().addRange(range);
info("Checking that cssHtmlTree.siBoundCopy() returns the correct " +

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

@ -19,11 +19,11 @@ registerCleanupFunction(() => {
* view is visible and ready
*/
function openComputedView() {
return openInspectorSidebarTab("computedview").then(objects => {
return openInspectorSidebarTab("computedview").then(({toolbox, inspector}) => {
return {
toolbox: objects.toolbox,
inspector: objects.inspector,
view: objects.view.view
toolbox,
inspector,
view: inspector.computedview.view
};
});
}

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

@ -6,7 +6,10 @@
"use strict";
var { utils: Cu } = Components;
const {Cu} = require("chrome");
const {setTimeout, clearTimeout} =
Cu.import("resource://gre/modules/Timer.jsm", {});
const DEFAULT_PREVIEW_TEXT = "Abc";
const PREVIEW_UPDATE_DELAY = 150;
@ -16,8 +19,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/Console.jsm");
function FontInspector(inspector, window)
{
function FontInspector(inspector, window) {
this.inspector = inspector;
this.pageStyle = this.inspector.pageStyle;
this.chromeDoc = window.document;
@ -32,10 +34,11 @@ FontInspector.prototype = {
this.inspector.selection.on("new-node", this.onNewNode);
this.inspector.sidebar.on("fontinspector-selected", this.onNewNode);
this.showAll = this.showAll.bind(this);
this.showAllButton = this.chromeDoc.getElementById("showall");
this.showAllButton = this.chromeDoc.getElementById("font-showall");
this.showAllButton.addEventListener("click", this.showAll);
this.previewTextChanged = this.previewTextChanged.bind(this);
this.previewInput = this.chromeDoc.getElementById("preview-text-input");
this.previewInput =
this.chromeDoc.getElementById("font-preview-text-input");
this.previewInput.addEventListener("input", this.previewTextChanged);
// Listen for theme changes as the color of the previews depend on the theme
@ -123,7 +126,8 @@ FontInspector.prototype = {
* Hide the font list. No node are selected.
*/
dim: function() {
this.chromeDoc.body.classList.add("dim");
let panel = this.chromeDoc.getElementById("sidebar-panel-fontinspector");
panel.classList.add("dim");
this.clear();
},
@ -131,7 +135,8 @@ FontInspector.prototype = {
* Show the font list. A node is selected.
*/
undim: function() {
this.chromeDoc.body.classList.remove("dim");
let panel = this.chromeDoc.getElementById("sidebar-panel-fontinspector");
panel.classList.remove("dim");
},
/**
@ -146,12 +151,13 @@ FontInspector.prototype = {
*/
update: Task.async(function*(showAllFonts) {
let node = this.inspector.selection.nodeFront;
let panel = this.chromeDoc.getElementById("sidebar-panel-fontinspector");
if (!node ||
!this.isActive() ||
!this.inspector.selection.isConnected() ||
!this.inspector.selection.isElementNode() ||
this.chromeDoc.body.classList.contains("dim")) {
panel.classList.contains("dim")) {
return;
}
@ -205,7 +211,7 @@ FontInspector.prototype = {
* Display the information of one font.
*/
render: function(font) {
let s = this.chromeDoc.querySelector("#template > section");
let s = this.chromeDoc.querySelector("#font-template > section");
s = s.cloneNode(true);
s.querySelector(".font-name").textContent = font.name;
@ -247,12 +253,4 @@ FontInspector.prototype = {
},
};
window.setPanel = function(panel) {
window.fontInspector = new FontInspector(panel, window);
};
window.onunload = function() {
if (window.fontInspector) {
window.fontInspector.destroy();
}
};
exports.FontInspector = FontInspector;

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

@ -1,52 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % fontinspectorDTD SYSTEM "chrome://devtools/locale/font-inspector.dtd" >
%fontinspectorDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&fontInspectorTitle;</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://devtools/skin/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://devtools/skin/fonts.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
</head>
<body class="theme-sidebar devtools-monospace" role="application">
<script type="application/javascript;version=1.8" src="fonts.js"></script>
<div>
<div class="devtools-toolbar preview-input-toolbar">
<div class="devtools-searchbox">
<input id="preview-text-input"
class="devtools-textinput"
placeholder="&previewHint;"/>
</div>
</div>
</div>
<div id="root">
<ul id="all-fonts"></ul>
<button id="showall">&showAllFonts;</button>
</div>
<div id="template">
<section class="font">
<div class="font-preview-container">
<img class="font-preview"></img>
</div>
<div class="font-info">
<h1 class="font-name"></h1>
<span class="font-is-local">&system;</span>
<span class="font-is-remote">&remote;</span>
<p class="font-format-url">
<input readonly="readonly" class="font-url"></input>
<span class="font-format"></span>
</p>
<p class="font-css">&usedAs; "<span class="font-css-name"></span>"</p>
<pre class="font-css-code"></pre>
</div>
</section>
</div>
</body>
</html>

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

@ -82,7 +82,7 @@ function* testShowAllFonts(inspector, viewDoc) {
info("testing showing all fonts");
let updated = inspector.once("fontinspector-updated");
viewDoc.querySelector("#showall").click();
viewDoc.querySelector("#font-showall").click();
yield updated;
// shouldn't change the node selection

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

@ -21,7 +21,7 @@ add_task(function*() {
let onUpdated = inspector.once("fontinspector-updated");
info("Clicking 'Select all' button.");
viewDoc.getElementById("showall").click();
viewDoc.getElementById("font-showall").click();
info("Waiting for font-inspector to update.");
yield onUpdated;

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

@ -36,7 +36,7 @@ var openFontInspectorForURL = Task.async(function*(url) {
return {
toolbox,
inspector,
view: inspector.sidebar.getWindowForTab("fontinspector").fontInspector
view: inspector.fontInspector
};
});
@ -51,7 +51,7 @@ function* updatePreviewText(view, text) {
info(`Changing the preview text to '${text}'`);
let doc = view.chromeDoc;
let input = doc.getElementById("preview-text-input");
let input = doc.getElementById("font-preview-text-input");
let update = view.inspector.once("fontinspector-updated");
info("Focusing the input field.");

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

@ -4,7 +4,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {Cc, Ci, Cu, Cr} = require("chrome");
"use strict";
const {Cc, Ci, Cu} = require("chrome");
Cu.import("resource://gre/modules/Services.jsm");
@ -19,6 +21,10 @@ loader.lazyGetter(this, "MarkupView", () => require("devtools/client/inspector/m
loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/client/inspector/breadcrumbs").HTMLBreadcrumbs);
loader.lazyGetter(this, "ToolSidebar", () => require("devtools/client/framework/sidebar").ToolSidebar);
loader.lazyGetter(this, "InspectorSearch", () => require("devtools/client/inspector/inspector-search").InspectorSearch);
loader.lazyGetter(this, "RuleViewTool", () => require("devtools/client/inspector/rules/rules").RuleViewTool);
loader.lazyGetter(this, "ComputedViewTool", () => require("devtools/client/inspector/computed/computed").ComputedViewTool);
loader.lazyGetter(this, "FontInspector", () => require("devtools/client/inspector/fonts/fonts").FontInspector);
loader.lazyGetter(this, "LayoutView", () => require("devtools/client/inspector/layout/layout").LayoutView);
loader.lazyGetter(this, "strings", () => {
return Services.strings.createBundle("chrome://devtools/locale/inspector.properties");
@ -352,23 +358,16 @@ InspectorPanel.prototype = {
this.sidebar.on("select", this._setDefaultSidebar);
this.sidebar.addTab("ruleview",
"chrome://devtools/content/inspector/rules/rules.xhtml",
"ruleview" == defaultTab);
this.ruleview = new RuleViewTool(this, this.panelWin);
this.computedview = new ComputedViewTool(this, this.panelWin);
this.sidebar.addTab("computedview",
"chrome://devtools/content/inspector/computed/computed.xhtml",
"computedview" == defaultTab);
if (Services.prefs.getBoolPref("devtools.fontinspector.enabled") && this.canGetUsedFontFaces) {
this.sidebar.addTab("fontinspector",
"chrome://devtools/content/inspector/fonts/fonts.xhtml",
"fontinspector" == defaultTab);
if (Services.prefs.getBoolPref("devtools.fontinspector.enabled") &&
this.canGetUsedFontFaces) {
this.fontInspector = new FontInspector(this, this.panelWin);
this.panelDoc.getElementById("sidebar-tab-fontinspector").hidden = false;
}
this.sidebar.addTab("layoutview",
"chrome://devtools/content/inspector/layout/layout.xhtml",
"layoutview" == defaultTab);
this.layoutview = new LayoutView(this, this.panelWin);
if (this.target.form.animationsActor) {
this.sidebar.addTab("animationinspector",
@ -376,7 +375,7 @@ InspectorPanel.prototype = {
"animationinspector" == defaultTab);
}
this.sidebar.show();
this.sidebar.show(defaultTab);
this.setupSidebarToggle();
},
@ -586,6 +585,22 @@ InspectorPanel.prototype = {
this._toolbox.off("select", this.updateDebuggerPausedWarning);
this._toolbox.off("host-changed", this.onToolboxHostChanged);
if (this.ruleview) {
this.ruleview.destroy();
}
if (this.computedview) {
this.computedview.destroy();
}
if (this.fontInspector) {
this.fontInspector.destroy();
}
if (this.layoutview) {
this.layoutview.destroy();
}
this.sidebar.off("select", this._setDefaultSidebar);
let sidebarDestroyer = this.sidebar.destroy();
this.sidebar = null;

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

@ -8,12 +8,20 @@
<?xml-stylesheet href="chrome://devtools/skin/common.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/inspector.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/rules.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/computed.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/fonts.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/layout.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % inspectorDTD SYSTEM "chrome://devtools/locale/inspector.dtd" >
%inspectorDTD;
<!ENTITY % inspectorDTD SYSTEM "chrome://devtools/locale/inspector.dtd"> %inspectorDTD;
<!ENTITY % styleinspectorDTD SYSTEM "chrome://devtools/locale/styleinspector.dtd"> %styleinspectorDTD;
<!ENTITY % fontinspectorDTD SYSTEM "chrome://devtools/locale/font-inspector.dtd"> %fontinspectorDTD;
<!ENTITY % layoutviewDTD SYSTEM "chrome://devtools/locale/layoutview.dtd"> %layoutviewDTD;
]>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml">
<script type="application/javascript;version=1.8"
src="chrome://devtools/content/shared/theme-switching.js"/>
@ -169,8 +177,145 @@
</vbox>
<splitter class="devtools-side-splitter"/>
<tabbox id="inspector-sidebar" handleCtrlTab="false" class="devtools-sidebar-tabs" hidden="true">
<tabs/>
<tabpanels flex="1"/>
<tabs>
<tab id="sidebar-tab-ruleview"
label="&ruleViewTitle;"
crop="end"/>
<tab id="sidebar-tab-computedview"
label="&computedViewTitle;"
crop="end"/>
<tab id="sidebar-tab-fontinspector"
label="&fontInspectorTitle;"
crop="end"
hidden="true"/>
<tab id="sidebar-tab-layoutview"
label="&layoutViewTitle;"
crop="end"/>
</tabs>
<tabpanels flex="1">
<tabpanel id="sidebar-panel-ruleview" class="devtools-monospace theme-sidebar">
<html:div id="ruleview-toolbar" class="devtools-toolbar devtools-sidebar-toolbar">
<html:div class="devtools-searchbox">
<html:input id="ruleview-searchbox"
class="devtools-searchinput devtools-rule-searchbox"
type="search"
placeholder="&filterStylesPlaceholder;"/>
<html:button id="ruleview-searchinput-clear" class="devtools-searchinput-clear"></html:button>
</html:div>
<html:button id="ruleview-add-rule-button" title="&addRuleButtonTooltip;" class="devtools-button"></html:button>
<html:button id="pseudo-class-panel-toggle" title="&togglePseudoClassPanel;" class="devtools-button"></html:button>
</html:div>
<html:div id="pseudo-class-panel" class="devtools-toolbar devtools-sidebar-toolbar" hidden="true" tabindex="-1">
<html:label><html:input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</html:label>
<html:label><html:input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</html:label>
<html:label><html:input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</html:label>
</html:div>
<html:div id="ruleview-container" class="ruleview">
</html:div>
</tabpanel>
<tabpanel id="sidebar-panel-computedview" class="devtools-monospace theme-sidebar">
<html:div class="devtools-toolbar devtools-sidebar-toolbar">
<html:div class="devtools-searchbox">
<html:input id="computedview-searchbox"
class="devtools-searchinput devtools-rule-searchbox"
type="search"
placeholder="&filterStylesPlaceholder;"/>
<html:button id="computedview-searchinput-clear" class="devtools-searchinput-clear"></html:button>
</html:div>
<checkbox id="browser-style-checkbox"
class="includebrowserstyles"
checked="false"
label="&browserStylesLabel;"/>
</html:div>
<html:div id="propertyContainer">
</html:div>
<html:div id="noResults" hidden="">
&noPropertiesFound;
</html:div>
</tabpanel>
<tabpanel id="sidebar-panel-fontinspector" class="devtools-monospace theme-sidebar">
<html:div class="devtools-toolbar devtools-sidebar-toolbar">
<html:div class="devtools-searchbox">
<html:input id="font-preview-text-input"
class="devtools-textinput"
type="search"
placeholder="&previewHint;"/>
</html:div>
</html:div>
<html:div id="font-container">
<html:ul id="all-fonts"></html:ul>
<html:button id="font-showall">&showAllFonts;</html:button>
</html:div>
<html:div id="font-template">
<html:section class="font">
<html:div class="font-preview-container">
<html:img class="font-preview"></html:img>
</html:div>
<html:div class="font-info">
<html:h1 class="font-name"></html:h1>
<html:span class="font-is-local">&system;</html:span>
<html:span class="font-is-remote">&remote;</html:span>
<html:p class="font-format-url">
<html:input readonly="readonly" class="font-url"></html:input>
<html:span class="font-format"></html:span>
</html:p>
<html:p class="font-css">&usedAs; "<html:span class="font-css-name"></html:span>"</html:p>
<html:pre class="font-css-code"></html:pre>
</html:div>
</html:section>
</html:div>
</tabpanel>
<tabpanel id="sidebar-panel-layoutview" class="devtools-monospace theme-sidebar">
<html:div id="layout-container">
<html:p id="layout-header">
<html:span id="layout-element-size"></html:span><html:span id="layout-element-position"></html:span>
</html:p>
<html:div id="layout-main">
<html:span class="layout-legend" data-box="margin" title="&margin.tooltip;">&margin.tooltip;</html:span>
<html:div id="layout-margins" data-box="margin" title="&margin.tooltip;">
<html:span class="layout-legend" data-box="border" title="&border.tooltip;">&border.tooltip;</html:span>
<html:div id="layout-borders" data-box="border" title="&border.tooltip;">
<html:span class="layout-legend" data-box="padding" title="&padding.tooltip;">&padding.tooltip;</html:span>
<html:div id="layout-padding" data-box="padding" title="&padding.tooltip;">
<html:div id="layout-content" data-box="content" title="&content.tooltip;">
</html:div>
</html:div>
</html:div>
</html:div>
<html:p class="layout-border layout-top"><html:span data-box="border" class="layout-editable" title="border-top"></html:span></html:p>
<html:p class="layout-border layout-right"><html:span data-box="border" class="layout-editable" title="border-right"></html:span></html:p>
<html:p class="layout-border layout-bottom"><html:span data-box="border" class="layout-editable" title="border-bottom"></html:span></html:p>
<html:p class="layout-border layout-left"><html:span data-box="border" class="layout-editable" title="border-left"></html:span></html:p>
<html:p class="layout-margin layout-top"><html:span data-box="margin" class="layout-editable" title="margin-top"></html:span></html:p>
<html:p class="layout-margin layout-right"><html:span data-box="margin" class="layout-editable" title="margin-right"></html:span></html:p>
<html:p class="layout-margin layout-bottom"><html:span data-box="margin" class="layout-editable" title="margin-bottom"></html:span></html:p>
<html:p class="layout-margin layout-left"><html:span data-box="margin" class="layout-editable" title="margin-left"></html:span></html:p>
<html:p class="layout-padding layout-top"><html:span data-box="padding" class="layout-editable" title="padding-top"></html:span></html:p>
<html:p class="layout-padding layout-right"><html:span data-box="padding" class="layout-editable" title="padding-right"></html:span></html:p>
<html:p class="layout-padding layout-bottom"><html:span data-box="padding" class="layout-editable" title="padding-bottom"></html:span></html:p>
<html:p class="layout-padding layout-left"><html:span data-box="padding" class="layout-editable" title="padding-left"></html:span></html:p>
<html:p class="layout-size"><html:span data-box="content" title="&content.tooltip;"></html:span></html:p>
</html:div>
<html:div style="display: none">
<html:p id="layout-dummy"></html:p>
</html:div>
</html:div>
</tabpanel>
</tabpanels>
</tabbox>
</box>
</window>

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

@ -6,16 +6,15 @@
"use strict";
var {utils: Cu, interfaces: Ci, classes: Cc} = Components;
const {Cc, Ci, Cu} = require("chrome");
const {InplaceEditor, editableItem} =
require("devtools/client/shared/inplace-editor");
const {ReflowFront} = require("devtools/server/actors/layout");
Cu.import("resource://gre/modules/Task.jsm");
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
Cu.import("resource://gre/modules/Console.jsm");
Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
const {InplaceEditor, editableItem} = require("devtools/client/shared/inplace-editor");
const {ReflowFront} = require("devtools/server/actors/layout");
const STRINGS_URI = "chrome://devtools/locale/shared.properties";
const SHARED_L10N = new ViewHelpers.L10N(STRINGS_URI);
const NUMERIC = /^-?[\d\.]+$/;
@ -60,7 +59,7 @@ EditingSession.prototype = {
// Create a hidden element for getPropertyFromRule to use
let div = this._doc.createElement("div");
div.setAttribute("style", "display: none");
this._doc.body.appendChild(div);
this._doc.getElementById("sidebar-panel-layoutview").appendChild(div);
this._element = this._doc.createElement("p");
div.appendChild(this._element);
@ -137,10 +136,9 @@ EditingSession.prototype = {
*/
function LayoutView(inspector, win) {
this.inspector = inspector;
this.doc = win.document;
this.sizeLabel = this.doc.querySelector(".size > span");
this.sizeHeadingLabel = this.doc.getElementById("element-size");
this.sizeLabel = this.doc.querySelector(".layout-size > span");
this.sizeHeadingLabel = this.doc.getElementById("layout-element-size");
this.init();
}
@ -158,50 +156,78 @@ LayoutView.prototype = {
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.inspector.sidebar.on("select", this.onSidebarSelect);
this.initBoxModelHighlighter();
// Store for the different dimensions of the node.
// 'selector' refers to the element that holds the value in view.xhtml;
// 'property' is what we are measuring;
// 'value' is the computed dimension, computed in update().
this.map = {
position: {selector: "#element-position",
property: "position",
value: undefined},
marginTop: {selector: ".margin.top > span",
property: "margin-top",
value: undefined},
marginBottom: {selector: ".margin.bottom > span",
property: "margin-bottom",
value: undefined},
marginLeft: {selector: ".margin.left > span",
property: "margin-left",
value: undefined},
marginRight: {selector: ".margin.right > span",
property: "margin-right",
value: undefined},
paddingTop: {selector: ".padding.top > span",
property: "padding-top",
value: undefined},
paddingBottom: {selector: ".padding.bottom > span",
property: "padding-bottom",
value: undefined},
paddingLeft: {selector: ".padding.left > span",
property: "padding-left",
value: undefined},
paddingRight: {selector: ".padding.right > span",
property: "padding-right",
value: undefined},
borderTop: {selector: ".border.top > span",
property: "border-top-width",
value: undefined},
borderBottom: {selector: ".border.bottom > span",
property: "border-bottom-width",
value: undefined},
borderLeft: {selector: ".border.left > span",
property: "border-left-width",
value: undefined},
borderRight: {selector: ".border.right > span",
property: "border-right-width",
value: undefined}
position: {
selector: "#layout-element-position",
property: "position",
value: undefined
},
marginTop: {
selector: ".layout-margin.layout-top > span",
property: "margin-top",
value: undefined
},
marginBottom: {
selector: ".layout-margin.layout-bottom > span",
property: "margin-bottom",
value: undefined
},
marginLeft: {
selector: ".layout-margin.layout-left > span",
property: "margin-left",
value: undefined
},
marginRight: {
selector: ".layout-margin.layout-right > span",
property: "margin-right",
value: undefined
},
paddingTop: {
selector: ".layout-padding.layout-top > span",
property: "padding-top",
value: undefined
},
paddingBottom: {
selector: ".layout-padding.layout-bottom > span",
property: "padding-bottom",
value: undefined
},
paddingLeft: {
selector: ".layout-padding.layout-left > span",
property: "padding-left",
value: undefined
},
paddingRight: {
selector: ".layout-padding.layout-right > span",
property: "padding-right",
value: undefined
},
borderTop: {
selector: ".layout-border.layout-top > span",
property: "border-top-width",
value: undefined
},
borderBottom: {
selector: ".layout-border.layout-bottom > span",
property: "border-bottom-width",
value: undefined
},
borderLeft: {
selector: ".layout-border.layout-left > span",
property: "border-left-width",
value: undefined
},
borderRight: {
selector: ".layout-border.layout-right > span",
property: "border-right-width",
value: undefined
}
};
// Make each element the dimensions editable
@ -219,6 +245,24 @@ LayoutView.prototype = {
}
this.onNewNode();
// Mark document as RTL or LTR:
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry);
let dir = chromeReg.isLocaleRTL("global");
let container = this.doc.getElementById("layout-container");
container.setAttribute("dir", dir ? "rtl" : "ltr");
},
initBoxModelHighlighter: function() {
let highlightElts = this.doc.querySelectorAll("#layout-container *[title]");
this.onHighlightMouseOver = this.onHighlightMouseOver.bind(this);
this.onHighlightMouseOut = this.onHighlightMouseOut.bind(this);
for (let element of highlightElts) {
element.addEventListener("mouseover", this.onHighlightMouseOver, true);
element.addEventListener("mouseout", this.onHighlightMouseOut, true);
}
},
/**
@ -256,7 +300,7 @@ LayoutView.prototype = {
*/
initEditor: function(element, event, dimension) {
let { property } = dimension;
let session = new EditingSession(document, this.elementRules);
let session = new EditingSession(this.doc, this.elementRules);
let initialValue = session.getProperty(property);
let editor = new InplaceEditor({
@ -264,7 +308,7 @@ LayoutView.prototype = {
initial: initialValue,
start: editor => {
editor.elt.parentNode.classList.add("editing");
editor.elt.parentNode.classList.add("layout-editing");
},
change: value => {
@ -288,7 +332,7 @@ LayoutView.prototype = {
},
done: (value, commit) => {
editor.elt.parentNode.classList.remove("editing");
editor.elt.parentNode.classList.remove("layout-editing");
if (!commit) {
session.revert();
session.destroy();
@ -321,6 +365,13 @@ LayoutView.prototype = {
* Destroy the nodes. Remove listeners.
*/
destroy: function() {
let highlightElts = this.doc.querySelectorAll("#layout-container *[title]");
for (let element of highlightElts) {
element.removeEventListener("mouseover", this.onHighlightMouseOver, true);
element.removeEventListener("mouseout", this.onHighlightMouseOut, true);
}
this.inspector.sidebar.off("layoutview-selected", this.onNewNode);
this.inspector.selection.off("new-node-front", this.onNewSelection);
this.inspector.sidebar.off("select", this.onSidebarSelect);
@ -360,6 +411,23 @@ LayoutView.prototype = {
return this.update();
},
onHighlightMouseOver: function(e) {
let region = e.target.getAttribute("data-box");
if (!region) {
return;
}
this.showBoxModel({
region,
showOnly: region,
onlyRegionArea: true
});
},
onHighlightMouseOut: function() {
this.hideBoxModel();
},
/**
* Stop tracking reflows and hide all values when no node is selected or the
* layout-view is hidden, otherwise track reflows and show values.
@ -371,7 +439,9 @@ LayoutView.prototype = {
}
this.isActive = isActive;
this.doc.body.classList.toggle("inactive", !isActive);
let panel = this.doc.getElementById("sidebar-panel-layoutview");
panel.classList.toggle("inactive", !isActive);
if (isActive) {
this.trackReflows();
} else {
@ -536,64 +606,12 @@ LayoutView.prototype = {
manageOverflowingText: function(span) {
let classList = span.parentNode.classList;
if (classList.contains("left") || classList.contains("right")) {
if (classList.contains("layout-left") ||
classList.contains("layout-right")) {
let force = span.textContent.length > LONG_TEXT_ROTATE_LIMIT;
classList.toggle("rotate", force);
classList.toggle("layout-rotate", force);
}
}
};
var elts;
var onmouseover = function(e) {
let region = e.target.getAttribute("data-box");
if (!region) {
return false;
}
this.layoutview.showBoxModel({
region,
showOnly: region,
onlyRegionArea: true
});
return false;
}.bind(window);
var onmouseout = function() {
this.layoutview.hideBoxModel();
return false;
}.bind(window);
window.setPanel = function(panel) {
this.layoutview = new LayoutView(panel, window);
// Box model highlighter mechanism
elts = document.querySelectorAll("*[title]");
for (let i = 0; i < elts.length; i++) {
let elt = elts[i];
elt.addEventListener("mouseover", onmouseover, true);
elt.addEventListener("mouseout", onmouseout, true);
}
// Mark document as RTL or LTR:
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry);
let dir = chromeReg.isLocaleRTL("global");
document.body.setAttribute("dir", dir ? "rtl" : "ltr");
window.parent.postMessage("layoutview-ready", "*");
};
window.onunload = function() {
if (this.layoutview) {
this.layoutview.destroy();
}
if (elts) {
for (let i = 0; i < elts.length; i++) {
let elt = elts[i];
elt.removeEventListener("mouseover", onmouseover, true);
elt.removeEventListener("mouseout", onmouseout, true);
}
}
};
exports.LayoutView = LayoutView;

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

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE html [
<!ENTITY % layoutviewDTD SYSTEM "chrome://devtools/locale/layoutview.dtd" >
%layoutviewDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<head>
<title>&layoutViewTitle;</title>
<script type="application/javascript;version=1.8"
src="chrome://devtools/content/shared/theme-switching.js"/>
<script type="application/javascript;version=1.8" src="layout.js"></script>
<link rel="stylesheet" href="chrome://devtools/skin/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://devtools/skin/layout.css" type="text/css"/>
</head>
<body class="theme-sidebar devtools-monospace">
<p id="header">
<span id="element-size"></span><span id="element-position"></span>
</p>
<div id="main">
<span class="legend" data-box="margin" title="&margin.tooltip;">&margin.tooltip;</span>
<div id="margins" data-box="margin" title="&margin.tooltip;">
<span class="legend" data-box="border" title="&border.tooltip;">&border.tooltip;</span>
<div id="borders" data-box="border" title="&border.tooltip;">
<span class="legend" data-box="padding" title="&padding.tooltip;">&padding.tooltip;</span>
<div id="padding" data-box="padding" title="&padding.tooltip;">
<div id="content" data-box="content" title="&content.tooltip;">
</div>
</div>
</div>
</div>
<p class="border top"><span data-box="border" class="editable" title="border-top"></span></p>
<p class="border right"><span data-box="border" class="editable" title="border-right"></span></p>
<p class="border bottom"><span data-box="border" class="editable" title="border-bottom"></span></p>
<p class="border left"><span data-box="border" class="editable" title="border-left"></span></p>
<p class="margin top"><span data-box="margin" class="editable" title="margin-top"></span></p>
<p class="margin right"><span data-box="margin" class="editable" title="margin-right"></span></p>
<p class="margin bottom"><span data-box="margin" class="editable" title="margin-bottom"></span></p>
<p class="margin left"><span data-box="margin" class="editable" title="margin-left"></span></p>
<p class="padding top"><span data-box="padding" class="editable" title="padding-top"></span></p>
<p class="padding right"><span data-box="padding" class="editable" title="padding-right"></span></p>
<p class="padding bottom"><span data-box="padding" class="editable" title="padding-bottom"></span></p>
<p class="padding left"><span data-box="padding" class="editable" title="padding-left"></span></p>
<p class="size"><span data-box="content" title="&content.tooltip;"></span></p>
</div>
<div style="display: none">
<p id="dummy"></p>
</div>
</body>
</html>

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

@ -9,42 +9,126 @@
// Expected values:
var res1 = [
{selector: "#element-size", value: "160" + "\u00D7" + "160.117"},
{selector: ".size > span", value: "100" + "\u00D7" + "100.117"},
{selector: ".margin.top > span", value: 30},
{selector: ".margin.left > span", value: "auto"},
{selector: ".margin.bottom > span", value: 30},
{selector: ".margin.right > span", value: "auto"},
{selector: ".padding.top > span", value: 20},
{selector: ".padding.left > span", value: 20},
{selector: ".padding.bottom > span", value: 20},
{selector: ".padding.right > span", value: 20},
{selector: ".border.top > span", value: 10},
{selector: ".border.left > span", value: 10},
{selector: ".border.bottom > span", value: 10},
{selector: ".border.right > span", value: 10},
{
selector: "#layout-element-size",
value: "160" + "\u00D7" + "160.117"
},
{
selector: ".layout-size > span",
value: "100" + "\u00D7" + "100.117"
},
{
selector: ".layout-margin.layout-top > span",
value: 30
},
{
selector: ".layout-margin.layout-left > span",
value: "auto"
},
{
selector: ".layout-margin.layout-bottom > span",
value: 30
},
{
selector: ".layout-margin.layout-right > span",
value: "auto"
},
{
selector: ".layout-padding.layout-top > span",
value: 20
},
{
selector: ".layout-padding.layout-left > span",
value: 20
},
{
selector: ".layout-padding.layout-bottom > span",
value: 20
},
{
selector: ".layout-padding.layout-right > span",
value: 20
},
{
selector: ".layout-border.layout-top > span",
value: 10
},
{
selector: ".layout-border.layout-left > span",
value: 10
},
{
selector: ".layout-border.layout-bottom > span",
value: 10
},
{
selector: ".layout-border.layout-right > span",
value: 10
},
];
var res2 = [
{selector: "#element-size", value: "190" + "\u00D7" + "210"},
{selector: ".size > span", value: "100" + "\u00D7" + "150"},
{selector: ".margin.top > span", value: 30},
{selector: ".margin.left > span", value: "auto"},
{selector: ".margin.bottom > span", value: 30},
{selector: ".margin.right > span", value: "auto"},
{selector: ".padding.top > span", value: 20},
{selector: ".padding.left > span", value: 20},
{selector: ".padding.bottom > span", value: 20},
{selector: ".padding.right > span", value: 50},
{selector: ".border.top > span", value: 10},
{selector: ".border.left > span", value: 10},
{selector: ".border.bottom > span", value: 10},
{selector: ".border.right > span", value: 10},
{
selector: "#layout-element-size",
value: "190" + "\u00D7" + "210"
},
{
selector: ".layout-size > span",
value: "100" + "\u00D7" + "150"
},
{
selector: ".layout-margin.layout-top > span",
value: 30
},
{
selector: ".layout-margin.layout-left > span",
value: "auto"
},
{
selector: ".layout-margin.layout-bottom > span",
value: 30
},
{
selector: ".layout-margin.layout-right > span",
value: "auto"
},
{
selector: ".layout-padding.layout-top > span",
value: 20
},
{
selector: ".layout-padding.layout-left > span",
value: 20
},
{
selector: ".layout-padding.layout-bottom > span",
value: 20
},
{
selector: ".layout-padding.layout-right > span",
value: 50
},
{
selector: ".layout-border.layout-top > span",
value: 10
},
{
selector: ".layout-border.layout-left > span",
value: 10
},
{
selector: ".layout-border.layout-bottom > span",
value: 10
},
{
selector: ".layout-border.layout-right > span",
value: 10
},
];
add_task(function*() {
let style = "div { position: absolute; top: 42px; left: 42px; height: 100.111px; width: 100px; border: 10px solid black; padding: 20px; margin: 30px auto;}";
let html = "<style>" + style + "</style><div></div>"
let html = "<style>" + style + "</style><div></div>";
yield addTab("data:text/html," + encodeURIComponent(html));
let {toolbox, inspector, view} = yield openLayoutView();

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

@ -34,7 +34,7 @@ function*(inspector, view) {
is(getStyle(node, "margin-top"), "", "Should be no margin-top on the element.")
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".margin.top > span");
let span = view.doc.querySelector(".layout-margin.layout-top > span");
is(span.textContent, 5, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -60,7 +60,7 @@ function*(inspector, view) {
is(getStyle(node, "margin-left"), "", "Should be no margin-top on the element.")
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".margin.left > span");
let span = view.doc.querySelector(".layout-margin.layout-left > span");
is(span.textContent, 10, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -97,7 +97,7 @@ function*(inspector, view) {
is(getStyle(node, "margin-left"), "20px", "Should be the right margin-top on the element.")
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".margin.left > span");
let span = view.doc.querySelector(".layout-margin.layout-left > span");
is(span.textContent, 20, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -127,7 +127,7 @@ function*(inspector, view) {
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".margin.right > span");
let span = view.doc.querySelector(".layout-margin.layout-right > span");
is(span.textContent, 15, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -153,7 +153,7 @@ function*(inspector, view) {
yield selectNode("#div4", inspector);
let span = view.doc.querySelector(".margin.top > span");
let span = view.doc.querySelector(".layout-margin.layout-top > span");
is(span.textContent, 1, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);

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

@ -34,7 +34,7 @@ function*(inspector, view) {
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".padding.bottom > span");
let span = view.doc.querySelector(".layout-padding.layout-bottom > span");
is(span.textContent, 5, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -63,7 +63,7 @@ function*(inspector, view) {
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".padding.left > span");
let span = view.doc.querySelector(".layout-padding.layout-left > span");
is(span.textContent, 5, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -92,7 +92,7 @@ function*(inspector, view) {
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".padding.left > span");
let span = view.doc.querySelector(".layout-padding.layout-left > span");
is(span.textContent, 5, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -121,7 +121,7 @@ function*(inspector, view) {
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".padding.left > span");
let span = view.doc.querySelector(".layout-padding.layout-left > span");
is(span.textContent, 5, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);

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

@ -27,7 +27,7 @@ add_task(function*() {
is(getStyle(node, "border-top-style"), "", "Should have the right border");
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".border.top > span");
let span = view.doc.querySelector(".layout-border.layout-top > span");
is(span.textContent, 0, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);

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

@ -32,7 +32,7 @@ function*(inspector, view) {
is(getStyle(node, "padding-top"), "", "Should have the right padding");
yield selectNode("#div1", inspector);
let span = view.doc.querySelector(".padding.top > span");
let span = view.doc.querySelector(".layout-padding.layout-top > span");
is(span.textContent, 3, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -65,7 +65,7 @@ function*(inspector, view) {
is(getStyle(node, "border-bottom-width"), "", "Should have the right border-bottom-width");
yield selectNode("#div2", inspector);
let span = view.doc.querySelector(".border.bottom > span");
let span = view.doc.querySelector(".layout-border.layout-bottom > span");
is(span.textContent, 16, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);
@ -91,7 +91,7 @@ function*(inspector, view) {
is(getStyle(node, "padding-right"), "", "Should have the right padding");
yield selectNode("#div3", inspector);
let span = view.doc.querySelector(".padding.right > span");
let span = view.doc.querySelector(".layout-padding.layout-right > span");
is(span.textContent, 32, "Should have the right value in the box model.");
EventUtils.synthesizeMouseAtCenter(span, {}, view.doc.defaultView);

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

@ -27,16 +27,16 @@ add_task(function*() {
highlighterOptions = options;
}
let elt = view.doc.getElementById("margins");
let elt = view.doc.getElementById("layout-margins");
yield testGuideOnLayoutHover(elt, "margin", inspector, view);
elt = view.doc.getElementById("borders");
elt = view.doc.getElementById("layout-borders");
yield testGuideOnLayoutHover(elt, "border", inspector, view);
elt = view.doc.getElementById("padding");
elt = view.doc.getElementById("layout-padding");
yield testGuideOnLayoutHover(elt, "padding", inspector, view);
elt = view.doc.getElementById("content");
elt = view.doc.getElementById("layout-content");
yield testGuideOnLayoutHover(elt, "content", inspector, view);
});

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

@ -7,18 +7,18 @@
// Test that longer values are rotated on the side
const res1 = [
{selector: ".margin.top > span", value: 30},
{selector: ".margin.left > span", value: "auto"},
{selector: ".margin.bottom > span", value: 30},
{selector: ".margin.right > span", value: "auto"},
{selector: ".padding.top > span", value: 20},
{selector: ".padding.left > span", value: 2000000},
{selector: ".padding.bottom > span", value: 20},
{selector: ".padding.right > span", value: 20},
{selector: ".border.top > span", value: 10},
{selector: ".border.left > span", value: 10},
{selector: ".border.bottom > span", value: 10},
{selector: ".border.right > span", value: 10},
{selector: ".layout-margin.layout-top > span", value: 30},
{selector: ".layout-margin.layout-left > span", value: "auto"},
{selector: ".layout-margin.layout-bottom > span", value: 30},
{selector: ".layout-margin.layout-right > span", value: "auto"},
{selector: ".layout-padding.layout-top > span", value: 20},
{selector: ".layout-padding.layout-left > span", value: 2000000},
{selector: ".layout-padding.layout-bottom > span", value: 20},
{selector: ".layout-padding.layout-right > span", value: 20},
{selector: ".layout-border.layout-top > span", value: 10},
{selector: ".layout-border.layout-left > span", value: 10},
{selector: ".layout-border.layout-bottom > span", value: 10},
{selector: ".layout-border.layout-right > span", value: 10},
];
const TEST_URI = encodeURIComponent([
@ -37,10 +37,12 @@ add_task(function*() {
for (let i = 0; i < res1.length; i++) {
let elt = view.doc.querySelector(res1[i].selector);
let isLong = elt.textContent.length > LONG_TEXT_ROTATE_LIMIT;
let classList = elt.parentNode.classList
let canBeRotated = classList.contains("left") || classList.contains("right");
let isRotated = classList.contains("rotate");
let classList = elt.parentNode.classList;
let canBeRotated = classList.contains("layout-left") ||
classList.contains("layout-right");
let isRotated = classList.contains("layout-rotate");
is(canBeRotated && isLong, isRotated, res1[i].selector + " correctly rotated.");
is(canBeRotated && isLong,
isRotated, res1[i].selector + " correctly rotated.");
}
});

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

@ -76,24 +76,24 @@ add_task(function*() {
info("Checking the regions tooltips");
ok(view.doc.querySelector("#margins").hasAttribute("title"),
ok(view.doc.querySelector("#layout-margins").hasAttribute("title"),
"The margin region has a tooltip");
is(view.doc.querySelector("#margins").getAttribute("title"), "margin",
is(view.doc.querySelector("#layout-margins").getAttribute("title"), "margin",
"The margin region has the correct tooltip content");
ok(view.doc.querySelector("#borders").hasAttribute("title"),
ok(view.doc.querySelector("#layout-borders").hasAttribute("title"),
"The border region has a tooltip");
is(view.doc.querySelector("#borders").getAttribute("title"), "border",
is(view.doc.querySelector("#layout-borders").getAttribute("title"), "border",
"The border region has the correct tooltip content");
ok(view.doc.querySelector("#padding").hasAttribute("title"),
ok(view.doc.querySelector("#layout-padding").hasAttribute("title"),
"The padding region has a tooltip");
is(view.doc.querySelector("#padding").getAttribute("title"), "padding",
is(view.doc.querySelector("#layout-padding").getAttribute("title"), "padding",
"The padding region has the correct tooltip content");
ok(view.doc.querySelector("#content").hasAttribute("title"),
ok(view.doc.querySelector("#layout-content").hasAttribute("title"),
"The content region has a tooltip");
is(view.doc.querySelector("#content").getAttribute("title"), "content",
is(view.doc.querySelector("#layout-content").getAttribute("title"), "content",
"The content region has the correct tooltip content");
for (let {selector, values} of VALUES_TEST_DATA) {

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

@ -19,7 +19,7 @@ function*(inspector, view) {
yield selectNode("p", inspector);
info("Checking that the layout-view shows the right value");
let paddingElt = view.doc.querySelector(".padding.top > span");
let paddingElt = view.doc.querySelector(".layout-padding.layout-top > span");
is(paddingElt.textContent, "50");
info("Listening for layout-view changes and modifying the padding");
@ -44,7 +44,7 @@ function*(inspector, view) {
yield selectNode("p", inspector);
info("Checking that the layout-view shows the right value");
let sizeElt = view.doc.querySelector(".size > span");
let sizeElt = view.doc.querySelector(".layout-size > span");
is(sizeElt.textContent, "100" + "\u00D7" + "100");
info("Listening for layout-view changes and modifying the size");
@ -70,7 +70,7 @@ function*(inspector, view) {
info("Checking that the layout-view shows the right value, which is the" +
"modified value from step one because of the bfcache");
let paddingElt = view.doc.querySelector(".padding.top > span");
let paddingElt = view.doc.querySelector(".layout-padding.layout-top > span");
is(paddingElt.textContent, "20");
info("Listening for layout-view changes and modifying the padding");

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

@ -26,7 +26,7 @@ function* assertLayoutView(inspector, view) {
yield selectNode("p", inspector);
info("Checking that the layout-view shows the right value");
let paddingElt = view.doc.querySelector(".padding.top > span");
let paddingElt = view.doc.querySelector(".layout-padding.layout-top > span");
is(paddingElt.textContent, "50");
info("Listening for layout-view changes and modifying the padding");

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

@ -22,7 +22,7 @@ function*(inspector, view, iframe2) {
yield selectNodeInIframe2("div", inspector);
info("Checking that the layout-view shows the right value");
let sizeElt = view.doc.querySelector(".size > span");
let sizeElt = view.doc.querySelector(".layout-size > span");
is(sizeElt.textContent, "400\u00D7200");
info("Listening for layout-view changes and modifying its size");
@ -46,7 +46,7 @@ function*(inspector, view, iframe2) {
yield selectNodeInIframe1("p", inspector);
info("Checking that the layout-view shows the right value");
let sizeElt = view.doc.querySelector(".size > span");
let sizeElt = view.doc.querySelector(".layout-size > span");
is(sizeElt.textContent, "100\u00D7100");
info("Listening for layout-view changes and modifying its size");

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

@ -52,7 +52,7 @@ function selectAndHighlightNode(nodeOrSelector, inspector) {
* view is visible and ready
*/
function openLayoutView() {
return openInspectorSidebarTab("layoutview").then(objects => {
return openInspectorSidebarTab("layoutview").then(({toolbox, inspector}) => {
// The actual highligher show/hide methods are mocked in layoutview tests.
// The highlighter is tested in devtools/inspector/test.
function mockHighlighter({highlighter}) {
@ -63,9 +63,13 @@ function openLayoutView() {
return promise.resolve();
};
}
mockHighlighter(objects.toolbox);
mockHighlighter(toolbox);
return objects;
return {
toolbox,
inspector,
view: inspector.layoutview
};
});
}

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

@ -1,209 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
:root {
-moz-control-character-visibility: visible;
}
body {
-moz-user-select: none;
}
/* Force height and width (possibly overflowing) from inline elements.
* This allows long overflows of text or input fields to still be styled with
* the container, rather than the background disappearing when scrolling */
#root {
float: left;
min-width: 100%;
}
body.dragging .tag-line {
cursor: grabbing;
}
#root-wrapper:after {
content: "";
display: block;
clear: both;
position:relative;
}
.html-editor {
display: none;
position: absolute;
z-index: 2;
/* Use the same margin/padding trick used by .child tags to ensure that
* the editor covers up any content to the left (including expander arrows
* and hover effects). */
margin-left: -1000em;
padding-left: 1000em;
}
.html-editor-inner {
border: solid .1px;
flex: 1 1 auto;
/* Keep the editor away from the markup view floating scrollbars */
-moz-margin-end: 12px;
}
.html-editor iframe {
height: 100%;
width: 100%;
border: none;
margin: 0;
padding: 0;
}
.children {
list-style: none;
padding: 0;
margin: 0;
}
/* Tags are organized in a UL/LI tree and indented thanks to a left padding.
* A very large padding is used in combination with a slightly smaller margin
* to make sure childs actually span from edge-to-edge. */
.child {
margin-left: -1000em;
padding-left: 1001em;
}
/* Normally this element takes space in the layout even if it's position: relative
* by adding height: 0 we let surrounding elements to fill the blank space */
.child.dragging {
position: relative;
pointer-events: none;
opacity: 0.7;
z-index: 1;
height: 0;
}
/* Indicates a tag-line in the markup-view as being an active drop target by
* drawing a horizontal line where the dragged element would be inserted if
* dropped here */
.tag-line.drop-target::before,
.tag-line.drag-target::before {
content: '';
position: absolute;
top: 0;
width: 100%;
/* Offset these by 1000px to make sure they cover the full width of the view */
padding-left: 1000px;
left: -1000px;
}
.tag-line.drag-target::before {
border-top: 2px solid var(--theme-content-color2);
}
.tag-line.drop-target::before {
border-top: 2px solid var(--theme-contrast-background);
}
/* In case the indicator is put on the closing .tag-line, the indentation level
* will become misleading, so we push it forward to match the indentation level */
ul.children + .tag-line::before {
margin-left: 14px;
}
.tag-line {
min-height: 1.4em;
line-height: 1.4em;
position: relative;
}
.html-editor-container {
position: relative;
min-height: 200px;
}
/* This extra element placed in each tag is positioned absolutely to cover the
* whole tag line and is used for background styling (when a selection is made
* or when the tag is flashing) */
.tag-line .tag-state {
position: absolute;
left: -1000em;
right: 0;
height: 100%;
z-index: 0;
}
.expander {
display: inline-block;
margin-left: -14px;
vertical-align: middle;
/* Make sure the expander still appears above the tag-state */
position: relative;
z-index: 1;
}
.child.collapsed .child {
display: none;
}
.child > .tag-line:first-child .close {
display: none;
}
.child.collapsed > .tag-line:first-child .close {
display: inline;
}
.child.collapsed > .tag-line ~ .tag-line {
display: none;
}
.child.collapsed .close {
display: inline;
}
.closing-bracket {
pointer-events: none;
}
.newattr {
display: inline-block;
width: 1em;
height: 1ex;
margin-right: -1em;
padding: 1px 0;
}
.attr-value .link {
text-decoration: underline;
}
.newattr:focus {
margin-right: 0;
}
.flash-out {
transition: background .5s;
}
.tag-line {
cursor: default;
}
.markupview-events {
display: none;
cursor: pointer;
}
.editor {
/* Make sure the editor still appears above the tag-state */
position: relative;
z-index: 1;
}
.editor.text {
display: inline-block;
}
.editor.text pre,
.editor.comment pre {
font: inherit;
}

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

@ -76,14 +76,23 @@ add_task(function*() {
EventUtils.sendKey("return", inspector.panelWin);
let editor = inplaceEditor(attr);
for (let i = 0; i < TEST_DATA.length; i ++) {
for (let i = 0; i < TEST_DATA.length; i++) {
// Expect a markupmutation event at the last iteration since that's when the
// attribute is actually created.
let onMutation = i === TEST_DATA.length - 1
? inspector.once("markupmutation") : null;
yield enterData(i, editor, inspector);
yield checkData(i, editor, inspector);
yield onMutation;
}
// Undoing the action will remove the new attribute, so make sure to wait for
// the markupmutation event here again.
let onMutation = inspector.once("markupmutation");
while (inspector.markup.undo.canUndo()) {
yield undoChange(inspector);
}
yield onMutation;
});
function enterData(index, editor, inspector) {

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

@ -13,6 +13,7 @@ add_task(function*() {
let {markup} = inspector;
info("Get a test container");
yield selectNode("#test", inspector);
let container = yield getContainerForSelector("#test", inspector);
info("Simulate a drag/drop on this container");

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

@ -18,10 +18,11 @@ add_task(function*() {
yield inspector.markup.expandNode(parentFront);
yield waitForMultipleChildrenUpdates(inspector);
info("Getting the ::before pseudo element");
info("Getting the ::before pseudo element and selecting it");
let parentContainer = yield getContainerForNodeFront(parentFront, inspector);
let beforePseudo = parentContainer.elt.children[1].firstChild.container;
parentContainer.elt.scrollIntoView(true);
yield selectNode(beforePseudo.node, inspector);
info("Simulate dragging the ::before pseudo element");
yield simulateNodeDrag(inspector, beforePseudo);
@ -33,10 +34,11 @@ add_task(function*() {
yield inspector.markup.expandNode(inputFront);
yield waitForMultipleChildrenUpdates(inspector);
info("Getting the anonymous node");
info("Getting the anonymous node and selecting it");
let inputContainer = yield getContainerForNodeFront(inputFront, inspector);
let anonymousDiv = inputContainer.elt.children[1].firstChild.container;
inputContainer.elt.scrollIntoView(true);
yield selectNode(anonymousDiv.node, inspector);
info("Simulate dragging the anonymous node");
yield simulateNodeDrag(inspector, anonymousDiv);

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

@ -48,27 +48,24 @@ function selectPreviousNodeWithArrowUp(inspector) {
}
function* selectWithBrowserMenu(inspector) {
let contentAreaContextMenu = document.querySelector("#contentAreaContextMenu");
let contextOpened = once(contentAreaContextMenu, "popupshown");
yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
type: "contextmenu",
button: 2
}, gBrowser.selectedBrowser);
// nsContextMenu also requires the popupNode to be set, but we can't set it to
// node under e10s as it's a CPOW, not a DOM node. But under e10s,
// nsContextMenu won't use the property anyway, so just try/catching is ok.
try {
document.popupNode = getNode("div");
} catch (e) {}
yield contextOpened;
let contentAreaContextMenu = document.querySelector("#contentAreaContextMenu");
let contextMenu = new nsContextMenu(contentAreaContextMenu);
yield contextMenu.inspectNode();
yield gContextMenu.inspectNode();
let contextClosed = once(contentAreaContextMenu, "popuphidden");
contentAreaContextMenu.hidden = true;
contentAreaContextMenu.hidePopup();
contextMenu.hiding();
yield inspector.once("inspector-updated");
yield contextClosed;
}
function* selectWithElementPicker(inspector, testActor) {

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

@ -24,7 +24,7 @@ const TEST_DATA = [
["down", "node5"],
["down", "node6"],
["down", "*comment*"],
["down" , "node7"],
["down", "node7"],
["right", "node7"],
["down", "*text*"],
["down", "node8"],
@ -83,10 +83,17 @@ add_task(function*() {
info("Checking the right node is selected");
checkSelectedNode(key, className, inspector);
}
// In theory, we should wait for the inspector-updated event at each iteration
// of the previous loop where we expect the current node to change (because
// changing the current node ends up refreshing the rule-view, breadcrumbs,
// ...), but this would make this test a *lot* slower. Instead, having a final
// catch-all event works too.
yield inspector.once("inspector-updated");
});
function pressKey(key) {
switch(key) {
switch (key) {
case "right":
EventUtils.synthesizeKey("VK_RIGHT", {});
break;
@ -115,12 +122,16 @@ function checkSelectedNode(key, className, inspector) {
let node = inspector.selection.nodeFront;
if (className == "*comment*") {
is(node.nodeType, Node.COMMENT_NODE, "Found a comment after pressing " + key);
is(node.nodeType, Node.COMMENT_NODE,
"Found a comment after pressing " + key);
} else if (className == "*text*") {
is(node.nodeType, Node.TEXT_NODE, "Found text after pressing " + key);
is(node.nodeType, Node.TEXT_NODE,
"Found text after pressing " + key);
} else if (className == "*doctype*") {
is(node.nodeType, Node.DOCUMENT_TYPE_NODE, "Found the doctype after pressing " + key);
is(node.nodeType, Node.DOCUMENT_TYPE_NODE,
"Found the doctype after pressing " + key);
} else {
is(node.className, className, "Found node: " + className + " after pressing " + key);
is(node.className, className,
"Found node: " + className + " after pressing " + key);
}
}

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

@ -219,7 +219,7 @@ function CssRuleView(inspector, document, store, pageStyle) {
autoSelect: true,
theme: "auto"
};
this.popup = new AutocompletePopup(this.styleWindow.parent.document, options);
this.popup = new AutocompletePopup(this.styleDocument, options);
this._showEmpty();

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

@ -1,57 +0,0 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE window [
<!ENTITY % inspectorDTD SYSTEM "chrome://devtools/locale/styleinspector.dtd">
%inspectorDTD;
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
class="theme-sidebar">
<head>
<title>&ruleViewTitle;</title>
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
<link rel="stylesheet" href="chrome://devtools/skin/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://devtools/skin/rules.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"/>
<script type="application/javascript;version=1.8">
window.setPanel = function(panel, iframe) {
let {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
let {RuleViewTool} = require("devtools/client/inspector/rules/rules");
this.ruleview = new RuleViewTool(panel, window);
}
window.onunload = function() {
if (this.ruleview) {
this.ruleview.destroy();
}
}
</script>
</head>
<body dir="&locale.dir;">
<div id="root" class="devtools-monospace">
<div id="ruleview-toolbar" class="devtools-toolbar">
<div class="devtools-searchbox">
<input id="ruleview-searchbox"
class="devtools-searchinput devtools-rule-searchbox"
type="search" placeholder="&filterStylesPlaceholder;"/>
<button id="ruleview-searchinput-clear" class="devtools-searchinput-clear"></button>
</div>
<button id="ruleview-add-rule-button" title="&addRuleButtonTooltip;" class="devtools-button"></button>
<button id="pseudo-class-panel-toggle" title="&togglePseudoClassPanel;" class="devtools-button"></button>
</div>
<div id="pseudo-class-panel" class="devtools-toolbar" hidden="true" tabindex="-1">
<label><input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</label>
<label><input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</label>
<label><input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</label>
</div>
</div>
<div id="ruleview-container" class="devtools-monospace">
</div>
</body>
</html>

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

@ -43,6 +43,6 @@ function* testCancelNew(view) {
"Should have cancelled creating a new text property.");
ok(!elementRuleEditor.propertyList.hasChildNodes(),
"Should not have any properties.");
is(view.styleDocument.body, view.styleDocument.activeElement,
is(view.styleDocument.activeElement, view.styleDocument.documentElement,
"Correct element has focus");
}

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

@ -71,7 +71,7 @@ add_task(function*() {
EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
yield onRuleViewChanged;
is(view.styleDocument.body, view.styleDocument.activeElement,
is(view.styleDocument.documentElement, view.styleDocument.activeElement,
"Correct element has focus");
is(elementRuleEditor.rule.textProps.length, 1,

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

@ -48,6 +48,6 @@ function* testCancelNewOnEscape(inspector, view) {
"Should have canceled creating a new text property.");
ok(!elementRuleEditor.propertyList.hasChildNodes(),
"Should not have any properties.");
is(view.styleDocument.body, view.styleDocument.activeElement,
is(view.styleDocument.documentElement, view.styleDocument.activeElement,
"Correct element has focus");
}

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

@ -41,7 +41,7 @@ add_task(function* () {
swatch.click();
yield onShown;
let testNode = yield getNode("#testid");
let testNode = getNode("#testid");
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
element: testNode,

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

@ -46,7 +46,7 @@ function* basicTest(view, name, result) {
swatch.click();
yield onShown;
let testNode = yield getNode("#testid");
let testNode = getNode("#testid");
yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], {
element: testNode,

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

@ -44,7 +44,7 @@ add_task(function*() {
let inspector = toolbox.getPanel("inspector");
yield inspector.once("inspector-updated");
let view = inspector.sidebar.getWindowForTab("ruleview")["ruleview"].view;
let view = inspector.ruleview.view;
checkRuleViewContent(view);
});

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

@ -17,15 +17,15 @@ const TEST_URI = `
add_task(function*() {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
let {view} = yield openRuleView();
let container = getRuleViewProperty(view, "body", "color").valueSpan;
checkColorCycling(container, inspector);
checkColorCycling(container, view);
});
function checkColorCycling(container, inspector) {
function checkColorCycling(container, view) {
let swatch = container.querySelector(".ruleview-colorswatch");
let valueNode = container.querySelector(".ruleview-color");
let win = inspector.sidebar.getWindowForTab("ruleview");
let win = view.styleWindow;
// Hex
is(valueNode.textContent, "#f00", "Color displayed as a hex value.");

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

@ -10,8 +10,8 @@
add_task(function*() {
yield addTab("data:text/html;charset=utf-8,sample document for bug 722691");
createDocument();
let {toolbox, inspector, view} = yield openRuleView();
let {inspector, view} = yield openRuleView();
yield selectNode("#test", inspector);
yield testMarginIncrements(view);
@ -23,16 +23,16 @@ add_task(function*() {
});
function createDocument() {
content.document.body.innerHTML = '' +
'<style>' +
' #test {' +
' margin-top:0px;' +
' padding-top: 0px;' +
' color:#000000;' +
' background-color: #000000;' +
' }' +
'</style>' +
'<div id="test"></div>';
content.document.body.innerHTML = "" +
"<style>" +
" #test {" +
" margin-top:0px;" +
" padding-top: 0px;" +
" color:#000000;" +
" background-color: #000000;" +
" }" +
"</style>" +
"<div id=\"test\"></div>";
}
function* testMarginIncrements(view) {
@ -64,13 +64,13 @@ function* testVariousUnitIncrements(view) {
2: {start: "0pt", end: "1pt", selectAll: true},
3: {start: "0pc", end: "1pc", selectAll: true},
4: {start: "0em", end: "1em", selectAll: true},
5: {start: "0%", end: "1%", selectAll: true},
5: {start: "0%", end: "1%", selectAll: true},
6: {start: "0in", end: "1in", selectAll: true},
7: {start: "0cm", end: "1cm", selectAll: true},
8: {start: "0mm", end: "1mm", selectAll: true},
9: {start: "0ex", end: "1ex", selectAll: true}
});
};
}
function* testHexIncrements(view) {
info("Testing keyboard increments with hex colors");
@ -81,12 +81,12 @@ function* testHexIncrements(view) {
yield runIncrementTest(hexColorPropEditor, view, {
1: {start: "#CCCCCC", end: "#CDCDCD", selectAll: true},
2: {shift: true, start: "#CCCCCC", end: "#DCDCDC", selectAll: true},
3: {start: "#CCCCCC", end: "#CDCCCC", selection: [1,3]},
4: {shift: true, start: "#CCCCCC", end: "#DCCCCC", selection: [1,3]},
3: {start: "#CCCCCC", end: "#CDCCCC", selection: [1, 3]},
4: {shift: true, start: "#CCCCCC", end: "#DCCCCC", selection: [1, 3]},
5: {start: "#FFFFFF", end: "#FFFFFF", selectAll: true},
6: {down: true, shift: true, start: "#000000", end: "#000000", selectAll: true}
});
};
}
function* testRgbIncrements(view) {
info("Testing keyboard increments with rgb colors");
@ -95,14 +95,14 @@ function* testRgbIncrements(view) {
let rgbColorPropEditor = idRuleEditor.rule.textProps[3].editor;
yield runIncrementTest(rgbColorPropEditor, view, {
1: {start: "rgb(0,0,0)", end: "rgb(0,1,0)", selection: [6,7]},
2: {shift: true, start: "rgb(0,0,0)", end: "rgb(0,10,0)", selection: [6,7]},
3: {start: "rgb(0,255,0)", end: "rgb(0,255,0)", selection: [6,9]},
4: {shift: true, start: "rgb(0,250,0)", end: "rgb(0,255,0)", selection: [6,9]},
5: {down: true, start: "rgb(0,0,0)", end: "rgb(0,0,0)", selection: [6,7]},
6: {down: true, shift: true, start: "rgb(0,5,0)", end: "rgb(0,0,0)", selection: [6,7]}
1: {start: "rgb(0,0,0)", end: "rgb(0,1,0)", selection: [6, 7]},
2: {shift: true, start: "rgb(0,0,0)", end: "rgb(0,10,0)", selection: [6, 7]},
3: {start: "rgb(0,255,0)", end: "rgb(0,255,0)", selection: [6, 9]},
4: {shift: true, start: "rgb(0,250,0)", end: "rgb(0,255,0)", selection: [6, 9]},
5: {down: true, start: "rgb(0,0,0)", end: "rgb(0,0,0)", selection: [6, 7]},
6: {down: true, shift: true, start: "rgb(0,5,0)", end: "rgb(0,0,0)", selection: [6, 7]}
});
};
}
function* testShorthandIncrements(view) {
info("Testing keyboard increments within shorthand values");
@ -111,17 +111,17 @@ function* testShorthandIncrements(view) {
let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
yield runIncrementTest(paddingPropEditor, view, {
1: {start: "0px 0px 0px 0px", end: "0px 1px 0px 0px", selection: [4,7]},
2: {shift: true, start: "0px 0px 0px 0px", end: "0px 10px 0px 0px", selection: [4,7]},
1: {start: "0px 0px 0px 0px", end: "0px 1px 0px 0px", selection: [4, 7]},
2: {shift: true, start: "0px 0px 0px 0px", end: "0px 10px 0px 0px", selection: [4, 7]},
3: {start: "0px 0px 0px 0px", end: "1px 0px 0px 0px", selectAll: true},
4: {shift: true, start: "0px 0px 0px 0px", end: "10px 0px 0px 0px", selectAll: true},
5: {down: true, start: "0px 0px 0px 0px", end: "0px 0px -1px 0px", selection: [8,11]},
5: {down: true, start: "0px 0px 0px 0px", end: "0px 0px -1px 0px", selection: [8, 11]},
6: {down: true, shift: true, start: "0px 0px 0px 0px", end: "-10px 0px 0px 0px", selectAll: true},
7: {up: true, start: "0.1em .1em 0em 0em", end: "0.1em 1.1em 0em 0em", selection: [6, 9]},
8: {up: true, alt: true, start: "0.1em .9em 0em 0em", end: "0.1em 1em 0em 0em", selection: [6, 9]},
9: {up: true, shift: true, start: "0.2em .2em 0em 0em", end: "0.2em 10.2em 0em 0em", selection: [6, 9]}
});
};
}
function* testOddCases(view) {
info("Testing some more odd cases");
@ -130,32 +130,38 @@ function* testOddCases(view) {
let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
yield runIncrementTest(marginPropEditor, view, {
1: {start: "98.7%", end: "99.7%", selection: [3,3]},
2: {alt: true, start: "98.7%", end: "98.8%", selection: [3,3]},
1: {start: "98.7%", end: "99.7%", selection: [3, 3]},
2: {alt: true, start: "98.7%", end: "98.8%", selection: [3, 3]},
3: {start: "0", end: "1"},
4: {down: true, start: "0", end: "-1"},
5: {start: "'a=-1'", end: "'a=0'", selection: [4,4]},
6: {start: "0 -1px", end: "0 0px", selection: [2,2]},
7: {start: "url(-1)", end: "url(-1)", selection: [4,4]},
8: {start: "url('test1.1.png')", end: "url('test1.2.png')", selection: [11,11]},
9: {start: "url('test1.png')", end: "url('test2.png')", selection: [9,9]},
10: {shift: true, start: "url('test1.1.png')", end: "url('test11.1.png')", selection: [9,9]},
11: {down: true, start: "url('test-1.png')", end: "url('test-2.png')", selection: [9,11]},
12: {start: "url('test1.1.png')", end: "url('test1.2.png')", selection: [11,12]},
13: {down: true, alt: true, start: "url('test-0.png')", end: "url('test--0.1.png')", selection: [10,11]},
14: {alt: true, start: "url('test--0.1.png')", end: "url('test-0.png')", selection: [10,14]}
5: {start: "'a=-1'", end: "'a=0'", selection: [4, 4]},
6: {start: "0 -1px", end: "0 0px", selection: [2, 2]},
7: {start: "url(-1)", end: "url(-1)", selection: [4, 4]},
8: {start: "url('test1.1.png')", end: "url('test1.2.png')", selection: [11, 11]},
9: {start: "url('test1.png')", end: "url('test2.png')", selection: [9, 9]},
10: {shift: true, start: "url('test1.1.png')", end: "url('test11.1.png')", selection: [9, 9]},
11: {down: true, start: "url('test-1.png')", end: "url('test-2.png')", selection: [9, 11]},
12: {start: "url('test1.1.png')", end: "url('test1.2.png')", selection: [11, 12]},
13: {down: true, alt: true, start: "url('test-0.png')", end: "url('test--0.1.png')", selection: [10, 11]},
14: {alt: true, start: "url('test--0.1.png')", end: "url('test-0.png')", selection: [10, 14]}
});
};
}
function* runIncrementTest(propertyEditor, view, tests) {
let editor = yield focusEditableField(view, propertyEditor.valueSpan);
for(let test in tests) {
for (let test in tests) {
yield testIncrement(editor, tests[test], view, propertyEditor);
}
// Blur the field to put back the UI in its initial state (and avoid pending
// requests when the test ends).
let onRuleViewChanged = view.once("ruleview-changed");
EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
yield onRuleViewChanged;
}
function* testIncrement(editor, options, view, {ruleEditor}) {
function* testIncrement(editor, options, view) {
editor.input.value = options.start;
let input = editor.input;

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

@ -33,14 +33,16 @@ add_task(function*() {
yield focusEditableField(view, propEditor.valueSpan);
info("Deleting all the text out of a value field");
let waitForUpdates = view.once("ruleview-changed");
let onRuleViewChanged = view.once("ruleview-changed");
yield sendCharsAndWaitForFocus(view, ruleEditor.element,
["VK_DELETE", "VK_RETURN"]);
yield waitForUpdates;
yield onRuleViewChanged;
info("Pressing enter a couple times to cycle through editors");
yield sendCharsAndWaitForFocus(view, ruleEditor.element, ["VK_RETURN"]);
onRuleViewChanged = view.once("ruleview-changed");
yield sendCharsAndWaitForFocus(view, ruleEditor.element, ["VK_RETURN"]);
yield onRuleViewChanged;
isnot(ruleEditor.rule.textProps[1].editor.nameSpan.style.display, "none",
"The name span is visible");

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

@ -19,25 +19,27 @@ add_task(function*() {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
yield selectNode("#testid", inspector);
yield testRenameProperty(inspector, view);
});
function* testRenameProperty(inspector, view) {
info("Get the color property editor");
let ruleEditor = getRuleViewRuleEditor(view, 0);
let propEditor = ruleEditor.rule.textProps[0].editor;
is(ruleEditor.rule.textProps[0].name, "color");
info("Focus on property name");
let editor = yield focusEditableField(ruleEditor.ruleView,
propEditor.nameSpan, 32, 1);
info("Focus the property name field");
yield focusEditableField(ruleEditor.ruleView, propEditor.nameSpan, 32, 1);
info("Renaming the property");
info("Rename the property to background-color");
// Expect 3 events: the value editor being focused, the ruleview-changed event
// which signals that the new value has been previewed (fires once when the
// value gets focused), and the markupmutation event since we're modifying an
// inline style.
let onValueFocus = once(ruleEditor.element, "focus", true);
let onModifications = ruleEditor.ruleView.once("ruleview-changed");
let onRuleViewChanged = ruleEditor.ruleView.once("ruleview-changed");
let onMutation = inspector.once("markupmutation");
EventUtils.sendString("background-color:", ruleEditor.doc.defaultView);
yield onValueFocus;
yield onModifications;
yield onRuleViewChanged;
yield onMutation;
is(ruleEditor.rule.textProps[0].name, "background-color");
yield waitForComputedStyleProperty("#testid", null, "background-color",
@ -45,4 +47,11 @@ function* testRenameProperty(inspector, view) {
is((yield getComputedStyleProperty("#testid", null, "color")),
"rgb(255, 255, 255)", "color is white");
}
// The value field is still focused. Blur it now and wait for the
// ruleview-changed event to avoid pending requests.
onRuleViewChanged = view.once("ruleview-changed");
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield onRuleViewChanged;
});

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

@ -57,6 +57,11 @@ function* testEditSelector(view, name) {
ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
ok(getRuleViewRuleEditor(view, 1).element.getAttribute("unmatched"),
"Rule with " + name + " does not match the current element.");
// Escape the new property editor after editing the selector
let onBlur = once(view.styleDocument.activeElement, "blur");
EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow);
yield onBlur;
}
function* checkModifiedElement(view, name) {

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

@ -30,51 +30,65 @@ add_task(function*() {
yield testEditableFieldFocus(inspector, view, "VK_TAB");
});
function* testEditableFieldFocus(inspector, view, commitKey, options={}) {
function* testEditableFieldFocus(inspector, view, commitKey) {
info("Click on the selector of the inline style ('element')");
let ruleEditor = getRuleViewRuleEditor(view, 0);
let onFocus = once(ruleEditor.element, "focus", true);
ruleEditor.selectorText.click();
yield onFocus;
assertEditor(view, ruleEditor.newPropSpan,
"Focus should be in the element property span");
info("Focus the next field with " + commitKey);
ruleEditor = getRuleViewRuleEditor(view, 1);
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield assertEditor(view, ruleEditor.selectorText,
yield focusNextEditableField(view, ruleEditor, commitKey);
assertEditor(view, ruleEditor.selectorText,
"Focus should have moved to the next rule selector");
for (let textProp of ruleEditor.rule.textProps) {
for (let i = 0; i < ruleEditor.rule.textProps.length; i++) {
let textProp = ruleEditor.rule.textProps[i];
let propEditor = textProp.editor;
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield assertEditor(view, propEditor.nameSpan,
info("Focus the next field with " + commitKey);
// Expect a ruleview-changed event if we are moving from a property value
// to the next property name (which occurs after the first iteration, as for
// i=0, the previous field is the selector).
let onRuleViewChanged = i > 0 ? view.once("ruleview-changed") : null;
yield focusNextEditableField(view, ruleEditor, commitKey);
yield onRuleViewChanged;
assertEditor(view, propEditor.nameSpan,
"Focus should have moved to the property name");
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield assertEditor(view, propEditor.valueSpan,
info("Focus the next field with " + commitKey);
yield focusNextEditableField(view, ruleEditor, commitKey);
assertEditor(view, propEditor.valueSpan,
"Focus should have moved to the property value");
}
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield assertEditor(view, ruleEditor.newPropSpan,
// Expect a ruleview-changed event again as we're bluring a property value.
let onRuleViewChanged = view.once("ruleview-changed");
yield focusNextEditableField(view, ruleEditor, commitKey);
yield onRuleViewChanged;
assertEditor(view, ruleEditor.newPropSpan,
"Focus should have moved to the new property span");
ruleEditor = getRuleViewRuleEditor(view, 2);
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield assertEditor(view, ruleEditor.selectorText,
yield focusNextEditableField(view, ruleEditor, commitKey);
assertEditor(view, ruleEditor.selectorText,
"Focus should have moved to the next rule selector");
info("Blur the selector field");
EventUtils.synthesizeKey("VK_ESCAPE", {});
}
function* focusNextEditableField(view, ruleEditor, commitKey, options) {
function* focusNextEditableField(view, ruleEditor, commitKey) {
let onFocus = once(ruleEditor.element, "focus", true);
EventUtils.synthesizeKey(commitKey, options, view.styleWindow);
EventUtils.synthesizeKey(commitKey, {}, view.styleWindow);
yield onFocus;
}
function* assertEditor(view, element, message) {
function assertEditor(view, element, message) {
let editor = inplaceEditor(view.styleDocument.activeElement);
is(inplaceEditor(element), editor, message);
}

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

@ -37,36 +37,42 @@ function* testEditableFieldFocus(inspector, view, commitKey, options={}) {
ruleEditor = getRuleViewRuleEditor(view, 1);
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield focusNextField(view, ruleEditor, commitKey, options);
assertEditor(view, ruleEditor.newPropSpan,
"Focus should have moved to the new property span");
for (let textProp of ruleEditor.rule.textProps.slice(0).reverse()) {
let propEditor = textProp.editor;
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield focusNextField(view, ruleEditor, commitKey, options);
yield assertEditor(view, propEditor.valueSpan,
"Focus should have moved to the property value");
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield focusNextFieldAndExpectChange(view, ruleEditor, commitKey, options);
yield assertEditor(view, propEditor.nameSpan,
"Focus should have moved to the property name");
}
ruleEditor = getRuleViewRuleEditor(view, 1);
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield focusNextField(view, ruleEditor, commitKey, options);
yield assertEditor(view, ruleEditor.selectorText,
"Focus should have moved to the '#testid' rule selector");
ruleEditor = getRuleViewRuleEditor(view, 0);
yield focusNextEditableField(view, ruleEditor, commitKey, options);
yield focusNextField(view, ruleEditor, commitKey, options);
assertEditor(view, ruleEditor.newPropSpan,
"Focus should have moved to the new property span");
}
function* focusNextEditableField(view, ruleEditor, commitKey, options) {
function* focusNextFieldAndExpectChange(view, ruleEditor, commitKey, options) {
let onRuleViewChanged = view.once("ruleview-changed");
yield focusNextField(view, ruleEditor, commitKey, options);
yield onRuleViewChanged;
}
function* focusNextField(view, ruleEditor, commitKey, options) {
let onFocus = once(ruleEditor.element, "focus", true);
EventUtils.synthesizeKey(commitKey, options, view.styleWindow);
yield onFocus;

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

@ -11,11 +11,11 @@ add_task(function*() {
yield addTab(TEST_URL);
let {view} = yield openRuleView();
info("Getting the filter swatch element");
info("Get the filter swatch element");
let swatch = getRuleViewProperty(view, "body", "filter").valueSpan
.querySelector(".ruleview-filterswatch");
let filterTooltip = view.tooltips.filterEditor;
info("Click on the filter swatch element");
// Clicking on a cssfilter swatch sets the current filter value in the tooltip
// which, in turn, makes the FilterWidget emit an "updated" event that causes
// the rule-view to refresh. So we must wait for the ruleview-changed event.
@ -23,17 +23,20 @@ add_task(function*() {
swatch.click();
yield onRuleViewChanged;
info("Get the cssfilter widget instance");
let filterTooltip = view.tooltips.filterEditor;
let widget = yield filterTooltip.widget;
info("Set a new value in the cssfilter widget");
onRuleViewChanged = view.once("ruleview-changed");
widget.setCssValue("blur(2px)");
yield waitForComputedStyleProperty("body", null, "filter", "blur(2px)");
yield onRuleViewChanged;
ok(true, "Changes previewed on the element");
onRuleViewChanged = view.once("ruleview-changed");
info("Pressing RETURN to commit changes");
info("Press RETURN to commit changes");
// Pressing return in the cssfilter tooltip triggeres 2 ruleview-changed
onRuleViewChanged = waitForNEvents(view, "ruleview-changed", 2);
EventUtils.sendKey("RETURN", widget.styleWindow);
yield onRuleViewChanged;

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

@ -36,8 +36,8 @@ add_task(function*() {
is(cmdUndo.getAttribute("disabled"), "true", "cmdUndo is disabled");
is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled");
is(cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled");
is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled");
is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled");
is(cmdCut.getAttribute("disabled"), "true", "cmdCut is disabled");
is(cmdCopy.getAttribute("disabled"), "true", "cmdCopy is disabled");
is(cmdPaste.getAttribute("disabled"), "true", "cmdPaste is disabled");
info("Closing context menu");

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

@ -97,8 +97,7 @@ function* checkSelectAll(view) {
info("Checking that _SelectAll() then copy returns the correct " +
"clipboard value");
view._contextmenu._onSelectAll();
let expectedPattern = "[\\r\\n]+" +
"element {[\\r\\n]+" +
let expectedPattern = "element {[\\r\\n]+" +
" margin: 10em;[\\r\\n]+" +
" font-size: 14pt;[\\r\\n]+" +
" font-family: helvetica,sans-serif;[\\r\\n]+" +

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

@ -48,11 +48,11 @@ addTab = function(url) {
* view is visible and ready
*/
function openRuleView() {
return openInspectorSidebarTab("ruleview").then(objects => {
return openInspectorSidebarTab("ruleview").then(({toolbox, inspector}) => {
return {
toolbox: objects.toolbox,
inspector: objects.inspector,
view: objects.view.view
toolbox,
inspector,
view: inspector.ruleview.view
};
});
}

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

@ -369,7 +369,7 @@ StyleInspectorMenu.prototype = {
*/
_onSelectAll: function() {
let selection = this.styleWindow.getSelection();
selection.selectAllChildren(this.styleDocument.documentElement);
selection.selectAllChildren(this.view.element);
},
/**

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

@ -19,8 +19,7 @@ add_task(function*() {
is(getRuleViewPropertyValue(view, "element", "color"), "red",
"The rule-view shows the properties for test node one");
let cView = inspector.sidebar.getWindowForTab("computedview")
.computedview.view;
let cView = inspector.computedview.view;
let prop = getComputedViewProperty(cView, "color");
ok(!prop, "The computed-view doesn't show the properties for test node one");

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

@ -250,18 +250,13 @@ function waitForToolboxFrameFocus(toolbox) {
var openInspectorSideBar = Task.async(function*(id) {
let {toolbox, inspector} = yield openInspector();
if (!hasSideBarTab(inspector, id)) {
info("Waiting for the " + id + " sidebar to be ready");
yield inspector.sidebar.once(id + "-ready");
}
info("Selecting the " + id + " sidebar");
inspector.sidebar.select(id);
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab(id)[id].view
view: inspector[id].view
};
});

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

@ -117,29 +117,24 @@ function* testBreadcrumbs(selector, inspector) {
function* clickOnInspectMenuItem(testActor, selector) {
info("Showing the contextual menu on node " + selector);
let contentAreaContextMenu = document.querySelector("#contentAreaContextMenu");
let contextOpened = once(contentAreaContextMenu, "popupshown");
yield testActor.synthesizeMouse({
selector: selector,
center: true,
options: {type: "contextmenu", button: 2}
});
// nsContextMenu also requires the popupNode to be set, but we can't set it to
// node under e10s as it's a CPOW, not a DOM node. But under e10s,
// nsContextMenu won't use the property anyway, so just try/catching is ok.
try {
document.popupNode = content.document.querySelector(selector);
} catch (e) {}
let contentAreaContextMenu = document.querySelector("#contentAreaContextMenu");
let contextMenu = new nsContextMenu(contentAreaContextMenu);
yield contextOpened;
info("Triggering inspect action and hiding the menu.");
yield contextMenu.inspectNode();
yield gContextMenu.inspectNode();
contentAreaContextMenu.hidden = true;
let contextClosed = once(contentAreaContextMenu, "popuphidden");
contentAreaContextMenu.hidePopup();
contextMenu.hiding();
info("Waiting for inspector to update.");
yield getActiveInspector().once("inspector-updated");
yield contextClosed;
}

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

@ -21,7 +21,10 @@ add_task(function*() {
info("Creating the test tab and opening the rule-view");
let {toolbox, inspector, testActor} = yield openInspectorForURL(TEST_URL);
let view = yield ensureRuleView(inspector);
info("Selecting the ruleview sidebar");
inspector.sidebar.select("ruleview");
let view = inspector.ruleview.view;
info("Selecting the test node");
yield selectNode("#div-1", inspector);
@ -134,15 +137,3 @@ function* assertPseudoRemovedFromView(inspector, testActor, ruleview) {
is(value, "", "pseudo-class removed from infobar selector");
yield inspector.toolbox.highlighter.hideBoxModel();
}
function* ensureRuleView(inspector) {
if (!inspector.sidebar.getWindowForTab("ruleview")) {
info("Waiting for ruleview initialization to complete.");
yield inspector.sidebar.once("ruleview-ready");
}
info("Selecting the ruleview sidebar");
inspector.sidebar.select("ruleview");
return inspector.sidebar.getWindowForTab("ruleview")["ruleview"].view;
}

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

@ -170,32 +170,15 @@ function getActiveInspector() {
var openInspectorSidebarTab = Task.async(function*(id, hostType) {
let {toolbox, inspector} = yield openInspector();
if (!hasSideBarTab(inspector, id)) {
info("Waiting for the " + id + " sidebar to be ready");
yield inspector.sidebar.once(id + "-ready");
}
info("Selecting the " + id + " sidebar");
inspector.sidebar.select(id);
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab(id)[id]
toolbox,
inspector
};
});
/**
* Checks whether the inspector's sidebar corresponding to the given id already
* exists
* @param {InspectorPanel}
* @param {String}
* @return {Boolean}
*/
function hasSideBarTab(inspector, id) {
return !!inspector.sidebar.getWindowForTab(id);
}
/**
* Get the NodeFront for a node that matches a given css selector, via the
* protocol.

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

@ -26,14 +26,9 @@ devtools.jar:
content/styleeditor/styleeditor.xul (styleeditor/styleeditor.xul)
content/styleeditor/styleeditor.css (styleeditor/styleeditor.css)
content/storage/storage.xul (storage/storage.xul)
content/inspector/computed/computed.xhtml (inspector/computed/computed.xhtml)
content/inspector/fonts/fonts.js (inspector/fonts/fonts.js)
content/inspector/fonts/fonts.xhtml (inspector/fonts/fonts.xhtml)
content/inspector/layout/layout.js (inspector/layout/layout.js)
content/inspector/layout/layout.xhtml (inspector/layout/layout.xhtml)
content/inspector/markup/markup.css (inspector/markup/markup.css)
content/inspector/markup/markup.xhtml (inspector/markup/markup.xhtml)
content/inspector/rules/rules.xhtml (inspector/rules/rules.xhtml)
content/animationinspector/animation-controller.js (animationinspector/animation-controller.js)
content/animationinspector/animation-panel.js (animationinspector/animation-panel.js)
content/animationinspector/animation-inspector.xhtml (animationinspector/animation-inspector.xhtml)

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

@ -27,7 +27,7 @@ Object.defineProperty(exports, "TargetFactory", {
});
const unloadObserver = {
observe: function(subject, topic, data) {
observe: function(subject) {
if (subject.wrappedJSObject === require("@loader/unload")) {
Services.obs.removeObserver(unloadObserver, "sdk:loader:destroy");
for (let definition of gDevTools.getToolDefinitionArray()) {

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

@ -253,7 +253,9 @@ var NetMonitorController = {
this._disconnection = promise.defer();
// Wait for the connection to finish first.
yield this._connection.promise;
if (!this.isConnected()) {
yield this._connection.promise;
}
// When debugging local or a remote instance, the connection is closed by
// the RemoteTarget. The webconsole actor is stopped on disconnect.

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

@ -17,6 +17,9 @@ pref("devtools.devedition.promo.url", "https://www.mozilla.org/firefox/developer
// Disable the error console
pref("devtools.errorconsole.enabled", false);
// DevTools development workflow
pref("devtools.loader.hotreload", false);
// Developer toolbar preferences
pref("devtools.toolbar.enabled", true);
pref("devtools.toolbar.visible", false);

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

@ -6,7 +6,6 @@
<?xml-stylesheet href="chrome://devtools/skin/projecteditor/projecteditor.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/content/debugger/debugger.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/common.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/content/inspector/markup/markup.css" type="text/css"?>
<?xml-stylesheet href="chrome://devtools/skin/markup.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>

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

@ -3,9 +3,6 @@
"use strict";
/* TODO: Bug 1242584 should make the following comment unnecessary */
/* import-globals-from ../../../framework/test/shared-redux-head.js */
// Test viewports basics after opening, like size and location
const TEST_URL = "http://example.org/";

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

@ -125,18 +125,13 @@ function waitForToolboxFrameFocus(toolbox) {
var openInspectorSideBar = Task.async(function*(id) {
let {toolbox, inspector} = yield openInspector();
if (!hasSideBarTab(inspector, id)) {
info("Waiting for the " + id + " sidebar to be ready");
yield inspector.sidebar.once(id + "-ready");
}
info("Selecting the " + id + " sidebar");
inspector.sidebar.select(id);
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab(id)[id].view
view: inspector[id].view
};
});

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

@ -6,8 +6,9 @@
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const loaders = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
const { devtools, DevToolsLoader } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { devtools } = Cu.import("resource://devtools/shared/Loader.jsm", {});
const { joinURI } = devtools.require("devtools/shared/path");
const { Services } = devtools.require("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
const BROWSER_BASED_DIRS = [
@ -17,6 +18,40 @@ const BROWSER_BASED_DIRS = [
"resource://devtools/client/shared/redux"
];
function clearCache() {
Services.obs.notifyObservers(null, "startupcache-invalidate", null);
}
function hotReloadFile(window, require, loader, componentProxies, fileURI) {
dump("Hot reloading: " + fileURI + "\n");
if (fileURI.match(/\.js$/)) {
// Test for React proxy components
const proxy = componentProxies.get(fileURI);
if (proxy) {
// Remove the old module and re-require the new one; the require
// hook in the loader will take care of the rest
delete loader.modules[fileURI];
clearCache();
require(fileURI);
}
} else if (fileURI.match(/\.css$/)) {
const links = [...window.document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "link")];
links.forEach(link => {
if (link.href.indexOf(fileURI) === 0) {
const parentNode = link.parentNode;
const newLink = window.document.createElementNS("http://www.w3.org/1999/xhtml", "link");
newLink.rel = "stylesheet";
newLink.type = "text/css";
newLink.href = fileURI + "?s=" + Math.random();
parentNode.insertBefore(newLink, link);
parentNode.removeChild(link);
}
});
}
}
/*
* Create a loader to be used in a browser environment. This evaluates
* modules in their own environment, but sets window (the normal
@ -45,6 +80,8 @@ const BROWSER_BASED_DIRS = [
function BrowserLoader(baseURI, window) {
const loaderOptions = devtools.require("@loader/options");
const dynamicPaths = {};
const componentProxies = new Map();
const hotReloadEnabled = Services.prefs.getBoolPref("devtools.loader.hotreload");
if(AppConstants.DEBUG || AppConstants.DEBUG_JS_MODULES) {
dynamicPaths["devtools/client/shared/vendor/react"] =
@ -81,12 +118,47 @@ function BrowserLoader(baseURI, window) {
}
};
if(hotReloadEnabled) {
opts.loadModuleHook = (module, require) => {
const { uri, exports } = module;
if (exports.prototype &&
exports.prototype.isReactComponent) {
const { createProxy, getForceUpdate } =
require("devtools/client/shared/vendor/react-proxy");
const React = require("devtools/client/shared/vendor/react");
if (!componentProxies.get(uri)) {
const proxy = createProxy(exports);
componentProxies.set(uri, proxy);
module.exports = proxy.get();
}
else {
const proxy = componentProxies.get(uri);
const instances = proxy.update(exports);
instances.forEach(getForceUpdate(React));
module.exports = proxy.get();
}
}
return exports;
}
}
const mainModule = loaders.Module(baseURI, joinURI(baseURI, "main.js"));
const mainLoader = loaders.Loader(opts);
const require = loaders.Require(mainLoader, mainModule);
if(hotReloadEnabled) {
const watcher = devtools.require("devtools/client/shared/file-watcher");
watcher.on("file-changed", (_, fileURI) => {
hotReloadFile(window, require, mainLoader, componentProxies, fileURI);
});
}
return {
loader: mainLoader,
require: loaders.Require(mainLoader, mainModule)
require: require
};
}

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

@ -0,0 +1,78 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* eslint-env worker */
/* global OS */
importScripts("resource://gre/modules/osfile.jsm");
const modifiedTimes = new Map();
function gatherFiles(path, fileRegex) {
let files = [];
const iterator = new OS.File.DirectoryIterator(path);
try {
for (let child in iterator) {
// Don't descend into test directories. Saves us some time and
// there's no reason to.
if (child.isDir && !child.path.endsWith("/test")) {
files = files.concat(gatherFiles(child.path, fileRegex));
} else if (child.path.match(fileRegex)) {
let info;
try {
info = OS.File.stat(child.path);
} catch (e) {
// Just ignore it.
continue;
}
files.push(child.path);
modifiedTimes.set(child.path, info.lastModificationDate.getTime());
}
}
} finally {
iterator.close();
}
return files;
}
function scanFiles(files, onChangedFile) {
files.forEach(file => {
let info;
try {
info = OS.File.stat(file);
} catch (e) {
// Just ignore it. It was probably deleted.
return;
}
const lastTime = modifiedTimes.get(file);
if (info.lastModificationDate.getTime() > lastTime) {
modifiedTimes.set(file, info.lastModificationDate.getTime());
onChangedFile(file);
}
});
}
onmessage = function(event) {
const { path, fileRegex } = event.data;
let info = OS.File.stat(path);
if (!info.isDir) {
throw new Error("watcher expects a directory as root path");
}
// We get a list of all the files upfront, which means we don't
// support adding new files. But you need to rebuild Firefox when
// adding a new file anyway.
const files = gatherFiles(path, fileRegex || /.*/);
// Every second, scan for file changes by stat-ing each of them and
// comparing modification time.
setInterval(() => {
scanFiles(files, changedFile => postMessage(changedFile));
}, 1000);
};

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

@ -0,0 +1,73 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Ci, ChromeWorker } = require("chrome");
const { Services } = require("resource://gre/modules/Services.jsm");
const EventEmitter = require("devtools/shared/event-emitter");
const HOTRELOAD_PREF = "devtools.loader.hotreload";
function resolveResourceURI(uri) {
const handler = Services.io.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
return handler.resolveURI(Services.io.newURI(uri, null, null));
}
function watchFiles(path, onFileChanged) {
if (!path.startsWith("devtools/")) {
throw new Error("`watchFiles` expects a devtools path");
}
// We need to figure out a local path to watch. We start with
// whatever devtools points to.
let resolvedRootURI = resolveResourceURI("resource://devtools");
if (resolvedRootURI.match(/\/obj\-.*/)) {
// Move from the built directory to the user's local files
resolvedRootURI = resolvedRootURI.replace(/\/obj\-.*/, "") + "/devtools";
}
resolvedRootURI = resolvedRootURI.replace(/^file:\/\//, "");
const localURI = resolvedRootURI + "/" + path.replace(/^devtools\//, "");
const watchWorker = new ChromeWorker(
"resource://devtools/client/shared/file-watcher-worker.js"
);
watchWorker.onmessage = event => {
// We need to turn a local path back into a resource URI (or
// chrome). This means that this system will only work when built
// files are symlinked, so that these URIs actually read from
// local sources. There might be a better way to do this.
const relativePath = event.data.replace(resolvedRootURI + "/", "");
if (relativePath.startsWith("client/themes")) {
onFileChanged(relativePath.replace("client/themes",
"chrome://devtools/skin"));
}
onFileChanged("resource://devtools/" + relativePath);
};
watchWorker.postMessage({ path: localURI, fileRegex: /\.(js|css)$/ });
return watchWorker;
}
EventEmitter.decorate(module.exports);
let watchWorker;
function onPrefChange() {
if (Services.prefs.getBoolPref(HOTRELOAD_PREF) && !watchWorker) {
watchWorker = watchFiles("devtools/client", changedFile => {
module.exports.emit("file-changed", changedFile);
});
}
else if(watchWorker) {
watchWorker.terminate();
watchWorker = null;
}
}
Services.prefs.addObserver(HOTRELOAD_PREF, {
observe: onPrefChange
}, false);
onPrefChange();

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

@ -25,6 +25,8 @@ DevToolsModules(
'devices.js',
'DOMHelpers.jsm',
'doorhanger.js',
'file-watcher-worker.js',
'file-watcher.js',
'frame-script-utils.js',
'getjson.js',
'inplace-editor.js',

3
devtools/client/shared/vendor/moz.build поставляемый
Просмотреть файл

@ -6,11 +6,14 @@
modules = []
# react-dev is used if either debug mode is enabled,
# so include it for both
if CONFIG['DEBUG_JS_MODULES'] or CONFIG['MOZ_DEBUG']:
modules += ['react-dev.js']
modules += [
'react-dom.js',
'react-proxy.js',
'react-redux.js',
'react.js',
'redux.js',

1909
devtools/client/shared/vendor/react-proxy.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -197,8 +197,12 @@ add_task(function*() {
yield findVariableViewProperties([{name: "ss2", value: "changed=ss2"}]);
// Clearing items
yield gWindow.clear();
// Clearing items. Bug 1233497 makes it so that we can no longer yield
// CPOWs from Tasks. We work around this by calling clear via a ContentTask
// instead.
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
return Task.spawn(content.wrappedJSObject.clear);
});
yield gUI.once("store-objects-cleared");

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше