This commit is contained in:
Ryan VanderMeulen 2015-05-04 15:53:32 -04:00
Родитель d73d4d7053 2f893755da
Коммит 3ae9df90e4
50 изменённых файлов: 803 добавлений и 264 удалений

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

@ -30,7 +30,7 @@ var permissionObserver = {
function onLoadPermission()
{
var uri = gDocument.documentURIObject;
var uri = BrowserUtils.makeURIFromCPOW(gDocument.documentURIObject);
var permTab = document.getElementById("permTab");
if (SitePermissions.isSupportedURI(uri)) {
gPermURI = uri;

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

@ -3,6 +3,8 @@
* 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/. */
Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
var security = {
// Display the server certificate (static)
viewCert : function () {
@ -135,7 +137,7 @@ var security = {
getService(Components.interfaces.nsIEffectiveTLDService);
var eTLD;
var uri = gDocument.documentURIObject;
var uri = BrowserUtils.makeURIFromCPOW(gDocument.documentURIObject);
try {
eTLD = eTLDService.getBaseDomain(uri);
}
@ -232,7 +234,7 @@ function securityOnLoad() {
var yesStr = pageInfoBundle.getString("yes");
var noStr = pageInfoBundle.getString("no");
var uri = gDocument.documentURIObject;
var uri = BrowserUtils.makeURIFromCPOW(gDocument.documentURIObject);
setText("security-privacy-cookies-value",
hostHasCookies(uri) ? yesStr : noStr);
setText("security-privacy-passwords-value",

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

@ -174,7 +174,6 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1099156 - test directly manipulates
skip-if = buildapp == 'mulet'
[browser_bug455852.js]
[browser_bug460146.js]
skip-if = e10s # Bug 866413 - PageInfo doesn't work in e10s
[browser_bug462289.js]
skip-if = toolkit == "cocoa" || e10s # Bug 1102017 - middle-button mousedown on selected tab2 does not activate tab - Didn't expect [object XULElement], but got it
[browser_bug462673.js]
@ -187,7 +186,6 @@ skip-if = buildapp == 'mulet'
skip-if = buildapp == 'mulet'
[browser_bug495058.js]
[browser_bug517902.js]
skip-if = e10s # Bug 866413 - PageInfo doesn't work in e10s
[browser_bug519216.js]
[browser_bug520538.js]
[browser_bug521216.js]
@ -335,7 +333,7 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1100662 - content access causing unc
skip-if = buildapp == 'mulet' || e10s # Bug 1093603 - test breaks with PopupNotifications.panel.firstElementChild is null
[browser_overflowScroll.js]
[browser_pageInfo.js]
skip-if = buildapp == 'mulet' || e10s # Bug 866413 - PageInfo doesn't work in e10s
skip-if = buildapp == 'mulet'
[browser_page_style_menu.js]
[browser_parsable_css.js]

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

@ -1,6 +1,4 @@
/* 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";
/*
* Test bug 427559 to make sure focused elements that are no longer on the page
@ -8,42 +6,48 @@
* tab with the now-gone element.
*/
// Default focus on a button and have it kill itself on blur
let testPage = 'data:text/html,<body><button onblur="this.parentNode.removeChild(this);"><script>document.body.firstChild.focus();</script></body>';
// Default focus on a button and have it kill itself on blur.
const URL = 'data:text/html;charset=utf-8,' +
'<body><button onblur="this.remove()">' +
'<script>document.body.firstChild.focus()</script></body>';
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
var browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function () {
browser.removeEventListener("load", arguments.callee, true);
executeSoon(function () {
var testPageWin = content;
is(browser.contentDocumentAsCPOW.activeElement.localName, "button", "button is focused");
addEventListener("focus", function focusedWindow(event) {
if (!String(event.target.location).startsWith("data:"))
return;
removeEventListener("focus", focusedWindow, true);
// Make sure focus is given to the window because the element is now gone
is(browser.contentDocumentAsCPOW.activeElement.localName, "body", "body is focused");
gBrowser.removeCurrentTab();
finish();
}, true);
// The test page loaded, so open an empty tab, select it, then restore
// the test tab. This causes the test page's focused element to be removed
// from its document.
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.removeCurrentTab();
});
}, true);
content.location = testPage;
function getFocusedLocalName(browser) {
return ContentTask.spawn(browser, null, function* () {
return content.document.activeElement.localName;
});
}
add_task(function* () {
gBrowser.selectedTab = gBrowser.addTab(URL);
let browser = gBrowser.selectedBrowser;
yield BrowserTestUtils.browserLoaded(browser);
is((yield getFocusedLocalName(browser)), "button", "button is focused");
let promiseFocused = ContentTask.spawn(browser, null, function* () {
return new Promise(resolve => {
content.addEventListener("focus", function onFocus({target}) {
if (String(target.location).startsWith("data:")) {
content.removeEventListener("focus", onFocus);
resolve();
}
});
});
});
// The test page loaded, so open an empty tab, select it, then restore
// the test tab. This causes the test page's focused element to be removed
// from its document.
gBrowser.selectedTab = gBrowser.addTab("about:blank");
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.removeCurrentTab();
// Wait until the original tab is focused again.
yield promiseFocused;
// Make sure focus is given to the window because the element is now gone.
is((yield getFocusedLocalName(browser)), "body", "body is focused");
// Cleanup.
gBrowser.removeCurrentTab();
});

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

@ -79,7 +79,6 @@ skip-if = !crashreporter
[browser_pluginCrashCommentAndURL.js]
skip-if = !crashreporter
[browser_pageInfo_plugins.js]
skip-if = e10s # Bug 866413
[browser_pluginplaypreview.js]
skip-if = e10s # bug 1148827
[browser_pluginplaypreview2.js]

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

@ -468,10 +468,14 @@ let gEditItemOverlay = {
if (!anyChanges)
return false;
// The panel could have been closed in the meanwhile.
if (!this._paneInfo)
return false;
// Ensure the tagsField is in sync, clean it up from empty tags
currentTags = this._paneInfo.bulkTagging ?
this._getCommonTags() :
PlacesUtils.tagging.getTagsForURI(this._uri);
PlacesUtils.tagging.getTagsForURI(this._paneInfo.uri);
this._initTextField(this._tagsField, currentTags.join(", "), false);
return true;
}),
@ -505,7 +509,7 @@ let gEditItemOverlay = {
// Here we update either the item title or its cached static title
let newTitle = this._namePicker.value;
if (!newTitle &&
PlacesUtils.bookmarks.getFolderIdForItem(itemId) == PlacesUtils.tagsFolderId) {
PlacesUtils.bookmarks.getFolderIdForItem(this._paneInfo.itemId) == PlacesUtils.tagsFolderId) {
// We don't allow setting an empty title for a tag, restore the old one.
this._initNamePicker();
}
@ -656,17 +660,17 @@ let gEditItemOverlay = {
* The identifier of the bookmarks folder.
*/
_getFolderMenuItem(aFolderId) {
let menuPopup = this._folderMenuList.menupopup;
let menupopup = this._folderMenuList.menupopup;
let menuItem = Array.prototype.find.call(
menuPopup.childNodes, menuItem => menuItem.folderId === aFolderId);
menupopup.childNodes, menuItem => menuItem.folderId === aFolderId);
if (menuItem !== undefined)
return menuItem;
// 3 special folders + separator + folder-items-count limit
if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
menupopup.removeChild(menuPopup.lastChild);
menupopup.removeChild(menupopup.lastChild);
return this._appendFolderItemToMenupopup(menuPopup, aFolderId);
return this._appendFolderItemToMenupopup(menupopup, aFolderId);
},
onFolderMenuListCommand(aEvent) {
@ -688,7 +692,8 @@ let gEditItemOverlay = {
// Move the item
let containerId = this._getFolderIdFromMenuList();
if (PlacesUtils.bookmarks.getFolderIdForItem(this._paneInfo.itemId) != containerId) {
if (PlacesUtils.bookmarks.getFolderIdForItem(this._paneInfo.itemId) != containerId &&
this._paneInfo.itemId != containerId) {
if (PlacesUIUtils.useAsyncTransactions) {
Task.spawn(function* () {
let newParentGuid = yield PlacesUtils.promiseItemGuid(containerId);
@ -708,7 +713,7 @@ let gEditItemOverlay = {
if (containerId != PlacesUtils.unfiledBookmarksFolderId &&
containerId != PlacesUtils.toolbarFolderId &&
containerId != PlacesUtils.bookmarksMenuFolderId) {
this._markFolderAsRecentlyUsed(container)
this._markFolderAsRecentlyUsed(containerId)
.catch(Components.utils.reportError);
}
}
@ -718,8 +723,8 @@ let gEditItemOverlay = {
if (!folderTreeRow.collapsed) {
var selectedNode = this._folderTree.selectedNode;
if (!selectedNode ||
PlacesUtils.getConcreteItemId(selectedNode) != container)
this._folderTree.selectItems([container]);
PlacesUtils.getConcreteItemId(selectedNode) != containerId)
this._folderTree.selectItems([containerId]);
}
},
@ -750,13 +755,15 @@ let gEditItemOverlay = {
let annotation = this._getLastUsedAnnotationObject(false);
while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) {
let folderId = this._recentFolders.pop().folderId;
let annoTxn = new PlacesSetItemAnnotationTransaction(folderId, anno);
let annoTxn = new PlacesSetItemAnnotationTransaction(folderId,
annotation);
txns.push(annoTxn);
}
// Mark folder as recently used
annotation = this._getLastUsedAnnotationObject(true);
let annoTxn = new PlacesSetItemAnnotationTransaction(aFolderId, anno);
let annoTxn = new PlacesSetItemAnnotationTransaction(aFolderId,
annotation);
txns.push(annoTxn);
let aggregate =
@ -983,7 +990,7 @@ let gEditItemOverlay = {
return;
if (aItemId == this._paneInfo.itemId) {
this._paneInfo.title = aNewTitle;
this._initTextField(this._namePicker);
this._initTextField(this._namePicker, aNewTitle);
}
else if (this._paneInfo.visibleRows.has("folderRow")) {
// If the title of a folder which is listed within the folders
@ -991,7 +998,7 @@ let gEditItemOverlay = {
// representing element.
let menupopup = this._folderMenuList.menupopup;
for (menuitem of menupopup.childNodes) {
if ("folderId" in menuItem && menuItem.folderId == aItemId) {
if ("folderId" in menuitem && menuitem.folderId == aItemId) {
menuitem.label = aNewTitle;
break;
}
@ -1002,16 +1009,18 @@ let gEditItemOverlay = {
// nsINavBookmarkObserver
onItemChanged(aItemId, aProperty, aIsAnnotationProperty, aValue,
aLastModified, aItemType) {
if (aProperty == "tags" && this._paneInfo.visibleRows.has("tagsRow"))
if (aProperty == "tags" && this._paneInfo.visibleRows.has("tagsRow")) {
this._onTagsChange(aItemId);
else if (!this._paneInfo.isItem || this._paneInfo.itemId != aItemId)
}
else if (aProperty == "title" && this._paneInfo.isItem) {
// This also updates titles of folders in the folder menu list.
this._onItemTitleChange(aItemId, aValue);
}
else if (!this._paneInfo.isItem || this._paneInfo.itemId != aItemId) {
return;
}
switch (aProperty) {
case "title":
if (this._paneInfo.isItem)
this._onItemTitleChange(aItemId, aValue);
break;
case "uri":
let newURI = NetUtil.newURI(aValue);
if (!newURI.equals(this._paneInfo.uri)) {

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

@ -1225,7 +1225,6 @@ var ViewMenu = {
url: { key: "URI", dir: "ascending" },
date: { key: "DATE", dir: "descending" },
visitCount: { key: "VISITCOUNT", dir: "descending" },
keyword: { key: "KEYWORD", dir: "ascending" },
dateAdded: { key: "DATEADDED", dir: "descending" },
lastModified: { key: "LASTMODIFIED", dir: "descending" },
description: { key: "ANNOTATION",

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

@ -390,9 +390,6 @@
<treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.keyword.label;" id="placesContentKeyword" anonid="keyword" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.description.label;" id="placesContentDescription" anonid="description" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>

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

@ -518,11 +518,10 @@ PlacesTreeView.prototype = {
COLUMN_TYPE_URI: 2,
COLUMN_TYPE_DATE: 3,
COLUMN_TYPE_VISITCOUNT: 4,
COLUMN_TYPE_KEYWORD: 5,
COLUMN_TYPE_DESCRIPTION: 6,
COLUMN_TYPE_DATEADDED: 7,
COLUMN_TYPE_LASTMODIFIED: 8,
COLUMN_TYPE_TAGS: 9,
COLUMN_TYPE_DESCRIPTION: 5,
COLUMN_TYPE_DATEADDED: 6,
COLUMN_TYPE_LASTMODIFIED: 7,
COLUMN_TYPE_TAGS: 8,
_getColumnType: function PTV__getColumnType(aColumn) {
let columnType = aColumn.element.getAttribute("anonid") || aColumn.id;
@ -536,8 +535,6 @@ PlacesTreeView.prototype = {
return this.COLUMN_TYPE_DATE;
case "visitCount":
return this.COLUMN_TYPE_VISITCOUNT;
case "keyword":
return this.COLUMN_TYPE_KEYWORD;
case "description":
return this.COLUMN_TYPE_DESCRIPTION;
case "dateAdded":
@ -568,10 +565,6 @@ PlacesTreeView.prototype = {
return [this.COLUMN_TYPE_VISITCOUNT, false];
case Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING:
return [this.COLUMN_TYPE_VISITCOUNT, true];
case Ci.nsINavHistoryQueryOptions.SORT_BY_KEYWORD_ASCENDING:
return [this.COLUMN_TYPE_KEYWORD, false];
case Ci.nsINavHistoryQueryOptions.SORT_BY_KEYWORD_DESCENDING:
return [this.COLUMN_TYPE_KEYWORD, true];
case Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_ASCENDING:
if (this._result.sortingAnnotation == PlacesUIUtils.DESCRIPTION_ANNO)
return [this.COLUMN_TYPE_DESCRIPTION, false];
@ -849,9 +842,7 @@ PlacesTreeView.prototype = {
this._invalidateCellValue(aNode, this.COLUMN_TYPE_TAGS);
},
nodeKeywordChanged: function PTV_nodeKeywordChanged(aNode, aNewKeyword) {
this._invalidateCellValue(aNode, this.COLUMN_TYPE_KEYWORD);
},
nodeKeywordChanged(aNode, aNewKeyword) {},
nodeAnnotationChanged: function PTV_nodeAnnotationChanged(aNode, aAnno) {
if (aAnno == PlacesUIUtils.DESCRIPTION_ANNO) {
@ -1444,10 +1435,6 @@ PlacesTreeView.prototype = {
return this._convertPRTimeToString(nodeTime);
case this.COLUMN_TYPE_VISITCOUNT:
return node.accessCount;
case this.COLUMN_TYPE_KEYWORD:
if (PlacesUtils.nodeIsBookmark(node))
return PlacesUtils.bookmarks.getKeywordForBookmark(node.itemId);
return "";
case this.COLUMN_TYPE_DESCRIPTION:
if (node.itemId != -1) {
try {
@ -1582,15 +1569,6 @@ PlacesTreeView.prototype = {
else
newSort = NHQO.SORT_BY_VISITCOUNT_DESCENDING;
break;
case this.COLUMN_TYPE_KEYWORD:
if (oldSort == NHQO.SORT_BY_KEYWORD_ASCENDING)
newSort = NHQO.SORT_BY_KEYWORD_DESCENDING;
else if (allowTriState && oldSort == NHQO.SORT_BY_KEYWORD_DESCENDING)
newSort = NHQO.SORT_BY_NONE;
else
newSort = NHQO.SORT_BY_KEYWORD_ASCENDING;
break;
case this.COLUMN_TYPE_DESCRIPTION:
if (oldSort == NHQO.SORT_BY_ANNOTATION_ASCENDING &&

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

@ -35,7 +35,6 @@ const SORT_LOOKUP_TABLE = {
url: { key: "URI", dir: "ASCENDING" },
date: { key: "DATE", dir: "DESCENDING" },
visitCount: { key: "VISITCOUNT", dir: "DESCENDING" },
keyword: { key: "KEYWORD", dir: "ASCENDING" },
dateAdded: { key: "DATEADDED", dir: "DESCENDING" },
lastModified: { key: "LASTMODIFIED", dir: "DESCENDING" },
description: { key: "ANNOTATION",

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

@ -572,7 +572,11 @@ let gDevToolsBrowser = {
let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.getToolbox(target);
toolbox ? toolbox.destroy() : gDevTools.showToolbox(target);
// If a toolbox exists, using toggle from the Main window :
// - should close a docked toolbox
// - should focus a windowed toolbox
let isDocked = toolbox && toolbox.hostType != devtools.Toolbox.HostType.WINDOW;
isDocked ? toolbox.destroy() : gDevTools.showToolbox(target);
},
toggleBrowserToolboxCommand: function(gBrowser) {

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

@ -47,6 +47,7 @@ skip-if = e10s # Bug 1069044 - destroyInspector may hang during shutdown
[browser_toolbox_sidebar_overflow_menu.js]
[browser_toolbox_tabsswitch_shortcuts.js]
[browser_toolbox_textbox_context_menu.js]
[browser_toolbox_toggle.js]
[browser_toolbox_tool_ready.js]
[browser_toolbox_tool_remote_reopen.js]
[browser_toolbox_transport_events.js]

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

@ -0,0 +1,86 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const URL = "data:text/html;charset=utf-8,Test toggling devtools using keyboard shortcuts";
add_task(function*() {
// Test with ACCEL+SHIFT+I / ACCEL+ALT+I (MacOSX) ; modifiers should match :
// - toolbox-key-toggle in browser/devtools/framework/toolbox-window.xul
// - key_devToolboxMenuItem in browser/base/content/browser.xul
info('Test toggle using CTRL+SHIFT+I/CMD+ALT+I');
yield testToggle('I', {
accelKey : true,
shiftKey : !navigator.userAgent.match(/Mac/),
altKey : navigator.userAgent.match(/Mac/),
});
// Test with F12 ; no modifiers
info('Test toggle using F12');
yield testToggle('VK_F12', {});
});
function* testToggle(key, modifiers) {
let tab = yield addTab(URL + " ; key : '" + key + "'");
yield gDevTools.showToolbox(TargetFactory.forTab(tab));
yield testToggleDockedToolbox(tab, key, modifiers);
yield testToggleDetachedToolbox(tab, key, modifiers);
yield cleanup();
}
function* testToggleDockedToolbox (tab, key, modifiers) {
let toolbox = getToolboxForTab(tab);
isnot(toolbox.hostType, devtools.Toolbox.HostType.WINDOW, "Toolbox is docked in the main window");
info('verify docked toolbox is destroyed when using toggle key');
let onToolboxDestroyed = once(gDevTools, "toolbox-destroyed");
EventUtils.synthesizeKey(key, modifiers);
yield onToolboxDestroyed;
ok(true, "Docked toolbox is destroyed when using a toggle key");
info('verify new toolbox is created when using toggle key');
let onToolboxReady = once(gDevTools, "toolbox-ready");
EventUtils.synthesizeKey(key, modifiers);
yield onToolboxReady;
ok(true, "Toolbox is created by using when toggle key");
}
function* testToggleDetachedToolbox (tab, key, modifiers) {
let toolbox = getToolboxForTab(tab);
info('change the toolbox hostType to WINDOW');
yield toolbox.switchHost(devtools.Toolbox.HostType.WINDOW);
is(toolbox.hostType, devtools.Toolbox.HostType.WINDOW, "Toolbox opened on separate window");
let toolboxWindow = toolbox._host._window;
info('Wait for focus on the toolbox window')
yield new Promise(resolve => waitForFocus(resolve, toolboxWindow));
info('Focus main window')
let onMainWindowFocus = once(window, "focus");
window.focus();
yield onMainWindowFocus;
ok(true, "Main window focused");
info('verify windowed toolbox is focused when using toggle key from the main window')
let onToolboxWindowFocus = once(toolboxWindow, "focus");
EventUtils.synthesizeKey(key, modifiers);
yield onToolboxWindowFocus;
ok(true, "Toolbox focused and not destroyed");
info('verify windowed toolbox is destroyed when using toggle key from its own window')
let onToolboxDestroyed = once(gDevTools, "toolbox-destroyed");
EventUtils.synthesizeKey(key, modifiers, toolboxWindow);
yield onToolboxDestroyed;
ok(true, "Toolbox destroyed");
}
function getToolboxForTab(tab) {
return gDevTools.getToolbox(TargetFactory.forTab(tab));
}
function* cleanup(toolbox) {
Services.prefs.setCharPref("devtools.toolbox.host", devtools.Toolbox.HostType.BOTTOM);
gBrowser.removeCurrentTab();
}

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

@ -26,6 +26,19 @@
key="&closeCmd.key;"
command="toolbox-cmd-close"
modifiers="accel"/>
<key id="toolbox-key-toggle"
key="&toggleToolbox.key;"
command="toolbox-cmd-close"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
<key id="toolbox-key-toggle-F12"
keycode="&toggleToolboxF12.keycode;"
keytext="&toggleToolboxF12.keytext;"
command="toolbox-cmd-close"/>
</keyset>
<iframe id="toolbox-iframe" flex="1" forceOwnRefreshDriver=""></iframe>

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

@ -774,9 +774,7 @@ InspectorPanel.prototype = {
}
let type = popupNode.dataset.type;
// Bug 1158822 will make "resource" type URLs open in devtools, but for now
// they're considered like "uri".
if (type === "uri" || type === "resource") {
if (type === "uri" || type === "cssresource" || type === "jsresource") {
// First make sure the target can resolve relative URLs.
this.target.actorHasMethod("inspector", "resolveRelativeURL").then(canResolve => {
if (!canResolve) {
@ -786,11 +784,20 @@ InspectorPanel.prototype = {
linkSeparator.removeAttribute("hidden");
// Links can't be opened in new tabs in the browser toolbox.
if (!this.target.chrome) {
if (type === "uri" && !this.target.chrome) {
linkFollow.removeAttribute("hidden");
linkFollow.setAttribute("label", this.strings.GetStringFromName(
"inspector.menu.openUrlInNewTab.label"));
} else if (type === "cssresource") {
linkFollow.removeAttribute("hidden");
linkFollow.setAttribute("label", this.toolboxStrings.GetStringFromName(
"toolbox.viewCssSourceInStyleEditor.label"));
} else if (type === "jsresource") {
linkFollow.removeAttribute("hidden");
linkFollow.setAttribute("label", this.toolboxStrings.GetStringFromName(
"toolbox.viewJsSourceInDebugger.label"));
}
linkCopy.removeAttribute("hidden");
linkCopy.setAttribute("label", this.strings.GetStringFromName(
"inspector.menu.copyUrlToClipboard.label"));
@ -1099,26 +1106,31 @@ InspectorPanel.prototype = {
let type = this.panelDoc.popupNode.dataset.type;
let link = this.panelDoc.popupNode.dataset.link;
// "resource" type links should open appropriate tool instead (bug 1158822).
if (type === "uri" || type === "resource") {
if (type === "uri" || type === "cssresource" || type === "jsresource") {
// Open link in a new tab.
// When the inspector menu was setup on click (see _setupNodeLinkMenu), we
// already checked that resolveRelativeURL existed.
this.inspector.resolveRelativeURL(link, this.selection.nodeFront).then(url => {
let browserWin = this.target.tab.ownerDocument.defaultView;
browserWin.openUILinkIn(url, "tab");
}, console.error);
if (type === "uri") {
let browserWin = this.target.tab.ownerDocument.defaultView;
browserWin.openUILinkIn(url, "tab");
} else if (type === "cssresource") {
return this.toolbox.viewSourceInStyleEditor(url);
} else if (type === "jsresource") {
return this.toolbox.viewSourceInDebugger(url);
}
}).catch(e => console.error(e));
} else if (type == "idref") {
// Select the node in the same document.
this.walker.document(this.selection.nodeFront).then(doc => {
this.walker.querySelector(doc, "#" + CSS.escape(link)).then(node => {
return this.walker.querySelector(doc, "#" + CSS.escape(link)).then(node => {
if (!node) {
this.emit("idref-attribute-link-failed");
return;
}
this.selection.setNodeFront(node);
}, console.error);
}, console.error);
});
}).catch(e => console.error(e));
}
},
@ -1179,18 +1191,21 @@ InspectorPanel.prototype = {
/////////////////////////////////////////////////////////////////////////
//// Initializers
loader.lazyGetter(InspectorPanel.prototype, "strings",
function () {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/inspector.properties");
});
loader.lazyGetter(InspectorPanel.prototype, "strings", function () {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/inspector.properties");
});
loader.lazyGetter(InspectorPanel.prototype, "toolboxStrings", function () {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/toolbox.properties");
});
loader.lazyGetter(this, "clipboardHelper", function() {
return Cc["@mozilla.org/widget/clipboardhelper;1"].
getService(Ci.nsIClipboardHelper);
});
loader.lazyGetter(this, "DOMUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
});

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

@ -118,7 +118,7 @@ browser.jar:
content/browser/devtools/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
content/browser/devtools/commandlinetooltip.xhtml (commandline/commandlinetooltip.xhtml)
content/browser/devtools/commandline/commands-index.js (commandline/commands-index.js)
content/browser/devtools/framework/toolbox-window.xul (framework/toolbox-window.xul)
* content/browser/devtools/framework/toolbox-window.xul (framework/toolbox-window.xul)
content/browser/devtools/framework/toolbox-options.xul (framework/toolbox-options.xul)
content/browser/devtools/framework/toolbox-options.js (framework/toolbox-options.js)
content/browser/devtools/framework/toolbox.xul (framework/toolbox.xul)

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

@ -85,7 +85,7 @@
--></span>
<span id="template-text" save="${elt}" class="editor text">
<pre save="${value}" style="display:inline-block;" tabindex="0"></pre>
<pre save="${value}" style="display:inline-block; white-space: normal;" tabindex="0"></pre>
</span>
<span id="template-comment"

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

@ -74,6 +74,7 @@ skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible
[browser_markupview_links_03.js]
[browser_markupview_links_04.js]
[browser_markupview_links_05.js]
[browser_markupview_links_06.js]
[browser_markupview_load_01.js]
[browser_markupview_html_edit_01.js]
[browser_markupview_html_edit_02.js]

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

@ -13,7 +13,7 @@ const TEST_DATA = [{
selector: "link",
attributes: [{
attributeName: "href",
links: [{type: "resource", value: "style.css"}]
links: [{type: "cssresource", value: "style.css"}]
}]
}, {
selector: "link[rel=icon]",
@ -95,7 +95,7 @@ const TEST_DATA = [{
selector: "script",
attributes: [{
attributeName: "src",
links: [{type: "resource", value: "lib_jquery_1.0.js"}]
links: [{type: "jsresource", value: "lib_jquery_1.0.js"}]
}]
}];

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

@ -10,6 +10,8 @@
const TEST_URL = TEST_URL_ROOT + "doc_markup_links.html";
const STRINGS = Services.strings
.createBundle("chrome://browser/locale/devtools/inspector.properties");
const TOOLBOX_STRINGS = Services.strings
.createBundle("chrome://browser/locale/devtools/toolbox.properties");
// The test case array contains objects with the following properties:
// - selector: css selector for the node to select in the inspector
@ -26,7 +28,7 @@ const TEST_DATA = [{
popupNodeSelector: ".link",
isLinkFollowItemVisible: true,
isLinkCopyItemVisible: true,
linkFollowItemLabel: STRINGS.GetStringFromName("inspector.menu.openUrlInNewTab.label"),
linkFollowItemLabel: TOOLBOX_STRINGS.GetStringFromName("toolbox.viewCssSourceInStyleEditor.label"),
linkCopyItemLabel: STRINGS.GetStringFromName("inspector.menu.copyUrlToClipboard.label")
}, {
selector: "link[rel=icon]",
@ -56,7 +58,7 @@ const TEST_DATA = [{
popupNodeSelector: ".link",
isLinkFollowItemVisible: true,
isLinkCopyItemVisible: true,
linkFollowItemLabel: STRINGS.GetStringFromName("inspector.menu.openUrlInNewTab.label"),
linkFollowItemLabel: TOOLBOX_STRINGS.GetStringFromName("toolbox.viewJsSourceInDebugger.label"),
linkCopyItemLabel: STRINGS.GetStringFromName("inspector.menu.copyUrlToClipboard.label")
}, {
selector: "p[for]",

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

@ -12,9 +12,6 @@ const TEST_URL = TEST_URL_ROOT + "doc_markup_links.html";
add_task(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
let linkFollow = inspector.panelDoc.getElementById("node-menu-link-follow");
let linkCopy = inspector.panelDoc.getElementById("node-menu-link-copy");
info("Select a node with a URI attribute");
yield selectNode("video", inspector);

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

@ -0,0 +1,51 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the contextual menu items shown when clicking on linked attributes
// for <script> and <link> tags actually open the right tools.
const TEST_URL = TEST_URL_ROOT + "doc_markup_links.html";
add_task(function*() {
let {toolbox, inspector} = yield addTab(TEST_URL).then(openInspector);
info("Select a node with a cssresource attribute");
yield selectNode("link", inspector);
info("Set the popupNode to the node that contains the uri");
let {editor} = yield getContainerForSelector("link", inspector);
let popupNode = editor.attrElements.get("href").querySelector(".link");
inspector.panelDoc.popupNode = popupNode;
info("Follow the link and wait for the style-editor to open");
let onStyleEditorReady = toolbox.once("styleeditor-ready");
inspector.followAttributeLink();
yield onStyleEditorReady;
// No real need to test that the editor opened on the right file here as this
// is already tested in /framework/test/browser_toolbox_view_source_*
ok(true, "The style-editor was open");
info("Switch back to the inspector");
yield toolbox.selectTool("inspector");
info("Select a node with a jsresource attribute");
yield selectNode("script", inspector);
info("Set the popupNode to the node that contains the uri");
({editor}) = yield getContainerForSelector("script", inspector);
popupNode = editor.attrElements.get("src").querySelector(".link");
inspector.panelDoc.popupNode = popupNode;
info("Follow the link and wait for the debugger to open");
let onDebuggerReady = toolbox.once("jsdebugger-ready");
inspector.followAttributeLink();
yield onDebuggerReady;
// No real need to test that the debugger opened on the right file here as
// this is already tested in /framework/test/browser_toolbox_view_source_*
ok(true, "The debugger was open");
});

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

@ -247,6 +247,8 @@ function InplaceEditor(aOptions, aEvent)
this.input.addEventListener("keyup", this._onKeyup, false);
}
this._updateSize();
if (aOptions.start) {
aOptions.start(this, aEvent);
}
@ -364,7 +366,6 @@ InplaceEditor.prototype = {
// account for the fact that after adding a newline the <pre> doesn't grow
// unless there's text content on the line.
width += 15;
this._measurement.textContent += "M";
this.input.style.height = this._measurement.offsetHeight + "px";
}

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

@ -18,8 +18,10 @@
* (e.g. <label for="input-id"> or <key command="command-id">).
* - TYPE_IDREF_LIST: a space separated list of IDREFs (e.g.
* <output for="id1 id2">).
* - TYPE_RESOURCE_URI: a URI to a javascript or css resource that can be opened
* in the devtools (e.g. <script src="uri">).
* - TYPE_JS_RESOURCE_URI: a URI to a javascript resource that can be opened in
* the devtools (e.g. <script src="uri">).
* - TYPE_CSS_RESOURCE_URI: a URI to a css resource that can be opened in the
* devtools (e.g. <link href="uri">).
*
* parseAttribute is the parser entry function, exported on this module.
*/
@ -29,7 +31,8 @@ const TYPE_URI = "uri";
const TYPE_URI_LIST = "uriList";
const TYPE_IDREF = "idref";
const TYPE_IDREF_LIST = "idrefList";
const TYPE_RESOURCE_URI = "resource";
const TYPE_JS_RESOURCE_URI = "jsresource";
const TYPE_CSS_RESOURCE_URI = "cssresource";
const SVG_NS = "http://www.w3.org/2000/svg";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
@ -65,7 +68,7 @@ const ATTRIBUTE_TYPES = [
{namespaceURI: HTML_NS, attributeName: "headers", tagName: "th", type: TYPE_IDREF_LIST},
{namespaceURI: HTML_NS, attributeName: "href", tagName: "a", type: TYPE_URI},
{namespaceURI: HTML_NS, attributeName: "href", tagName: "area", type: TYPE_URI},
{namespaceURI: "*", attributeName: "href", tagName: "link", type: TYPE_RESOURCE_URI,
{namespaceURI: "*", attributeName: "href", tagName: "link", type: TYPE_CSS_RESOURCE_URI,
isValid: (namespaceURI, tagName, attributes) => {
return getAttribute(attributes, "rel") === "stylesheet";
}},
@ -82,7 +85,7 @@ const ATTRIBUTE_TYPES = [
{namespaceURI: HTML_NS, attributeName: "ping", tagName: "area", type: TYPE_URI_LIST},
{namespaceURI: HTML_NS, attributeName: "poster", tagName: "video", type: TYPE_URI},
{namespaceURI: HTML_NS, attributeName: "profile", tagName: "head", type: TYPE_URI},
{namespaceURI: "*", attributeName: "src", tagName: "script", type: TYPE_RESOURCE_URI},
{namespaceURI: "*", attributeName: "src", tagName: "script", type: TYPE_JS_RESOURCE_URI},
{namespaceURI: HTML_NS, attributeName: "src", tagName: "input", type: TYPE_URI},
{namespaceURI: HTML_NS, attributeName: "src", tagName: "frame", type: TYPE_URI},
{namespaceURI: HTML_NS, attributeName: "src", tagName: "iframe", type: TYPE_URI},
@ -137,9 +140,15 @@ let parsers = {
}
return data;
},
[TYPE_RESOURCE_URI]: function(attributeValue) {
[TYPE_JS_RESOURCE_URI]: function(attributeValue) {
return [{
type: TYPE_RESOURCE_URI,
type: TYPE_JS_RESOURCE_URI,
value: attributeValue
}];
},
[TYPE_CSS_RESOURCE_URI]: function(attributeValue) {
return [{
type: TYPE_CSS_RESOURCE_URI,
value: attributeValue
}];
},
@ -169,7 +178,7 @@ let parsers = {
* be an array of {name, value} objects.
* @param {String} attributeName The name of the attribute to parse.
* @return {Array} An array of tokens that represents the value. Each token is
* an object {type: [string|uri|resource|idref], value}.
* an object {type: [string|uri|jsresource|cssresource|idref], value}.
* For instance parsing the ping attribute in <a ping="uri1 uri2"> returns:
* [
* {type: "uri", value: "uri2"},

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

@ -51,7 +51,7 @@ const TEST_DATA = [{
attributeValue: "styles.css",
otherAttributes: [{name: "rel", value: "stylesheet"}],
expected: [
{value: "styles.css", type: "resource"}
{value: "styles.css", type: "cssresource"}
]
}, {
tagName: "link",
@ -103,7 +103,7 @@ const TEST_DATA = [{
attributeName: "src",
attributeValue: "script.js",
expected: [
{value: "script.js", type: "resource"}
{value: "script.js", type: "jsresource"}
]
}];

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

@ -93,6 +93,7 @@ const CONSOLE_API_LEVELS_TO_SEVERITIES = {
table: "log",
debug: "log",
dir: "log",
dirxml: "log",
group: "log",
groupCollapsed: "log",
groupEnd: "log",
@ -2982,7 +2983,8 @@ Widgets.ObjectRenderers.add({
_renderDocumentNode: function()
{
let fn = Widgets.ObjectRenderers.byKind.ObjectWithURL.prototype._renderElement;
let fn =
Widgets.ObjectRenderers.byKind.ObjectWithURL.prototype._renderElement;
this.element = fn.call(this, this.objectActor,
this.objectActor.preview.location);
this.element.classList.add("documentNode");

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

@ -384,3 +384,4 @@ skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
[browser_webconsole_console_api_stackframe.js]
[browser_webconsole_column_numbers.js]
[browser_console_open_or_focus.js]
[browser_webconsole_bug_922212_console_dirxml.js]

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

@ -9,7 +9,7 @@
"use strict";
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for bug 659907: " +
"Expand console object with a dir method"
"Expand console object with a dir method";
let test = asyncTest(function*() {
yield loadTab(TEST_URI);

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

@ -0,0 +1,49 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that console.dirxml works as intended.
"use strict";
const TEST_URI = `data:text/html;charset=utf-8,Web Console test for bug 922212:
Add console.dirxml`;
let test = asyncTest(function*() {
yield loadTab(TEST_URI);
let hud = yield openConsole();
hud.jsterm.clearOutput();
// Should work like console.log(window)
hud.jsterm.execute("console.dirxml(window)");
let [result] = yield waitForMessages({
webconsole: hud,
messages: [{
name: "console.dirxml(window) output:",
text: /Window \u2192/,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
hud.jsterm.clearOutput();
hud.jsterm.execute("console.dirxml(document.body)");
// Should work like console.log(document.body);
[result] = yield waitForMessages({
webconsole: hud,
messages: [{
name: "console.dirxml(document.body) output:",
text: "<body>",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
let msg = [...result.matched][0];
yield checkLinkToInspector(true, msg);
});

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

@ -1474,7 +1474,8 @@ function checkOutputForInputs(hud, inputTests)
if (typeof entry.inspectorIcon == "boolean") {
let msg = [...result.matched][0];
yield checkLinkToInspector(entry, msg);
info("Checking Inspector Link: " + entry.input);
yield checkLinkToInspector(entry.inspectorIcon, msg);
}
}
@ -1516,7 +1517,8 @@ function checkOutputForInputs(hud, inputTests)
yield checkObjectClick(entry, msg);
}
if (typeof entry.inspectorIcon == "boolean") {
yield checkLinkToInspector(entry, msg);
info("Checking Inspector Link: " + entry.input);
yield checkLinkToInspector(entry.inspectorIcon, msg);
}
}
@ -1556,30 +1558,6 @@ function checkOutputForInputs(hud, inputTests)
yield promise.resolve(null);
}
function checkLinkToInspector(entry, msg)
{
info("Checking Inspector Link: " + entry.input);
let elementNodeWidget = [...msg._messageObject.widgets][0];
if (!elementNodeWidget) {
ok(!entry.inspectorIcon, "The message has no ElementNode widget");
return;
}
return elementNodeWidget.linkToInspector().then(() => {
// linkToInspector resolved, check for the .open-inspector element
if (entry.inspectorIcon) {
ok(msg.querySelectorAll(".open-inspector").length,
"The ElementNode widget is linked to the inspector");
} else {
ok(!msg.querySelectorAll(".open-inspector").length,
"The ElementNode widget isn't linked to the inspector");
}
}, () => {
// linkToInspector promise rejected, node not linked to inspector
ok(!entry.inspectorIcon, "The ElementNode widget isn't linked to the inspector");
});
}
function onVariablesViewOpen(entry, {resolve, reject}, event, view, options)
{
info("Variables view opened: " + entry.input);
@ -1646,6 +1624,36 @@ function once(target, eventName, useCapture=false) {
return deferred.promise;
}
/**
* Checks a link to the inspector
*
* @param {boolean} hasLinkToInspector Set to true if the message should
* link to the inspector panel.
* @param {element} msg The message to test.
*/
function checkLinkToInspector(hasLinkToInspector, msg)
{
let elementNodeWidget = [...msg._messageObject.widgets][0];
if (!elementNodeWidget) {
ok(!hasLinkToInspector, "The message has no ElementNode widget");
return;
}
return elementNodeWidget.linkToInspector().then(() => {
// linkToInspector resolved, check for the .open-inspector element
if (hasLinkToInspector) {
ok(msg.querySelectorAll(".open-inspector").length,
"The ElementNode widget is linked to the inspector");
} else {
ok(!msg.querySelectorAll(".open-inspector").length,
"The ElementNode widget isn't linked to the inspector");
}
}, () => {
// linkToInspector promise rejected, node not linked to inspector
ok(!hasLinkToInspector, "The ElementNode widget isn't linked to the inspector");
});
}
function getSourceActor(aSources, aURL) {
let item = aSources.getItemForAttachment(a => a.source.url === aURL);
return item && item.value;

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

@ -6,7 +6,7 @@
function test() {
console.log("start");
console.clear()
console.dirxml()
console.timeStamp()
console.log("end");
}
</script>

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

@ -130,6 +130,7 @@ const LEVELS = {
table: SEVERITY_LOG,
debug: SEVERITY_LOG,
dir: SEVERITY_LOG,
dirxml: SEVERITY_LOG,
group: SEVERITY_LOG,
groupCollapsed: SEVERITY_LOG,
groupEnd: SEVERITY_LOG,
@ -1285,7 +1286,11 @@ WebConsoleFrame.prototype = {
clipboardText = clipboardArray.join(" ");
break;
}
case "dirxml": {
// We just alias console.dirxml() with console.log().
aMessage.level = "log";
return WCF_logConsoleAPIMessage.call(this, aMessage);
}
case "group":
case "groupCollapsed":
clipboardText = body = aMessage.groupName;

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

@ -85,20 +85,6 @@ inspector.menu.openUrlInNewTab.label=Open Link in New Tab
# that allows to copy that URL in the clipboard.
inspector.menu.copyUrlToClipboard.label=Copy Link Address
# LOCALIZATION NOTE (inspector.menu.openFileInDebugger.label): This is the label
# of a menu item in the inspector contextual-menu that appears when the user
# right-clicks on the attribute of a node in the inspector that is a URL to a
# javascript filename, and that allows to open the corresponding file in the
# debugger.
inspector.menu.openFileInDebugger.label=Open File in Debugger
# LOCALIZATION NOTE (inspector.menu.openFileInStyleEditor.label): This is the
# label of a menu item in the inspector contextual-menu that appears when the
# user right-clicks on the attribute of a node in the inspector that is a URL to
# a css filename, and that allows to open the corresponding file in the style
# editor.
inspector.menu.openFileInStyleEditor.label=Open File in Style-Editor
# LOCALIZATION NOTE (inspector.menu.selectElement.label): This is the label of a
# menu item in the inspector contextual-menu that appears when the user right-
# clicks on the attribute of a node in the inspector that is the ID of another

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

@ -6,6 +6,9 @@
<!-- LOCALIZATION NOTE : FILE Do not translate key -->
<!ENTITY closeCmd.key "W">
<!ENTITY toggleToolbox.key "I">
<!ENTITY toggleToolboxF12.keycode "VK_F12">
<!ENTITY toggleToolboxF12.keytext "F12">
<!ENTITY toolboxCloseButton.tooltip "Close Developer Tools">
<!ENTITY toolboxOptionsButton.key "O">

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

@ -88,3 +88,15 @@ options.lightTheme.label=Light theme
# Used as a message in the alert displayed when trying to open a browser
# content toolbox and there is no content process running
toolbox.noContentProcess.message=No content process running.
# LOCALIZATION NOTE (toolbox.viewCssSourceInStyleEditor.label)
# Used as a message in either tooltips or contextual menu items to open the
# corresponding URL as a css file in the Style-Editor tool.
# DEV NOTE: Mostly used wherever toolbox.viewSourceInStyleEditor is used.
toolbox.viewCssSourceInStyleEditor.label=Open File in Style-Editor
# LOCALIZATION NOTE (toolbox.viewJsSourceInDebugger.label)
# Used as a message in either tooltips or contextual menu items to open the
# corresponding URL as a js file in the Debugger tool.
# DEV NOTE: Mostly used wherever toolbox.viewSourceInDebugger is used.
toolbox.viewJsSourceInDebugger.label=Open File in Debugger

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

@ -85,7 +85,6 @@
<!ENTITY col.url.label "Location">
<!ENTITY col.mostrecentvisit.label "Most Recent Visit">
<!ENTITY col.visitcount.label "Visit Count">
<!ENTITY col.keyword.label "Keyword">
<!ENTITY col.description.label "Description">
<!ENTITY col.dateadded.label "Added">
<!ENTITY col.lastmodified.label "Last Modified">

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

@ -36,8 +36,6 @@ view.sortBy.1.date.label=Sort by Most Recent Visit
view.sortBy.1.date.accesskey=V
view.sortBy.1.visitCount.label=Sort by Visit Count
view.sortBy.1.visitCount.accesskey=C
view.sortBy.1.keyword.label=Sort by Keyword
view.sortBy.1.keyword.accesskey=K
view.sortBy.1.description.label=Sort by Description
view.sortBy.1.description.accesskey=D
view.sortBy.1.dateAdded.label=Sort by Added

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

@ -7,6 +7,7 @@
this.EXPORTED_SYMBOLS = [ "Feeds" ];
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
@ -37,8 +38,11 @@ this.Feeds = {
}
if (aIsFeed) {
// re-create the principal as it may be a CPOW.
let principalURI = BrowserUtils.makeURIFromCPOW(aPrincipal.URI);
let principalToCheck = Services.scriptSecurityManager.getNoAppCodebasePrincipal(principalURI);
try {
BrowserUtils.urlSecurityCheck(aLink.href, aPrincipal,
BrowserUtils.urlSecurityCheck(aLink.href, principalToCheck,
Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
return type || "application/rss+xml";
}

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

@ -814,6 +814,7 @@ Console::Trace(JSContext* aCx)
// Displays an interactive listing of all the properties of an object.
METHOD(Dir, "dir");
METHOD(Dirxml, "dirxml");
METHOD(Group, "group")
METHOD(GroupCollapsed, "groupCollapsed")

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

@ -74,6 +74,9 @@ public:
void
Dir(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Dirxml(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Group(JSContext* aCx, const Sequence<JS::Value>& aData);
@ -116,6 +119,7 @@ private:
MethodTable,
MethodTrace,
MethodDir,
MethodDirxml,
MethodGroup,
MethodGroupCollapsed,
MethodGroupEnd,

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

@ -16,6 +16,7 @@ interface Console {
void table(any... data);
void trace();
void dir(any... data);
void dirxml(any... data);
void group(any... data);
void groupCollapsed(any... data);
void groupEnd(any... data);
@ -32,8 +33,6 @@ interface Console {
[BinaryName="noopMethod"]
void clear();
[BinaryName="noopMethod"]
void dirxml();
[BinaryName="noopMethod"]
void markTimeline();
[BinaryName="noopMethod"]
void timeline();

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

@ -17,13 +17,19 @@ import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@ -32,6 +38,7 @@ import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
@ -40,20 +47,30 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
LayerView.ZoomedViewListener, GeckoEventListener {
private static final String LOGTAG = "Gecko" + ZoomedView.class.getSimpleName();
private static final int DEFAULT_ZOOM_FACTOR = 3;
private static final int W_CAPTURED_VIEW_IN_PERCENT = 80;
private static final float[] ZOOM_FACTORS_LIST = {2.0f, 3.0f, 1.5f};
private static final int W_CAPTURED_VIEW_IN_PERCENT = 50;
private static final int H_CAPTURED_VIEW_IN_PERCENT = 50;
private static final int MINIMUM_DELAY_BETWEEN_TWO_RENDER_CALLS_NS = 1000000;
private static final int DELAY_BEFORE_NEXT_RENDER_REQUEST_MS = 2000;
private int zoomFactor;
private float zoomFactor;
private int currentZoomFactorIndex;
private ImageView zoomedImageView;
private LayerView layerView;
private int viewWidth;
private int viewHeight;
private int viewHeight; // Only the zoomed view height, no toolbar, no shadow ...
private int viewContainerWidth;
private int viewContainerHeight; // Zoomed view height with toolbar and other elements like shadow, ...
private int containterSize; // shadow, margin, ...
private Point lastPosition;
private boolean shouldSetVisibleOnUpdate;
private PointF returnValue;
private ImageView closeButton;
private TextView changeZoomFactorButton;
private boolean toolbarOnTop;
private float offsetDueToToolBarPosition;
private int toolbarHeight;
private int cornerRadius;
private boolean stopUpdateView;
@ -64,6 +81,39 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private long startTimeReRender;
private long lastStartTimeReRender;
private class RoundedBitmapDrawable extends BitmapDrawable {
private Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
final float cornerRadius;
final boolean squareOnTopOfDrawable;
RoundedBitmapDrawable(Resources res, Bitmap bitmap, boolean squareOnTop, int radius) {
super(res, bitmap);
squareOnTopOfDrawable = squareOnTop;
final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
paint.setAntiAlias(true);
paint.setShader(shader);
cornerRadius = radius;
}
@Override
public void draw(Canvas canvas) {
int height = getBounds().height();
int width = getBounds().width();
RectF rect = new RectF(0.0f, 0.0f, width, height);
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint);
//draw rectangles over the corners we want to be square
if (squareOnTopOfDrawable) {
canvas.drawRect(0, 0, cornerRadius, cornerRadius, paint);
canvas.drawRect(width - cornerRadius, 0, width, cornerRadius, paint);
} else {
canvas.drawRect(0, height - cornerRadius, cornerRadius, height, paint);
canvas.drawRect(width - cornerRadius, height - cornerRadius, width, height, paint);
}
}
}
private class ZoomedViewTouchListener implements View.OnTouchListener {
private float originRawX;
private float originRawY;
@ -87,16 +137,18 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
if (dragged) {
dragged = false;
} else {
GeckoEvent eClickInZoomedView = GeckoEvent.createBroadcastEvent("Gesture:ClickInZoomedView", "");
GeckoAppShell.sendEventToGecko(eClickInZoomedView);
layerView.dispatchTouchEvent(actionDownEvent);
actionDownEvent.recycle();
PointF convertedPosition = getUnzoomedPositionFromPointInZoomedView(event.getX(), event.getY());
MotionEvent e = MotionEvent.obtain(event.getDownTime(), event.getEventTime(),
MotionEvent.ACTION_UP, convertedPosition.x, convertedPosition.y,
event.getMetaState());
layerView.dispatchTouchEvent(e);
e.recycle();
if (isClickInZoomedView(event.getY())) {
GeckoEvent eClickInZoomedView = GeckoEvent.createBroadcastEvent("Gesture:ClickInZoomedView", "");
GeckoAppShell.sendEventToGecko(eClickInZoomedView);
layerView.dispatchTouchEvent(actionDownEvent);
actionDownEvent.recycle();
PointF convertedPosition = getUnzoomedPositionFromPointInZoomedView(event.getX(), event.getY());
MotionEvent e = MotionEvent.obtain(event.getDownTime(), event.getEventTime(),
MotionEvent.ACTION_UP, convertedPosition.x, convertedPosition.y,
event.getMetaState());
layerView.dispatchTouchEvent(e);
e.recycle();
}
}
break;
@ -113,6 +165,11 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
return true;
}
private boolean isClickInZoomedView(float y) {
return ((toolbarOnTop && y > toolbarHeight) ||
(!toolbarOnTop && y < ZoomedView.this.viewHeight));
}
private boolean moveZoomedView(MotionEvent event) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) ZoomedView.this.getLayoutParams();
if ((!dragged) && (Math.abs((int) (event.getRawX() - originRawX)) < PanZoomController.CLICK_THRESHOLD)
@ -143,19 +200,21 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
public ZoomedView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
returnValue = new PointF();
currentZoomFactorIndex = 0;
zoomFactor = ZOOM_FACTORS_LIST[currentZoomFactorIndex];
requestRenderRunnable = new Runnable() {
@Override
public void run() {
requestZoomedViewRender();
}
};
EventDispatcher.getInstance().registerGeckoThreadListener(this, "Gesture:nothingDoneOnLongPress",
EventDispatcher.getInstance().registerGeckoThreadListener(this,
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange");
}
void destroy() {
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Gesture:nothingDoneOnLongPress",
EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange");
}
@ -165,15 +224,29 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
@Override
protected void onFinishInflate() {
super.onFinishInflate();
ImageView closeButton = (ImageView) findViewById(R.id.dialog_close);
closeButton = (ImageView) findViewById(R.id.dialog_close);
closeButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
stopZoomDisplay();
}
});
changeZoomFactorButton = (TextView) findViewById(R.id.change_zoom_factor);
changeZoomFactorButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
changeZoomFactor();
}
});
setTextInZoomFactorButton(ZOOM_FACTORS_LIST[0]);
zoomedImageView = (ImageView) findViewById(R.id.zoomed_image_view);
zoomedImageView.setOnTouchListener(new ZoomedViewTouchListener());
this.setOnTouchListener(new ZoomedViewTouchListener());
toolbarHeight = getResources().getDimensionPixelSize(R.dimen.zoomed_view_toolbar_height);
containterSize = getResources().getDimensionPixelSize(R.dimen.drawable_dropshadow_size);
cornerRadius = getResources().getDimensionPixelSize(R.dimen.button_corner_radius);
moveToolbar(true);
}
/*
@ -181,6 +254,10 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
* LayerView
*/
private PointF getUnzoomedPositionFromPointInZoomedView(float x, float y) {
if (toolbarOnTop && y > toolbarHeight) {
y = y - toolbarHeight;
}
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
PointF offset = metrics.getMarginOffset();
final float parentWidth = metrics.getWidth();
@ -199,14 +276,15 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
*/
(((float) params.leftMargin) - offset.x) *
((parentWidth - offset.x - (viewWidth / zoomFactor)) /
(parentWidth - offset.x - viewWidth)));
(parentWidth - offset.x - viewContainerWidth)));
// Same comments here vertically
returnValue.y = (int) ((y / zoomFactor) +
offset.y +
offset.y -
offsetDueToToolBarPosition +
(((float) params.topMargin) - offset.y) *
((parentHeight - offset.y - (viewHeight / zoomFactor)) /
(parentHeight - offset.y - viewHeight)));
((parentHeight - offset.y + offsetDueToToolBarPosition - (viewHeight / zoomFactor)) /
(parentHeight - offset.y - viewContainerHeight)));
return returnValue;
}
@ -232,14 +310,14 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
* the LayerView to the ZoomedView.
*/
((parentWidth - offset.x - (viewWidth / zoomFactor)) /
(parentWidth - offset.x - viewWidth)))
(parentWidth - offset.x - viewContainerWidth)))
+ offset.x); // The offset of the layerView
// Same comments here vertically
returnValue.y = (int) ((((y - (viewHeight / (2 * zoomFactor)))) /
((parentHeight - offset.y - (viewHeight / zoomFactor)) /
(parentHeight - offset.y - viewHeight)))
returnValue.y = (int) ((((y + offsetDueToToolBarPosition - (viewHeight / (2 * zoomFactor)))) /
((parentHeight - offset.y + offsetDueToToolBarPosition - (viewHeight / zoomFactor)) /
(parentHeight - offset.y - viewContainerHeight)))
+ offset.y);
return returnValue;
@ -259,14 +337,20 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
if (newTopMargin < topMarginMin) {
newLayoutParams.topMargin = topMarginMin;
} else if (newTopMargin + viewHeight > parentHeight) {
newLayoutParams.topMargin = (int) (parentHeight - viewHeight);
} else if (newTopMargin + viewContainerHeight > parentHeight) {
newLayoutParams.topMargin = (int) (parentHeight - viewContainerHeight);
}
if (newLeftMargin < leftMarginMin) {
newLayoutParams.leftMargin = leftMarginMin;
} else if (newLeftMargin + viewWidth > parentWidth) {
newLayoutParams.leftMargin = (int) (parentWidth - viewWidth);
} else if (newLeftMargin + viewContainerWidth > parentWidth) {
newLayoutParams.leftMargin = (int) (parentWidth - viewContainerWidth);
}
if (newLayoutParams.topMargin < topMarginMin + 1) {
moveToolbar(false);
} else if (newLayoutParams.topMargin + viewContainerHeight > parentHeight - 1) {
moveToolbar(true);
}
setLayoutParams(newLayoutParams);
@ -275,6 +359,37 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
requestZoomedViewRender();
}
private void moveToolbar(boolean moveTop) {
if (toolbarOnTop == moveTop) {
return;
}
toolbarOnTop = moveTop;
if (toolbarOnTop) {
offsetDueToToolBarPosition = toolbarHeight;
} else {
offsetDueToToolBarPosition = 0;
}
RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) zoomedImageView.getLayoutParams();
RelativeLayout.LayoutParams pChangeZoomFactorButton = (RelativeLayout.LayoutParams) changeZoomFactorButton.getLayoutParams();
RelativeLayout.LayoutParams pCloseButton = (RelativeLayout.LayoutParams) closeButton.getLayoutParams();
if (moveTop) {
p.addRule(RelativeLayout.BELOW, R.id.change_zoom_factor);
pChangeZoomFactorButton.addRule(RelativeLayout.BELOW, 0);
pCloseButton.addRule(RelativeLayout.BELOW, 0);
} else {
p.addRule(RelativeLayout.BELOW, 0);
pChangeZoomFactorButton.addRule(RelativeLayout.BELOW, R.id.zoomed_image_view);
pCloseButton.addRule(RelativeLayout.BELOW, R.id.zoomed_image_view);
}
pChangeZoomFactorButton.addRule(RelativeLayout.ALIGN_LEFT, R.id.zoomed_image_view);
pCloseButton.addRule(RelativeLayout.ALIGN_RIGHT, R.id.zoomed_image_view);
zoomedImageView.setLayoutParams(p);
changeZoomFactorButton.setLayoutParams(pChangeZoomFactorButton);
closeButton.setLayoutParams(pCloseButton);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@ -299,13 +414,12 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private void setCapturedSize(ImmutableViewportMetrics metrics) {
float parentMinSize = Math.min(metrics.getWidth(), metrics.getHeight());
// For metrics.zoomFactor lower than 1, the zoom factor of the zoomed view is calculated
// to get always the same size for the content in the zoomed view.
// For metrics.zoomFactor greater than 1, the zoom factor is always set to the default
// value DEFAULT_ZOOM_FACTOR, thus the zoomed view is always a zoom of the normal view.
zoomFactor = Math.max(DEFAULT_ZOOM_FACTOR, (int) (DEFAULT_ZOOM_FACTOR / metrics.zoomFactor));
viewWidth = (int) (parentMinSize * W_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor;
viewHeight = (int) (parentMinSize * H_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor;
viewWidth = (int) ((parentMinSize * W_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor);
viewHeight = (int) ((parentMinSize * H_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor);
viewContainerHeight = viewHeight + toolbarHeight +
2 * containterSize; // Top and bottom shadows
viewContainerWidth = viewWidth +
2 * containterSize; // Right and left shadows
// Display in zoomedview is corrupted when width is an odd number
// More details about this issue here: bug 776906 comment 11
viewWidth &= ~0x1;
@ -343,13 +457,31 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
}
}
private void changeZoomFactor() {
if (currentZoomFactorIndex < ZOOM_FACTORS_LIST.length - 1) {
currentZoomFactorIndex++;
} else {
currentZoomFactorIndex = 0;
}
zoomFactor = ZOOM_FACTORS_LIST[currentZoomFactorIndex];
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
refreshZoomedViewSize(metrics);
setTextInZoomFactorButton(zoomFactor);
}
private void setTextInZoomFactorButton(float zoom) {
final String percentageValue = Integer.toString((int) (100*zoom));
changeZoomFactorButton.setText(getResources().getString(R.string.percent, percentageValue));
}
@Override
public void handleMessage(final String event, final JSONObject message) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
try {
if (event.equals("Gesture:nothingDoneOnLongPress") || event.equals("Gesture:clusteredLinksClicked")) {
if (event.equals("Gesture:clusteredLinksClicked")) {
final JSONObject clickPosition = message.getJSONObject("clickPosition");
int left = clickPosition.getInt("x");
int top = clickPosition.getInt("y");
@ -373,6 +505,10 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private void moveUsingGeckoPosition(int leftFromGecko, int topFromGecko) {
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
final float parentHeight = metrics.getHeight();
// moveToolbar is called before getZoomedViewTopLeftPositionFromTouchPosition in order to
// correctly center vertically the zoomed area
moveToolbar((topFromGecko * metrics.zoomFactor > parentHeight / 2));
PointF convertedPosition = getZoomedViewTopLeftPositionFromTouchPosition((leftFromGecko * metrics.zoomFactor),
(topFromGecko * metrics.zoomFactor));
moveZoomedView(metrics, convertedPosition.x, convertedPosition.y);
@ -406,8 +542,8 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
} catch (Exception iae) {
Log.w(LOGTAG, iae.toString());
}
BitmapDrawable ob3 = new BitmapDrawable(getResources(), sb3);
if (zoomedImageView != null) {
RoundedBitmapDrawable ob3 = new RoundedBitmapDrawable(getResources(), sb3, toolbarOnTop, cornerRadius);
zoomedImageView.setImageDrawable(ob3);
}
}

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

@ -614,6 +614,14 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY colon ":">
<!-- LOCALIZATION NOTE (percent): The percent sign is appended after a number to
display a percentage value. formatS is the number, #37 is the code to display a percent sign.
This format string is typically used by getString method, in such method the percent sign
is a reserved caracter. In order to display one percent sign in the result of getString,
double percent signs must be inserted in the format string.
This entity is used in the zoomed view to display the zoom factor-->
<!ENTITY percent "&formatS;&#37;&#37;">
<!-- These are only used for accessibility for the done and overflow-menu buttons in the actionbar.
They are never shown to users -->
<!ENTITY actionbar_menu "Menu">

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

@ -10,24 +10,37 @@
android:id="@+id/zoomed_view_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="@android:color/white"
android:visibility="gone" >
android:background="@drawable/dropshadow"
android:padding="@dimen/drawable_dropshadow_size"
android:visibility="gone">
<ImageView
android:id="@+id/zoomed_image_view"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#000000"
android:padding="1dip" />
<ImageView
android:id="@+id/dialog_close"
android:background="@drawable/close"
android:layout_height="20dp"
android:layout_width="20dp"
android:layout_gravity ="top|right" />
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="@drawable/toolbar_grey_round">
<TextView
android:id="@+id/change_zoom_factor"
android:layout_width="wrap_content"
android:layout_height="@dimen/zoomed_view_toolbar_height"
android:background="@android:color/transparent"
android:padding="12dip"
android:layout_alignLeft="@+id/zoomed_image_view"
android:textSize="16sp"
android:textColor="@color/text_and_tabs_tray_grey"/>
<ImageView
android:id="@+id/dialog_close"
android:scaleType="center"
android:layout_width="@dimen/zoomed_view_toolbar_height"
android:layout_height="@dimen/zoomed_view_toolbar_height"
android:layout_alignRight="@id/zoomed_image_view"
android:src="@drawable/close_edit_mode_selector"/>
<ImageView
android:id="@id/zoomed_image_view"
android:layout_below="@id/change_zoom_factor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
</org.mozilla.gecko.ZoomedView>

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

@ -205,6 +205,10 @@
<dimen name="horizontal_drag_area">256dp</dimen>
<!-- ZoomedView dimensions. -->
<dimen name="zoomed_view_toolbar_height">44dp</dimen>
<dimen name="drawable_dropshadow_size">3dp</dimen>
<!-- Find-In-Page dialog dimensions. -->
<dimen name="find_in_page_text_margin_left">5dip</dimen>
<dimen name="find_in_page_text_margin_right">12dip</dimen>

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

@ -528,5 +528,7 @@
<string name="colon">&colon;</string>
<string name="percent">&percent;</string>
<string name="remote_tabs_last_synced">&remote_tabs_last_synced;</string>
</resources>

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

@ -157,6 +157,9 @@ RootActor.prototype = {
// Added in Gecko 40, indicating that the backend isn't stupid about
// sending resumption packets on tab navigation.
noNeedToFakeResumptionOnNavigation: true,
// Added in Firefox 40. Indicates that the backend supports registering custom
// commands through the WebConsoleCommands API.
webConsoleCommands: true,
// Whether root actor exposes tab actors
// if allowChromeProcess is true, you can fetch a ChromeActor instance
// to debug chrome and any non-content ressource via getProcess request

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

@ -632,18 +632,103 @@ BrowserTabList.prototype.onCloseWindow = DevToolsUtils.makeInfallible(function(a
exports.BrowserTabList = BrowserTabList;
/**
* Creates a tab actor for handling requests to a browser tab, like
* attaching and detaching. TabActor respects the actor factories
* registered with DebuggerServer.addTabActor.
* Creates a TabActor whose main goal is to manage lifetime and
* expose the tab actors being registered via DebuggerServer.registerModule.
* But also track the lifetime of the document being tracked.
*
* ### Main requests:
*
* `attach`/`detach` requests:
* - start/stop document watching:
* Starts watching for new documents and emits `tabNavigated` and
* `frameUpdate` over RDP.
* - retrieve the thread actor:
* Instantiates a ThreadActor that can be later attached to in order to
* debug JS sources in the document.
* `switchToFrame`:
* Change the targeted document of the whole TabActor, and its child tab actors
* to an iframe or back to its original document.
*
* Most of the TabActor properties (like `chromeEventHandler` or `docShells`)
* are meant to be used by the various child tab actors.
*
* ### RDP events:
*
* - `tabNavigated`:
* Sent when the tab is about to navigate or has just navigated to
* a different document.
* This event contains the following attributes:
* * url (string) The new URI being loaded.
* * nativeConsoleAPI (boolean) `false` if the console API of the page has been
* overridden (e.g. by Firebug),
* `true` if the Gecko implementation is used.
* * state (string) `start` if we just start requesting the new URL,
* `stop` if the new URL is done loading.
* * isFrameSwitching (boolean) Indicates the event is dispatched when
* switching the TabActor context to
* a different frame. When we switch to
* an iframe, there is no document load.
* The targeted document is most likely
* going to be already done loading.
* * title (string) The document title being loaded.
* (sent only on state=stop)
*
* - `frameUpdate`:
* Sent when there was a change in the child frames contained in the document
* or when the tab's context was switched to another frame.
* This event can have four different forms depending on the type of incident:
* * One or many frames are updated:
* { frames: [{ id, url, title, parentID }, ...] }
* * One frame got destroyed:
* { frames: [{ id, destroy: true }]}
* * All frames got destroyed:
* { destroyAll: true }
* * We switched the context of the TabActor to a specific frame:
* { selected: #id }
*
* ### Internal, non-rdp events:
* Various events are also dispatched on the TabActor itself that are not
* related to RDP, so, not sent to the client. They all relate to the documents
* tracked by the TabActor (its main targeted document, but also any of its iframes).
* - will-navigate
* This event fires once navigation starts.
* All pending user prompts are dealt with,
* but it is fired before the first request starts.
* - navigate
* This event is fired once the document's readyState is "complete".
* - window-ready
* This event is fired on three distinct scenarios:
* * When a new Window object is crafted, equivalent of `DOMWindowCreated`.
* It is dispatched before any page script is executed.
* * We will have already received a window-ready event for this window
* when it was created, but we received a window-destroyed event when
* it was frozen into the bfcache, and now the user navigated back to
* this page, so it's now live again and we should resume handling it.
* * For each existing document, when an `attach` request is received.
* At this point scripts in the page will be already loaded.
* - window-destroyed
* This event is fired in two cases:
* * When the window object is destroyed, i.e. when the related document
* is garbage collected. This can happen when the tab is closed or the
* iframe is removed from the DOM.
* It is equivalent of `inner-window-destroyed` event.
* * When the page goes into the bfcache and gets frozen.
* The equivalent of `pagehide`.
* - changed-toplevel-document
* This event fires when we switch the TabActor targeted document
* to one of its iframes, or back to its original top document.
* It is dispatched between window-destroyed and window-ready.
*
* Note that *all* these events are dispatched in the following order
* when we switch the context of the TabActor to a given iframe:
* will-navigate, window-destroyed, changed-toplevel-document, window-ready, navigate
*
* This class is subclassed by BrowserTabActor and
* ContentActor. Subclasses are expected to implement a getter
* the docShell properties.
* for the docShell property.
*
* @param aConnection DebuggerServerConnection
* The conection to the client.
* @param aChromeEventHandler
* An object on which listen for DOMWindowCreated and pageshow events.
*/
function TabActor(aConnection)
{

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

@ -25,6 +25,11 @@ function evaluateJS(input) {
return new Promise((resolve) => gState.client.evaluateJS(input, resolve));
}
function* evaluateJSAndCheckResult(input, result) {
let response = yield evaluateJS(input);
checkObject(response, {result});
}
function startTest()
{
removeEventListener("load", startTest);
@ -138,6 +143,34 @@ tests = [
WebConsoleCommands.unregister("$foo");
ok(!WebConsoleCommands.hasCommand("$foo"), "$foo should be unregistered");
nextTest();
}),
Task.async(function* unregisterAfterOverridingTwice() {
WebConsoleCommands.register("keys", (owner, obj) => "command 1");
info("checking the value of the first override");
yield evaluateJSAndCheckResult("keys('foo');", "command 1");
let orig = WebConsoleCommands.getCommand("keys");
WebConsoleCommands.register("keys", (owner, obj) => {
if (obj === "quack")
return "bang!";
return orig(owner, obj);
});
info("checking the values after the second override");
yield evaluateJSAndCheckResult("keys({});", "command 1");
yield evaluateJSAndCheckResult("keys('quack');", "bang!");
WebConsoleCommands.unregister("keys");
info("checking the value after unregistration (should restore " +
"the original command)");
yield evaluateJSAndCheckResult("keys({});", {
class: "Array",
preview: {items: []}
});
nextTest();
})
];

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

@ -1529,6 +1529,19 @@ ConsoleAPIListener.prototype =
*/
let WebConsoleCommands = {
_registeredCommands: new Map(),
_originalCommands: new Map(),
/**
* @private
* Reserved for built-in commands. To register a command from the code of an
* add-on, see WebConsoleCommands.register instead.
*
* @see WebConsoleCommands.register
*/
_registerOriginal: function (name, command) {
this.register(name, command);
this._originalCommands.set(name, this.getCommand(name));
},
/**
* Register a new command.
@ -1564,10 +1577,16 @@ let WebConsoleCommands = {
/**
* Unregister a command.
*
* If the command being unregister overrode a built-in command,
* the latter is restored.
*
* @param {string} name The name of the command
*/
unregister: function(name) {
this._registeredCommands.delete(name);
if (this._originalCommands.has(name)) {
this.register(name, this._originalCommands.get(name));
}
},
/**
@ -1611,7 +1630,7 @@ exports.WebConsoleCommands = WebConsoleCommands;
* @return nsIDOMNode or null
* The result of calling document.querySelector(aSelector).
*/
WebConsoleCommands.register("$", function JSTH_$(aOwner, aSelector)
WebConsoleCommands._registerOriginal("$", function JSTH_$(aOwner, aSelector)
{
return aOwner.window.document.querySelector(aSelector);
});
@ -1624,7 +1643,7 @@ WebConsoleCommands.register("$", function JSTH_$(aOwner, aSelector)
* @return nsIDOMNodeList
* Returns the result of document.querySelectorAll(aSelector).
*/
WebConsoleCommands.register("$$", function JSTH_$$(aOwner, aSelector)
WebConsoleCommands._registerOriginal("$$", function JSTH_$$(aOwner, aSelector)
{
return aOwner.window.document.querySelectorAll(aSelector);
});
@ -1635,7 +1654,7 @@ WebConsoleCommands.register("$$", function JSTH_$$(aOwner, aSelector)
* @return object|undefined
* Returns last console evaluation or undefined
*/
WebConsoleCommands.register("$_", {
WebConsoleCommands._registerOriginal("$_", {
get: function(aOwner) {
return aOwner.consoleActor.getLastConsoleInputEvaluation();
}
@ -1651,7 +1670,7 @@ WebConsoleCommands.register("$_", {
* Context to run the xPath query on. Uses window.document if not set.
* @return array of nsIDOMNode
*/
WebConsoleCommands.register("$x", function JSTH_$x(aOwner, aXPath, aContext)
WebConsoleCommands._registerOriginal("$x", function JSTH_$x(aOwner, aXPath, aContext)
{
let nodes = new aOwner.window.wrappedJSObject.Array();
let doc = aOwner.window.document;
@ -1673,7 +1692,7 @@ WebConsoleCommands.register("$x", function JSTH_$x(aOwner, aXPath, aContext)
* @return Object representing the current selection in the
* Inspector, or null if no selection exists.
*/
WebConsoleCommands.register("$0", {
WebConsoleCommands._registerOriginal("$0", {
get: function(aOwner) {
return aOwner.makeDebuggeeValue(aOwner.selectedNode);
}
@ -1682,7 +1701,7 @@ WebConsoleCommands.register("$0", {
/**
* Clears the output of the WebConsole.
*/
WebConsoleCommands.register("clear", function JSTH_clear(aOwner)
WebConsoleCommands._registerOriginal("clear", function JSTH_clear(aOwner)
{
aOwner.helperResult = {
type: "clearOutput",
@ -1692,7 +1711,7 @@ WebConsoleCommands.register("clear", function JSTH_clear(aOwner)
/**
* Clears the input history of the WebConsole.
*/
WebConsoleCommands.register("clearHistory", function JSTH_clearHistory(aOwner)
WebConsoleCommands._registerOriginal("clearHistory", function JSTH_clearHistory(aOwner)
{
aOwner.helperResult = {
type: "clearHistory",
@ -1706,7 +1725,7 @@ WebConsoleCommands.register("clearHistory", function JSTH_clearHistory(aOwner)
* Object to return the property names from.
* @return array of strings
*/
WebConsoleCommands.register("keys", function JSTH_keys(aOwner, aObject)
WebConsoleCommands._registerOriginal("keys", function JSTH_keys(aOwner, aObject)
{
return aOwner.window.wrappedJSObject.Object.keys(WebConsoleUtils.unwrap(aObject));
});
@ -1718,7 +1737,7 @@ WebConsoleCommands.register("keys", function JSTH_keys(aOwner, aObject)
* Object to display the values from.
* @return array of string
*/
WebConsoleCommands.register("values", function JSTH_values(aOwner, aObject)
WebConsoleCommands._registerOriginal("values", function JSTH_values(aOwner, aObject)
{
let arrValues = new aOwner.window.wrappedJSObject.Array();
let obj = WebConsoleUtils.unwrap(aObject);
@ -1733,7 +1752,7 @@ WebConsoleCommands.register("values", function JSTH_values(aOwner, aObject)
/**
* Opens a help window in MDN.
*/
WebConsoleCommands.register("help", function JSTH_help(aOwner)
WebConsoleCommands._registerOriginal("help", function JSTH_help(aOwner)
{
aOwner.helperResult = { type: "help" };
});
@ -1749,7 +1768,7 @@ WebConsoleCommands.register("help", function JSTH_help(aOwner)
* a window object. If you call cd() with no arguments, the current
* eval scope is cleared back to its default (the top window).
*/
WebConsoleCommands.register("cd", function JSTH_cd(aOwner, aWindow)
WebConsoleCommands._registerOriginal("cd", function JSTH_cd(aOwner, aWindow)
{
if (!aWindow) {
aOwner.consoleActor.evalWindow = null;
@ -1778,7 +1797,7 @@ WebConsoleCommands.register("cd", function JSTH_cd(aOwner, aWindow)
* @param object aObject
* Object to inspect.
*/
WebConsoleCommands.register("inspect", function JSTH_inspect(aOwner, aObject)
WebConsoleCommands._registerOriginal("inspect", function JSTH_inspect(aOwner, aObject)
{
let dbgObj = aOwner.makeDebuggeeValue(aObject);
let grip = aOwner.createValueGrip(dbgObj);
@ -1796,7 +1815,7 @@ WebConsoleCommands.register("inspect", function JSTH_inspect(aOwner, aObject)
* Object to print to the output.
* @return string
*/
WebConsoleCommands.register("pprint", function JSTH_pprint(aOwner, aObject)
WebConsoleCommands._registerOriginal("pprint", function JSTH_pprint(aOwner, aObject)
{
if (aObject === null || aObject === undefined || aObject === true ||
aObject === false) {
@ -1843,7 +1862,7 @@ WebConsoleCommands.register("pprint", function JSTH_pprint(aOwner, aObject)
* A value you want to output as a string.
* @return void
*/
WebConsoleCommands.register("print", function JSTH_print(aOwner, aValue)
WebConsoleCommands._registerOriginal("print", function JSTH_print(aOwner, aValue)
{
aOwner.helperResult = { rawOutput: true };
if (typeof aValue === "symbol") {
@ -1863,7 +1882,7 @@ WebConsoleCommands.register("print", function JSTH_print(aOwner, aValue)
* A value you want to copy as a string.
* @return void
*/
WebConsoleCommands.register("copy", function JSTH_copy(aOwner, aValue)
WebConsoleCommands._registerOriginal("copy", function JSTH_copy(aOwner, aValue)
{
let payload;
try {