зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c. a=merge
This commit is contained in:
Коммит
3ae9df90e4
|
@ -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;%%">
|
||||
|
||||
<!-- 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">:</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 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче