Merge mozilla-central to mozilla-inbound. r=merge a=merge CLOSED TREE

This commit is contained in:
Csoregi Natalia 2017-11-14 01:00:48 +02:00
Родитель df6a317358 8f1a81caad
Коммит 6232db29bd
183 изменённых файлов: 4189 добавлений и 1763 удалений

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

@ -76,7 +76,6 @@ var CompactTheme = {
// If the compact theme is going to be applied in gBrowserInit.onLoad,
// then preload it now. This prevents a flash of unstyled content where the
// normal theme is applied while the compact theme stylesheet is loading.
if (AppConstants.INSTALL_COMPACT_THEMES &&
this != Services.appShell.hiddenDOMWindow && CompactTheme.isThemeCurrentlyApplied) {
if (this != Services.appShell.hiddenDOMWindow && CompactTheme.isThemeCurrentlyApplied) {
CompactTheme.createStyleSheet();
}

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

@ -1776,8 +1776,7 @@ var BookmarkingUI = {
view.addEventListener("ViewShowing", this);
view.addEventListener("ViewHiding", this);
anchor.setAttribute("closemenu", "none");
PanelUI.showSubView("PanelUI-bookmarks", anchor,
CustomizableUI.AREA_PANEL, event);
PanelUI.showSubView("PanelUI-bookmarks", anchor, event);
},
onCommand: function BUI_onCommand(aEvent) {

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

@ -525,18 +525,19 @@ var gSync = {
openSyncedTabsPanel() {
let placement = CustomizableUI.getPlacementOfWidget("sync-button");
let area = placement ? placement.area : CustomizableUI.AREA_NAVBAR;
let area = placement && placement.area;
let anchor = document.getElementById("sync-button") ||
document.getElementById("PanelUI-menu-button");
if (area == CustomizableUI.AREA_PANEL) {
// The button is in the panel, so we need to show the panel UI, then our
// subview.
PanelUI.show().then(() => {
PanelUI.showSubView("PanelUI-remotetabs", anchor, area);
}).catch(Cu.reportError);
if (area == CustomizableUI.AREA_FIXED_OVERFLOW_PANEL) {
// The button is in the overflow panel, so we need to show the panel,
// then show our subview.
let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
navbar.overflowable.show().then(() => {
PanelUI.showSubView("PanelUI-remotetabs", anchor);
}, Cu.reportError);
} else {
// It is placed somewhere else - just try and show it.
PanelUI.showSubView("PanelUI-remotetabs", anchor, area);
PanelUI.showSubView("PanelUI-remotetabs", anchor);
}
},

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

@ -3777,11 +3777,6 @@ const BrowserSearch = {
searchBar.select();
focusUrlBarIfSearchFieldIsNotActive(searchBar);
};
if (placement && placement.area == CustomizableUI.AREA_PANEL) {
// The panel is not constructed until the first time it is shown.
PanelUI.show().then(focusSearchBar);
return;
}
if (placement && searchBar &&
((searchBar.parentNode.getAttribute("overflowedItem") == "true" &&
placement.area == CustomizableUI.AREA_NAVBAR) ||

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

@ -928,7 +928,7 @@
<toolbarbutton id="library-button" class="toolbarbutton-1 chromeclass-toolbar-additional subviewbutton-nav"
removable="true"
onmousedown="PanelUI.showSubView('appMenu-libraryView', this, null, event);"
onmousedown="PanelUI.showSubView('appMenu-libraryView', this, event);"
closemenu="none"
cui-areatype="toolbar"
tooltiptext="&libraryButton.tooltip;"
@ -1152,7 +1152,7 @@
</toolbarbutton>
<toolbaritem id="search-container"
class="chromeclass-toolbar-additional panel-wide-item"
class="chromeclass-toolbar-additional"
title="&searchItem.title;"
align="center"
flex="100"

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

@ -8,7 +8,6 @@
const PREF_LWTHEME_USED_THEMES = "lightweightThemes.usedThemes";
const COMPACT_LIGHT_ID = "firefox-compact-light@mozilla.org";
const COMPACT_DARK_ID = "firefox-compact-dark@mozilla.org";
const SKIP_TEST = !AppConstants.INSTALL_COMPACT_THEMES;
const {LightweightThemeManager} = Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
registerCleanupFunction(() => {
@ -18,11 +17,6 @@ registerCleanupFunction(() => {
});
add_task(async function startTests() {
if (SKIP_TEST) {
ok(true, "No need to run this test since themes aren't installed");
return;
}
info("Setting the current theme to null");
LightweightThemeManager.currentTheme = null;
ok(!CompactTheme.isStyleSheetEnabled, "There is no compact style sheet when no lw theme is applied.");
@ -60,10 +54,6 @@ function dummyLightweightTheme(id) {
}
add_task(async function testLightweightThemePreview() {
if (SKIP_TEST) {
ok(true, "No need to run this test since themes aren't installed");
return;
}
info("Setting compact to current and previewing others");
LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID);
ok(CompactTheme.isStyleSheetEnabled, "The compact stylesheet is enabled.");

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

@ -1,3 +1,4 @@
/* global gBrowser */
Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
@ -119,6 +120,41 @@ add_task(async function() {
urlOptIn: true
};
// Deferred promise object used by the test to wait for the crash handler
let crashDeferred = PromiseUtils.defer();
// Clear out any minidumps we create from plugin crashes, this is needed
// because we do not submit the crash otherwise the submission process would
// have deleted the crash dump files for us.
let crashObserver = (subject, topic, data) => {
if (topic != "plugin-crashed") {
return;
}
let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
let minidumpID = propBag.getPropertyAsAString("pluginDumpID");
Services.crashmanager.ensureCrashIsPresent(minidumpID).then(() => {
let dirSvc = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
let minidumpDir = dirSvc.get("UAppData", Ci.nsIFile);
minidumpDir.append("Crash Reports");
minidumpDir.append("pending");
let pluginDumpFile = minidumpDir.clone();
pluginDumpFile.append(minidumpID + ".dmp");
let extraFile = minidumpDir.clone();
extraFile.append(minidumpID + ".extra");
pluginDumpFile.remove(false);
extraFile.remove(false);
crashDeferred.resolve();
});
};
Services.obs.addObserver(crashObserver, "plugin-crashed");
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
let pluginCrashed = promisePluginCrashed();
@ -141,6 +177,9 @@ add_task(async function() {
Assert.equal(!!pleaseSubmit && content.getComputedStyle(pleaseSubmit).display == "block",
aConfig.shouldSubmissionUIBeVisible, "Plugin crash UI should not be visible");
});
await crashDeferred.promise;
Services.obs.removeObserver(crashObserver, "plugin-crashed");
});
function promisePluginCrashed() {
@ -155,9 +194,11 @@ function promisePluginCrashed() {
}
function onSubmitStatus(aSubject, aData) {
// Wait for success or failed, doesn't matter which.
if (aData != "success" && aData != "failed")
if (aData === "submitting") {
return false;
}
is(aData, "success", "The crash report should be submitted successfully");
let propBag = aSubject.QueryInterface(Ci.nsIPropertyBag);
if (aData == "success") {
@ -176,20 +217,22 @@ function onSubmitStatus(aSubject, aData) {
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
let val = getPropertyBagValue(extra, "PluginUserComment");
if (config.comment)
if (config.comment) {
is(val, config.comment,
"Comment in extra data should match comment in textbox");
else
} else {
ok(val === undefined,
"Comment should be absent from extra data when textbox is empty");
}
val = getPropertyBagValue(extra, "PluginContentURL");
if (config.urlOptIn)
if (config.urlOptIn) {
is(val, gBrowser.currentURI.spec,
"URL in extra data should match browser URL when opt-in checked");
else
} else {
ok(val === undefined,
"URL should be absent from extra data when opt-in not checked");
}
return true;
}

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

@ -131,7 +131,7 @@ var whitelist = [
// Bug 1343837
{file: "chrome://global/content/findUtils.js"},
// Bug 1348362
{file: "chrome://global/skin/icons/warning-64.png", platforms: ["linux", "win"]},
{file: "chrome://global/skin/icons/warning-64.png", platforms: ["linux"]},
// Bug 1348525
{file: "chrome://global/skin/splitter/grip-bottom.gif", platforms: ["linux"]},
{file: "chrome://global/skin/splitter/grip-left.gif", platforms: ["linux"]},

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

@ -6,14 +6,14 @@
* when opened through a touch event. */
async function openAndCheckMenu(menu, target) {
is(menu.state, "closed", "Menu panel is initally closed.");
is(menu.state, "closed", `Menu panel (${menu.id}) is initally closed.`);
let popupshown = BrowserTestUtils.waitForEvent(menu, "popupshown");
EventUtils.synthesizeNativeTapAtCenter(target);
await popupshown;
is(menu.state, "open", "Menu panel is open.");
is(menu.getAttribute("touchmode"), "true", "Menu panel is in touchmode.");
is(menu.state, "open", `Menu panel (${menu.id}) is open.`);
is(menu.getAttribute("touchmode"), "true", `Menu panel (${menu.id}) is in touchmode.`);
menu.hidePopup();
@ -21,8 +21,8 @@ async function openAndCheckMenu(menu, target) {
EventUtils.synthesizeMouseAtCenter(target, {});
await popupshown;
is(menu.state, "open", "Menu panel is open.");
ok(!menu.hasAttribute("touchmode"), "Menu panel is not in touchmode.");
is(menu.state, "open", `Menu panel (${menu.id}) is open.`);
ok(!menu.hasAttribute("touchmode"), `Menu panel (${menu.id}) is not in touchmode.`);
menu.hidePopup();
}
@ -38,10 +38,10 @@ async function openAndCheckCustomizationUIMenu(target) {
if (menu.state != "open") {
await BrowserTestUtils.waitForEvent(menu, "popupshown");
is(menu.state, "open", "Menu is open");
is(menu.state, "open", `Menu for ${target.id} is open`);
}
is(menu.getAttribute("touchmode"), "true", "Menu is in touchmode.");
is(menu.getAttribute("touchmode"), "true", `Menu for ${target.id} is in touchmode.`);
menu.hidePopup();
@ -53,10 +53,10 @@ async function openAndCheckCustomizationUIMenu(target) {
if (menu.state != "open") {
await BrowserTestUtils.waitForEvent(menu, "popupshown");
is(menu.state, "open", "Menu is open");
is(menu.state, "open", `Menu for ${target.id} is open`);
}
ok(!menu.hasAttribute("touchmode"), "Menu is not in touchmode.");
ok(!menu.hasAttribute("touchmode"), `Menu for ${target.id} is not in touchmode.`);
menu.hidePopup();
}

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

@ -13,7 +13,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
PanelWideWidgetTracker: "resource:///modules/PanelWideWidgetTracker.jsm",
SearchWidgetTracker: "resource:///modules/SearchWidgetTracker.jsm",
CustomizableWidgets: "resource:///modules/CustomizableWidgets.jsm",
DeferredTask: "resource://gre/modules/DeferredTask.jsm",
@ -160,8 +159,6 @@ var gUIStateBeforeReset = {
autoTouchMode: null,
};
var gDefaultPanelPlacements = null;
XPCOMUtils.defineLazyGetter(this, "log", () => {
let scope = {};
Cu.import("resource://gre/modules/Console.jsm", scope);
@ -1630,7 +1627,7 @@ var CustomizableUIInternal = {
}
}
ownerWindow.PanelUI.showSubView(aWidget.viewId, anchor, area, aEvent);
ownerWindow.PanelUI.showSubView(aWidget.viewId, anchor, aEvent);
}
},
@ -1649,10 +1646,7 @@ var CustomizableUIInternal = {
},
_getPanelForNode(aNode) {
let panel = aNode;
while (panel && panel.localName != "panel")
panel = panel.parentNode;
return panel;
return aNode.closest("panel");
},
/*
@ -2961,11 +2955,6 @@ var CustomizableUIInternal = {
Object.freeze(CustomizableUIInternal);
this.CustomizableUI = {
/**
* Constant reference to the ID of the menu panel.
* DEPRECATED.
*/
AREA_PANEL: "PanelUI-contents",
/**
* Constant reference to the ID of the navigation toolbar.
*/
@ -3019,15 +3008,6 @@ this.CustomizableUI = {
*/
SOURCE_EXTERNAL: "external",
/**
* The class used to distinguish items that span the entire menu panel.
*/
WIDE_PANEL_CLASS: "panel-wide-item",
/**
* The (constant) number of columns in the menu panel.
*/
PANEL_COLUMN_COUNT: 3,
/**
* Constant indicating the reason the event was fired was a window closing
*/

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

@ -34,7 +34,6 @@ XPCOMUtils.defineLazyGetter(this, "BrandBundle", function() {
const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const kPrefCustomizationDebug = "browser.uiCustomization.debug";
const kWidePanelItemClass = "panel-wide-item";
XPCOMUtils.defineLazyGetter(this, "log", () => {
let scope = {};
@ -153,7 +152,6 @@ const CustomizableWidgets = [
viewId: "PanelUI-history",
shortcutId: "key_gotoHistory",
tooltiptext: "history-panelmenu.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
recentlyClosedTabsPanel: "appMenu-library-recentlyClosedTabs",
recentlyClosedWindowsPanel: "appMenu-library-recentlyClosedWindows",
handleEvent(event) {
@ -245,7 +243,6 @@ const CustomizableWidgets = [
tooltiptext: "remotetabs-panelmenu.tooltiptext2",
type: "view",
viewId: "PanelUI-remotetabs",
defaultArea: CustomizableUI.AREA_PANEL,
deckIndices: {
DECKINDEX_TABS: 0,
DECKINDEX_TABSDISABLED: 1,
@ -524,7 +521,6 @@ const CustomizableWidgets = [
}, {
id: "privatebrowsing-button",
shortcutId: "key_privatebrowsing",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand(e) {
let win = e.target.ownerGlobal;
win.OpenBrowserWindow({private: true});
@ -533,7 +529,6 @@ const CustomizableWidgets = [
id: "save-page-button",
shortcutId: "key_savePage",
tooltiptext: "save-page-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand(aEvent) {
let win = aEvent.target.ownerGlobal;
win.saveBrowser(win.gBrowser.selectedBrowser);
@ -542,7 +537,6 @@ const CustomizableWidgets = [
id: "find-button",
shortcutId: "key_find",
tooltiptext: "find-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand(aEvent) {
let win = aEvent.target.ownerGlobal;
if (win.gFindBar) {
@ -553,7 +547,6 @@ const CustomizableWidgets = [
id: "open-file-button",
shortcutId: "openFileKb",
tooltiptext: "open-file-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand(aEvent) {
let win = aEvent.target.ownerGlobal;
win.BrowserOpenFileWindow();
@ -582,7 +575,6 @@ const CustomizableWidgets = [
id: "add-ons-button",
shortcutId: "key_openAddons",
tooltiptext: "add-ons-button.tooltiptext3",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand(aEvent) {
let win = aEvent.target.ownerGlobal;
win.BrowserOpenAddonsMgr();
@ -591,7 +583,6 @@ const CustomizableWidgets = [
id: "zoom-controls",
type: "custom",
tooltiptext: "zoom-controls.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
onBuild(aDocument) {
let buttons = [{
id: "zoom-out-button",
@ -626,7 +617,6 @@ const CustomizableWidgets = [
node.setAttribute("removable", "true");
node.classList.add("chromeclass-toolbar-additional");
node.classList.add("toolbaritem-combined-buttons");
node.classList.add(kWidePanelItemClass);
buttons.forEach(function(aButton, aIndex) {
if (aIndex != 0)
@ -641,7 +631,6 @@ const CustomizableWidgets = [
id: "edit-controls",
type: "custom",
tooltiptext: "edit-controls.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
onBuild(aDocument) {
let buttons = [{
id: "cut-button",
@ -674,7 +663,6 @@ const CustomizableWidgets = [
node.setAttribute("removable", "true");
node.classList.add("chromeclass-toolbar-additional");
node.classList.add("toolbaritem-combined-buttons");
node.classList.add(kWidePanelItemClass);
buttons.forEach(function(aButton, aIndex) {
if (aIndex != 0)
@ -711,7 +699,6 @@ const CustomizableWidgets = [
type: "view",
viewId: "PanelUI-feeds",
tooltiptext: "feed-button.tooltiptext2",
defaultArea: CustomizableUI.AREA_PANEL,
onClick(aEvent) {
let win = aEvent.target.ownerGlobal;
let feeds = win.gBrowser.selectedBrowser.feeds;
@ -751,7 +738,6 @@ const CustomizableWidgets = [
type: "view",
viewId: "PanelUI-characterEncodingView",
tooltiptext: "characterencoding-button2.tooltiptext",
defaultArea: CustomizableUI.AREA_PANEL,
maybeDisableMenu(aDocument) {
let window = aDocument.defaultView;
return !(window.gBrowser &&
@ -924,7 +910,6 @@ const CustomizableWidgets = [
let preferencesButton = {
id: "preferences-button",
defaultArea: CustomizableUI.AREA_PANEL,
onCommand(aEvent) {
let win = aEvent.target.ownerGlobal;
win.openPreferences(undefined, {origin: "preferencesButton"});

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

@ -893,14 +893,6 @@ CustomizeMode.prototype = {
wrapper.setAttribute("flex", aNode.getAttribute("flex"));
}
if (aPlace == "panel") {
if (aNode.classList.contains(CustomizableUI.WIDE_PANEL_CLASS)) {
wrapper.setAttribute("haswideitem", "true");
} else if (wrapper.hasAttribute("haswideitem")) {
wrapper.removeAttribute("haswideitem");
}
}
let removable = aPlace == "palette" || CustomizableUI.isWidgetRemovable(aNode);
wrapper.setAttribute("removable", removable);
@ -2262,8 +2254,7 @@ CustomizeMode.prototype = {
let originArea = this._getCustomizableParent(draggedWrapper);
let positionManager = DragPositionManager.getManagerForArea(targetArea);
let draggedSize = this._getDragItemSize(aDragOverNode, aDraggedItem);
let isWide = aDraggedItem.classList.contains(CustomizableUI.WIDE_PANEL_CLASS);
positionManager.insertPlaceholder(targetArea, aDragOverNode, isWide, draggedSize,
positionManager.insertPlaceholder(targetArea, aDragOverNode, draggedSize,
originArea == targetArea);
},
@ -2373,7 +2364,7 @@ CustomizeMode.prototype = {
dragX -= bounds.left;
dragY -= bounds.top;
// Find the closest node:
targetNode = positionManager.find(aAreaElement, dragX, dragY, aDraggedItemId);
targetNode = positionManager.find(aAreaElement, dragX, dragY);
}
return targetNode || aEvent.target;
},

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

@ -10,7 +10,6 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var gManagers = new WeakMap();
const kPaletteId = "customization-palette";
const kPlaceholderClass = "panel-customization-placeholder";
this.EXPORTED_SYMBOLS = ["DragPositionManager"];
@ -25,45 +24,34 @@ function AreaPositionManager(aContainer) {
top: containerRect.top,
width: containerRect.width
};
this._inPanel = aContainer.id == CustomizableUI.AREA_PANEL;
this._horizontalDistance = null;
this.update(aContainer);
}
AreaPositionManager.prototype = {
_nodePositionStore: null,
_wideCache: null,
update(aContainer) {
this._nodePositionStore = new WeakMap();
this._wideCache = new Set();
let last = null;
let singleItemHeight;
for (let child of aContainer.children) {
if (child.hidden) {
continue;
}
let isNodeWide = this._checkIfWide(child);
if (isNodeWide) {
this._wideCache.add(child.id);
}
let coordinates = this._lazyStoreGet(child);
// We keep a baseline horizontal distance between non-wide nodes around
// We keep a baseline horizontal distance between nodes around
// for use when we can't compare with previous/next nodes
if (!this._horizontalDistance && last && !isNodeWide) {
if (!this._horizontalDistance && last) {
this._horizontalDistance = coordinates.left - last.left;
}
// We also keep the basic height of non-wide items for use below:
if (!isNodeWide && !singleItemHeight) {
// We also keep the basic height of items for use below:
if (!singleItemHeight) {
singleItemHeight = coordinates.height;
}
last = !isNodeWide ? coordinates : null;
}
if (this._inPanel) {
this._heightToWidthFactor = CustomizableUI.PANEL_COLUMN_COUNT;
} else {
this._heightToWidthFactor = this._containerInfo.width / singleItemHeight;
last = coordinates;
}
this._heightToWidthFactor = this._containerInfo.width / singleItemHeight;
},
/**
@ -74,7 +62,7 @@ AreaPositionManager.prototype = {
* where dy is more heavily weighted by a factor corresponding to the
* ratio between the container's width and the height of its elements.
*/
find(aContainer, aX, aY, aDraggedItemId) {
find(aContainer, aX, aY) {
let closest = null;
let minCartesian = Number.MAX_VALUE;
let containerX = this._containerInfo.left;
@ -85,11 +73,6 @@ AreaPositionManager.prototype = {
let offsetY = coordinates.y - containerY;
let hDiff = offsetX - aX;
let vDiff = offsetY - aY;
// For wide widgets, we're always going to be further from the center
// horizontally. Compensate:
if (this.isWide(node)) {
hDiff /= CustomizableUI.PANEL_COLUMN_COUNT;
}
// Then compensate for the height/width ratio so that we prefer items
// which are in the same row:
hDiff /= this._heightToWidthFactor;
@ -103,13 +86,6 @@ AreaPositionManager.prototype = {
// Now correct this node based on what we're dragging
if (closest) {
let doc = aContainer.ownerDocument;
let draggedItem = doc.getElementById(aDraggedItemId);
// If dragging a wide item, always pick the first item in a row:
if (this._inPanel && draggedItem &&
draggedItem.classList.contains(CustomizableUI.WIDE_PANEL_CLASS)) {
return this._firstInRow(closest);
}
let targetBounds = this._lazyStoreGet(closest);
let farSide = this._dir == "ltr" ? "right" : "left";
let outsideX = targetBounds[farSide];
@ -131,9 +107,8 @@ AreaPositionManager.prototype = {
* they would have if we had inserted something before aBefore. We use CSS
* transforms for this, which are CSS transitioned.
*/
insertPlaceholder(aContainer, aBefore, aWide, aSize, aIsFromThisArea) {
insertPlaceholder(aContainer, aBefore, aSize, aIsFromThisArea) {
let isShifted = false;
let shiftDown = aWide;
for (let child of aContainer.children) {
// Don't need to shift hidden nodes:
if (child.getAttribute("hidden") == "true") {
@ -142,31 +117,15 @@ AreaPositionManager.prototype = {
// If this is the node before which we're inserting, start shifting
// everything that comes after. One exception is inserting at the end
// of the menupanel, in which case we do not shift the placeholders:
if (child == aBefore && !child.classList.contains(kPlaceholderClass)) {
if (child == aBefore) {
isShifted = true;
// If the node before which we're inserting is wide, we should
// shift everything one row down:
if (!shiftDown && this.isWide(child)) {
shiftDown = true;
}
}
// If we're moving items before a wide node that were already there,
// it's possible it's not necessary to shift nodes
// including & after the wide node.
if (this.__undoShift) {
isShifted = false;
}
if (isShifted) {
// Conversely, if we're adding something before a wide node, for
// simplicity's sake we move everything including the wide node down:
if (this.__moveDown) {
shiftDown = true;
}
if (aIsFromThisArea && !this._lastPlaceholderInsertion) {
child.setAttribute("notransition", "true");
}
// Determine the CSS transform based on the next node:
child.style.transform = this._getNextPos(child, shiftDown, aSize);
child.style.transform = this._diffWithNext(child, aSize);
} else {
// If we're not shifting this node, reset the transform
child.style.transform = "";
@ -181,20 +140,9 @@ AreaPositionManager.prototype = {
child.removeAttribute("notransition");
}
}
delete this.__moveDown;
delete this.__undoShift;
this._lastPlaceholderInsertion = aBefore;
},
isWide(aNode) {
return this._wideCache.has(aNode.id);
},
_checkIfWide(aNode) {
return this._inPanel && aNode && aNode.firstChild &&
aNode.firstChild.classList.contains(CustomizableUI.WIDE_PANEL_CLASS);
},
/**
* Reset all the transforms in this container, optionally without
* transitioning them.
@ -221,14 +169,6 @@ AreaPositionManager.prototype = {
}
},
_getNextPos(aNode, aShiftDown, aSize) {
// Shifting down is easy:
if (this._inPanel && aShiftDown) {
return "translate(0, " + aSize.height + "px)";
}
return this._diffWithNext(aNode, aSize);
},
_diffWithNext(aNode, aSize) {
let xDiff;
let yDiff = null;
@ -240,42 +180,16 @@ AreaPositionManager.prototype = {
if (next) {
let otherBounds = this._lazyStoreGet(next);
xDiff = otherBounds[side] - nodeBounds[side];
// If the next node is a wide item in the panel, check if we could maybe
// just move further out in the same row, without snapping to the next
// one. This happens, for example, if moving an item that's before a wide
// node within its own row of items. There will be space to drop this
// item within the row, and the rest of the items do not need to shift.
if (this.isWide(next)) {
let otherXDiff = this._moveNextBasedOnPrevious(aNode, nodeBounds,
this._firstInRow(aNode));
// If this has the same sign as our original shift, we're still
// snapping to the start of the row. In this case, we should move
// everything after us a row down, so as not to display two nodes on
// top of each other:
// (we would be able to get away with checking for equality instead of
// equal signs here, but one of these is based on the x coordinate of
// the first item in row N and one on that for row N - 1, so this is
// safer, as their margins might differ)
if ((otherXDiff < 0) == (xDiff < 0)) {
this.__moveDown = true;
} else {
// Otherwise, we succeeded and can move further out. This also means
// we can stop shifting the rest of the content:
xDiff = otherXDiff;
this.__undoShift = true;
}
} else {
// We set this explicitly because otherwise some strange difference
// between the height and the actual difference between line creeps in
// and messes with alignments
yDiff = otherBounds.top - nodeBounds.top;
}
// We set this explicitly because otherwise some strange difference
// between the height and the actual difference between line creeps in
// and messes with alignments
yDiff = otherBounds.top - nodeBounds.top;
} else {
// We don't have a sibling whose position we can use. First, let's see
// if we're also the first item (which complicates things):
let firstNode = this._firstInRow(aNode);
if (aNode == firstNode) {
// Maybe we stored the horizontal distance between non-wide nodes,
// Maybe we stored the horizontal distance between nodes,
// if not, we'll use the width of the incoming node as a proxy:
xDiff = this._horizontalDistance || aSize.width;
} else {

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

@ -1032,35 +1032,6 @@ this.PanelMultiView = class {
const EXTRA_MARGIN_PX = 20;
maxHeight -= EXTRA_MARGIN_PX;
this._viewStack.style.maxHeight = maxHeight + "px";
// When using block-in-box layout inside a scrollable frame, like in the
// main menu contents scroller, if we allow the contents to scroll then
// it will not cause its container to expand. Thus, we layout first
// without any scrolling (using "display: flex;"), and only if the view
// exceeds the available space we set the height explicitly and enable
// scrolling.
let mainView = this._mainView;
if (mainView && mainView.hasAttribute("blockinboxworkaround")) {
let blockInBoxWorkaround = () => {
let mainViewHeight =
this._dwu.getBoundsWithoutFlushing(mainView).height;
if (mainViewHeight > maxHeight) {
mainView.style.height = maxHeight + "px";
mainView.setAttribute("exceeding", "true");
}
};
// On Windows, we cannot measure the full height of the main view
// until it is visible. Unfortunately, this causes a visible jump when
// the view needs to scroll, but there is no easy way around this.
if (AppConstants.platform == "win") {
// We register a "once" listener so we don't need to store the value
// of maxHeight elsewhere on the object.
this._panel.addEventListener("popupshown", blockInBoxWorkaround,
{ once: true });
} else {
blockInBoxWorkaround();
}
}
break;
}
case "popupshown":
@ -1097,13 +1068,6 @@ this.PanelMultiView = class {
this._viewContainer.style.removeProperty("max-width");
}
// Always try to layout the panel normally when reopening it. This is
// also the layout that will be used in customize mode.
let mainView = this._mainView;
if (mainView && mainView.hasAttribute("blockinboxworkaround")) {
mainView.style.removeProperty("height");
mainView.removeAttribute("exceeding");
}
this._dispatchViewEvent(this.node, "PanelMultiViewHidden");
break;
}

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

@ -1,172 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
this.EXPORTED_SYMBOLS = ["PanelWideWidgetTracker"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
var gPanel = CustomizableUI.AREA_PANEL;
// We keep track of the widget placements for the panel locally:
var gPanelPlacements = [];
// All the wide widgets we know of:
var gWideWidgets = new Set();
// All the widgets we know of:
var gSeenWidgets = new Set();
var PanelWideWidgetTracker = {
// Listeners used to validate panel contents whenever they change:
onWidgetAdded(aWidgetId, aArea, aPosition) {
if (aArea == gPanel) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
let moveForward = this.shouldMoveForward(aWidgetId, aPosition);
this.adjustWidgets(aWidgetId, moveForward);
}
},
onWidgetMoved(aWidgetId, aArea, aOldPosition, aNewPosition) {
if (aArea == gPanel) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
let moveForward = this.shouldMoveForward(aWidgetId, aNewPosition);
this.adjustWidgets(aWidgetId, moveForward);
}
},
onWidgetRemoved(aWidgetId, aPrevArea) {
if (aPrevArea == gPanel) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
this.adjustWidgets(aWidgetId, false);
}
},
onWidgetReset(aWidgetId) {
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
},
// Listener to keep abreast of any new nodes. We use the DOM one because
// we need access to the actual node's classlist, so we can't use the ones above.
// Furthermore, onWidgetCreated only fires for API-based widgets, not for XUL ones.
onWidgetAfterDOMChange(aNode, aNextNode, aContainer) {
if (!gSeenWidgets.has(aNode.id)) {
if (aNode.classList.contains(CustomizableUI.WIDE_PANEL_CLASS)) {
gWideWidgets.add(aNode.id);
}
gSeenWidgets.add(aNode.id);
}
},
// When widgets get destroyed, we remove them from our sets of stuff we care about:
onWidgetDestroyed(aWidgetId) {
gSeenWidgets.delete(aWidgetId);
gWideWidgets.delete(aWidgetId);
},
shouldMoveForward(aWidgetId, aPosition) {
let currentWidgetAtPosition = gPanelPlacements[aPosition + 1];
let rv = gWideWidgets.has(currentWidgetAtPosition) && !gWideWidgets.has(aWidgetId);
// We might now think we can move forward, but for that we need at least 2 more small
// widgets to be present:
if (rv) {
let furtherWidgets = gPanelPlacements.slice(aPosition + 2);
let realWidgets = 0;
if (furtherWidgets.length >= 2) {
while (furtherWidgets.length && realWidgets < 2) {
let w = furtherWidgets.shift();
if (!gWideWidgets.has(w) && this.checkWidgetStatus(w)) {
realWidgets++;
}
}
}
if (realWidgets < 2) {
rv = false;
}
}
return rv;
},
adjustWidgets(aWidgetId, aMoveForwards) {
if (this.adjusting) {
return;
}
this.adjusting = true;
let widgetsAffected = gPanelPlacements.filter((w) => gWideWidgets.has(w));
// If we're moving the wide widgets forwards (down/to the right in the panel)
// we want to start with the last widgets. Otherwise we move widgets over other wide
// widgets, which might mess up their order. Likewise, if moving backwards we should start with
// the first widget and work our way down/right from there.
let compareFn = aMoveForwards ? ((a, b) => a < b) : ((a, b) => a > b);
widgetsAffected.sort((a, b) => compareFn(gPanelPlacements.indexOf(a),
gPanelPlacements.indexOf(b)));
for (let widget of widgetsAffected) {
this.adjustPosition(widget, aMoveForwards);
}
this.adjusting = false;
},
// This function is called whenever an item gets moved in the menu panel. It
// adjusts the position of widgets within the panel to prevent "gaps" between
// wide widgets that could be filled up with single column widgets
adjustPosition(aWidgetId, aMoveForwards) {
// Make sure that there are n % columns = 0 narrow buttons before the widget.
let placementIndex = gPanelPlacements.indexOf(aWidgetId);
let prevSiblingCount = 0;
let fixedPos = null;
while (placementIndex--) {
let thisWidgetId = gPanelPlacements[placementIndex];
if (gWideWidgets.has(thisWidgetId)) {
continue;
}
let widgetStatus = this.checkWidgetStatus(thisWidgetId);
if (!widgetStatus) {
continue;
}
if (widgetStatus == "public-only") {
fixedPos = !fixedPos ? placementIndex : Math.min(fixedPos, placementIndex);
prevSiblingCount = 0;
} else {
prevSiblingCount++;
}
}
if (fixedPos !== null || prevSiblingCount % CustomizableUI.PANEL_COLUMN_COUNT) {
let desiredPos = (fixedPos !== null) ? fixedPos : gPanelPlacements.indexOf(aWidgetId);
let desiredChange = -(prevSiblingCount % CustomizableUI.PANEL_COLUMN_COUNT);
if (aMoveForwards && fixedPos == null) {
// +1 because otherwise we'd count ourselves:
desiredChange = CustomizableUI.PANEL_COLUMN_COUNT + desiredChange + 1;
}
desiredPos += desiredChange;
CustomizableUI.moveWidgetWithinArea(aWidgetId, desiredPos);
}
},
/*
* Check whether a widget id is actually known anywhere.
* @returns false if the widget doesn't exist,
* "public-only" if it's not shown in private windows
* "real" if it does exist and is shown even in private windows
*/
checkWidgetStatus(aWidgetId) {
let widgetWrapper = CustomizableUI.getWidget(aWidgetId);
// This widget might not actually exist:
if (!widgetWrapper) {
return false;
}
// This widget might still not actually exist:
if (widgetWrapper.provider == CustomizableUI.PROVIDER_XUL &&
widgetWrapper.instances.length == 0) {
return false;
}
// Or it might only be there some of the time:
if (widgetWrapper.provider == CustomizableUI.PROVIDER_API &&
widgetWrapper.showInPrivateBrowsing === false) {
return "public-only";
}
return "real";
},
init() {
// Initialize our local placements copy and register the listener
gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
CustomizableUI.addListener(this);
},
};

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

@ -367,11 +367,9 @@ const PanelUI = {
*
* @param aViewId the ID of the subview to show.
* @param aAnchor the element that spawned the subview.
* @param aPlacementArea the CustomizableUI area that aAnchor is in.
* @param aEvent the event triggering the view showing.
*/
async showSubView(aViewId, aAnchor, aPlacementArea, aEvent) {
async showSubView(aViewId, aAnchor, aEvent) {
let domEvent = null;
if (aEvent) {
if (aEvent.type == "mousedown" && aEvent.button != 0) {

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

@ -16,7 +16,6 @@ EXTRA_JS_MODULES += [
'CustomizeMode.jsm',
'DragPositionManager.jsm',
'PanelMultiView.jsm',
'PanelWideWidgetTracker.jsm',
'ScrollbarSampler.jsm',
'SearchWidgetTracker.jsm',
]

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

@ -9,7 +9,6 @@ const kAPIWidgetId = "feed-button";
const kPanel = CustomizableUI.AREA_FIXED_OVERFLOW_PANEL;
const kToolbar = CustomizableUI.AREA_NAVBAR;
const kVisiblePalette = "customization-palette";
const kPlaceholderClass = "panel-customization-placeholder";
function checkWrapper(id) {
is(document.querySelectorAll("#wrapper-" + id).length, 1, "There should be exactly 1 wrapper for " + id + " in the customizing window.");
@ -43,7 +42,7 @@ var move = {
if (targetNode.customizationTarget) {
targetNode = targetNode.customizationTarget;
}
let items = targetNode.querySelectorAll("toolbarpaletteitem:not(." + kPlaceholderClass + ")");
let items = targetNode.querySelectorAll("toolbarpaletteitem");
if (target == kPanel) {
targetNode = items[items.length - 1];
} else {
@ -124,7 +123,7 @@ async function checkToolbar(id, method) {
async function checkPanel(id, method) {
let panelPlacements = getAreaWidgetIds(kPanel);
await move[method](id, kPanel);
let children = document.getElementById(kPanel).querySelectorAll("toolbarpaletteitem:not(." + kPlaceholderClass + ")");
let children = document.getElementById(kPanel).querySelectorAll("toolbarpaletteitem");
let otherChildren = otherWin.document.getElementById(kPanel).children;
let newPlacements = panelPlacements.concat([id]);
// Relative position of the new item from the end:

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

@ -125,10 +125,6 @@ function removeNonOriginalButtons() {
CustomizableUI.removeWidgetFromArea("sync-button");
}
function restoreNonOriginalButtons() {
CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
}
function assertAreaPlacements(areaId, expectedPlacements) {
let actualPlacements = getAreaWidgetIds(areaId);
placementArraysEqual(areaId, actualPlacements, expectedPlacements);

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

@ -642,30 +642,28 @@ BrowserGlue.prototype = {
SessionStore.init();
if (AppConstants.INSTALL_COMPACT_THEMES) {
let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
LightweightThemeManager.addBuiltInTheme({
id: "firefox-compact-light@mozilla.org",
name: gBrowserBundle.GetStringFromName("lightTheme.name"),
description: gBrowserBundle.GetStringFromName("lightTheme.description"),
headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
textcolor: "black",
accentcolor: "white",
author: vendorShortName,
});
LightweightThemeManager.addBuiltInTheme({
id: "firefox-compact-dark@mozilla.org",
name: gBrowserBundle.GetStringFromName("darkTheme.name"),
description: gBrowserBundle.GetStringFromName("darkTheme.description"),
headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
textcolor: "white",
accentcolor: "black",
author: vendorShortName,
});
}
LightweightThemeManager.addBuiltInTheme({
id: "firefox-compact-light@mozilla.org",
name: gBrowserBundle.GetStringFromName("lightTheme.name"),
description: gBrowserBundle.GetStringFromName("lightTheme.description"),
headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
textcolor: "black",
accentcolor: "white",
author: vendorShortName,
});
LightweightThemeManager.addBuiltInTheme({
id: "firefox-compact-dark@mozilla.org",
name: gBrowserBundle.GetStringFromName("darkTheme.name"),
description: gBrowserBundle.GetStringFromName("darkTheme.description"),
headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
textcolor: "white",
accentcolor: "black",
author: vendorShortName,
});
// Initialize the default l10n resource sources for L10nRegistry.

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

@ -101,13 +101,7 @@ function updateZoomUI(aBrowser, aAnimate = false) {
}
Components.utils.import("resource:///modules/CustomizableUI.jsm");
let customizationListener = {
onAreaNodeRegistered(aAreaType, aAreaNode) {
if (aAreaType == CustomizableUI.AREA_PANEL) {
updateZoomUI(aAreaNode.ownerGlobal.gBrowser.selectedBrowser);
}
}
};
let customizationListener = {};
customizationListener.onWidgetAdded =
customizationListener.onWidgetRemoved =
customizationListener.onWidgetMoved = function(aWidgetId) {

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

@ -8,7 +8,7 @@
--drag-drop-transition-duration: .3s;
}
#main-window[customizing] .customization-target:not(#PanelUI-contents):not(#widget-overflow-fixed-list) {
#main-window[customizing] .customization-target:not(#widget-overflow-fixed-list) {
min-width: 100px;
}
@ -174,7 +174,6 @@ toolbarpaletteitem[mousedown] {
cursor: -moz-grabbing;
}
.panel-customization-placeholder,
toolbarpaletteitem[place="palette"],
toolbarpaletteitem[place="panel"] {
transition: transform var(--drag-drop-transition-duration) ease-in-out;
@ -194,7 +193,6 @@ toolbarpaletteitem toolbarbutton[disabled] {
}
#widget-overflow-fixed-list > toolbarpaletteitem[notransition][place="panel"],
toolbarpaletteitem[notransition].panel-customization-placeholder,
toolbarpaletteitem[notransition][place="toolbar"],
toolbarpaletteitem[notransition][place="palette"],
toolbarpaletteitem[notransition][place="panel"] {
@ -203,7 +201,8 @@ toolbarpaletteitem[notransition][place="panel"] {
toolbarpaletteitem > toolbarbutton > .toolbarbutton-icon,
toolbarpaletteitem > toolbarbutton > .toolbarbutton-badge-stack > .toolbarbutton-icon,
toolbarpaletteitem > toolbaritem.panel-wide-item {
toolbarpaletteitem > #search-container,
toolbarpaletteitem > toolbaritem.toolbaritem-combined-buttons {
transition: transform var(--drag-drop-transition-duration) cubic-bezier(.6, 2, .75, 1.5) !important;
}
@ -212,7 +211,8 @@ toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-badge-stack > .to
transform: scale(1.3);
}
toolbarpaletteitem[mousedown] > toolbaritem.panel-wide-item {
toolbarpaletteitem[mousedown] > #search-container,
toolbarpaletteitem[mousedown] > toolbaritem.toolbaritem-combined-buttons {
transform: scale(1.1);
}

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

@ -237,35 +237,6 @@ panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
}
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
line-height: 1.2;
max-height: 2.4em;
}
.panelUI-grid .toolbarbutton-1:not([auto-hyphens="off"]) > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
.panelUI-grid .toolbarbutton-1:not([auto-hyphens="off"]) > .toolbarbutton-multiline-text {
-moz-hyphens: auto;
}
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
position: absolute;
clip: rect(-0.1em, auto, 2.6em, auto);
}
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-text,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-multiline-text {
text-align: center;
/* Need to override toolkit theming which sets margin: 0 !important; */
margin: 2px 0 0 !important;
}
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text {
text-align: center;
margin: -1px 0 0;
}
#wrapper-edit-controls:-moz-any([place="palette"],[place="panel"]) > #edit-controls,
#wrapper-zoom-controls:-moz-any([place="palette"],[place="panel"]) > #zoom-controls {
margin-inline-start: 0;
@ -416,44 +387,12 @@ photonpanelmultiview .panel-subview-body {
padding-bottom: 0;
}
#PanelUI-contents {
display: block;
flex: 1 0 auto;
margin-left: auto;
margin-right: auto;
padding: .5em 0;
max-width: @menuPanelWidth@;
}
#PanelUI-contents-scroller {
-moz-box-flex: 1;
overflow-y: auto;
overflow-x: hidden;
width: @menuPanelWidth@;
padding-left: 5px;
padding-right: 5px;
-moz-box-align: center;
}
/* Allow box layout to take over when the view exceeds the available space. */
#PanelUI-mainView:not([exceeding]) > #PanelUI-contents-scroller {
display: flex;
}
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon {
min-width: 0;
min-height: 0;
margin: 0;
}
.panelUI-grid .toolbarbutton-1,
.panel-customization-placeholder-child {
-moz-appearance: none;
-moz-box-orient: vertical;
width: calc(@menuPanelButtonWidth@);
height: calc(51px + 2.2em);
}
.animate-out {
animation-name: widget-animate-out;
animation-fill-mode: forwards;
@ -495,8 +434,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton
/* above we treat the container as the icon for the margins, that is so the
/* badge itself is positioned correctly. Here we make sure that the icon itself
/* has the minimum size we want, but no padding/margin. */
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon {
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon {
width: @panelPaletteIconSize@;
height: @panelPaletteIconSize@;
min-width: @panelPaletteIconSize@;

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

@ -193,13 +193,22 @@ tabbrowser {
100% { transform: translateX(100%); }
}
#TabsToolbar[brighttext] .tab-throbber[busy]:not([visuallyselected=true])::before {
/* Don't change the --tab-loading-fill variable because this should only affect
tabs that are not visually selected. */
fill: #717171;
opacity: 1;
}
:root[sessionrestored] .tab-throbber[progress]::before {
fill: var(--tab-loading-fill);
opacity: 1;
}
#TabsToolbar[brighttext] .tabbrowser-tab:not([visuallyselected=true]) {
--tab-loading-fill: #bbbbff;
#TabsToolbar[brighttext] .tab-throbber[progress]:not([visuallyselected=true])::before {
/* Don't change the --tab-loading-fill variable because this should only affect
tabs that are not visually selected. */
fill: #84c1ff;
}
#tabbrowser-tabs[schedulepressure] .tab-throbber,

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

@ -317,15 +317,15 @@ OptionsPanel.prototype = {
}
// Labels for these new buttons are nightly only and mostly intended for working on
// devtools. They should not be localized.
// devtools.
let prefDefinitions = [{
pref: "devtools.webconsole.new-frontend-enabled",
label: "Enable new console frontend",
label: L10N.getStr("toolbox.options.enableNewConsole.label"),
id: "devtools-new-webconsole",
parentId: "webconsole-options"
}, {
pref: "devtools.debugger.new-debugger-frontend",
label: "Enable new debugger frontend",
label: L10N.getStr("toolbox.options.enableNewDebugger.label"),
id: "devtools-new-debugger",
parentId: "debugger-options"
}];

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

@ -33,6 +33,10 @@ require.config({
JSONView.debug
? "resource://devtools-client-shared/vendor/react-dom-dev"
: "resource://devtools-client-shared/vendor/react-dom",
"devtools/client/shared/vendor/react-prop-types":
JSONView.debug
? "resource://devtools-client-shared/vendor/react-prop-types-dev"
: "resource://devtools-client-shared/vendor/react-prop-types",
}
});

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

@ -195,3 +195,12 @@ toolbox.sourceMapFailure=Source map error: %1$S\nResource URL: %2$S\nSource Map
# The text of the error: %1$S
# The URL of the source: %2$S
toolbox.sourceMapSourceFailure=Error while fetching an original source: %1$S\nSource URL: %2$S
# LOCALIZATION NOTE (toolbox.options.enableNewDebugger.label): Label of the options panel
# checkbox to enable the new debugger frontend. Displayed only in Nightly and local
# builds.
toolbox.options.enableNewDebugger.label=Enable new debugger frontend
# LOCALIZATION NOTE (toolbox.options.enableNewConsole.label): Label of the options panel
# checkbox to enable the new console frontend. Displayed only in Nightly and local builds.
toolbox.options.enableNewConsole.label=Enable new console frontend

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

@ -137,6 +137,10 @@
padding-inline-end: 5px;
}
.network-monitor .tree-container .treeTable .treeValueCell input{
color: var(--string-color);
}
/* Source editor in tab panels */
/* If there is a source editor shows up in the last row of TreeView,

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

@ -402,29 +402,25 @@ select > option.divider {
.device-modal {
border-radius: 2px;
box-shadow: var(--rdm-box-shadow);
display: none;
position: absolute;
margin: auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 642px;
width: 800px;
max-width: 90%;
height: 650px;
z-index: 1;
}
/* Handles the opening/closing of the modal */
#device-modal-wrapper.opened .device-modal {
animation: fade-in-and-up 0.3s ease;
animation-fill-mode: forwards;
display: block;
animation: fade-in-and-up 0.3s ease forwards;
}
#device-modal-wrapper.closed .device-modal {
animation: fade-down-and-out 0.3s ease;
animation-fill-mode: forwards;
display: block;
animation: fade-down-and-out 0.3s ease forwards;
}
#device-modal-wrapper.opened .modal-overlay {
@ -444,7 +440,6 @@ select > option.divider {
flex-wrap: wrap;
overflow: auto;
height: 515px;
width: 600px;
margin: 20px 20px 0;
}

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

@ -107,6 +107,8 @@ function BrowserLoaderBuilder({ baseURI, window, useOnlyShared, commonLibRequire
"resource://devtools/client/shared/vendor/react-dom-dev";
dynamicPaths["devtools/client/shared/vendor/react-dom-server"] =
"resource://devtools/client/shared/vendor/react-dom-server-dev";
dynamicPaths["devtools/client/shared/vendor/react-prop-types"] =
"resource://devtools/client/shared/vendor/react-prop-types-dev";
}
const opts = {

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

@ -4,7 +4,9 @@
"use strict";
const { DOM: dom, Component, PropTypes } = require("devtools/client/shared/vendor/react");
const { Component } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
class AutocompletePopup extends Component {
static get propTypes() {

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

@ -4,9 +4,11 @@
"use strict";
const { DOM: dom, Component, PropTypes } = require("devtools/client/shared/vendor/react");
const { getSourceNames, parseURL,
isScratchpadScheme, getSourceMappedFile } = require("devtools/client/shared/source-utils");
const { Component } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { getSourceNames, parseURL, isScratchpadScheme, getSourceMappedFile } =
require("devtools/client/shared/source-utils");
const { LocalizationHelper } = require("devtools/shared/l10n");
const l10n = new LocalizationHelper("devtools/client/locales/components.properties");

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

@ -23,11 +23,9 @@
// | | |
// +-----------------------+---------------------+
const {
DOM: dom,
Component,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { assert } = require("devtools/shared/DevToolsUtils");
class HSplitBox extends Component {

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

@ -4,14 +4,14 @@
"use strict";
const React = require("devtools/client/shared/vendor/react");
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const Immutable = require("devtools/client/shared/vendor/immutable");
const { LocalizationHelper } = require("devtools/shared/l10n");
const l10n = new LocalizationHelper("devtools/client/locales/components.properties");
// Shortcuts
const { PropTypes, Component, DOM } = React;
const { div, span, button } = DOM;
const l10n = new LocalizationHelper("devtools/client/locales/components.properties");
const { div, span, button } = dom;
// Priority Levels
const PriorityLevels = {

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

@ -6,7 +6,9 @@
"use strict";
const { DOM: dom, Component, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
const AutocompletePopup = createFactory(require("devtools/client/shared/components/AutoCompletePopup"));

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

@ -6,10 +6,12 @@
"use strict";
const { DOM, Component, PropTypes } = require("devtools/client/shared/vendor/react");
const { Component } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
// Shortcuts
const { button } = DOM;
const { button } = dom;
/**
* Sidebar toggle button. This button is used to exapand

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

@ -4,8 +4,9 @@
"use strict";
const React = require("devtools/client/shared/vendor/react");
const { DOM: dom, Component, createFactory, PropTypes } = React;
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { LocalizationHelper } = require("devtools/shared/l10n");
const Frame = createFactory(require("./Frame"));

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

@ -4,8 +4,9 @@
/* eslint-env browser */
"use strict";
const React = require("devtools/client/shared/vendor/react");
const { DOM: dom, Component, createFactory, PropTypes } = React;
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const AUTO_EXPAND_DEPTH = 0;
const NUMBER_OF_OFFSCREEN_ITEMS = 1;

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

@ -4,9 +4,10 @@
"use strict";
const React = require("devtools/client/shared/vendor/react");
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { Component, DOM: dom, PropTypes } = React;
class Draggable extends Component {
static get propTypes() {

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

@ -4,10 +4,11 @@
"use strict";
const React = require("devtools/client/shared/vendor/react");
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const Draggable = React.createFactory(require("devtools/client/shared/components/splitter/Draggable"));
const { Component, DOM: dom, PropTypes } = React;
const Draggable = createFactory(require("devtools/client/shared/components/splitter/Draggable"));
/**
* This component represents a Splitter. The splitter supports vertical

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

@ -8,14 +8,16 @@
"use strict";
const { DOM, Component, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const Tabs = createFactory(require("devtools/client/shared/components/tabs/Tabs").Tabs);
const Menu = require("devtools/client/framework/menu");
const MenuItem = require("devtools/client/framework/menu-item");
// Shortcuts
const { div } = DOM;
const { div } = dom;
/**
* Renders Tabbar component.

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

@ -7,8 +7,9 @@
"use strict";
define(function (require, exports, module) {
const React = require("devtools/client/shared/vendor/react");
const { Component, DOM } = React;
const { Component } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
/**
@ -34,26 +35,26 @@ define(function (require, exports, module) {
class Tabs extends Component {
static get propTypes() {
return {
className: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.string,
React.PropTypes.object
className: PropTypes.oneOfType([
PropTypes.array,
PropTypes.string,
PropTypes.object
]),
tabActive: React.PropTypes.number,
onMount: React.PropTypes.func,
onBeforeChange: React.PropTypes.func,
onAfterChange: React.PropTypes.func,
children: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.element
tabActive: PropTypes.number,
onMount: PropTypes.func,
onBeforeChange: PropTypes.func,
onAfterChange: PropTypes.func,
children: PropTypes.oneOfType([
PropTypes.array,
PropTypes.element
]).isRequired,
showAllTabsMenu: React.PropTypes.bool,
onAllTabsMenuClick: React.PropTypes.func,
showAllTabsMenu: PropTypes.bool,
onAllTabsMenuClick: PropTypes.func,
// Set true will only render selected panel on DOM. It's complete
// opposite of the created array, and it's useful if panels content
// is unpredictable and update frequently.
renderOnlySelected: React.PropTypes.bool,
renderOnlySelected: PropTypes.bool,
};
}
@ -267,14 +268,14 @@ define(function (require, exports, module) {
// left and right arrow keys.
// See also `onKeyDown()` event handler.
return (
DOM.li({
dom.li({
className,
key: index,
ref,
role: "presentation",
},
DOM.span({className: "devtools-tab-line"}),
DOM.a({
dom.span({className: "devtools-tab-line"}),
dom.a({
id: id ? id + "-tab" : "tab-" + index,
tabIndex: isTabSelected ? 0 : -1,
"aria-controls": id ? id + "-panel" : "panel-" + index,
@ -284,7 +285,7 @@ define(function (require, exports, module) {
},
title,
badge && !isTabSelected && showBadge() ?
DOM.span({ className: "tab-badge" }, badge)
dom.span({ className: "tab-badge" }, badge)
:
null
)
@ -295,15 +296,15 @@ define(function (require, exports, module) {
// Display the menu only if there is not enough horizontal
// space for all tabs (and overflow happened).
let allTabsMenu = this.state.overflow ? (
DOM.div({
dom.div({
className: "all-tabs-menu",
onClick: this.props.onAllTabsMenuClick,
})
) : null;
return (
DOM.nav({className: "tabs-navigation"},
DOM.ul({className: "tabs-menu", role: "tablist"},
dom.nav({className: "tabs-navigation"},
dom.ul({className: "tabs-menu", role: "tablist"},
tabs
),
allTabsMenu
@ -351,7 +352,7 @@ define(function (require, exports, module) {
let panel = tab.panel || tab;
return (
DOM.div({
dom.div({
id: id ? id + "-panel" : "panel-" + index,
key: index,
style: style,
@ -365,7 +366,7 @@ define(function (require, exports, module) {
});
return (
DOM.div({className: "panels"},
dom.div({className: "panels"},
panels
)
);
@ -373,7 +374,7 @@ define(function (require, exports, module) {
render() {
return (
DOM.div({ className: ["tabs", this.props.className].join(" ") },
dom.div({ className: ["tabs", this.props.className].join(" ") },
this.renderMenuItems(),
this.renderPanels()
)
@ -387,16 +388,16 @@ define(function (require, exports, module) {
class Panel extends Component {
static get propTypes() {
return {
title: React.PropTypes.string.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.element
title: PropTypes.string.isRequired,
children: PropTypes.oneOfType([
PropTypes.array,
PropTypes.element
]).isRequired
};
}
render() {
return DOM.div({className: "tab-panel"},
return dom.div({className: "tab-panel"},
this.props.children
);
}

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

@ -28,8 +28,9 @@ var { require: browserRequire } = BrowserLoader({
window
});
let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
let React = browserRequire("devtools/client/shared/vendor/react");
let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
let dom = browserRequire("devtools/client/shared/vendor/react-dom-factories");
var TestUtils = React.addons.TestUtils;
var EXAMPLE_URL = "http://example.com/browser/browser/devtools/shared/test/";
@ -200,7 +201,7 @@ function renderComponent(component, props) {
// By default, renderIntoDocument() won't work for stateless components, but
// it will work if the stateless component is wrapped in a stateful one.
// See https://github.com/facebook/react/issues/4839
const wrappedEl = React.DOM.span({}, [el]);
const wrappedEl = dom.span({}, [el]);
const renderedComponent = TestUtils.renderIntoDocument(wrappedEl);
return ReactDOM.findDOMNode(renderedComponent).children[0];
}

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

@ -26,7 +26,8 @@ Test all-tabs menu.
window.onload = Task.async(function* () {
try {
const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
const { Component, createFactory, DOM } = browserRequire("devtools/client/shared/vendor/react");
const { Component, createFactory } = browserRequire("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const Tabbar = createFactory(browserRequire("devtools/client/shared/components/tabs/TabBar"));
// Create container for the TabBar. Set smaller width
@ -47,7 +48,7 @@ window.onload = Task.async(function* () {
class TabPanelClass extends Component {
render() {
return DOM.div({}, "content");
return dom.div({}, "content");
}
}

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

@ -21,11 +21,13 @@ window.onload = Task.async(function* () {
try {
const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
const React = browserRequire("devtools/client/shared/vendor/react");
const Tree = React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const Tree =
React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
const treeProps = Object.assign({}, TEST_TREE_INTERFACE, {
renderItem: (item, depth, focused, arrow) => {
return React.DOM.div(
return dom.div(
{
id: item,
style: { marginLeft: depth * 16 + "px" }

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

@ -7,9 +7,9 @@
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
// ReactJS
const { Component, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const { Component } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
/**
* Render the default cell used for toggle buttons

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

@ -7,9 +7,10 @@
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
const React = require("devtools/client/shared/vendor/react");
const { Component, PropTypes } = React;
const { input, span, td } = React.DOM;
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { input, span, td } = dom;
/**
* This template represents a cell in TreeView row. It's rendered

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

@ -7,9 +7,10 @@
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
const React = require("devtools/client/shared/vendor/react");
const { Component, PropTypes } = React;
const { thead, tr, td, div } = React.DOM;
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { thead, tr, td, div } = dom;
/**
* This component is responsible for rendering tree header.

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

@ -7,10 +7,11 @@
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
const React = require("devtools/client/shared/vendor/react");
const { Component, createFactory, PropTypes } = React;
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
const { tr } = React.DOM;
const { tr } = dom;
// Tree
const TreeCell = createFactory(require("./TreeCell"));

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

@ -7,9 +7,11 @@
// Make this available to both AMD and CJS environments
define(function (require, exports, module) {
const { cloneElement, Component, createFactory, DOM: dom, PropTypes } =
const { cloneElement, Component, createFactory } =
require("devtools/client/shared/vendor/react");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
// Reps
const { ObjectProvider } = require("./ObjectProvider");

37
devtools/client/shared/vendor/REACT_PROP_TYPES_UPGRADING.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,37 @@
[//]: # (
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/.
)
# Upgrading react-prop-types
## Getting the Source
```bash
git clone the latest version from https://github.com/facebook/prop-types
cd prop-types
```
## Building
```bash
npm install
NODE_ENV=development browserify index.js -t envify --standalone PropTypes -o react-prop-types-dev.js
NODE_ENV=production browserify index.js -t envify --standalone PropTypes -o react-prop-types.js
```
## Adding Version Info
Add the version to the top of `react-prop-types.js` and `react-prop-types-dev.js`.
```js
/**
* react-prop-types v15.6.0
*/
```
## Copying files to your Firefox repo
```bash
mv react-prop-types.js /firefox/repo/devtools/client/shared/vendor/react-prop-types-dev.js
mv react-prop-types-dev.js /firefox/repo/devtools/client/shared/vendor/react-prop-types-dev.js
```

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

@ -1,5 +1,5 @@
[//]: # (
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 thisfile, You can obtain one at http://mozilla.org/MPL/2.0/.
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
)
# Upgrading React

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

@ -8,28 +8,16 @@ DIRS += [
'stringvalidator',
]
modules = []
modules += [
DevToolsModules(
'immutable.js',
'jsol.js',
'jszip.js',
'lodash.js',
'react-addons-shallow-compare.js',
]
# react dev versions are used if either debug mode is enabled,
# or enable-debug-js-modules is set in .mozconfig so include it for
# both
if CONFIG['DEBUG_JS_MODULES'] or CONFIG['MOZ_DEBUG']:
modules += [
'react-dev.js',
'react-dom-dev.js',
'react-dom-server-dev.js',
]
modules += [
'react-dom-factories.js',
'react-dom-server.js',
'react-dom.js',
'react-prop-types.js',
'react-redux.js',
'react-virtualized.js',
'react.js',
@ -38,6 +26,15 @@ modules += [
'seamless-immutable.js',
'WasmDis.js',
'WasmParser.js',
]
)
DevToolsModules(*modules)
# react dev versions are used if either debug mode is enabled,
# or enable-debug-js-modules is set in .mozconfig so include it for
# both
if CONFIG['DEBUG_JS_MODULES'] or CONFIG['MOZ_DEBUG']:
DevToolsModules(
'react-dev.js',
'react-dom-dev.js',
'react-dom-server-dev.js',
'react-prop-types-dev.js',
)

195
devtools/client/shared/vendor/react-dom-factories.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,195 @@
'use strict';
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
(function(f) {
if (typeof exports === 'object' && typeof module !== 'undefined') {
module.exports = f(require('devtools/client/shared/vendor/react'));
/* global define */
} else if (typeof define === 'function' && define.amd) {
define(['devtools/client/shared/vendor/react'], f);
} else {
var g;
if (typeof window !== 'undefined') {
g = window;
} else if (typeof global !== 'undefined') {
g = global;
} else if (typeof self !== 'undefined') {
g = self;
} else {
g = this;
}
if (typeof g.React === 'undefined') {
throw Error('React module should be required before ReactDOMFactories');
}
g.ReactDOMFactories = f(g.React);
}
})(function(React) {
/**
* Create a factory that creates HTML tag elements.
*/
function createDOMFactory(type) {
var factory = React.createElement.bind(null, type);
// Expose the type on the factory and the prototype so that it can be
// easily accessed on elements. E.g. `<Foo />.type === Foo`.
// This should not be named `constructor` since this may not be the function
// that created the element, and it may not even be a constructor.
factory.type = type;
return factory;
};
/**
* Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
*/
var ReactDOMFactories = {
a: createDOMFactory('a'),
abbr: createDOMFactory('abbr'),
address: createDOMFactory('address'),
area: createDOMFactory('area'),
article: createDOMFactory('article'),
aside: createDOMFactory('aside'),
audio: createDOMFactory('audio'),
b: createDOMFactory('b'),
base: createDOMFactory('base'),
bdi: createDOMFactory('bdi'),
bdo: createDOMFactory('bdo'),
big: createDOMFactory('big'),
blockquote: createDOMFactory('blockquote'),
body: createDOMFactory('body'),
br: createDOMFactory('br'),
button: createDOMFactory('button'),
canvas: createDOMFactory('canvas'),
caption: createDOMFactory('caption'),
cite: createDOMFactory('cite'),
code: createDOMFactory('code'),
col: createDOMFactory('col'),
colgroup: createDOMFactory('colgroup'),
data: createDOMFactory('data'),
datalist: createDOMFactory('datalist'),
dd: createDOMFactory('dd'),
del: createDOMFactory('del'),
details: createDOMFactory('details'),
dfn: createDOMFactory('dfn'),
dialog: createDOMFactory('dialog'),
div: createDOMFactory('div'),
dl: createDOMFactory('dl'),
dt: createDOMFactory('dt'),
em: createDOMFactory('em'),
embed: createDOMFactory('embed'),
fieldset: createDOMFactory('fieldset'),
figcaption: createDOMFactory('figcaption'),
figure: createDOMFactory('figure'),
footer: createDOMFactory('footer'),
form: createDOMFactory('form'),
h1: createDOMFactory('h1'),
h2: createDOMFactory('h2'),
h3: createDOMFactory('h3'),
h4: createDOMFactory('h4'),
h5: createDOMFactory('h5'),
h6: createDOMFactory('h6'),
head: createDOMFactory('head'),
header: createDOMFactory('header'),
hgroup: createDOMFactory('hgroup'),
hr: createDOMFactory('hr'),
html: createDOMFactory('html'),
i: createDOMFactory('i'),
iframe: createDOMFactory('iframe'),
img: createDOMFactory('img'),
input: createDOMFactory('input'),
ins: createDOMFactory('ins'),
kbd: createDOMFactory('kbd'),
keygen: createDOMFactory('keygen'),
label: createDOMFactory('label'),
legend: createDOMFactory('legend'),
li: createDOMFactory('li'),
link: createDOMFactory('link'),
main: createDOMFactory('main'),
map: createDOMFactory('map'),
mark: createDOMFactory('mark'),
menu: createDOMFactory('menu'),
menuitem: createDOMFactory('menuitem'),
meta: createDOMFactory('meta'),
meter: createDOMFactory('meter'),
nav: createDOMFactory('nav'),
noscript: createDOMFactory('noscript'),
object: createDOMFactory('object'),
ol: createDOMFactory('ol'),
optgroup: createDOMFactory('optgroup'),
option: createDOMFactory('option'),
output: createDOMFactory('output'),
p: createDOMFactory('p'),
param: createDOMFactory('param'),
picture: createDOMFactory('picture'),
pre: createDOMFactory('pre'),
progress: createDOMFactory('progress'),
q: createDOMFactory('q'),
rp: createDOMFactory('rp'),
rt: createDOMFactory('rt'),
ruby: createDOMFactory('ruby'),
s: createDOMFactory('s'),
samp: createDOMFactory('samp'),
script: createDOMFactory('script'),
section: createDOMFactory('section'),
select: createDOMFactory('select'),
small: createDOMFactory('small'),
source: createDOMFactory('source'),
span: createDOMFactory('span'),
strong: createDOMFactory('strong'),
style: createDOMFactory('style'),
sub: createDOMFactory('sub'),
summary: createDOMFactory('summary'),
sup: createDOMFactory('sup'),
table: createDOMFactory('table'),
tbody: createDOMFactory('tbody'),
td: createDOMFactory('td'),
textarea: createDOMFactory('textarea'),
tfoot: createDOMFactory('tfoot'),
th: createDOMFactory('th'),
thead: createDOMFactory('thead'),
time: createDOMFactory('time'),
title: createDOMFactory('title'),
tr: createDOMFactory('tr'),
track: createDOMFactory('track'),
u: createDOMFactory('u'),
ul: createDOMFactory('ul'),
var: createDOMFactory('var'),
video: createDOMFactory('video'),
wbr: createDOMFactory('wbr'),
// SVG
circle: createDOMFactory('circle'),
clipPath: createDOMFactory('clipPath'),
defs: createDOMFactory('defs'),
ellipse: createDOMFactory('ellipse'),
g: createDOMFactory('g'),
image: createDOMFactory('image'),
line: createDOMFactory('line'),
linearGradient: createDOMFactory('linearGradient'),
mask: createDOMFactory('mask'),
path: createDOMFactory('path'),
pattern: createDOMFactory('pattern'),
polygon: createDOMFactory('polygon'),
polyline: createDOMFactory('polyline'),
radialGradient: createDOMFactory('radialGradient'),
rect: createDOMFactory('rect'),
stop: createDOMFactory('stop'),
svg: createDOMFactory('svg'),
text: createDOMFactory('text'),
tspan: createDOMFactory('tspan'),
};
// due to wrapper and conditionals at the top, this will either become
// `module.exports ReactDOMFactories` if that is available,
// otherwise it will be defined via `define(['react'], ReactDOMFactories)`
// if that is available,
// otherwise it will be defined as global variable.
return ReactDOMFactories;
});

960
devtools/client/shared/vendor/react-prop-types-dev.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,960 @@
/**
* react-prop-types v15.6.0
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.PropTypes = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
if ("development" !== 'production') {
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
var loggedTypeFailures = {};
}
/**
* Assert that the values match with the type specs.
* Error messages are memorized and will only be shown once.
*
* @param {object} typeSpecs Map of name to a ReactPropType
* @param {object} values Runtime values that need to be type-checked
* @param {string} location e.g. "prop", "context", "child context"
* @param {string} componentName Name of the component for error messages.
* @param {?Function} getStack Returns the component stack.
* @private
*/
function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
if ("development" !== 'production') {
for (var typeSpecName in typeSpecs) {
if (typeSpecs.hasOwnProperty(typeSpecName)) {
var error;
// Prop type validation may throw. In case they do, we don't want to
// fail the render phase where it didn't fail before. So we log it.
// After these have been cleaned up, we'll let them throw.
try {
// This is intentionally an invariant that gets caught. It's the same
// behavior as without this statement except with a better message.
invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]);
error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
} catch (ex) {
error = ex;
}
warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error);
if (error instanceof Error && !(error.message in loggedTypeFailures)) {
// Only monitor this failure once because there tends to be a lot of the
// same error.
loggedTypeFailures[error.message] = true;
var stack = getStack ? getStack() : '';
warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : '');
}
}
}
}
}
module.exports = checkPropTypes;
},{"./lib/ReactPropTypesSecret":5,"fbjs/lib/invariant":7,"fbjs/lib/warning":8}],2:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var emptyFunction = require('fbjs/lib/emptyFunction');
var invariant = require('fbjs/lib/invariant');
var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
module.exports = function() {
function shim(props, propName, componentName, location, propFullName, secret) {
if (secret === ReactPropTypesSecret) {
// It is still safe when called from React.
return;
}
invariant(
false,
'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
'Use PropTypes.checkPropTypes() to call them. ' +
'Read more at http://fb.me/use-check-prop-types'
);
};
shim.isRequired = shim;
function getShim() {
return shim;
};
// Important!
// Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.
var ReactPropTypes = {
array: shim,
bool: shim,
func: shim,
number: shim,
object: shim,
string: shim,
symbol: shim,
any: shim,
arrayOf: getShim,
element: shim,
instanceOf: getShim,
node: shim,
objectOf: getShim,
oneOf: getShim,
oneOfType: getShim,
shape: getShim,
exact: getShim
};
ReactPropTypes.checkPropTypes = emptyFunction;
ReactPropTypes.PropTypes = ReactPropTypes;
return ReactPropTypes;
};
},{"./lib/ReactPropTypesSecret":5,"fbjs/lib/emptyFunction":6,"fbjs/lib/invariant":7}],3:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var emptyFunction = require('fbjs/lib/emptyFunction');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
var assign = require('object-assign');
var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
var checkPropTypes = require('./checkPropTypes');
module.exports = function(isValidElement, throwOnDirectAccess) {
/* global Symbol */
var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
/**
* Returns the iterator method function contained on the iterable object.
*
* Be sure to invoke the function with the iterable as context:
*
* var iteratorFn = getIteratorFn(myIterable);
* if (iteratorFn) {
* var iterator = iteratorFn.call(myIterable);
* ...
* }
*
* @param {?object} maybeIterable
* @return {?function}
*/
function getIteratorFn(maybeIterable) {
var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
if (typeof iteratorFn === 'function') {
return iteratorFn;
}
}
/**
* Collection of methods that allow declaration and validation of props that are
* supplied to React components. Example usage:
*
* var Props = require('ReactPropTypes');
* var MyArticle = React.createClass({
* propTypes: {
* // An optional string prop named "description".
* description: Props.string,
*
* // A required enum prop named "category".
* category: Props.oneOf(['News','Photos']).isRequired,
*
* // A prop named "dialog" that requires an instance of Dialog.
* dialog: Props.instanceOf(Dialog).isRequired
* },
* render: function() { ... }
* });
*
* A more formal specification of how these methods are used:
*
* type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
* decl := ReactPropTypes.{type}(.isRequired)?
*
* Each and every declaration produces a function with the same signature. This
* allows the creation of custom validation functions. For example:
*
* var MyLink = React.createClass({
* propTypes: {
* // An optional string or URI prop named "href".
* href: function(props, propName, componentName) {
* var propValue = props[propName];
* if (propValue != null && typeof propValue !== 'string' &&
* !(propValue instanceof URI)) {
* return new Error(
* 'Expected a string or an URI for ' + propName + ' in ' +
* componentName
* );
* }
* }
* },
* render: function() {...}
* });
*
* @internal
*/
var ANONYMOUS = '<<anonymous>>';
// Important!
// Keep this list in sync with production version in `./factoryWithThrowingShims.js`.
var ReactPropTypes = {
array: createPrimitiveTypeChecker('array'),
bool: createPrimitiveTypeChecker('boolean'),
func: createPrimitiveTypeChecker('function'),
number: createPrimitiveTypeChecker('number'),
object: createPrimitiveTypeChecker('object'),
string: createPrimitiveTypeChecker('string'),
symbol: createPrimitiveTypeChecker('symbol'),
any: createAnyTypeChecker(),
arrayOf: createArrayOfTypeChecker,
element: createElementTypeChecker(),
instanceOf: createInstanceTypeChecker,
node: createNodeChecker(),
objectOf: createObjectOfTypeChecker,
oneOf: createEnumTypeChecker,
oneOfType: createUnionTypeChecker,
shape: createShapeTypeChecker,
exact: createStrictShapeTypeChecker,
};
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
/*eslint-disable no-self-compare*/
function is(x, y) {
// SameValue algorithm
if (x === y) {
// Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return x !== 0 || 1 / x === 1 / y;
} else {
// Step 6.a: NaN == NaN
return x !== x && y !== y;
}
}
/*eslint-enable no-self-compare*/
/**
* We use an Error-like object for backward compatibility as people may call
* PropTypes directly and inspect their output. However, we don't use real
* Errors anymore. We don't inspect their stack anyway, and creating them
* is prohibitively expensive if they are created too often, such as what
* happens in oneOfType() for any type before the one that matched.
*/
function PropTypeError(message) {
this.message = message;
this.stack = '';
}
// Make `instanceof Error` still work for returned errors.
PropTypeError.prototype = Error.prototype;
function createChainableTypeChecker(validate) {
if ("development" !== 'production') {
var manualPropTypeCallCache = {};
var manualPropTypeWarningCount = 0;
}
function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
componentName = componentName || ANONYMOUS;
propFullName = propFullName || propName;
if (secret !== ReactPropTypesSecret) {
if (throwOnDirectAccess) {
// New behavior only for users of `prop-types` package
invariant(
false,
'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
'Use `PropTypes.checkPropTypes()` to call them. ' +
'Read more at http://fb.me/use-check-prop-types'
);
} else if ("development" !== 'production' && typeof console !== 'undefined') {
// Old behavior for people using React.PropTypes
var cacheKey = componentName + ':' + propName;
if (
!manualPropTypeCallCache[cacheKey] &&
// Avoid spamming the console because they are often not actionable except for lib authors
manualPropTypeWarningCount < 3
) {
warning(
false,
'You are manually calling a React.PropTypes validation ' +
'function for the `%s` prop on `%s`. This is deprecated ' +
'and will throw in the standalone `prop-types` package. ' +
'You may be seeing this warning due to a third-party PropTypes ' +
'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.',
propFullName,
componentName
);
manualPropTypeCallCache[cacheKey] = true;
manualPropTypeWarningCount++;
}
}
}
if (props[propName] == null) {
if (isRequired) {
if (props[propName] === null) {
return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
}
return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
}
return null;
} else {
return validate(props, propName, componentName, location, propFullName);
}
}
var chainedCheckType = checkType.bind(null, false);
chainedCheckType.isRequired = checkType.bind(null, true);
return chainedCheckType;
}
function createPrimitiveTypeChecker(expectedType) {
function validate(props, propName, componentName, location, propFullName, secret) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== expectedType) {
// `propValue` being instance of, say, date/regexp, pass the 'object'
// check, but we can offer a more precise error message here rather than
// 'of type `object`'.
var preciseType = getPreciseType(propValue);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createAnyTypeChecker() {
return createChainableTypeChecker(emptyFunction.thatReturnsNull);
}
function createArrayOfTypeChecker(typeChecker) {
function validate(props, propName, componentName, location, propFullName) {
if (typeof typeChecker !== 'function') {
return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.');
}
var propValue = props[propName];
if (!Array.isArray(propValue)) {
var propType = getPropType(propValue);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.'));
}
for (var i = 0; i < propValue.length; i++) {
var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret);
if (error instanceof Error) {
return error;
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function createElementTypeChecker() {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
if (!isValidElement(propValue)) {
var propType = getPropType(propValue);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createInstanceTypeChecker(expectedClass) {
function validate(props, propName, componentName, location, propFullName) {
if (!(props[propName] instanceof expectedClass)) {
var expectedClassName = expectedClass.name || ANONYMOUS;
var actualClassName = getClassName(props[propName]);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createEnumTypeChecker(expectedValues) {
if (!Array.isArray(expectedValues)) {
"development" !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0;
return emptyFunction.thatReturnsNull;
}
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
for (var i = 0; i < expectedValues.length; i++) {
if (is(propValue, expectedValues[i])) {
return null;
}
}
var valuesString = JSON.stringify(expectedValues);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
}
return createChainableTypeChecker(validate);
}
function createObjectOfTypeChecker(typeChecker) {
function validate(props, propName, componentName, location, propFullName) {
if (typeof typeChecker !== 'function') {
return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.');
}
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== 'object') {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.'));
}
for (var key in propValue) {
if (propValue.hasOwnProperty(key)) {
var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
if (error instanceof Error) {
return error;
}
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function createUnionTypeChecker(arrayOfTypeCheckers) {
if (!Array.isArray(arrayOfTypeCheckers)) {
"development" !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
return emptyFunction.thatReturnsNull;
}
for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
var checker = arrayOfTypeCheckers[i];
if (typeof checker !== 'function') {
warning(
false,
'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' +
'received %s at index %s.',
getPostfixForTypeWarning(checker),
i
);
return emptyFunction.thatReturnsNull;
}
}
function validate(props, propName, componentName, location, propFullName) {
for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
var checker = arrayOfTypeCheckers[i];
if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) {
return null;
}
}
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.'));
}
return createChainableTypeChecker(validate);
}
function createNodeChecker() {
function validate(props, propName, componentName, location, propFullName) {
if (!isNode(props[propName])) {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createShapeTypeChecker(shapeTypes) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== 'object') {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
}
for (var key in shapeTypes) {
var checker = shapeTypes[key];
if (!checker) {
continue;
}
var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
if (error) {
return error;
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function createStrictShapeTypeChecker(shapeTypes) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== 'object') {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
}
// We need to check all keys in case some are required but missing from
// props.
var allKeys = assign({}, props[propName], shapeTypes);
for (var key in allKeys) {
var checker = shapeTypes[key];
if (!checker) {
return new PropTypeError(
'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' +
'\nBad object: ' + JSON.stringify(props[propName], null, ' ') +
'\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ')
);
}
var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
if (error) {
return error;
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function isNode(propValue) {
switch (typeof propValue) {
case 'number':
case 'string':
case 'undefined':
return true;
case 'boolean':
return !propValue;
case 'object':
if (Array.isArray(propValue)) {
return propValue.every(isNode);
}
if (propValue === null || isValidElement(propValue)) {
return true;
}
var iteratorFn = getIteratorFn(propValue);
if (iteratorFn) {
var iterator = iteratorFn.call(propValue);
var step;
if (iteratorFn !== propValue.entries) {
while (!(step = iterator.next()).done) {
if (!isNode(step.value)) {
return false;
}
}
} else {
// Iterator will provide entry [k,v] tuples rather than values.
while (!(step = iterator.next()).done) {
var entry = step.value;
if (entry) {
if (!isNode(entry[1])) {
return false;
}
}
}
}
} else {
return false;
}
return true;
default:
return false;
}
}
function isSymbol(propType, propValue) {
// Native Symbol.
if (propType === 'symbol') {
return true;
}
// 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol'
if (propValue['@@toStringTag'] === 'Symbol') {
return true;
}
// Fallback for non-spec compliant Symbols which are polyfilled.
if (typeof Symbol === 'function' && propValue instanceof Symbol) {
return true;
}
return false;
}
// Equivalent of `typeof` but with special handling for array and regexp.
function getPropType(propValue) {
var propType = typeof propValue;
if (Array.isArray(propValue)) {
return 'array';
}
if (propValue instanceof RegExp) {
// Old webkits (at least until Android 4.0) return 'function' rather than
// 'object' for typeof a RegExp. We'll normalize this here so that /bla/
// passes PropTypes.object.
return 'object';
}
if (isSymbol(propType, propValue)) {
return 'symbol';
}
return propType;
}
// This handles more types than `getPropType`. Only used for error messages.
// See `createPrimitiveTypeChecker`.
function getPreciseType(propValue) {
if (typeof propValue === 'undefined' || propValue === null) {
return '' + propValue;
}
var propType = getPropType(propValue);
if (propType === 'object') {
if (propValue instanceof Date) {
return 'date';
} else if (propValue instanceof RegExp) {
return 'regexp';
}
}
return propType;
}
// Returns a string that is postfixed to a warning about an invalid type.
// For example, "undefined" or "of type array"
function getPostfixForTypeWarning(value) {
var type = getPreciseType(value);
switch (type) {
case 'array':
case 'object':
return 'an ' + type;
case 'boolean':
case 'date':
case 'regexp':
return 'a ' + type;
default:
return type;
}
}
// Returns class name of the object, if any.
function getClassName(propValue) {
if (!propValue.constructor || !propValue.constructor.name) {
return ANONYMOUS;
}
return propValue.constructor.name;
}
ReactPropTypes.checkPropTypes = checkPropTypes;
ReactPropTypes.PropTypes = ReactPropTypes;
return ReactPropTypes;
};
},{"./checkPropTypes":1,"./lib/ReactPropTypesSecret":5,"fbjs/lib/emptyFunction":6,"fbjs/lib/invariant":7,"fbjs/lib/warning":8,"object-assign":9}],4:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
if ("development" !== 'production') {
var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
Symbol.for &&
Symbol.for('react.element')) ||
0xeac7;
var isValidElement = function(object) {
return typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE;
};
// By explicitly using `prop-types` you are opting into new development behavior.
// http://fb.me/prop-types-in-prod
var throwOnDirectAccess = true;
module.exports = require('./factoryWithTypeCheckers')(isValidElement, throwOnDirectAccess);
} else {
// By explicitly using `prop-types` you are opting into new production behavior.
// http://fb.me/prop-types-in-prod
module.exports = require('./factoryWithThrowingShims')();
}
},{"./factoryWithThrowingShims":2,"./factoryWithTypeCheckers":3}],5:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
module.exports = ReactPropTypesSecret;
},{}],6:[function(require,module,exports){
"use strict";
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/
function makeEmptyFunction(arg) {
return function () {
return arg;
};
}
/**
* This function accepts and discards inputs; it has no side effects. This is
* primarily useful idiomatically for overridable function endpoints which
* always need to be callable, since JS lacks a null-call idiom ala Cocoa.
*/
var emptyFunction = function emptyFunction() {};
emptyFunction.thatReturns = makeEmptyFunction;
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
emptyFunction.thatReturnsThis = function () {
return this;
};
emptyFunction.thatReturnsArgument = function (arg) {
return arg;
};
module.exports = emptyFunction;
},{}],7:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
/**
* Use invariant() to assert state which your program assumes to be true.
*
* Provide sprintf-style format (only %s is supported) and arguments
* to provide information about what broke and what you were
* expecting.
*
* The invariant message will be stripped in production, but the invariant
* will remain to ensure logic does not differ in production.
*/
var validateFormat = function validateFormat(format) {};
if ("development" !== 'production') {
validateFormat = function validateFormat(format) {
if (format === undefined) {
throw new Error('invariant requires an error message argument');
}
};
}
function invariant(condition, format, a, b, c, d, e, f) {
validateFormat(format);
if (!condition) {
var error;
if (format === undefined) {
error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
} else {
var args = [a, b, c, d, e, f];
var argIndex = 0;
error = new Error(format.replace(/%s/g, function () {
return args[argIndex++];
}));
error.name = 'Invariant Violation';
}
error.framesToPop = 1; // we don't care about invariant's own frame
throw error;
}
}
module.exports = invariant;
},{}],8:[function(require,module,exports){
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
var emptyFunction = require('./emptyFunction');
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
* paths. Removing the logging code for production environments will keep the
* same logic and follow the same code paths.
*/
var warning = emptyFunction;
if ("development" !== 'production') {
var printWarning = function printWarning(format) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var argIndex = 0;
var message = 'Warning: ' + format.replace(/%s/g, function () {
return args[argIndex++];
});
if (typeof console !== 'undefined') {
console.error(message);
}
try {
// --- Welcome to debugging React ---
// This error was thrown as a convenience so that you can use this stack
// to find the callsite that caused this warning to fire.
throw new Error(message);
} catch (x) {}
};
warning = function warning(condition, format) {
if (format === undefined) {
throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
}
if (format.indexOf('Failed Composite propType: ') === 0) {
return; // Ignore CompositeComponent proptype check.
}
if (!condition) {
for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
args[_key2 - 2] = arguments[_key2];
}
printWarning.apply(undefined, [format].concat(args));
}
};
}
module.exports = warning;
},{"./emptyFunction":6}],9:[function(require,module,exports){
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
'use strict';
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};
},{}]},{},[4])(4)
});

960
devtools/client/shared/vendor/react-prop-types.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,960 @@
/**
* react-prop-types v15.6.0
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.PropTypes = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
if ("production" !== 'production') {
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
var loggedTypeFailures = {};
}
/**
* Assert that the values match with the type specs.
* Error messages are memorized and will only be shown once.
*
* @param {object} typeSpecs Map of name to a ReactPropType
* @param {object} values Runtime values that need to be type-checked
* @param {string} location e.g. "prop", "context", "child context"
* @param {string} componentName Name of the component for error messages.
* @param {?Function} getStack Returns the component stack.
* @private
*/
function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
if ("production" !== 'production') {
for (var typeSpecName in typeSpecs) {
if (typeSpecs.hasOwnProperty(typeSpecName)) {
var error;
// Prop type validation may throw. In case they do, we don't want to
// fail the render phase where it didn't fail before. So we log it.
// After these have been cleaned up, we'll let them throw.
try {
// This is intentionally an invariant that gets caught. It's the same
// behavior as without this statement except with a better message.
invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]);
error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
} catch (ex) {
error = ex;
}
warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error);
if (error instanceof Error && !(error.message in loggedTypeFailures)) {
// Only monitor this failure once because there tends to be a lot of the
// same error.
loggedTypeFailures[error.message] = true;
var stack = getStack ? getStack() : '';
warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : '');
}
}
}
}
}
module.exports = checkPropTypes;
},{"./lib/ReactPropTypesSecret":5,"fbjs/lib/invariant":7,"fbjs/lib/warning":8}],2:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var emptyFunction = require('fbjs/lib/emptyFunction');
var invariant = require('fbjs/lib/invariant');
var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
module.exports = function() {
function shim(props, propName, componentName, location, propFullName, secret) {
if (secret === ReactPropTypesSecret) {
// It is still safe when called from React.
return;
}
invariant(
false,
'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
'Use PropTypes.checkPropTypes() to call them. ' +
'Read more at http://fb.me/use-check-prop-types'
);
};
shim.isRequired = shim;
function getShim() {
return shim;
};
// Important!
// Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.
var ReactPropTypes = {
array: shim,
bool: shim,
func: shim,
number: shim,
object: shim,
string: shim,
symbol: shim,
any: shim,
arrayOf: getShim,
element: shim,
instanceOf: getShim,
node: shim,
objectOf: getShim,
oneOf: getShim,
oneOfType: getShim,
shape: getShim,
exact: getShim
};
ReactPropTypes.checkPropTypes = emptyFunction;
ReactPropTypes.PropTypes = ReactPropTypes;
return ReactPropTypes;
};
},{"./lib/ReactPropTypesSecret":5,"fbjs/lib/emptyFunction":6,"fbjs/lib/invariant":7}],3:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var emptyFunction = require('fbjs/lib/emptyFunction');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
var assign = require('object-assign');
var ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');
var checkPropTypes = require('./checkPropTypes');
module.exports = function(isValidElement, throwOnDirectAccess) {
/* global Symbol */
var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
/**
* Returns the iterator method function contained on the iterable object.
*
* Be sure to invoke the function with the iterable as context:
*
* var iteratorFn = getIteratorFn(myIterable);
* if (iteratorFn) {
* var iterator = iteratorFn.call(myIterable);
* ...
* }
*
* @param {?object} maybeIterable
* @return {?function}
*/
function getIteratorFn(maybeIterable) {
var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
if (typeof iteratorFn === 'function') {
return iteratorFn;
}
}
/**
* Collection of methods that allow declaration and validation of props that are
* supplied to React components. Example usage:
*
* var Props = require('ReactPropTypes');
* var MyArticle = React.createClass({
* propTypes: {
* // An optional string prop named "description".
* description: Props.string,
*
* // A required enum prop named "category".
* category: Props.oneOf(['News','Photos']).isRequired,
*
* // A prop named "dialog" that requires an instance of Dialog.
* dialog: Props.instanceOf(Dialog).isRequired
* },
* render: function() { ... }
* });
*
* A more formal specification of how these methods are used:
*
* type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
* decl := ReactPropTypes.{type}(.isRequired)?
*
* Each and every declaration produces a function with the same signature. This
* allows the creation of custom validation functions. For example:
*
* var MyLink = React.createClass({
* propTypes: {
* // An optional string or URI prop named "href".
* href: function(props, propName, componentName) {
* var propValue = props[propName];
* if (propValue != null && typeof propValue !== 'string' &&
* !(propValue instanceof URI)) {
* return new Error(
* 'Expected a string or an URI for ' + propName + ' in ' +
* componentName
* );
* }
* }
* },
* render: function() {...}
* });
*
* @internal
*/
var ANONYMOUS = '<<anonymous>>';
// Important!
// Keep this list in sync with production version in `./factoryWithThrowingShims.js`.
var ReactPropTypes = {
array: createPrimitiveTypeChecker('array'),
bool: createPrimitiveTypeChecker('boolean'),
func: createPrimitiveTypeChecker('function'),
number: createPrimitiveTypeChecker('number'),
object: createPrimitiveTypeChecker('object'),
string: createPrimitiveTypeChecker('string'),
symbol: createPrimitiveTypeChecker('symbol'),
any: createAnyTypeChecker(),
arrayOf: createArrayOfTypeChecker,
element: createElementTypeChecker(),
instanceOf: createInstanceTypeChecker,
node: createNodeChecker(),
objectOf: createObjectOfTypeChecker,
oneOf: createEnumTypeChecker,
oneOfType: createUnionTypeChecker,
shape: createShapeTypeChecker,
exact: createStrictShapeTypeChecker,
};
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
/*eslint-disable no-self-compare*/
function is(x, y) {
// SameValue algorithm
if (x === y) {
// Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return x !== 0 || 1 / x === 1 / y;
} else {
// Step 6.a: NaN == NaN
return x !== x && y !== y;
}
}
/*eslint-enable no-self-compare*/
/**
* We use an Error-like object for backward compatibility as people may call
* PropTypes directly and inspect their output. However, we don't use real
* Errors anymore. We don't inspect their stack anyway, and creating them
* is prohibitively expensive if they are created too often, such as what
* happens in oneOfType() for any type before the one that matched.
*/
function PropTypeError(message) {
this.message = message;
this.stack = '';
}
// Make `instanceof Error` still work for returned errors.
PropTypeError.prototype = Error.prototype;
function createChainableTypeChecker(validate) {
if ("production" !== 'production') {
var manualPropTypeCallCache = {};
var manualPropTypeWarningCount = 0;
}
function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
componentName = componentName || ANONYMOUS;
propFullName = propFullName || propName;
if (secret !== ReactPropTypesSecret) {
if (throwOnDirectAccess) {
// New behavior only for users of `prop-types` package
invariant(
false,
'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
'Use `PropTypes.checkPropTypes()` to call them. ' +
'Read more at http://fb.me/use-check-prop-types'
);
} else if ("production" !== 'production' && typeof console !== 'undefined') {
// Old behavior for people using React.PropTypes
var cacheKey = componentName + ':' + propName;
if (
!manualPropTypeCallCache[cacheKey] &&
// Avoid spamming the console because they are often not actionable except for lib authors
manualPropTypeWarningCount < 3
) {
warning(
false,
'You are manually calling a React.PropTypes validation ' +
'function for the `%s` prop on `%s`. This is deprecated ' +
'and will throw in the standalone `prop-types` package. ' +
'You may be seeing this warning due to a third-party PropTypes ' +
'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.',
propFullName,
componentName
);
manualPropTypeCallCache[cacheKey] = true;
manualPropTypeWarningCount++;
}
}
}
if (props[propName] == null) {
if (isRequired) {
if (props[propName] === null) {
return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
}
return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
}
return null;
} else {
return validate(props, propName, componentName, location, propFullName);
}
}
var chainedCheckType = checkType.bind(null, false);
chainedCheckType.isRequired = checkType.bind(null, true);
return chainedCheckType;
}
function createPrimitiveTypeChecker(expectedType) {
function validate(props, propName, componentName, location, propFullName, secret) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== expectedType) {
// `propValue` being instance of, say, date/regexp, pass the 'object'
// check, but we can offer a more precise error message here rather than
// 'of type `object`'.
var preciseType = getPreciseType(propValue);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createAnyTypeChecker() {
return createChainableTypeChecker(emptyFunction.thatReturnsNull);
}
function createArrayOfTypeChecker(typeChecker) {
function validate(props, propName, componentName, location, propFullName) {
if (typeof typeChecker !== 'function') {
return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.');
}
var propValue = props[propName];
if (!Array.isArray(propValue)) {
var propType = getPropType(propValue);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.'));
}
for (var i = 0; i < propValue.length; i++) {
var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret);
if (error instanceof Error) {
return error;
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function createElementTypeChecker() {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
if (!isValidElement(propValue)) {
var propType = getPropType(propValue);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createInstanceTypeChecker(expectedClass) {
function validate(props, propName, componentName, location, propFullName) {
if (!(props[propName] instanceof expectedClass)) {
var expectedClassName = expectedClass.name || ANONYMOUS;
var actualClassName = getClassName(props[propName]);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createEnumTypeChecker(expectedValues) {
if (!Array.isArray(expectedValues)) {
"production" !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0;
return emptyFunction.thatReturnsNull;
}
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
for (var i = 0; i < expectedValues.length; i++) {
if (is(propValue, expectedValues[i])) {
return null;
}
}
var valuesString = JSON.stringify(expectedValues);
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
}
return createChainableTypeChecker(validate);
}
function createObjectOfTypeChecker(typeChecker) {
function validate(props, propName, componentName, location, propFullName) {
if (typeof typeChecker !== 'function') {
return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.');
}
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== 'object') {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.'));
}
for (var key in propValue) {
if (propValue.hasOwnProperty(key)) {
var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
if (error instanceof Error) {
return error;
}
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function createUnionTypeChecker(arrayOfTypeCheckers) {
if (!Array.isArray(arrayOfTypeCheckers)) {
"production" !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
return emptyFunction.thatReturnsNull;
}
for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
var checker = arrayOfTypeCheckers[i];
if (typeof checker !== 'function') {
warning(
false,
'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' +
'received %s at index %s.',
getPostfixForTypeWarning(checker),
i
);
return emptyFunction.thatReturnsNull;
}
}
function validate(props, propName, componentName, location, propFullName) {
for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
var checker = arrayOfTypeCheckers[i];
if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) {
return null;
}
}
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.'));
}
return createChainableTypeChecker(validate);
}
function createNodeChecker() {
function validate(props, propName, componentName, location, propFullName) {
if (!isNode(props[propName])) {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.'));
}
return null;
}
return createChainableTypeChecker(validate);
}
function createShapeTypeChecker(shapeTypes) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== 'object') {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
}
for (var key in shapeTypes) {
var checker = shapeTypes[key];
if (!checker) {
continue;
}
var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
if (error) {
return error;
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function createStrictShapeTypeChecker(shapeTypes) {
function validate(props, propName, componentName, location, propFullName) {
var propValue = props[propName];
var propType = getPropType(propValue);
if (propType !== 'object') {
return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
}
// We need to check all keys in case some are required but missing from
// props.
var allKeys = assign({}, props[propName], shapeTypes);
for (var key in allKeys) {
var checker = shapeTypes[key];
if (!checker) {
return new PropTypeError(
'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' +
'\nBad object: ' + JSON.stringify(props[propName], null, ' ') +
'\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ')
);
}
var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
if (error) {
return error;
}
}
return null;
}
return createChainableTypeChecker(validate);
}
function isNode(propValue) {
switch (typeof propValue) {
case 'number':
case 'string':
case 'undefined':
return true;
case 'boolean':
return !propValue;
case 'object':
if (Array.isArray(propValue)) {
return propValue.every(isNode);
}
if (propValue === null || isValidElement(propValue)) {
return true;
}
var iteratorFn = getIteratorFn(propValue);
if (iteratorFn) {
var iterator = iteratorFn.call(propValue);
var step;
if (iteratorFn !== propValue.entries) {
while (!(step = iterator.next()).done) {
if (!isNode(step.value)) {
return false;
}
}
} else {
// Iterator will provide entry [k,v] tuples rather than values.
while (!(step = iterator.next()).done) {
var entry = step.value;
if (entry) {
if (!isNode(entry[1])) {
return false;
}
}
}
}
} else {
return false;
}
return true;
default:
return false;
}
}
function isSymbol(propType, propValue) {
// Native Symbol.
if (propType === 'symbol') {
return true;
}
// 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol'
if (propValue['@@toStringTag'] === 'Symbol') {
return true;
}
// Fallback for non-spec compliant Symbols which are polyfilled.
if (typeof Symbol === 'function' && propValue instanceof Symbol) {
return true;
}
return false;
}
// Equivalent of `typeof` but with special handling for array and regexp.
function getPropType(propValue) {
var propType = typeof propValue;
if (Array.isArray(propValue)) {
return 'array';
}
if (propValue instanceof RegExp) {
// Old webkits (at least until Android 4.0) return 'function' rather than
// 'object' for typeof a RegExp. We'll normalize this here so that /bla/
// passes PropTypes.object.
return 'object';
}
if (isSymbol(propType, propValue)) {
return 'symbol';
}
return propType;
}
// This handles more types than `getPropType`. Only used for error messages.
// See `createPrimitiveTypeChecker`.
function getPreciseType(propValue) {
if (typeof propValue === 'undefined' || propValue === null) {
return '' + propValue;
}
var propType = getPropType(propValue);
if (propType === 'object') {
if (propValue instanceof Date) {
return 'date';
} else if (propValue instanceof RegExp) {
return 'regexp';
}
}
return propType;
}
// Returns a string that is postfixed to a warning about an invalid type.
// For example, "undefined" or "of type array"
function getPostfixForTypeWarning(value) {
var type = getPreciseType(value);
switch (type) {
case 'array':
case 'object':
return 'an ' + type;
case 'boolean':
case 'date':
case 'regexp':
return 'a ' + type;
default:
return type;
}
}
// Returns class name of the object, if any.
function getClassName(propValue) {
if (!propValue.constructor || !propValue.constructor.name) {
return ANONYMOUS;
}
return propValue.constructor.name;
}
ReactPropTypes.checkPropTypes = checkPropTypes;
ReactPropTypes.PropTypes = ReactPropTypes;
return ReactPropTypes;
};
},{"./checkPropTypes":1,"./lib/ReactPropTypesSecret":5,"fbjs/lib/emptyFunction":6,"fbjs/lib/invariant":7,"fbjs/lib/warning":8,"object-assign":9}],4:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
if ("production" !== 'production') {
var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
Symbol.for &&
Symbol.for('react.element')) ||
0xeac7;
var isValidElement = function(object) {
return typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE;
};
// By explicitly using `prop-types` you are opting into new development behavior.
// http://fb.me/prop-types-in-prod
var throwOnDirectAccess = true;
module.exports = require('./factoryWithTypeCheckers')(isValidElement, throwOnDirectAccess);
} else {
// By explicitly using `prop-types` you are opting into new production behavior.
// http://fb.me/prop-types-in-prod
module.exports = require('./factoryWithThrowingShims')();
}
},{"./factoryWithThrowingShims":2,"./factoryWithTypeCheckers":3}],5:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
module.exports = ReactPropTypesSecret;
},{}],6:[function(require,module,exports){
"use strict";
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/
function makeEmptyFunction(arg) {
return function () {
return arg;
};
}
/**
* This function accepts and discards inputs; it has no side effects. This is
* primarily useful idiomatically for overridable function endpoints which
* always need to be callable, since JS lacks a null-call idiom ala Cocoa.
*/
var emptyFunction = function emptyFunction() {};
emptyFunction.thatReturns = makeEmptyFunction;
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
emptyFunction.thatReturnsThis = function () {
return this;
};
emptyFunction.thatReturnsArgument = function (arg) {
return arg;
};
module.exports = emptyFunction;
},{}],7:[function(require,module,exports){
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
/**
* Use invariant() to assert state which your program assumes to be true.
*
* Provide sprintf-style format (only %s is supported) and arguments
* to provide information about what broke and what you were
* expecting.
*
* The invariant message will be stripped in production, but the invariant
* will remain to ensure logic does not differ in production.
*/
var validateFormat = function validateFormat(format) {};
if ("production" !== 'production') {
validateFormat = function validateFormat(format) {
if (format === undefined) {
throw new Error('invariant requires an error message argument');
}
};
}
function invariant(condition, format, a, b, c, d, e, f) {
validateFormat(format);
if (!condition) {
var error;
if (format === undefined) {
error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
} else {
var args = [a, b, c, d, e, f];
var argIndex = 0;
error = new Error(format.replace(/%s/g, function () {
return args[argIndex++];
}));
error.name = 'Invariant Violation';
}
error.framesToPop = 1; // we don't care about invariant's own frame
throw error;
}
}
module.exports = invariant;
},{}],8:[function(require,module,exports){
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
var emptyFunction = require('./emptyFunction');
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
* paths. Removing the logging code for production environments will keep the
* same logic and follow the same code paths.
*/
var warning = emptyFunction;
if ("production" !== 'production') {
var printWarning = function printWarning(format) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var argIndex = 0;
var message = 'Warning: ' + format.replace(/%s/g, function () {
return args[argIndex++];
});
if (typeof console !== 'undefined') {
console.error(message);
}
try {
// --- Welcome to debugging React ---
// This error was thrown as a convenience so that you can use this stack
// to find the callsite that caused this warning to fire.
throw new Error(message);
} catch (x) {}
};
warning = function warning(condition, format) {
if (format === undefined) {
throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
}
if (format.indexOf('Failed Composite propType: ') === 0) {
return; // Ignore CompositeComponent proptype check.
}
if (!condition) {
for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
args[_key2 - 2] = arguments[_key2];
}
printWarning.apply(undefined, [format].concat(args));
}
};
}
module.exports = warning;
},{"./emptyFunction":6}],9:[function(require,module,exports){
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
'use strict';
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};
},{}]},{},[4])(4)
});

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

@ -827,9 +827,9 @@ a.learn-more-link.webconsole-learn-more-link {
.webconsole-filterbar-primary {
display: flex;
/* We want the toolbar (which contain the text search input) to be at least 200px
so we don't allow to shrink it */
flex: 100 0 200px;
/* We want the toolbar (which contain the text search input) to fit
the content, we don't allow to shrink/overlap it */
flex: 100 0 -moz-fit-content;
align-items: center;
min-height: var(--primary-toolbar-height);
}
@ -865,6 +865,7 @@ a.learn-more-link.webconsole-learn-more-link {
text-align: end;
align-items: center;
min-height: var(--primary-toolbar-height);
line-height: var(--primary-toolbar-height);
}
.webconsole-filterbar-filtered-messages .filter-message-text {

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

@ -203,6 +203,7 @@ skip-if = true # Bug 1403188
[browser_jsterm_autocomplete_escape_key.js]
[browser_jsterm_autocomplete_extraneous_closing_brackets.js]
[browser_jsterm_autocomplete_helpers.js]
[browser_jsterm_autocomplete_in_chrome_tab.js]
[browser_jsterm_autocomplete_in_debugger_stackframe.js]
[browser_jsterm_autocomplete_inside_text.js]
[browser_jsterm_autocomplete_nav_and_tab_key.js]
@ -223,23 +224,15 @@ subsuite = clipboard
[browser_netmonitor_shows_reqs_in_webconsole.js]
[browser_webconsole_allow_mixedcontent_securityerrors.js]
tags = mcb
skip-if = true # Bug 1403452
# old console skip-if = (os == 'win' && bits == 64) # Bug 1390001
[browser_webconsole_batching.js]
[browser_webconsole_block_mixedcontent_securityerrors.js]
tags = mcb
skip-if = true # Bug 1403899
# old console skip-if = (os == 'win' && bits == 64) # Bug 1390001
[browser_webconsole_cached_messages.js]
[browser_webconsole_cd_iframe.js]
skip-if = true # Bug 1406030
[browser_webconsole_certificate_messages.js]
skip-if = true # Bug 1408925
# old console skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
[browser_webconsole_charset.js]
skip-if = true # Bug 1404400
[browser_webconsole_chrome.js]
skip-if = true # Bug 1408926
[browser_webconsole_click_function_to_source.js]
skip-if = true # Bug 1406038
[browser_webconsole_clickable_urls.js]

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

@ -0,0 +1,22 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that code completion works properly in chrome tabs, like about:config.
"use strict";
add_task(async function () {
const hud = await openNewTabAndConsole("about:config");
ok(hud, "we have a console");
ok(hud.iframeWindow, "we have the console UI window");
const {jsterm} = hud;
ok(jsterm, "we have a jsterm");
ok(hud.outputNode, "we have an output node");
// Test typing 'docu'.
await jstermSetValueAndComplete(jsterm, "docu");
is(jsterm.completeNode.value, " ment", "'docu' completion");
});

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

@ -14,56 +14,37 @@
"use strict";
const TEST_URI = "https://example.com/browser/devtools/client/webconsole/" +
"test/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Web/Security/" +
"Mixed_content" + DOCS_GA_PARAMS;
"new-console-output/test/mochitest/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI =
"https://developer.mozilla.org/docs/Web/Security/Mixed_content" + DOCS_GA_PARAMS;
add_task(function* () {
yield pushPrefEnv();
add_task(async function () {
await Promise.all([
pushPref("security.mixed_content.block_active_content", false),
pushPref("security.mixed_content.block_display_content", false),
]);
yield loadTab(TEST_URI);
const hud = await openNewTabAndConsole(TEST_URI);
let hud = yield openConsole();
const activeContentText = "Loading mixed (insecure) active content " +
"\u201chttp://example.com/\u201d on a secure page";
const displayContentText = "Loading mixed (insecure) display content " +
"\u201chttp://example.com/tests/image/test/mochitest/blue.png\u201d on a secure page";
let results = yield waitForMessages({
webconsole: hud,
messages: [
{
name: "Logged mixed active content",
text: "Loading mixed (insecure) active content " +
"\u201chttp://example.com/\u201d on a secure page",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING,
objects: true,
},
{
name: "Logged mixed passive content - image",
text: "Loading mixed (insecure) display content " +
"\u201chttp://example.com/tests/image/test/mochitest/blue.png\u201d " +
"on a secure page",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING,
objects: true,
},
],
});
const waitUntilWarningMessage = text =>
waitFor(() => findMessage(hud, text, ".message.warn"), undefined, 100);
yield testClickOpenNewTab(hud, results);
const onMixedActiveContent = waitUntilWarningMessage(activeContentText);
const onMixedDisplayContent = waitUntilWarningMessage(displayContentText);
await onMixedDisplayContent;
ok(true, "Mixed display content warning message is visible");
const mixedActiveContentMessage = await onMixedActiveContent;
ok(true, "Mixed active content warning message is visible");
info("Clicking on the Learn More link");
const learnMoreLink = mixedActiveContentMessage.querySelector(".learn-more-link");
const url = await simulateLinkClick(learnMoreLink);
is(url, LEARN_MORE_URI, `Clicking the provided link opens ${url}`);
});
function pushPrefEnv() {
let deferred = defer();
let options = {"set":
[["security.mixed_content.block_active_content", false],
["security.mixed_content.block_display_content", false]
]};
SpecialPowers.pushPrefEnv(options, deferred.resolve);
return deferred.promise;
}
function testClickOpenNewTab(hud, results) {
let warningNode = results[0].clickableElements[0];
ok(warningNode, "link element");
ok(warningNode.classList.contains("learn-more-link"), "link class name");
return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
}

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

@ -12,99 +12,79 @@
// by clicking on the doorhanger shield and validates that the
// appropriate messages are logged to console.
// Bug 875456 - Log mixed content messages from the Mixed Content
// Blocker to the Security Pane in the Web Console
// Blocker to the Security Pane in the Web Console.
"use strict";
const TEST_URI = "https://example.com/browser/devtools/client/webconsole/" +
"test/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI = "https://developer.mozilla.org/docs/Web/Security/" +
"Mixed_content" + DOCS_GA_PARAMS;
"new-console-output/test/mochitest/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI =
"https://developer.mozilla.org/docs/Web/Security/Mixed_content" + DOCS_GA_PARAMS;
add_task(function* () {
yield pushPrefEnv();
const blockedActiveContentText = "Blocked loading mixed active content " +
"\u201chttp://example.com/\u201d";
const blockedDisplayContentText = "Blocked loading mixed display content " +
"\u201chttp://example.com/tests/image/test/mochitest/blue.png\u201d";
const activeContentText = "Loading mixed (insecure) active content " +
"\u201chttp://example.com/\u201d on a secure page";
const displayContentText = "Loading mixed (insecure) display content " +
"\u201chttp://example.com/tests/image/test/mochitest/blue.png\u201d on a secure page";
let { browser } = yield loadTab(TEST_URI);
add_task(async function() {
await pushPrefEnv();
let hud = yield openConsole();
const hud = await openNewTabAndConsole(TEST_URI);
let results = yield waitForMessages({
webconsole: hud,
messages: [
{
name: "Logged blocking mixed active content",
text: "Blocked loading mixed active content \u201chttp://example.com/\u201d",
category: CATEGORY_SECURITY,
severity: SEVERITY_ERROR,
objects: true,
},
{
name: "Logged blocking mixed passive content - image",
text: "Blocked loading mixed active content \u201chttp://example.com/\u201d",
category: CATEGORY_SECURITY,
severity: SEVERITY_ERROR,
objects: true,
},
],
});
const waitForErrorMessage = text =>
waitFor(() => findMessage(hud, text, ".message.error"), undefined, 100);
yield testClickOpenNewTab(hud, results[0]);
const onBlockedIframe = waitForErrorMessage(blockedActiveContentText);
const onBlockedImage = waitForErrorMessage(blockedDisplayContentText);
let results2 = yield mixedContentOverrideTest2(hud, browser);
await onBlockedImage;
ok(true, "Blocked mixed display content error message is visible");
yield testClickOpenNewTab(hud, results2[0]);
const blockedMixedActiveContentMessage = await onBlockedIframe;
ok(true, "Blocked mixed active content error message is visible");
info("Clicking on the Learn More link");
let learnMoreLink = blockedMixedActiveContentMessage.querySelector(".learn-more-link");
let url = await simulateLinkClick(learnMoreLink);
is(url, LEARN_MORE_URI, `Clicking the provided link opens ${url}`);
info("Test disabling mixed content protection");
let {gIdentityHandler} = gBrowser.ownerGlobal;
ok(gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
"Mixed Active Content state appeared on identity box");
// Disabe mixed content protection.
gIdentityHandler.disableMixedContentProtection();
const waitForWarningMessage = text =>
waitFor(() => findMessage(hud, text, ".message.warn"), undefined, 100);
const onMixedActiveContent = waitForWarningMessage(activeContentText);
const onMixedDisplayContent = waitForWarningMessage(displayContentText);
await onMixedDisplayContent;
ok(true, "Mixed display content warning message is visible");
const mixedActiveContentMessage = await onMixedActiveContent;
ok(true, "Mixed active content warning message is visible");
info("Clicking on the Learn More link");
learnMoreLink = mixedActiveContentMessage.querySelector(".learn-more-link");
url = await simulateLinkClick(learnMoreLink);
is(url, LEARN_MORE_URI, `Clicking the provided link opens ${url}`);
});
function pushPrefEnv() {
let deferred = defer();
let options = {
"set": [
["security.mixed_content.block_active_content", true],
["security.mixed_content.block_display_content", true],
["security.mixed_content.use_hsts", false],
["security.mixed_content.send_hsts_priming", false],
]
};
SpecialPowers.pushPrefEnv(options, deferred.resolve);
return deferred.promise;
}
function mixedContentOverrideTest2(hud, browser) {
let deferred = defer();
let {gIdentityHandler} = browser.ownerGlobal;
ok(gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
"Mixed Active Content state appeared on identity box");
gIdentityHandler.disableMixedContentProtection();
waitForMessages({
webconsole: hud,
messages: [
{
name: "Logged blocking mixed active content",
text: "Loading mixed (insecure) active content " +
"\u201chttp://example.com/\u201d on a secure page",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING,
objects: true,
},
{
name: "Logged blocking mixed passive content - image",
text: "Loading mixed (insecure) display content" +
" \u201chttp://example.com/tests/image/test/mochitest/blue.png\u201d" +
" on a secure page",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING,
objects: true,
},
],
}).then(msgs => deferred.resolve(msgs), console.error);
return deferred.promise;
}
function testClickOpenNewTab(hud, match) {
let warningNode = match.clickableElements[0];
ok(warningNode, "link element");
ok(warningNode.classList.contains("learn-more-link"), "link class name");
return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
const prefs = [
["security.mixed_content.block_active_content", true],
["security.mixed_content.block_display_content", true],
["security.mixed_content.use_hsts", false],
["security.mixed_content.send_hsts_priming", false],
];
return Promise.all(prefs.map(([pref, value]) => pushPref(pref, value)));
}

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

@ -7,75 +7,39 @@
"use strict";
const TEST_URI = "data:text/html;charset=utf8,Web Console weak crypto " +
"warnings test";
const TEST_URI_PATH = "/browser/devtools/client/webconsole/test/" +
"test-certificate-messages.html";
const TEST_URI = "data:text/html;charset=utf8,Web Console weak crypto warnings test";
const TEST_URI_PATH = "/browser/devtools/client/webconsole/new-console-output/test/" +
"mochitest/test-certificate-messages.html";
var gWebconsoleTests = [
{url: "https://sha1ee.example.com" + TEST_URI_PATH,
name: "SHA1 warning displayed successfully",
warning: ["SHA-1"], nowarning: ["SSL 3.0", "RC4"]},
{url: "https://sha256ee.example.com" + TEST_URI_PATH,
name: "SSL warnings appropriately not present",
warning: [], nowarning: ["SHA-1", "SSL 3.0", "RC4"]},
];
const SHA1_URL = "https://sha1ee.example.com" + TEST_URI_PATH;
const SHA256_URL = "https://sha256ee.example.com" + TEST_URI_PATH;
const TRIGGER_MSG = "If you haven't seen ssl warnings yet, you won't";
var gHud = undefined, gContentBrowser;
var gCurrentTest;
const cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
.getService(Ci.nsICacheStorageService);
function test() {
registerCleanupFunction(function () {
gHud = gContentBrowser = null;
});
add_task(async function () {
const hud = await openNewTabAndConsole(TEST_URI);
loadTab(TEST_URI).then(({browser}) => {
gContentBrowser = browser;
openConsole().then(runTestLoop);
});
}
info("Test SHA1 warnings");
let onContentLog = waitForMessage(hud, TRIGGER_MSG);
let onSha1Warning = waitForMessage(hud, "SHA-1");
await loadDocument(SHA1_URL);
await Promise.all([onContentLog, onSha1Warning]);
function runTestLoop(theHud) {
gCurrentTest = gWebconsoleTests.shift();
if (!gCurrentTest) {
finishTest();
return;
}
if (!gHud) {
gHud = theHud;
}
gHud.jsterm.clearOutput();
gContentBrowser.addEventListener("load", onLoad, true);
if (gCurrentTest.pref) {
SpecialPowers.pushPrefEnv({"set": gCurrentTest.pref},
function () {
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, gCurrentTest.url);
});
} else {
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, gCurrentTest.url);
}
}
let {textContent} = hud.outputNode;
ok(!textContent.includes("SSL 3.0"), "There is no warning message for SSL 3.0");
ok(!textContent.includes("RC4"), "There is no warning message for RC4");
function onLoad() {
gContentBrowser.removeEventListener("load", onLoad, true);
info("Test SSL warnings appropriately not present");
onContentLog = waitForMessage(hud, TRIGGER_MSG);
await loadDocument(SHA256_URL);
await onContentLog;
waitForSuccess({
name: gCurrentTest.name,
validator: function () {
if (gHud.outputNode.textContent.indexOf(TRIGGER_MSG) >= 0) {
for (let warning of gCurrentTest.warning) {
if (gHud.outputNode.textContent.indexOf(warning) < 0) {
return false;
}
}
for (let nowarning of gCurrentTest.nowarning) {
if (gHud.outputNode.textContent.indexOf(nowarning) >= 0) {
return false;
}
}
return true;
}
}
}).then(runTestLoop);
}
textContent = hud.outputNode.textContent;
ok(!textContent.includes("SHA-1"), "There is no warning message for SHA-1");
ok(!textContent.includes("SSL 3.0"), "There is no warning message for SSL 3.0");
ok(!textContent.includes("RC4"), "There is no warning message for RC4");
cache.clear();
});

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

@ -1,38 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that code completion works properly in chrome tabs, like about:credits.
"use strict";
function test() {
Task.spawn(function* () {
const {tab} = yield loadTab("about:config");
ok(tab, "tab loaded");
const hud = yield openConsole(tab);
ok(hud, "we have a console");
ok(hud.iframeWindow, "we have the console UI window");
let jsterm = hud.jsterm;
ok(jsterm, "we have a jsterm");
let input = jsterm.inputNode;
ok(hud.outputNode, "we have an output node");
// Test typing 'docu'.
input.value = "docu";
input.setSelectionRange(4, 4);
let deferred = defer();
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, function () {
is(jsterm.completeNode.value, " ment", "'docu' completion");
deferred.resolve(null);
});
yield deferred.promise;
}).then(finishTest);
}

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

@ -3,10 +3,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from ../../../../framework/test/shared-head.js */
/* exported WCUL10n, openNewTabAndConsole, waitForMessages, waitForMessage, waitFor,
findMessage, openContextMenu, hideContextMenu, loadDocument, hasFocus,
waitForNodeMutation, testOpenInDebugger, checkClickOnNode, jstermSetValueAndComplete,
openDebugger, openConsole */
/* eslint no-unused-vars: [2, {"vars": "local"}] */
"use strict";
@ -18,6 +15,9 @@ Services.scriptloader.loadSubScript(
var {HUDService} = require("devtools/client/webconsole/hudservice");
var WCUL10n = require("devtools/client/webconsole/webconsole-l10n");
const DOCS_GA_PARAMS = "?utm_source=mozilla" +
"&utm_medium=firefox-console-errors" +
"&utm_campaign=default";
Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", true);
registerCleanupFunction(function* () {
@ -209,7 +209,7 @@ function hideContextMenu(hud) {
function loadDocument(url, browser = gBrowser.selectedBrowser) {
return new Promise(resolve => {
browser.addEventListener("load", resolve, {capture: true, once: true});
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
BrowserTestUtils.loadURI(browser, url);
});
}
@ -363,4 +363,28 @@ async function openConsole(tab) {
let target = TargetFactory.forTab(tab || gBrowser.selectedTab);
const toolbox = await gDevTools.showToolbox(target, "webconsole");
return toolbox.getCurrentPanel().hud;
};
}
/**
* Fake clicking a link and return the URL we would have navigated to.
* This function should be used to check external links since we can't access
* network in tests.
*
* @param ElementNode element
* The <a> element we want to simulate click on.
* @returns Promise
* A Promise that resolved when the link clik simulation occured.
*/
function simulateLinkClick(element) {
return new Promise((resolve) => {
// Override openUILinkIn to prevent navigating.
let oldOpenUILinkIn = window.openUILinkIn;
window.openUILinkIn = function (link) {
window.openUILinkIn = oldOpenUILinkIn;
resolve(link);
};
// Click on the link.
element.click();
});
}

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

@ -314,9 +314,6 @@ DevToolsStartup.prototype = {
viewId: "PanelUI-developer",
shortcutId: "key_toggleToolbox",
tooltiptext: "developer-button.tooltiptext2",
defaultArea: AppConstants.MOZ_DEV_EDITION ?
CustomizableUI.AREA_NAVBAR :
CustomizableUI.AREA_PANEL,
onViewShowing: (event) => {
if (Services.prefs.getBoolPref(DEVTOOLS_ENABLED_PREF)) {
// If DevTools are enabled, initialize DevTools to create all menuitems in the
@ -361,6 +358,9 @@ DevToolsStartup.prototype = {
doc.getElementById("PanelUI-multiView").appendChild(view);
}
};
if (AppConstants.MOZ_DEV_EDITION) {
item.defaultArea = CustomizableUI.AREA_NAVBAR;
}
CustomizableUI.createWidget(item);
CustomizableWidgets.push(item);
},

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

@ -1928,8 +1928,8 @@ KeyframeEffectReadOnly::ContainsAnimatedScale(const nsIFrame* aFrame) const
// here just to be safe.
return true;
}
gfxSize size = baseStyle.GetScaleValue(aFrame);
if (size != gfxSize(1.0f, 1.0f)) {
gfx::Size size = baseStyle.GetScaleValue(aFrame);
if (size != gfx::Size(1.0f, 1.0f)) {
return true;
}
@ -1938,14 +1938,14 @@ KeyframeEffectReadOnly::ContainsAnimatedScale(const nsIFrame* aFrame) const
// really matter.
for (const AnimationPropertySegment& segment : prop.mSegments) {
if (!segment.mFromValue.IsNull()) {
gfxSize from = segment.mFromValue.GetScaleValue(aFrame);
if (from != gfxSize(1.0f, 1.0f)) {
gfx::Size from = segment.mFromValue.GetScaleValue(aFrame);
if (from != gfx::Size(1.0f, 1.0f)) {
return true;
}
}
if (!segment.mToValue.IsNull()) {
gfxSize to = segment.mToValue.GetScaleValue(aFrame);
if (to != gfxSize(1.0f, 1.0f)) {
gfx::Size to = segment.mToValue.GetScaleValue(aFrame);
if (to != gfx::Size(1.0f, 1.0f)) {
return true;
}
}

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ResponsiveImageSelector.h"
#include "mozilla/ServoStyleSet.h"
#include "nsIURI.h"
#include "nsIDocument.h"
#include "nsContentUtils.h"
@ -241,11 +242,18 @@ bool
ResponsiveImageSelector::SetSizesFromDescriptor(const nsAString & aSizes)
{
ClearSelectedCandidate();
mSizeQueries.Clear();
mSizeValues.Clear();
if (Document()->IsStyledByServo()) {
NS_ConvertUTF16toUTF8 sizes(aSizes);
mServoSourceSizeList.reset(Servo_SourceSizeList_Parse(&sizes));
return !!mServoSourceSizeList;
}
nsCSSParser cssParser;
mSizeQueries.Clear();
mSizeValues.Clear();
return cssParser.ParseSourceSizeList(aSizes, nullptr, 0,
mSizeQueries, mSizeValues);
}
@ -364,11 +372,11 @@ ResponsiveImageSelector::SelectImage(bool aReselect)
}
nsIDocument* doc = Document();
nsIPresShell *shell = doc ? doc->GetShell() : nullptr;
nsPresContext *pctx = shell ? shell->GetPresContext() : nullptr;
nsCOMPtr<nsIURI> baseURI = mOwnerNode ? mOwnerNode->GetBaseURI() : nullptr;
nsIPresShell* shell = doc->GetShell();
nsPresContext* pctx = shell ? shell->GetPresContext() : nullptr;
nsCOMPtr<nsIURI> baseURI = mOwnerNode->GetBaseURI();
if (!pctx || !doc || !baseURI) {
if (!pctx || !baseURI) {
return oldBest != -1;
}
@ -388,7 +396,7 @@ ResponsiveImageSelector::SelectImage(bool aReselect)
double computedWidth = -1;
for (int i = 0; i < numCandidates; i++) {
if (mCandidates[i].IsComputedFromWidth()) {
DebugOnly<bool> computeResult = \
DebugOnly<bool> computeResult =
ComputeFinalWidthForCurrentViewport(&computedWidth);
MOZ_ASSERT(computeResult,
"Computed candidates not allowed without sizes data");
@ -439,34 +447,38 @@ ResponsiveImageSelector::GetSelectedCandidateIndex()
bool
ResponsiveImageSelector::ComputeFinalWidthForCurrentViewport(double *aWidth)
{
unsigned int numSizes = mSizeQueries.Length();
nsIDocument* doc = Document();
nsIPresShell *presShell = doc ? doc->GetShell() : nullptr;
nsPresContext *pctx = presShell ? presShell->GetPresContext() : nullptr;
nsIPresShell* presShell = doc->GetShell();
nsPresContext* pctx = presShell ? presShell->GetPresContext() : nullptr;
if (!pctx) {
return false;
}
MOZ_ASSERT(numSizes == mSizeValues.Length(),
"mSizeValues length differs from mSizeQueries");
unsigned int i;
for (i = 0; i < numSizes; i++) {
if (mSizeQueries[i]->Matches(pctx, nullptr)) {
break;
}
}
nscoord effectiveWidth;
if (i == numSizes) {
// No match defaults to 100% viewport
nsCSSValue defaultWidth(100.0f, eCSSUnit_ViewportWidth);
effectiveWidth = nsRuleNode::CalcLengthWithInitialFont(pctx,
defaultWidth);
if (doc->IsStyledByServo()) {
effectiveWidth = presShell->StyleSet()->AsServo()->EvaluateSourceSizeList(
mServoSourceSizeList.get());
} else {
effectiveWidth = nsRuleNode::CalcLengthWithInitialFont(pctx,
mSizeValues[i]);
unsigned int numSizes = mSizeQueries.Length();
MOZ_ASSERT(numSizes == mSizeValues.Length(),
"mSizeValues length differs from mSizeQueries");
unsigned int i;
for (i = 0; i < numSizes; i++) {
if (mSizeQueries[i]->Matches(pctx, nullptr)) {
break;
}
}
if (i == numSizes) {
// No match defaults to 100% viewport
nsCSSValue defaultWidth(100.0f, eCSSUnit_ViewportWidth);
effectiveWidth = nsRuleNode::CalcLengthWithInitialFont(pctx,
defaultWidth);
} else {
effectiveWidth = nsRuleNode::CalcLengthWithInitialFont(pctx,
mSizeValues[i]);
}
}
*aWidth = nsPresContext::AppUnitsToDoubleCSSPixels(std::max(effectiveWidth, 0));

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

@ -7,6 +7,8 @@
#ifndef mozilla_dom_responsiveimageselector_h__
#define mozilla_dom_responsiveimageselector_h__
#include "mozilla/UniquePtr.h"
#include "mozilla/ServoBindingTypes.h"
#include "nsAutoPtr.h"
#include "nsISupports.h"
#include "nsIContent.h"
@ -120,6 +122,10 @@ private:
// resolve the absolute URL at selection time
nsCOMPtr<nsIURI> mSelectedCandidateURL;
// Servo bits.
UniquePtr<RawServoSourceSizeList> mServoSourceSizeList;
// Gecko bits.
nsTArray< nsAutoPtr<nsMediaQuery> > mSizeQueries;
nsTArray<nsCSSValue> mSizeValues;
};

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

@ -56,7 +56,7 @@
#include "nsIDocument.h"
#include "nsINamed.h"
#include "nsISelectionController.h"//for the enums
#include "nsISelectionController.h" //for the enums
#include "nsAutoCopyListener.h"
#include "SelectionChangeListener.h"
#include "nsCopySupport.h"

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

@ -100,6 +100,10 @@
#include "MP4Decoder.h"
#include "FrameStatistics.h"
#include "nsIFrame.h"
#include "nsDisplayList.h"
#include "SVGObserverUtils.h"
#ifdef MOZ_ANDROID_HLS_SUPPORT
#include "HLSDecoder.h"
#endif
@ -5343,7 +5347,7 @@ CreateAudioTrack(AudioStreamTrack* aStreamTrack)
nsAutoString id;
nsAutoString label;
aStreamTrack->GetId(id);
aStreamTrack->GetLabel(label);
aStreamTrack->GetLabel(label, CallerType::System);
return MediaTrackList::CreateAudioTrack(id, NS_LITERAL_STRING("main"),
label, EmptyString(), true);
@ -5355,7 +5359,7 @@ CreateVideoTrack(VideoStreamTrack* aStreamTrack)
nsAutoString id;
nsAutoString label;
aStreamTrack->GetId(id);
aStreamTrack->GetLabel(label);
aStreamTrack->GetLabel(label, CallerType::System);
return MediaTrackList::CreateVideoTrack(id, NS_LITERAL_STRING("main"),
label, EmptyString(),
@ -6403,6 +6407,39 @@ bool HTMLMediaElement::RemoveDecoderPrincipalChangeObserver(DecoderPrincipalChan
return mDecoderPrincipalChangeObservers.RemoveElement(aObserver);
}
void
HTMLMediaElement::Invalidate(bool aImageSizeChanged,
Maybe<nsIntSize>& aNewIntrinsicSize,
bool aForceInvalidate)
{
nsIFrame* frame = GetPrimaryFrame();
if (aNewIntrinsicSize) {
UpdateMediaSize(aNewIntrinsicSize.value());
if (frame) {
nsPresContext* presContext = frame->PresContext();
nsIPresShell* presShell = presContext->PresShell();
presShell->FrameNeedsReflow(
frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
}
}
RefPtr<ImageContainer> imageContainer = GetImageContainer();
bool asyncInvalidate =
imageContainer && imageContainer->IsAsync() && !aForceInvalidate;
if (frame) {
if (aImageSizeChanged) {
frame->InvalidateFrame();
} else {
frame->InvalidateLayer(DisplayItemType::TYPE_VIDEO,
nullptr,
nullptr,
asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0);
}
}
SVGObserverUtils::InvalidateDirectRenderingObservers(this);
}
void HTMLMediaElement::UpdateMediaSize(const nsIntSize& aSize)
{
if (IsVideo() && mReadyState != HAVE_NOTHING &&

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

@ -243,8 +243,9 @@ public:
// Called after the MediaStream we're playing rendered a frame to aContainer
// with a different principalHandle than the previous frame.
void PrincipalHandleChangedForVideoFrameContainer(VideoFrameContainer* aContainer,
const PrincipalHandle& aNewPrincipalHandle);
void PrincipalHandleChangedForVideoFrameContainer(
VideoFrameContainer* aContainer,
const PrincipalHandle& aNewPrincipalHandle) override;
// Dispatch events
virtual void DispatchAsyncEvent(const nsAString& aName) final override;
@ -330,6 +331,10 @@ public:
// been set.
void UpdateInitialMediaSize(const nsIntSize& aSize);
void Invalidate(bool aImageSizeChanged,
Maybe<nsIntSize>& aNewIntrinsicSize,
bool aForceInvalidate) override;
// Returns the CanPlayStatus indicating if we can handle the
// full MIME type including the optional codecs parameter.
static CanPlayStatus GetCanPlay(const nsAString& aType,

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

@ -63,7 +63,7 @@
#include "nsIHttpChannel.h"
#include "nsIFile.h"
#include "nsFrameSelection.h"
#include "nsISelectionPrivate.h"//for toStringwithformat code
#include "nsISelectionPrivate.h" //for toStringwithformat code
#include "nsContentUtils.h"
#include "nsJSUtils.h"

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

@ -5,6 +5,8 @@
#include "AudioStreamTrack.h"
#include "nsContentUtils.h"
#include "mozilla/dom/AudioStreamTrackBinding.h"
namespace mozilla {
@ -16,5 +18,15 @@ AudioStreamTrack::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return AudioStreamTrackBinding::Wrap(aCx, this, aGivenProto);
}
void
AudioStreamTrack::GetLabel(nsAString& aLabel, CallerType aCallerType)
{
if (nsContentUtils::ResistFingerprinting(aCallerType)) {
aLabel.AssignLiteral("Internal Microphone");
return;
}
MediaStreamTrack::GetLabel(aLabel, aCallerType);
}
} // namespace dom
} // namespace mozilla

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

@ -29,6 +29,8 @@ public:
// WebIDL
void GetKind(nsAString& aKind) override { aKind.AssignLiteral("audio"); }
void GetLabel(nsAString& aLabel, CallerType aCallerType) override;
protected:
already_AddRefed<MediaStreamTrack> CloneInternal(DOMMediaStream* aOwningStream,
TrackID aTrackID) override

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

@ -8,6 +8,10 @@
#include "mozilla/UniquePtr.h"
#include "MediaInfo.h"
#include "MediaSegment.h"
#include "nsSize.h"
class nsIDocument;
namespace mozilla {
@ -174,6 +178,19 @@ public:
return nullptr;
}
// Called by the frame container to notify the layout engine that the
// size of the image has changed, or the video needs to be be repainted
// for some other reason.
virtual void Invalidate(bool aImageSizeChanged,
Maybe<nsIntSize>& aNewIntrinsicSize,
bool aForceInvalidate) {}
// Called after the MediaStream we're playing rendered a frame to aContainer
// with a different principalHandle than the previous frame.
virtual void PrincipalHandleChangedForVideoFrameContainer(
VideoFrameContainer* aContainer,
const PrincipalHandle& aNewPrincipalHandle) {}
/*
* Servo only methods go here. Please provide default implementations so they
* can build in Gecko without any modification.

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

@ -9,6 +9,7 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/MediaManager.h"
#include "MediaTrackConstraints.h"
#include "nsContentUtils.h"
#include "nsIEventTarget.h"
#include "nsINamed.h"
#include "nsIScriptGlobalObject.h"
@ -197,7 +198,7 @@ MediaDevices::GetUserMedia(const MediaStreamConstraints& aConstraints,
}
already_AddRefed<Promise>
MediaDevices::EnumerateDevices(ErrorResult &aRv)
MediaDevices::EnumerateDevices(CallerType aCallerType, ErrorResult &aRv)
{
nsPIDOMWindowInner* window = GetOwner();
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window);
@ -207,7 +208,7 @@ MediaDevices::EnumerateDevices(ErrorResult &aRv)
RefPtr<EnumDevResolver> resolver = new EnumDevResolver(p, window->WindowID());
RefPtr<GumRejecter> rejecter = new GumRejecter(p);
aRv = MediaManager::Get()->EnumerateDevices(window, resolver, rejecter);
aRv = MediaManager::Get()->EnumerateDevices(window, resolver, rejecter, aCallerType);
return p.forget();
}
@ -232,6 +233,12 @@ MediaDevices::OnDeviceChange()
return;
}
// Do not fire event to content script when
// privacy.resistFingerprinting is true.
if (nsContentUtils::ShouldResistFingerprinting()) {
return;
}
if (!mFuzzTimer)
{
mFuzzTimer = NS_NewTimer();

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

@ -43,7 +43,7 @@ public:
CallerType aCallerType, ErrorResult &aRv);
already_AddRefed<Promise>
EnumerateDevices(ErrorResult &aRv);
EnumerateDevices(CallerType aCallerType, ErrorResult &aRv);
virtual void OnDeviceChange() override;

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

@ -2169,6 +2169,29 @@ enum class GetUserMediaSecurityState {
Privileged = 6
};
/**
* This function is used in getUserMedia when privacy.resistFingerprinting is true.
* Only mediaSource of audio/video constraint will be kept.
*/
static void
ReduceConstraint(
mozilla::dom::OwningBooleanOrMediaTrackConstraints& aConstraint) {
// Not requesting stream.
if (!IsOn(aConstraint)) {
return;
}
// It looks like {audio: true}, do nothing.
if (!aConstraint.IsMediaTrackConstraints()) {
return;
}
// Keep mediaSource, ignore all other constraints.
auto& c = aConstraint.GetAsMediaTrackConstraints();
nsString mediaSource = c.mMediaSource;
aConstraint.SetAsMediaTrackConstraints().mMediaSource = mediaSource;
}
/**
* The entry point for this file. A call from Navigator::mozGetUserMedia
* will end up here. MediaManager is a singleton that is responsible
@ -2280,6 +2303,13 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
return rv;
}
const bool resistFingerprinting = nsContentUtils::ResistFingerprinting(aCallerType);
if (resistFingerprinting) {
ReduceConstraint(c.mVideo);
ReduceConstraint(c.mAudio);
}
if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
c.mVideo.SetAsBoolean() = false;
}
@ -2509,7 +2539,7 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
RefPtr<MediaManager> self = this;
p->Then([self, onSuccess, onFailure, windowID, c, windowListener,
sourceListener, askPermission, prefs, isHTTPS, callID, principalInfo,
isChrome](SourceSet*& aDevices) mutable {
isChrome, resistFingerprinting](SourceSet*& aDevices) mutable {
// grab result
auto devices = MakeRefPtr<Refcountable<UniquePtr<SourceSet>>>(aDevices);
@ -2523,7 +2553,7 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
p2->Then([self, onSuccess, onFailure, windowID, c,
windowListener, sourceListener, askPermission, prefs, isHTTPS,
callID, principalInfo, isChrome, devices
callID, principalInfo, isChrome, devices, resistFingerprinting
](const char*& badConstraint) mutable {
// Ensure that the captured 'this' pointer and our windowID are still good.
@ -2547,7 +2577,13 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
}
if (!(*devices)->Length()) {
RefPtr<MediaStreamError> error =
new MediaStreamError(window, NS_LITERAL_STRING("NotFoundError"));
new MediaStreamError(
window,
// When privacy.resistFingerprinting = true, no available
// device implies content script is requesting a fake
// device, so report NotAllowedError.
resistFingerprinting ? NS_LITERAL_STRING("NotAllowedError")
: NS_LITERAL_STRING("NotFoundError"));
onFailure->OnError(error);
return;
}
@ -2791,7 +2827,8 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
nsresult
MediaManager::EnumerateDevices(nsPIDOMWindowInner* aWindow,
nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnFailure)
nsIDOMGetUserMediaErrorCallback* aOnFailure,
dom::CallerType aCallerType)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(!sInShutdown, NS_ERROR_FAILURE);
@ -2818,7 +2855,8 @@ MediaManager::EnumerateDevices(nsPIDOMWindowInner* aWindow,
RefPtr<SourceListener> sourceListener = new SourceListener();
windowListener->Register(sourceListener);
bool fake = Preferences::GetBool("media.navigator.streams.fake");
bool fake = Preferences::GetBool("media.navigator.streams.fake") ||
nsContentUtils::ResistFingerprinting(aCallerType);
RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowId,
MediaSourceEnum::Camera,

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

@ -257,7 +257,8 @@ public:
nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow,
nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnFailure);
nsIDOMGetUserMediaErrorCallback* aOnFailure,
dom::CallerType aCallerType);
nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow, dom::Promise& aPromise);
void OnNavigation(uint64_t aWindowID);

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

@ -259,9 +259,18 @@ MediaStreamTrack::GetConstraints(dom::MediaTrackConstraints& aResult)
}
void
MediaStreamTrack::GetSettings(dom::MediaTrackSettings& aResult)
MediaStreamTrack::GetSettings(dom::MediaTrackSettings& aResult, CallerType aCallerType)
{
GetSource().GetSettings(aResult);
// Spoof values when privacy.resistFingerprinting is true.
if (!nsContentUtils::ResistFingerprinting(aCallerType)) {
return;
}
if (aResult.mFacingMode.WasPassed()) {
aResult.mFacingMode.Value().Assign(NS_ConvertASCIItoUTF16(
VideoFacingModeEnumValues::strings[uint8_t(VideoFacingModeEnum::User)].value));
}
}
already_AddRefed<Promise>

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

@ -15,6 +15,7 @@
#include "mozilla/dom/MediaTrackSettingsBinding.h"
#include "mozilla/media/MediaUtils.h"
#include "mozilla/WeakPtr.h"
#include "nsContentUtils.h"
#include "nsError.h"
#include "nsID.h"
#include "nsIPrincipal.h"
@ -280,12 +281,12 @@ public:
// WebIDL
virtual void GetKind(nsAString& aKind) = 0;
void GetId(nsAString& aID) const;
void GetLabel(nsAString& aLabel) { GetSource().GetLabel(aLabel); }
virtual void GetLabel(nsAString& aLabel, CallerType /* aCallerType */) { GetSource().GetLabel(aLabel); }
bool Enabled() { return mEnabled; }
void SetEnabled(bool aEnabled);
void Stop();
void GetConstraints(dom::MediaTrackConstraints& aResult);
void GetSettings(dom::MediaTrackSettings& aResult);
void GetSettings(dom::MediaTrackSettings& aResult, CallerType aCallerType);
already_AddRefed<Promise>
ApplyConstraints(const dom::MediaTrackConstraints& aConstraints,

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

@ -5,13 +5,8 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VideoFrameContainer.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/Telemetry.h"
#include "nsIFrame.h"
#include "nsDisplayList.h"
#include "SVGObserverUtils.h"
#include "MediaDecoderOwner.h"
using namespace mozilla::layers;
@ -43,18 +38,18 @@ private:
}
VideoFrameContainer::VideoFrameContainer(
dom::HTMLMediaElement* aElement,
MediaDecoderOwner* aOwner,
already_AddRefed<ImageContainer> aContainer)
: mElement(aElement)
: mOwner(aOwner)
, mImageContainer(aContainer)
, mMutex("nsVideoFrameContainer")
, mBlackImage(nullptr)
, mFrameID(0)
, mPendingPrincipalHandle(PRINCIPAL_HANDLE_NONE)
, mFrameIDForPendingPrincipalHandle(0)
, mMainThread(aElement->AbstractMainThread())
, mMainThread(aOwner->AbstractMainThread())
{
NS_ASSERTION(aElement, "aElement must not be null");
NS_ASSERTION(aOwner, "aOwner must not be null");
NS_ASSERTION(mImageContainer, "aContainer must not be null");
}
@ -295,9 +290,9 @@ void VideoFrameContainer::SetCurrentFramesLocked(const gfx::IntSize& aIntrinsicS
"PrincipalHandleOrImageSizeChanged",
[this, self, principalHandle, imageSizeChanged]() {
mMainThreadState.mImageSizeChanged = imageSizeChanged;
if (mElement && principalHandle != PRINCIPAL_HANDLE_NONE) {
mElement->PrincipalHandleChangedForVideoFrameContainer(
this, principalHandle);
if (mOwner && principalHandle != PRINCIPAL_HANDLE_NONE) {
mOwner->PrincipalHandleChangedForVideoFrameContainer(this,
principalHandle);
}
}));
}
@ -346,7 +341,6 @@ ImageContainer* VideoFrameContainer::GetImageContainer() {
return mImageContainer;
}
double VideoFrameContainer::GetFrameDelay()
{
return mImageContainer->GetPaintDelay().ToSeconds();
@ -356,40 +350,22 @@ void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags)
{
NS_ASSERTION(NS_IsMainThread(), "Must call on main thread");
if (!mElement) {
// Element has been destroyed
if (!mOwner) {
// Owner has been destroyed
return;
}
nsIFrame* frame = mElement->GetPrimaryFrame();
bool invalidateFrame = mMainThreadState.mImageSizeChanged;
bool imageSizeChanged = mMainThreadState.mImageSizeChanged;
mMainThreadState.mImageSizeChanged = false;
Maybe<nsIntSize> intrinsicSize;
if (mMainThreadState.mIntrinsicSizeChanged) {
mElement->UpdateMediaSize(mMainThreadState.mIntrinsicSize);
intrinsicSize = Some(mMainThreadState.mIntrinsicSize);
mMainThreadState.mIntrinsicSizeChanged = false;
if (frame) {
nsPresContext* presContext = frame->PresContext();
nsIPresShell* presShell = presContext->PresShell();
presShell->FrameNeedsReflow(
frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
}
}
bool asyncInvalidate = mImageContainer &&
mImageContainer->IsAsync() &&
!(aFlags & INVALIDATE_FORCE);
if (frame) {
if (invalidateFrame) {
frame->InvalidateFrame();
} else {
frame->InvalidateLayer(DisplayItemType::TYPE_VIDEO, nullptr, nullptr,
asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0);
}
}
SVGObserverUtils::InvalidateDirectRenderingObservers(mElement);
bool forceInvalidate = aFlags & INVALIDATE_FORCE;
mOwner->Invalidate(imageSizeChanged, intrinsicSize, forceInvalidate);
}
} // namespace mozilla

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

@ -18,9 +18,7 @@
namespace mozilla {
namespace dom {
class HTMLMediaElement;
} // namespace dom
class MediaDecoderOwner;
/**
* This object is used in the decoder backend threads and the main thread
@ -38,7 +36,7 @@ public:
typedef layers::ImageContainer ImageContainer;
typedef layers::Image Image;
VideoFrameContainer(dom::HTMLMediaElement* aElement,
VideoFrameContainer(MediaDecoderOwner* aOwner,
already_AddRefed<ImageContainer> aContainer);
// Call on any thread
@ -92,7 +90,7 @@ public:
void Invalidate() override { InvalidateWithFlags(INVALIDATE_DEFAULT); }
void InvalidateWithFlags(uint32_t aFlags);
ImageContainer* GetImageContainer();
void ForgetElement() { mElement = nullptr; }
void ForgetElement() { mOwner = nullptr; }
uint32_t GetDroppedImageCount() { return mImageContainer->GetDroppedImageCount(); }
@ -100,9 +98,9 @@ protected:
void SetCurrentFramesLocked(const gfx::IntSize& aIntrinsicSize,
const nsTArray<ImageContainer::NonOwningImage>& aImages);
// Non-addreffed pointer to the element. The element calls ForgetElement
// to clear this reference when the element is destroyed.
dom::HTMLMediaElement* mElement;
// Non-addreffed pointer to the owner. The ownenr calls ForgetElement
// to clear this reference when the owner is destroyed.
MediaDecoderOwner* mOwner;
RefPtr<ImageContainer> mImageContainer;
struct

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

@ -7,6 +7,7 @@
#include "MediaStreamVideoSink.h"
#include "MediaStreamGraph.h"
#include "nsContentUtils.h"
#include "mozilla/dom/VideoStreamTrackBinding.h"
@ -31,5 +32,15 @@ VideoStreamTrack::RemoveVideoOutput(MediaStreamVideoSink* aSink)
GetOwnedStream()->RemoveVideoOutput(aSink, mTrackID);
}
void
VideoStreamTrack::GetLabel(nsAString& aLabel, CallerType aCallerType)
{
if (nsContentUtils::ResistFingerprinting(aCallerType)) {
aLabel.AssignLiteral("Internal Camera");
return;
}
MediaStreamTrack::GetLabel(aLabel, aCallerType);
}
} // namespace dom
} // namespace mozilla

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

@ -35,6 +35,8 @@ public:
// WebIDL
void GetKind(nsAString& aKind) override { aKind.AssignLiteral("video"); }
void GetLabel(nsAString& aLabel, CallerType aCallerType) override;
protected:
already_AddRefed<MediaStreamTrack> CloneInternal(DOMMediaStream* aOwningStream,
TrackID aTrackID) override

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

@ -7,6 +7,7 @@
#include "MediaQueue.h"
#include "VideoSink.h"
#include "MediaPrefs.h"
#include "VideoUtils.h"
#include "mozilla/IntegerPrintfMacros.h"

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

@ -306,3 +306,4 @@ skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator,
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_verifyDescriptions.html]
skip-if = (android_version == '18')
[test_fingerprinting_resistance.html]

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

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="mediaStreamPlayback.js"></script>
</head>
<body>
<script>
/* global SimpleTest SpecialPowers */
async function testEnumerateDevices(expectDevices) {
let devices = await navigator.mediaDevices.enumerateDevices();
if (!expectDevices) {
SimpleTest.is(devices.length, 0, "testEnumerateDevices: No devices");
return;
}
let cams = devices.filter((device) => device.kind == "videoinput");
let mics = devices.filter((device) => device.kind == "audioinput");
SimpleTest.ok((cams.length == 1) && (mics.length == 1),
"testEnumerateDevices: a microphone and a camera");
}
async function testGetUserMedia(expectDevices) {
const constraints = [
{audio: true}, {video: true}, {audio: true, video: true}
];
for (let constraint of constraints) {
let message = "getUserMedia(" + JSON.stringify(constraint) + ")";
try {
let stream = await navigator.mediaDevices.getUserMedia(constraint);
SimpleTest.ok(expectDevices, message + " resolved");
if (!expectDevices) {
continue;
}
// We only do testGetUserMedia(true) when privacy.resistFingerprinting
// is true, test if MediaStreamTrack.label is spoofed.
for (let track of stream.getTracks()) {
switch (track.kind) {
case "audio":
SimpleTest.is(track.label, "Internal Microphone", "AudioStreamTrack.label");
break;
case "video":
SimpleTest.is(track.label, "Internal Camera", "VideoStreamTrack.label");
break;
default:
SimpleTest.ok(false, "Unknown kind: " + track.kind);
break;
}
track.stop();
}
} catch (e) {
if (!expectDevices) {
SimpleTest.is(e.name, "NotAllowedError", message + " throws NotAllowedError");
} else {
SimpleTest.ok(false, message + " failed: " + e);
}
}
}
}
async function testDevices() {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true],
["media.navigator.streams.fake", true]
]
});
await testEnumerateDevices(true); // should list a microphone and a camera
await testGetUserMedia(true); // should get audio and video streams
}
async function testNoDevices() {
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", false],
["media.navigator.streams.fake", false],
["media.audio_loopback_dev", "foo"],
["media.video_loopback_dev", "bar"]
]
});
await testEnumerateDevices(false); // should list nothing
await SpecialPowers.pushPrefEnv({
set: [
["privacy.resistFingerprinting", true]
]
});
await testEnumerateDevices(true); // should list a microphone and a camera
await testGetUserMedia(false); // should reject with NotAllowedError
}
createHTML({
title: "Neutralize the threat of fingerprinting of media devices API when 'privacy.resistFingerprinting' is true",
bug: "1372073"
});
runTest(async () => {
// Make sure enumerateDevices and getUserMedia work when
// privacy.resistFingerprinting is true.
await testDevices();
// Test that absence of devices can't be detected.
await testNoDevices();
});
</script>
</body>
</html>

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

@ -16,7 +16,7 @@ interface MediaDevices : EventTarget {
attribute EventHandler ondevicechange;
MediaTrackSupportedConstraints getSupportedConstraints();
[Throws]
[Throws, NeedsCallerType]
Promise<sequence<MediaDeviceInfo>> enumerateDevices();
[Throws, NeedsCallerType]

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

@ -77,6 +77,7 @@ enum MediaStreamTrackState {
interface MediaStreamTrack : EventTarget {
readonly attribute DOMString kind;
readonly attribute DOMString id;
[NeedsCallerType]
readonly attribute DOMString label;
attribute boolean enabled;
// readonly attribute boolean muted;
@ -90,6 +91,7 @@ interface MediaStreamTrack : EventTarget {
void stop ();
// MediaTrackCapabilities getCapabilities ();
MediaTrackConstraints getConstraints ();
[NeedsCallerType]
MediaTrackSettings getSettings ();
[Throws, NeedsCallerType]

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

@ -97,6 +97,13 @@ public:
return *this;
}
template<typename A, typename B>
EditorDOMPointBase& operator=(const RangeBoundaryBase<A, B>& aOther)
{
RangeBoundaryBase<ParentType, RefType>::operator=(aOther);
return *this;
}
private:
static nsIContent* GetRef(nsINode* aContainerNode, nsIContent* aPointedNode)
{

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

@ -1651,15 +1651,19 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
}
// Smart splitting rules
NS_ENSURE_TRUE(aSelection.GetRangeAt(0) &&
aSelection.GetRangeAt(0)->GetStartContainer(),
NS_ERROR_FAILURE);
OwningNonNull<nsINode> node = *aSelection.GetRangeAt(0)->GetStartContainer();
nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
int32_t offset = aSelection.GetRangeAt(0)->StartOffset();
nsRange* firstRange = aSelection.GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
}
EditorDOMPoint atStartOfSelection(firstRange->StartRef());
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
// Do nothing if the node is read-only
if (!htmlEditor->IsModifiableNode(node)) {
if (!htmlEditor->IsModifiableNode(atStartOfSelection.Container())) {
*aCancel = true;
return NS_OK;
}
@ -1675,7 +1679,8 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
// Look for the nearest parent block. However, don't return error even if
// there is no block parent here because in such case, i.e., editing host
// is an inline element, we should insert <br> simply.
RefPtr<Element> blockParent = HTMLEditor::GetBlock(node, host);
RefPtr<Element> blockParent =
HTMLEditor::GetBlock(*atStartOfSelection.Container(), host);
ParagraphSeparator separator = htmlEditor->GetDefaultParagraphSeparator();
bool insertBRElement;
@ -1712,7 +1717,8 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
// If we cannot insert a <p>/<div> element at the selection, we should insert
// a <br> element instead.
if (insertBRElement) {
nsresult rv = StandardBreakImpl(node, offset, aSelection);
nsresult rv = StandardBreakImpl(*atStartOfSelection.Container(),
atStartOfSelection.Offset(), aSelection);
NS_ENSURE_SUCCESS(rv, rv);
*aHandled = true;
return NS_OK;
@ -1729,22 +1735,25 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditRules::MakeBasicBlock() failed");
// Reinitialize node/offset in case they're not inside the new block
if (NS_WARN_IF(!aSelection.GetRangeAt(0) ||
!aSelection.GetRangeAt(0)->GetStartContainer())) {
firstRange = aSelection.GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return NS_ERROR_FAILURE;
}
node = *aSelection.GetRangeAt(0)->GetStartContainer();
child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
offset = aSelection.GetRangeAt(0)->StartOffset();
blockParent = mHTMLEditor->GetBlock(node, host);
atStartOfSelection = firstRange->StartRef();
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
blockParent = mHTMLEditor->GetBlock(*atStartOfSelection.Container(), host);
if (NS_WARN_IF(!blockParent)) {
return NS_ERROR_UNEXPECTED;
}
if (NS_WARN_IF(blockParent == host)) {
// Didn't create a new block for some reason, fall back to <br>
rv = StandardBreakImpl(node, offset, aSelection);
rv = StandardBreakImpl(*atStartOfSelection.Container(),
atStartOfSelection.Offset(), aSelection);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -1767,15 +1776,20 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
nsCOMPtr<Element> listItem = IsInListItem(blockParent);
if (listItem && listItem != host) {
ReturnInListItem(aSelection, *listItem, node, offset);
*aHandled = true;
return NS_OK;
} else if (HTMLEditUtils::IsHeader(*blockParent)) {
// Headers: close (or split) header
ReturnInHeader(aSelection, *blockParent, node, offset);
ReturnInListItem(aSelection, *listItem, *atStartOfSelection.Container(),
atStartOfSelection.Offset());
*aHandled = true;
return NS_OK;
}
if (HTMLEditUtils::IsHeader(*blockParent)) {
// Headers: close (or split) header
ReturnInHeader(aSelection, *blockParent, *atStartOfSelection.Container(),
atStartOfSelection.Offset());
*aHandled = true;
return NS_OK;
}
// XXX Ideally, we should take same behavior with both <p> container and
// <div> container. However, we are still using <br> as default
// paragraph separator (non-standard) and we've split only <p> container
@ -1783,22 +1797,25 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
// Gmail. So, let's use traditional odd behavior only when the default
// paragraph separator is <br>. Otherwise, take consistent behavior
// between <p> container and <div> container.
else if ((separator == ParagraphSeparator::br &&
blockParent->IsHTMLElement(nsGkAtoms::p)) ||
(separator != ParagraphSeparator::br &&
blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
if ((separator == ParagraphSeparator::br &&
blockParent->IsHTMLElement(nsGkAtoms::p)) ||
(separator != ParagraphSeparator::br &&
blockParent->IsAnyOfHTMLElements(nsGkAtoms::p, nsGkAtoms::div))) {
// Paragraphs: special rules to look for <br>s
nsresult rv =
ReturnInParagraph(&aSelection, blockParent, node,
offset, child, aCancel, aHandled);
NS_ENSURE_SUCCESS(rv, rv);
EditActionResult result = ReturnInParagraph(aSelection, *blockParent);
if (NS_WARN_IF(result.Failed())) {
return result.Rv();
}
*aHandled = result.Handled();
*aCancel = result.Canceled();
// Fall through, we may not have handled it in ReturnInParagraph()
}
// If not already handled then do the standard thing
if (!(*aHandled)) {
*aHandled = true;
return StandardBreakImpl(node, offset, aSelection);
return StandardBreakImpl(*atStartOfSelection.Container(),
atStartOfSelection.Offset(), aSelection);
}
return NS_OK;
}
@ -6711,133 +6728,139 @@ HTMLEditRules::ReturnInHeader(Selection& aSelection,
return NS_OK;
}
/**
* ReturnInParagraph() does the right thing for returns pressed in paragraphs.
* For our purposes, this means either <p> or <div>, which is not in keeping
* with the semantics of <div>, but is necessary for compatibility with other
* browsers.
*/
nsresult
HTMLEditRules::ReturnInParagraph(Selection* aSelection,
nsINode* aPara,
nsINode* aNode,
int32_t aOffset,
nsIContent* aChildAtOffset,
bool* aCancel,
bool* aHandled)
EditActionResult
HTMLEditRules::ReturnInParagraph(Selection& aSelection,
nsINode& aParentDivOrP)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
if (!aSelection || !aPara || !node || !aCancel || !aHandled) {
return NS_ERROR_NULL_POINTER;
if (NS_WARN_IF(!mHTMLEditor)) {
return EditActionResult(NS_ERROR_NOT_AVAILABLE);
}
*aCancel = false;
*aHandled = false;
int32_t offset;
nsCOMPtr<nsINode> parent = EditorBase::GetNodeLocation(node, &offset);
RefPtr<HTMLEditor> htmlEditor = mHTMLEditor;
NS_ENSURE_STATE(mHTMLEditor);
bool doesCRCreateNewP = mHTMLEditor->GetReturnInParagraphCreatesNewParagraph();
nsRange* firstRange = aSelection.GetRangeAt(0);
if (NS_WARN_IF(!firstRange)) {
return EditActionResult(NS_ERROR_FAILURE);
}
bool newBRneeded = false;
bool newSelNode = false;
nsCOMPtr<nsIContent> sibling;
nsCOMPtr<nsIDOMNode> selNode = GetAsDOMNode(aNode);
int32_t selOffset = aOffset;
EditorDOMPoint atStartOfSelection(firstRange->StartRef());
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
return EditActionResult(NS_ERROR_FAILURE);
}
MOZ_ASSERT(atStartOfSelection.IsSetAndValid());
NS_ENSURE_STATE(mHTMLEditor);
if (aNode == aPara && doesCRCreateNewP) {
// we are at the edges of the block, newBRneeded not needed!
sibling = node->AsContent();
} else if (EditorBase::IsTextNode(aNode)) {
bool doesCRCreateNewP = htmlEditor->GetReturnInParagraphCreatesNewParagraph();
bool splitAfterNewBR = false;
nsCOMPtr<nsIContent> brNode;
// Point to split aParentDivOrP.
// XXX If we don't need to use nsIDOMNode here, we should use EditorDOMPoint.
nsCOMPtr<nsIDOMNode> containerAtSplitPoint =
GetAsDOMNode(atStartOfSelection.Container());
int32_t offsetAtSplitPoint = atStartOfSelection.Offset();
EditorRawDOMPoint pointToInsertBR;
if (doesCRCreateNewP &&
atStartOfSelection.Container() == &aParentDivOrP) {
// We are at the edges of the block, so, we don't need to create new <br>.
brNode = nullptr;
} else if (EditorBase::IsTextNode(atStartOfSelection.Container())) {
// at beginning of text node?
if (!aOffset) {
if (atStartOfSelection.IsStartOfContainer()) {
// is there a BR prior to it?
NS_ENSURE_STATE(mHTMLEditor);
sibling = mHTMLEditor->GetPriorHTMLSibling(node);
if (!sibling || !mHTMLEditor ||
!mHTMLEditor->IsVisibleBRElement(sibling) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(sibling))) {
NS_ENSURE_STATE(mHTMLEditor);
newBRneeded = true;
brNode = htmlEditor->GetPriorHTMLSibling(atStartOfSelection.Container());
if (!brNode ||
!htmlEditor->IsVisibleBRElement(brNode) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(brNode))) {
pointToInsertBR.Set(atStartOfSelection.Container());
brNode = nullptr;
}
} else if (aOffset == static_cast<int32_t>(node->Length())) {
} else if (atStartOfSelection.IsEndOfContainer()) {
// we're at the end of text node...
// is there a BR after to it?
NS_ENSURE_STATE(mHTMLEditor);
sibling = mHTMLEditor->GetNextHTMLSibling(node);
if (!sibling || !mHTMLEditor ||
!mHTMLEditor->IsVisibleBRElement(sibling) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(sibling))) {
NS_ENSURE_STATE(mHTMLEditor);
newBRneeded = true;
offset++;
brNode = htmlEditor->GetNextHTMLSibling(atStartOfSelection.Container());
if (!brNode ||
!htmlEditor->IsVisibleBRElement(brNode) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(brNode))) {
pointToInsertBR.Set(atStartOfSelection.Container());
DebugOnly<bool> advanced = pointToInsertBR.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset to after the container of selection start");
brNode = nullptr;
}
} else {
nsCOMPtr<nsINode> leftNode = atStartOfSelection.Container();
if (doesCRCreateNewP) {
nsCOMPtr<nsIDOMNode> tmp;
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIDOMNode> leftDOMNode;
nsresult rv =
mHTMLEditor->SplitNode(selNode, aOffset, getter_AddRefs(tmp));
NS_ENSURE_SUCCESS(rv, rv);
selNode = tmp;
htmlEditor->SplitNode(containerAtSplitPoint, offsetAtSplitPoint,
getter_AddRefs(leftDOMNode));
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionResult(rv);
}
containerAtSplitPoint = leftDOMNode;
leftNode = do_QueryInterface(leftDOMNode);
}
newBRneeded = true;
offset++;
// We need to put new <br> after the left node if given node was split
// above.
pointToInsertBR.Set(leftNode);
DebugOnly<bool> advanced = pointToInsertBR.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Failed to advance offset to after the container of selection start");
}
} else {
// not in a text node.
// is there a BR prior to it?
nsCOMPtr<nsIContent> nearNode;
NS_ENSURE_STATE(mHTMLEditor);
nearNode =
mHTMLEditor->GetPreviousEditableHTMLNode(
EditorRawDOMPoint(node, aChildAtOffset, aOffset));
NS_ENSURE_STATE(mHTMLEditor);
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
htmlEditor->GetPreviousEditableHTMLNode(atStartOfSelection.AsRaw());
if (!nearNode || !htmlEditor->IsVisibleBRElement(nearNode) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
// is there a BR after it?
NS_ENSURE_STATE(mHTMLEditor);
nearNode =
mHTMLEditor->GetNextEditableHTMLNode(
EditorRawDOMPoint(node, aChildAtOffset, aOffset));
NS_ENSURE_STATE(mHTMLEditor);
if (!nearNode || !mHTMLEditor->IsVisibleBRElement(nearNode) ||
htmlEditor->GetNextEditableHTMLNode(atStartOfSelection.AsRaw());
if (!nearNode || !htmlEditor->IsVisibleBRElement(nearNode) ||
TextEditUtils::HasMozAttr(GetAsDOMNode(nearNode))) {
newBRneeded = true;
parent = node;
offset = aOffset;
newSelNode = true;
pointToInsertBR = atStartOfSelection;
splitAfterNewBR = true;
}
}
if (!newBRneeded) {
sibling = nearNode;
if (!pointToInsertBR.IsSet() && TextEditUtils::IsBreak(nearNode)) {
brNode = nearNode;
}
}
if (newBRneeded) {
// if CR does not create a new P, default to BR creation
NS_ENSURE_TRUE(doesCRCreateNewP, NS_OK);
if (pointToInsertBR.IsSet()) {
// Don't modify the DOM tree if mHTMLEditor disappeared.
if (NS_WARN_IF(!mHTMLEditor)) {
return EditActionResult(NS_ERROR_NOT_AVAILABLE);
}
NS_ENSURE_STATE(mHTMLEditor);
sibling = mHTMLEditor->CreateBR(parent, offset);
if (newSelNode) {
// if CR does not create a new P, default to BR creation
if (NS_WARN_IF(!doesCRCreateNewP)) {
return EditActionResult(NS_OK);
}
brNode = htmlEditor->CreateBR(pointToInsertBR.Container(),
pointToInsertBR.Offset());
if (splitAfterNewBR) {
// We split the parent after the br we've just inserted.
selNode = GetAsDOMNode(parent);
selOffset = offset + 1;
containerAtSplitPoint = GetAsDOMNode(pointToInsertBR.Container());
offsetAtSplitPoint = pointToInsertBR.Offset() + 1;
}
}
*aHandled = true;
return SplitParagraph(GetAsDOMNode(aPara), sibling, aSelection,
address_of(selNode), &selOffset);
EditActionResult result(
SplitParagraph(GetAsDOMNode(&aParentDivOrP), brNode, &aSelection,
address_of(containerAtSplitPoint), &offsetAtSplitPoint));
result.MarkAsHandled();
if (NS_WARN_IF(result.Failed())) {
return result;
}
return result;
}
/**
* SplitParagraph() splits a paragraph at selection point, possibly deleting a
* br.
*/
nsresult
HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
nsIContent* aBRNode,
@ -6846,7 +6869,7 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
int32_t* aOffset)
{
nsCOMPtr<Element> para = do_QueryInterface(aPara);
NS_ENSURE_TRUE(para && aBRNode && aSelNode && *aSelNode && aOffset &&
NS_ENSURE_TRUE(para && aSelNode && *aSelNode && aOffset &&
aSelection, NS_ERROR_NULL_POINTER);
// split para
@ -6874,7 +6897,8 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
}
// get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p)
NS_ENSURE_STATE(mHTMLEditor);
if (mHTMLEditor->IsVisibleBRElement(aBRNode)) {
if (aBRNode &&
mHTMLEditor->IsVisibleBRElement(aBRNode)) {
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->DeleteNode(aBRNode);
NS_ENSURE_SUCCESS(rv, rv);

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

@ -294,15 +294,45 @@ protected:
nsAtom& DefaultParagraphSeparator();
nsresult ReturnInHeader(Selection& aSelection, Element& aHeader,
nsINode& aNode, int32_t aOffset);
nsresult ReturnInParagraph(Selection* aSelection, nsINode* aHeader,
nsINode* aTextNode, int32_t aOffset,
nsIContent* aChildAtOffset, bool* aCancel,
bool* aHandled);
/**
* ReturnInParagraph() does the right thing for Enter key press or
* 'insertParagraph' command in aParentDivOrP. aParentDivOrP will be
* split at start of first selection range.
*
* @param aSelection The selection. aParentDivOrP will be split at
* start of the first selection range.
* @param aParentDivOrP The parent block. This must be <p> or <div>
* element.
* @return Returns with NS_OK if this doesn't meat any
* unexpected situation. If this method tries to
* split the paragraph, marked as handled.
*/
EditActionResult ReturnInParagraph(Selection& aSelection,
nsINode& aParentDivOrP);
/**
* SplitParagraph() splits the parent block, aPara, at aSelNode - aOffset.
*
* @param aPara The parent block to be split.
* @param aBRNode Next <br> node if there is. Otherwise, nullptr.
* If this is not nullptr, the <br> node may be removed.
* @param aSelection The selection.
* @param aSelNode Set the selection container to split aPara at.
* Actual container node will be set by this method.
* XXX: The only caller ReturnInParagraph() doesn't need
* this result.
* @param aOffset Set the offset in the container.
* Actual offset will be set by this method.
* XXX: The only caller ReturnInParagraph() doesn't need
* this result.
*/
nsresult SplitParagraph(nsIDOMNode* aPara,
nsIContent* aBRNode,
Selection* aSelection,
nsCOMPtr<nsIDOMNode>* aSelNode,
int32_t* aOffset);
nsresult ReturnInListItem(Selection& aSelection, Element& aHeader,
nsINode& aNode, int32_t aOffset);
nsresult AfterEditInner(EditAction action,

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

@ -11,7 +11,7 @@
#include "ClientLayerManager.h" // for ClientLayerManager, etc
#include "Layers.h" // for CanvasLayer, etc
#include "mozilla/Attributes.h" // for override
#include "mozilla/layers/CanvasClient.h"// for CanvasClient, etc
#include "mozilla/layers/CanvasClient.h" // for CanvasClient, etc
#include "mozilla/layers/LayersMessages.h" // for CanvasLayerAttributes, etc
#include "mozilla/mozalloc.h" // for operator delete
#include "nsDebug.h" // for NS_ASSERTION

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

@ -22,8 +22,8 @@
#include "mozilla/layers/PaintThread.h"
#include "mozilla/layers/PLayerTransactionChild.h"
#include "mozilla/layers/PTextureChild.h"
#include "mozilla/layers/TextureClient.h"// for TextureClient
#include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
#include "mozilla/layers/TextureClient.h" // for TextureClient
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"

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

@ -11,7 +11,7 @@
#include "base/task.h" // for CancelableTask, etc
#include "base/thread.h" // for Thread
#ifdef XP_WIN
#include "mozilla/gfx/DeviceManagerDx.h"// for DeviceManagerDx
#include "mozilla/gfx/DeviceManagerDx.h" // for DeviceManagerDx
#endif
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/layers/AnimationHelper.h" // for CompositorAnimationStorage

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

@ -652,13 +652,13 @@ gfxUtils::ClipToRegion(DrawTarget* aTarget, const nsIntRegion& aRegion)
}
}
/*static*/ gfxFloat
gfxUtils::ClampToScaleFactor(gfxFloat aVal, bool aRoundDown)
/*static*/ float
gfxUtils::ClampToScaleFactor(float aVal, bool aRoundDown)
{
// Arbitary scale factor limitation. We can increase this
// for better scaling performance at the cost of worse
// quality.
static const gfxFloat kScaleResolution = 2;
static const float kScaleResolution = 2;
// Negative scaling is just a flip and irrelevant to
// our resolution calculation.
@ -672,7 +672,7 @@ gfxUtils::ClampToScaleFactor(gfxFloat aVal, bool aRoundDown)
aVal = 1 / aVal;
}
gfxFloat power = log(aVal)/log(kScaleResolution);
float power = logf(aVal)/logf(kScaleResolution);
// If power is within 1e-5 of an integer, round to nearest to
// prevent floating point errors, otherwise round up to the
@ -689,7 +689,7 @@ gfxUtils::ClampToScaleFactor(gfxFloat aVal, bool aRoundDown)
power = ceil(power);
}
gfxFloat scale = pow(kScaleResolution, power);
float scale = powf(kScaleResolution, power);
if (inverse) {
scale = 1 / scale;

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

@ -149,7 +149,7 @@ public:
* aVal. If aRoundDown is specified, the power of 2 will rather be less than
* or equal to aVal.
*/
static gfxFloat ClampToScaleFactor(gfxFloat aVal, bool aRoundDown = false);
static float ClampToScaleFactor(float aVal, bool aRoundDown = false);
/**
* Clears surface to aColor (which defaults to transparent black).

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

@ -11,9 +11,3 @@ for header in ('GCAnnotations.h', 'GCAPI.h', 'HeapAPI.h', 'RootingAPI.h', 'Slice
with Files('public/TrackedOptimizationInfo.h'):
BUG_COMPONENT = component_jit
with Files("src/**"):
SCHEDULES.inclusive += ['jittest', 'jsreftest']
with Files("public/**"):
SCHEDULES.inclusive += ['jittest', 'jsreftest']

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

@ -495,6 +495,15 @@ function rfloor_object(i) {
return i;
}
let uceFault_floor_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_floor_double'));
function rfloor_double(i) {
const x = Math.floor(i + (-1 >>> 0));
if (uceFault_floor_double(i) || uceFault_floor_double(i))
assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
assertRecoveredOnBailout(x, true);
return i;
}
var uceFault_ceil_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_ceil_number'));
function rceil_number(i) {
var x = Math.ceil(-i - 0.12010799100);
@ -504,6 +513,15 @@ function rceil_number(i) {
return i;
}
let uceFault_ceil_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_ceil_double'));
function rceil_double(i) {
const x = Math.floor(i + (-1 >>> 0));
if (uceFault_ceil_double(i) || uceFault_ceil_double(i))
assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
assertRecoveredOnBailout(x, true);
return i;
}
var uceFault_round_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_round'));
function rround_number(i) {
var x = Math.round(i + 1.4);
@ -1391,8 +1409,10 @@ for (j = 100 - max; j < 100; j++) {
rinline_arguments_length_1(i);
rinline_arguments_length_3(i, 0, 1);
rfloor_number(i);
rfloor_double(i);
rfloor_object(i);
rceil_number(i);
rceil_double(i);
rround_number(i);
rround_double(i);
rcharCodeAt(i);

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