зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. r=merge a=merge CLOSED TREE
This commit is contained in:
Коммит
6232db29bd
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
@ -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)
|
||||
});
|
|
@ -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);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче