mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
bc713a9541
@ -5,6 +5,10 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict';
|
||||
/**
|
||||
* B2G-specific actors that extend BrowserRootActor and BrowserTabActor,
|
||||
* overriding some of their methods.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The function that creates the root actor. DebuggerServer expects to find this
|
||||
@ -24,67 +28,52 @@ function createRootActor(connection) {
|
||||
* The conection to the client.
|
||||
*/
|
||||
function DeviceRootActor(connection) {
|
||||
this.conn = connection;
|
||||
this._tabActors = new WeakMap();
|
||||
this._tabActorPool = null;
|
||||
this._actorFactories = null;
|
||||
BrowserRootActor.call(this, connection);
|
||||
this.browser = Services.wm.getMostRecentWindow('navigator:browser');
|
||||
}
|
||||
|
||||
DeviceRootActor.prototype = {
|
||||
/**
|
||||
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
|
||||
*/
|
||||
sayHello: function DRA_sayHello() {
|
||||
return {
|
||||
from: 'root',
|
||||
applicationType: 'browser',
|
||||
traits: []
|
||||
};
|
||||
},
|
||||
DeviceRootActor.prototype = new BrowserRootActor();
|
||||
|
||||
/**
|
||||
* Disconnects the actor from the browser window.
|
||||
*/
|
||||
disconnect: function DRA_disconnect() {
|
||||
let actor = this._tabActors.get(this.browser);
|
||||
if (actor) {
|
||||
actor.exit();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Disconnects the actor from the browser window.
|
||||
*/
|
||||
DeviceRootActor.prototype.disconnect = function DRA_disconnect() {
|
||||
let actor = this._tabActors.get(this.browser);
|
||||
if (actor) {
|
||||
actor.exit();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the listTabs request. Builds a list of actors for the single
|
||||
* tab (window) running in the process. The actors will survive
|
||||
* until at least the next listTabs request.
|
||||
*/
|
||||
onListTabs: function DRA_onListTabs() {
|
||||
let actor = this._tabActors.get(this.browser);
|
||||
if (!actor) {
|
||||
actor = new DeviceTabActor(this.conn, this.browser);
|
||||
// this.actorID is set by ActorPool when an actor is put into one.
|
||||
actor.parentID = this.actorID;
|
||||
this._tabActors.set(this.browser, actor);
|
||||
}
|
||||
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
actorPool.addActor(actor);
|
||||
|
||||
// Now drop the old actorID -> actor map. Actors that still mattered were
|
||||
// added to the new map, others will go away.
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
return {
|
||||
'from': 'root',
|
||||
'selected': 0,
|
||||
'tabs': [actor.grip()]
|
||||
};
|
||||
/**
|
||||
* Handles the listTabs request. Builds a list of actors for the single
|
||||
* tab (window) running in the process. The actors will survive
|
||||
* until at least the next listTabs request.
|
||||
*/
|
||||
DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
|
||||
let actor = this._tabActors.get(this.browser);
|
||||
if (!actor) {
|
||||
actor = new DeviceTabActor(this.conn, this.browser);
|
||||
// this.actorID is set by ActorPool when an actor is put into one.
|
||||
actor.parentID = this.actorID;
|
||||
this._tabActors.set(this.browser, actor);
|
||||
}
|
||||
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
actorPool.addActor(actor);
|
||||
|
||||
// Now drop the old actorID -> actor map. Actors that still mattered were
|
||||
// added to the new map, others will go away.
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
return {
|
||||
'from': 'root',
|
||||
'selected': 0,
|
||||
'tabs': [actor.grip()]
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -104,219 +93,58 @@ DeviceRootActor.prototype.requestTypes = {
|
||||
* The browser instance that contains this tab.
|
||||
*/
|
||||
function DeviceTabActor(connection, browser) {
|
||||
this.conn = connection;
|
||||
this._browser = browser;
|
||||
BrowserTabActor.call(this, connection, browser);
|
||||
}
|
||||
|
||||
DeviceTabActor.prototype = {
|
||||
get browser() {
|
||||
return this._browser;
|
||||
},
|
||||
DeviceTabActor.prototype = new BrowserTabActor();
|
||||
|
||||
get exited() {
|
||||
return !this.browser;
|
||||
},
|
||||
|
||||
get attached() {
|
||||
return !!this._attached
|
||||
},
|
||||
|
||||
_tabPool: null,
|
||||
get tabActorPool() {
|
||||
return this._tabPool;
|
||||
},
|
||||
|
||||
_contextPool: null,
|
||||
get contextActorPool() {
|
||||
return this._contextPool;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the specified breakpoint to the default actor pool connection, in order
|
||||
* to be alive as long as the server is.
|
||||
*
|
||||
* @param BreakpointActor actor
|
||||
* The actor object.
|
||||
*/
|
||||
addToBreakpointPool: function DTA_addToBreakpointPool(actor) {
|
||||
this.conn.addActor(actor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the specified breakpint from the default actor pool.
|
||||
*
|
||||
* @param string actor
|
||||
* The actor ID.
|
||||
*/
|
||||
removeFromBreakpointPool: function DTA_removeFromBreakpointPool(actor) {
|
||||
this.conn.removeActor(actor);
|
||||
},
|
||||
|
||||
actorPrefix: 'tab',
|
||||
|
||||
grip: function DTA_grip() {
|
||||
dbg_assert(!this.exited,
|
||||
'grip() should not be called on exited browser actor.');
|
||||
dbg_assert(this.actorID,
|
||||
'tab should have an actorID.');
|
||||
return {
|
||||
'actor': this.actorID,
|
||||
'title': this.browser.title,
|
||||
'url': this.browser.document.documentURI
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the actor is removed from the connection.
|
||||
*/
|
||||
disconnect: function DTA_disconnect() {
|
||||
this._detach();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by the root actor when the underlying tab is closed.
|
||||
*/
|
||||
exit: function DTA_exit() {
|
||||
if (this.exited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.attached) {
|
||||
this._detach();
|
||||
this.conn.send({
|
||||
'from': this.actorID,
|
||||
'type': 'tabDetached'
|
||||
});
|
||||
}
|
||||
|
||||
this._browser = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the actual work of attaching to a tab.
|
||||
*/
|
||||
_attach: function DTA_attach() {
|
||||
if (this._attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a pool for tab-lifetime actors.
|
||||
dbg_assert(!this._tabPool, 'Should not have a tab pool if we were not attached.');
|
||||
this._tabPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._tabPool);
|
||||
|
||||
// ... and a pool for context-lifetime actors.
|
||||
this._pushContext();
|
||||
|
||||
this._attached = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a thread actor and a pool for context-lifetime actors. It then sets
|
||||
* up the content window for debugging.
|
||||
*/
|
||||
_pushContext: function DTA_pushContext() {
|
||||
dbg_assert(!this._contextPool, "Can't push multiple contexts");
|
||||
|
||||
this._contextPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
|
||||
this.threadActor = new ThreadActor(this);
|
||||
this._addDebuggees(this.browser.wrappedJSObject);
|
||||
this._contextPool.addActor(this.threadActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided window and all windows in its frame tree as debuggees.
|
||||
*/
|
||||
_addDebuggees: function DTA__addDebuggees(content) {
|
||||
this.threadActor.addDebuggee(content);
|
||||
let frames = content.frames;
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
this._addDebuggees(frames[i]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Exits the current thread actor and removes the context-lifetime actor pool.
|
||||
* The content window is no longer being debugged after this call.
|
||||
*/
|
||||
_popContext: function DTA_popContext() {
|
||||
dbg_assert(!!this._contextPool, 'No context to pop.');
|
||||
|
||||
this.conn.removeActorPool(this._contextPool);
|
||||
this._contextPool = null;
|
||||
this.threadActor.exit();
|
||||
this.threadActor = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the actual work of detaching from a tab.
|
||||
*/
|
||||
_detach: function DTA_detach() {
|
||||
if (!this.attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._popContext();
|
||||
|
||||
// Shut down actors that belong to this tab's pool.
|
||||
this.conn.removeActorPool(this._tabPool);
|
||||
this._tabPool = null;
|
||||
|
||||
this._attached = false;
|
||||
},
|
||||
|
||||
// Protocol Request Handlers
|
||||
|
||||
onAttach: function DTA_onAttach(aRequest) {
|
||||
if (this.exited) {
|
||||
return { type: 'exited' };
|
||||
}
|
||||
|
||||
this._attach();
|
||||
|
||||
return { type: 'tabAttached', threadActor: this.threadActor.actorID };
|
||||
},
|
||||
|
||||
onDetach: function DTA_onDetach(aRequest) {
|
||||
if (!this.attached) {
|
||||
return { error: 'wrongState' };
|
||||
}
|
||||
|
||||
this._detach();
|
||||
|
||||
return { type: 'detached' };
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to enter a nested event loop by disabling debuggee events.
|
||||
*/
|
||||
preNest: function DTA_preNest() {
|
||||
let windowUtils = this.browser
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.suppressEventHandling(true);
|
||||
windowUtils.suspendTimeouts();
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to exit a nested event loop by enabling debuggee events.
|
||||
*/
|
||||
postNest: function DTA_postNest(aNestData) {
|
||||
let windowUtils = this.browser
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.resumeTimeouts();
|
||||
windowUtils.suppressEventHandling(false);
|
||||
DeviceTabActor.prototype.grip = function DTA_grip() {
|
||||
dbg_assert(!this.exited,
|
||||
'grip() should not be called on exited browser actor.');
|
||||
dbg_assert(this.actorID,
|
||||
'tab should have an actorID.');
|
||||
return {
|
||||
'actor': this.actorID,
|
||||
'title': this.browser.title,
|
||||
'url': this.browser.document.documentURI
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The request types this actor can handle.
|
||||
* Creates a thread actor and a pool for context-lifetime actors. It then sets
|
||||
* up the content window for debugging.
|
||||
*/
|
||||
DeviceTabActor.prototype.requestTypes = {
|
||||
'attach': DeviceTabActor.prototype.onAttach,
|
||||
'detach': DeviceTabActor.prototype.onDetach
|
||||
DeviceTabActor.prototype._pushContext = function DTA_pushContext() {
|
||||
dbg_assert(!this._contextPool, "Can't push multiple contexts");
|
||||
|
||||
this._contextPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
|
||||
this.threadActor = new ThreadActor(this);
|
||||
this._addDebuggees(this.browser.wrappedJSObject);
|
||||
this._contextPool.addActor(this.threadActor);
|
||||
};
|
||||
|
||||
// Protocol Request Handlers
|
||||
|
||||
/**
|
||||
* Prepare to enter a nested event loop by disabling debuggee events.
|
||||
*/
|
||||
DeviceTabActor.prototype.preNest = function DTA_preNest() {
|
||||
let windowUtils = this.browser
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.suppressEventHandling(true);
|
||||
windowUtils.suspendTimeouts();
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare to exit a nested event loop by enabling debuggee events.
|
||||
*/
|
||||
DeviceTabActor.prototype.postNest = function DTA_postNest(aNestData) {
|
||||
let windowUtils = this.browser
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.resumeTimeouts();
|
||||
windowUtils.suppressEventHandling(false);
|
||||
};
|
||||
|
@ -544,6 +544,7 @@ function startDebugger() {
|
||||
if (!DebuggerServer.initialized) {
|
||||
// Allow remote connections.
|
||||
DebuggerServer.init(function () { return true; });
|
||||
DebuggerServer.addBrowserActors();
|
||||
DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
|
||||
}
|
||||
|
||||
|
@ -88,17 +88,18 @@
|
||||
|
||||
<command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
|
||||
<command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
|
||||
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();"/>
|
||||
<command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focus();" disabled="true"/>
|
||||
<command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
|
||||
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();"/>
|
||||
<command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();"/>
|
||||
<command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();"/>
|
||||
<command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();"/>
|
||||
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
|
||||
<command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();"/>
|
||||
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
|
||||
<command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
|
||||
<command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
|
||||
<command id="Tools:Sanitize"
|
||||
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
|
||||
<command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
|
||||
@ -190,8 +191,7 @@
|
||||
label="&devToolbarMenu.label;"
|
||||
type="checkbox" autocheck="false"
|
||||
command="Tools:DevToolbar"
|
||||
key="key_devToolbar"
|
||||
disabled="true" hidden="true"/>
|
||||
key="key_devToolbar"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_WebConsole"
|
||||
label="&webConsoleCmd.label;"
|
||||
type="checkbox" autocheck="false"
|
||||
@ -201,48 +201,40 @@
|
||||
label="&inspectMenu.label;"
|
||||
type="checkbox" autocheck="false"
|
||||
command="Tools:Inspect"
|
||||
key="key_inspect"
|
||||
disabled="true" hidden="true"/>
|
||||
key="key_inspect"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_Debugger"
|
||||
label="&debuggerMenu.label2;"
|
||||
type="checkbox" autocheck="false"
|
||||
command="Tools:Debugger"
|
||||
key="key_debugger"
|
||||
disabled="true" hidden="true"/>
|
||||
key="key_debugger"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_RemoteDebugger"
|
||||
label="&remoteDebuggerMenu.label;"
|
||||
command="Tools:RemoteDebugger"
|
||||
disabled="true" hidden="true"/>
|
||||
command="Tools:RemoteDebugger"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
|
||||
label="&chromeDebuggerMenu.label;"
|
||||
command="Tools:ChromeDebugger"
|
||||
disabled="true" hidden="true"/>
|
||||
command="Tools:ChromeDebugger"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_Scratchpad"
|
||||
label="&scratchpad.label;"
|
||||
command="Tools:Scratchpad"
|
||||
key="key_scratchpad"
|
||||
disabled="true" hidden="true"/>
|
||||
key="key_scratchpad"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_StyleEditor"
|
||||
label="&styleeditor.label;"
|
||||
type="checkbox" autocheck="false"
|
||||
command="Tools:StyleEditor"
|
||||
key="key_styleeditor"
|
||||
disabled="true" hidden="true"/>
|
||||
key="key_styleeditor"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_ResponsiveUI"
|
||||
label="&responsiveDesignTool.label;"
|
||||
type="checkbox" autocheck="false"
|
||||
command="Tools:ResponsiveUI"
|
||||
key="key_responsiveUI"
|
||||
disabled="true" hidden="true"/>
|
||||
key="key_responsiveUI"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_PageSource"
|
||||
label="&pageSourceCmd.label;"
|
||||
key="key_viewSource"
|
||||
command="View:PageSource"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
|
||||
hidden="true"
|
||||
label="&errorConsoleCmd.label;"
|
||||
key="key_errorConsole"
|
||||
oncommand="toJavaScriptConsole();"/>
|
||||
command="Tools:ErrorConsole"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_GetMoreTools"
|
||||
label="&getMoreDevtoolsCmd.label;"
|
||||
oncommand="openUILinkIn('https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/', 'tab');"/>
|
||||
@ -292,7 +284,7 @@
|
||||
<key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
|
||||
#endif
|
||||
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
|
||||
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
|
||||
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" command="Tools:ErrorConsole" modifiers="accel,shift"/>
|
||||
<key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
|
||||
keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
|
||||
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
|
||||
|
@ -1402,9 +1402,9 @@ var gBrowserInit = {
|
||||
// Enable developer toolbar?
|
||||
let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled");
|
||||
if (devToolbarEnabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_DevToolbar");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:DevToolbar");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
document.getElementById("Tools:DevToolbarFocus").removeAttribute("disabled");
|
||||
|
||||
// Show the toolbar if it was previously visible
|
||||
@ -1416,25 +1416,25 @@ var gBrowserInit = {
|
||||
// Enable Inspector?
|
||||
let enabled = gPrefService.getBoolPref("devtools.inspector.enabled");
|
||||
if (enabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_Inspect");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:Inspect");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Enable Debugger?
|
||||
let enabled = gPrefService.getBoolPref("devtools.debugger.enabled");
|
||||
if (enabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_Debugger");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:Debugger");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Enable Remote Debugger?
|
||||
let enabled = gPrefService.getBoolPref("devtools.debugger.remote-enabled");
|
||||
if (enabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_RemoteDebugger");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:RemoteDebugger");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Enable Chrome Debugger?
|
||||
@ -1442,34 +1442,34 @@ var gBrowserInit = {
|
||||
gPrefService.getBoolPref("devtools.debugger.chrome-enabled") &&
|
||||
gPrefService.getBoolPref("devtools.debugger.remote-enabled");
|
||||
if (enabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_ChromeDebugger");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:ChromeDebugger");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Enable Error Console?
|
||||
// XXX Temporarily always-enabled, see bug 601201
|
||||
let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled");
|
||||
if (consoleEnabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_ErrorConsole");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:ErrorConsole");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Enable Scratchpad in the UI, if the preference allows this.
|
||||
let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName);
|
||||
if (scratchpadEnabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_Scratchpad");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:Scratchpad");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Enable Style Editor?
|
||||
let styleEditorEnabled = gPrefService.getBoolPref(StyleEditor.prefEnabledName);
|
||||
if (styleEditorEnabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_StyleEditor");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:StyleEditor");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
@ -1484,9 +1484,9 @@ var gBrowserInit = {
|
||||
// Enable Responsive UI?
|
||||
let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled");
|
||||
if (responsiveUIEnabled) {
|
||||
let broadcaster = document.getElementById("devtoolsMenuBroadcaster_ResponsiveUI");
|
||||
broadcaster.removeAttribute("disabled");
|
||||
broadcaster.removeAttribute("hidden");
|
||||
let cmd = document.getElementById("Tools:ResponsiveUI");
|
||||
cmd.removeAttribute("disabled");
|
||||
cmd.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
let appMenuButton = document.getElementById("appmenu-button");
|
||||
|
@ -1070,6 +1070,14 @@
|
||||
onclick="contentAreaClick(event, false);"/>
|
||||
<statuspanel id="statusbar-display" inactive="true"/>
|
||||
</vbox>
|
||||
<splitter id="devtools-side-splitter" hidden="true"/>
|
||||
<vbox id="devtools-sidebar-box" hidden="true"
|
||||
style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
|
||||
<toolbar id="devtools-sidebar-toolbar"
|
||||
class="devtools-toolbar"
|
||||
nowindowdrag="true"/>
|
||||
<deck id="devtools-sidebar-deck" flex="1"/>
|
||||
</vbox>
|
||||
<splitter id="social-sidebar-splitter"
|
||||
class="chromeclass-extrachrome"
|
||||
observes="socialSidebarBroadcaster"/>
|
||||
@ -1081,14 +1089,6 @@
|
||||
flex="1"
|
||||
style="min-width: 14em; width: 18em; max-width: 36em;"/>
|
||||
</vbox>
|
||||
<splitter id="devtools-side-splitter" hidden="true"/>
|
||||
<vbox id="devtools-sidebar-box" hidden="true"
|
||||
style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
|
||||
<toolbar id="devtools-sidebar-toolbar"
|
||||
class="devtools-toolbar"
|
||||
nowindowdrag="true"/>
|
||||
<deck id="devtools-sidebar-deck" flex="1"/>
|
||||
</vbox>
|
||||
<vbox id="browser-border-end" hidden="true" layer="true"/>
|
||||
</hbox>
|
||||
|
||||
|
@ -10,11 +10,8 @@ relativesrcdir = browser/devtools/tilt/test
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_BROWSER_FILES = head.js
|
||||
|
||||
# browser_tilt* disabled on Linux due to bug 759157
|
||||
ifneq (gtk2,$(MOZ_WIDGET_TOOLKIT))
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
MOCHITEST_BROWSER_FILES = \
|
||||
head.js \
|
||||
browser_tilt_01_lazy_getter.js \
|
||||
browser_tilt_02_notifications-seq.js \
|
||||
browser_tilt_02_notifications.js \
|
||||
@ -60,6 +57,5 @@ MOCHITEST_BROWSER_FILES += \
|
||||
browser_tilt_visualizer.js \
|
||||
browser_tilt_zoom.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -538,7 +538,7 @@ var WebConsoleUtils = {
|
||||
value = aObject[propName];
|
||||
presentable = this.presentableValueFor(value);
|
||||
}
|
||||
catch (ex) {
|
||||
catch (ex) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -735,6 +735,8 @@ const OPEN_CLOSE_BODY = {
|
||||
"(": ")",
|
||||
};
|
||||
|
||||
const MAX_COMPLETIONS = 256;
|
||||
|
||||
/**
|
||||
* Analyses a given string to find the last statement that is interesting for
|
||||
* later completion.
|
||||
@ -895,9 +897,9 @@ function JSPropertyProvider(aScope, aInputValue)
|
||||
return null;
|
||||
}
|
||||
|
||||
// If obj is undefined or null, then there is no chance to run completion
|
||||
// on it. Exit here.
|
||||
if (typeof obj === "undefined" || obj === null) {
|
||||
// If obj is undefined or null (which is what "== null" does),
|
||||
// then there is no chance to run completion on it. Exit here.
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -918,9 +920,9 @@ function JSPropertyProvider(aScope, aInputValue)
|
||||
matchProp = properties[0].trimLeft();
|
||||
}
|
||||
|
||||
// If obj is undefined or null, then there is no chance to run
|
||||
// completion on it. Exit here.
|
||||
if (typeof obj === "undefined" || obj === null) {
|
||||
// If obj is undefined or null (which is what "== null" does),
|
||||
// then there is no chance to run completion on it. Exit here.
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -929,12 +931,7 @@ function JSPropertyProvider(aScope, aInputValue)
|
||||
return null;
|
||||
}
|
||||
|
||||
let matches = [];
|
||||
for (let prop in obj) {
|
||||
if (prop.indexOf(matchProp) == 0) {
|
||||
matches.push(prop);
|
||||
}
|
||||
}
|
||||
let matches = Object.keys(getMatchedProps(obj, matchProp));
|
||||
|
||||
return {
|
||||
matchProp: matchProp,
|
||||
@ -942,5 +939,55 @@ function JSPropertyProvider(aScope, aInputValue)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all accessible properties on this object.
|
||||
* Filter those properties by name.
|
||||
* Take only a certain number of those.
|
||||
*
|
||||
* @param object obj
|
||||
* Object whose properties we want to collect.
|
||||
*
|
||||
* @param string matchProp
|
||||
* Filter for properties that match this one.
|
||||
* Defaults to the empty string (which always matches).
|
||||
*
|
||||
* @return object
|
||||
* Object whose keys are all accessible properties on the object.
|
||||
*/
|
||||
function getMatchedProps(aObj, aMatchProp = "")
|
||||
{
|
||||
let c = MAX_COMPLETIONS;
|
||||
let names = {}; // Using an Object to avoid duplicates.
|
||||
let ownNames = Object.getOwnPropertyNames(aObj);
|
||||
for (let i = 0; i < ownNames.length; i++) {
|
||||
if (ownNames[i].indexOf(aMatchProp) == 0) {
|
||||
if (names[ownNames[i]] != true) {
|
||||
c--;
|
||||
if (c < 0) {
|
||||
return names;
|
||||
}
|
||||
names[ownNames[i]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We need to recursively go up the prototype chain.
|
||||
aObj = Object.getPrototypeOf(aObj);
|
||||
if (aObj !== null) {
|
||||
let parentScope = getMatchedProps(aObj, aMatchProp);
|
||||
for (let name in parentScope) {
|
||||
if (names[name] != true) {
|
||||
c--;
|
||||
if (c < 0) {
|
||||
return names;
|
||||
}
|
||||
names[name] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
return JSPropertyProvider;
|
||||
})(WebConsoleUtils);
|
||||
|
@ -35,33 +35,58 @@ function consoleOpened(aHud) {
|
||||
|
||||
ok(popup.isOpen, "popup is open");
|
||||
|
||||
is(popup.itemCount, 4, "popup.itemCount is correct");
|
||||
// 4 values, and the following properties:
|
||||
// __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
|
||||
// hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString
|
||||
// toSource unwatch valueOf watch constructor.
|
||||
is(popup.itemCount, 18, "popup.itemCount is correct");
|
||||
|
||||
let sameItems = popup.getItems();
|
||||
is(sameItems.every(function(aItem, aIndex) {
|
||||
return aItem.label == "item" + aIndex;
|
||||
}), true, "getItems returns back the same items");
|
||||
let sameItems = popup.getItems().map(function(e) {return e.label;});
|
||||
ok(sameItems.every(function(prop, index) {
|
||||
return [
|
||||
"__defineGetter__",
|
||||
"__defineSetter__",
|
||||
"__lookupGetter__",
|
||||
"__lookupSetter__",
|
||||
"constructor",
|
||||
"hasOwnProperty",
|
||||
"isPrototypeOf",
|
||||
"item0",
|
||||
"item1",
|
||||
"item2",
|
||||
"item3",
|
||||
"propertyIsEnumerable",
|
||||
"toLocaleString",
|
||||
"toSource",
|
||||
"toString",
|
||||
"unwatch",
|
||||
"valueOf",
|
||||
"watch",
|
||||
][index] === prop}), "getItems returns the items we expect");
|
||||
|
||||
is(popup.selectedIndex, -1, "no index is selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
|
||||
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
|
||||
|
||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||
is(popup.selectedItem.label, "item0", "item0 is selected");
|
||||
is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
|
||||
is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
|
||||
is(completeNode.value, prefix + "__defineGetter__",
|
||||
"completeNode.value holds __defineGetter__");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(popup.selectedIndex, 1, "index 1 is selected");
|
||||
is(popup.selectedItem.label, "item1", "item1 is selected");
|
||||
is(completeNode.value, prefix + "item1", "completeNode.value holds item1");
|
||||
is(popup.selectedItem.label, "__defineSetter__", "__defineSetter__ is selected");
|
||||
is(completeNode.value, prefix + "__defineSetter__",
|
||||
"completeNode.value holds __defineSetter__");
|
||||
|
||||
EventUtils.synthesizeKey("VK_UP", {});
|
||||
|
||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||
is(popup.selectedItem.label, "item0", "item0 is selected");
|
||||
is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
|
||||
is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
|
||||
is(completeNode.value, prefix + "__defineGetter__",
|
||||
"completeNode.value holds __defineGetter__");
|
||||
|
||||
popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false);
|
||||
|
||||
@ -83,7 +108,7 @@ function autocompletePopupHidden()
|
||||
|
||||
ok(!popup.isOpen, "popup is not open");
|
||||
|
||||
is(inputNode.value, "window.foobarBug585991.item0",
|
||||
is(inputNode.value, "window.foobarBug585991.__defineGetter__",
|
||||
"completion was successful after VK_TAB");
|
||||
|
||||
ok(!completeNode.value, "completeNode is empty");
|
||||
@ -93,16 +118,17 @@ function autocompletePopupHidden()
|
||||
|
||||
ok(popup.isOpen, "popup is open");
|
||||
|
||||
is(popup.itemCount, 4, "popup.itemCount is correct");
|
||||
is(popup.itemCount, 18, "popup.itemCount is correct");
|
||||
|
||||
is(popup.selectedIndex, -1, "no index is selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
|
||||
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
|
||||
|
||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||
is(popup.selectedItem.label, "item0", "item0 is selected");
|
||||
is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
|
||||
is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
|
||||
is(completeNode.value, prefix + "__defineGetter__",
|
||||
"completeNode.value holds __defineGetter__");
|
||||
|
||||
popup._panel.addEventListener("popuphidden", function onHidden() {
|
||||
popup._panel.removeEventListener("popuphidden", onHidden, false);
|
||||
@ -140,29 +166,31 @@ function testReturnKey()
|
||||
|
||||
ok(popup.isOpen, "popup is open");
|
||||
|
||||
is(popup.itemCount, 4, "popup.itemCount is correct");
|
||||
|
||||
is(popup.itemCount, 18, "popup.itemCount is correct");
|
||||
|
||||
is(popup.selectedIndex, -1, "no index is selected");
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
let prefix = jsterm.inputNode.value.replace(/[\S]/g, " ");
|
||||
|
||||
is(popup.selectedIndex, 0, "index 0 is selected");
|
||||
is(popup.selectedItem.label, "item0", "item0 is selected");
|
||||
is(completeNode.value, prefix + "item0", "completeNode.value holds item0");
|
||||
is(popup.selectedItem.label, "__defineGetter__", "__defineGetter__ is selected");
|
||||
is(completeNode.value, prefix + "__defineGetter__",
|
||||
"completeNode.value holds __defineGetter__");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {});
|
||||
|
||||
is(popup.selectedIndex, 1, "index 1 is selected");
|
||||
is(popup.selectedItem.label, "item1", "item1 is selected");
|
||||
is(completeNode.value, prefix + "item1", "completeNode.value holds item1");
|
||||
is(popup.selectedItem.label, "__defineSetter__", "__defineSetter__ is selected");
|
||||
is(completeNode.value, prefix + "__defineSetter__",
|
||||
"completeNode.value holds __defineSetter__");
|
||||
|
||||
popup._panel.addEventListener("popuphidden", function onHidden() {
|
||||
popup._panel.removeEventListener("popuphidden", onHidden, false);
|
||||
|
||||
ok(!popup.isOpen, "popup is not open after VK_RETURN");
|
||||
|
||||
is(inputNode.value, "window.foobarBug585991.item1",
|
||||
is(inputNode.value, "window.foobarBug585991.__defineSetter__",
|
||||
"completion was successful after VK_RETURN");
|
||||
|
||||
ok(!completeNode.value, "completeNode is empty");
|
||||
|
@ -34,8 +34,12 @@ function consoleOpened(aHud) {
|
||||
|
||||
ok(popup.isOpen, "popup is open");
|
||||
|
||||
// |props| values, and the following properties:
|
||||
// __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__
|
||||
// constructor hasOwnProperty isPrototypeOf propertyIsEnumerable
|
||||
// toLocaleString toSource toString unwatch valueOf watch.
|
||||
let props = WCU.namesAndValuesOf(content.wrappedJSObject.document.body);
|
||||
is(popup.itemCount, props.length, "popup.itemCount is correct");
|
||||
is(popup.itemCount, 14 + props.length, "popup.itemCount is correct");
|
||||
|
||||
popup._panel.addEventListener("popuphidden", autocompletePopupHidden, false);
|
||||
|
||||
|
@ -50,6 +50,14 @@ function testCompletion(hud) {
|
||||
is(input.selectionEnd, 8, "end selection is alright");
|
||||
is(jsterm.completeNode.value.replace(/ /g, ""), "", "'docu' completed");
|
||||
|
||||
// Test typing 'window.O' and press tab.
|
||||
input.value = "window.O";
|
||||
input.setSelectionRange(8, 8);
|
||||
jsterm.complete(jsterm.COMPLETE_FORWARD, testNext);
|
||||
yield;
|
||||
|
||||
is(input.value, "window.Object", "'window.O' tab completion");
|
||||
|
||||
// Test typing 'document.getElem'.
|
||||
input.value = "document.getElem";
|
||||
input.setSelectionRange(16, 16);
|
||||
|
@ -454,7 +454,7 @@ addonListDesc=List installed add-ons
|
||||
# LOCALIZATION NOTE (addonListTypeDesc) A very short description of the
|
||||
# 'addon list <type>' command. This string is designed to be shown in a menu
|
||||
# alongside the command name, which is why it should be as short as possible.
|
||||
addonListTypeDesc=Select an addon type
|
||||
addonListTypeDesc=Select an add-on type
|
||||
|
||||
# LOCALIZATION NOTE (addonListDictionaryHeading, addonListExtensionHeading,
|
||||
# addonListLocaleHeading, addonListPluginHeading, addonListThemeHeading,
|
||||
@ -465,18 +465,18 @@ addonListExtensionHeading=The following extensions are currently installed:
|
||||
addonListLocaleHeading=The following locales are currently installed:
|
||||
addonListPluginHeading=The following plugins are currently installed:
|
||||
addonListThemeHeading=The following themes are currently installed:
|
||||
addonListAllHeading=The following addons are currently installed:
|
||||
addonListUnknownHeading=The following addons of the selected type are currently installed:
|
||||
addonListAllHeading=The following add-ons are currently installed:
|
||||
addonListUnknownHeading=The following add-ons of the selected type are currently installed:
|
||||
|
||||
# LOCALIZATION NOTE (addonNameDesc) A very short description of the
|
||||
# name parameter of numerous addon commands. This string is designed to be shown
|
||||
# name parameter of numerous add-on commands. This string is designed to be shown
|
||||
# in a menu alongside the command name, which is why it should be as short as
|
||||
# possible.
|
||||
addonNameDesc=The name of the add-on
|
||||
|
||||
# LOCALIZATION NOTE (addonNoneOfType) Used in the output of the 'addon list'
|
||||
# command when a search for addons of a particular type were not found.
|
||||
addonNoneOfType=There are no addons of that type installed.
|
||||
# command when a search for add-ons of a particular type were not found.
|
||||
addonNoneOfType=There are no add-ons of that type installed.
|
||||
|
||||
# LOCALIZATION NOTE (addonEnableDesc) A very short description of the
|
||||
# 'addon enable <type>' command. This string is designed to be shown in a menu
|
||||
@ -484,12 +484,12 @@ addonNoneOfType=There are no addons of that type installed.
|
||||
addonEnableDesc=Enable the specified add-on
|
||||
|
||||
# LOCALIZATION NOTE (addonAlreadyEnabled) Used in the output of the
|
||||
# 'addon enable' command when an attempt is made to enable an addon is already
|
||||
# 'addon enable' command when an attempt is made to enable an add-on is already
|
||||
# enabled.
|
||||
addonAlreadyEnabled=%S is already enabled.
|
||||
|
||||
# LOCALIZATION NOTE (addonEnabled) Used in the output of the 'addon enable'
|
||||
# command when an addon is enabled.
|
||||
# command when an add-on is enabled.
|
||||
addonEnabled=%S enabled.
|
||||
|
||||
# LOCALIZATION NOTE (addonDisableDesc) A very short description of the
|
||||
@ -498,12 +498,12 @@ addonEnabled=%S enabled.
|
||||
addonDisableDesc=Disable the specified add-on
|
||||
|
||||
# LOCALIZATION NOTE (addonAlreadyDisabled) Used in the output of the
|
||||
# 'addon disable' command when an attempt is made to disable an addon is already
|
||||
# 'addon disable' command when an attempt is made to disable an add-on is already
|
||||
# disabled.
|
||||
addonAlreadyDisabled=%S is already disabled.
|
||||
|
||||
# LOCALIZATION NOTE (addonDisabled) Used in the output of the 'addon disable'
|
||||
# command when an addon is disabled.
|
||||
# command when an add-on is disabled.
|
||||
addonDisabled=%S disabled.
|
||||
|
||||
# LOCALIZATION NOTE (exportDesc) A very short description of the 'export'
|
||||
|
@ -36,8 +36,6 @@ CPPSRCS = \
|
||||
nsDOMDragEvent.cpp \
|
||||
nsDOMMutationEvent.cpp \
|
||||
nsDOMPopupBlockedEvent.cpp \
|
||||
nsDOMDeviceLightEvent.cpp \
|
||||
nsDOMDeviceOrientationEvent.cpp \
|
||||
nsDOMDeviceMotionEvent.cpp \
|
||||
nsDOMBeforeUnloadEvent.cpp \
|
||||
nsDOMXULCommandEvent.cpp \
|
||||
@ -65,7 +63,6 @@ CPPSRCS = \
|
||||
nsDOMSettingsEvent.cpp \
|
||||
nsDOMTouchEvent.cpp \
|
||||
nsDOMCompositionEvent.cpp \
|
||||
nsDOMApplicationEvent.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_B2G_RIL
|
||||
|
@ -1,68 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsDOMApplicationEvent.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
|
||||
DOMCI_DATA(MozApplicationEvent, nsDOMMozApplicationEvent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMozApplicationEvent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplication)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplication)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMMozApplicationEvent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMMozApplicationEvent)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozApplicationEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
|
||||
NS_IMPL_RELEASE_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMozApplicationEvent::GetApplication(mozIDOMApplication** aApplication)
|
||||
{
|
||||
NS_IF_ADDREF(*aApplication = mApplication);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMozApplicationEvent::InitMozApplicationEvent(const nsAString& aType,
|
||||
bool aCanBubble,
|
||||
bool aCancelable,
|
||||
mozIDOMApplication* aApplication)
|
||||
{
|
||||
nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mApplication = aApplication;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMMozApplicationEvent::InitFromCtor(const nsAString& aType, JSContext* aCx, jsval* aVal)
|
||||
{
|
||||
mozilla::dom::MozApplicationEventInit d;
|
||||
nsresult rv = d.Init(aCx, aVal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return InitMozApplicationEvent(aType, d.bubbles, d.cancelable, d.application);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewDOMMozApplicationEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
nsPresContext* aPresContext,
|
||||
nsEvent* aEvent)
|
||||
{
|
||||
nsDOMMozApplicationEvent* e = new nsDOMMozApplicationEvent(aPresContext, aEvent);
|
||||
return CallQueryInterface(e, aInstancePtrResult);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsDOMApplicationEvent_h__
|
||||
#define nsDOMApplicationEvent_h__
|
||||
|
||||
#include "nsIDOMApplicationRegistry.h"
|
||||
#include "nsDOMEvent.h"
|
||||
|
||||
class nsDOMMozApplicationEvent : public nsDOMEvent,
|
||||
public nsIDOMMozApplicationEvent
|
||||
{
|
||||
public:
|
||||
nsDOMMozApplicationEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
||||
: nsDOMEvent(aPresContext, aEvent) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMMozApplicationEvent, nsDOMEvent)
|
||||
// Forward to base class
|
||||
NS_FORWARD_TO_NSDOMEVENT
|
||||
|
||||
NS_DECL_NSIDOMMOZAPPLICATIONEVENT
|
||||
|
||||
virtual nsresult InitFromCtor(const nsAString& aType, JSContext* aCx, jsval* aVal);
|
||||
|
||||
private:
|
||||
nsCOMPtr<mozIDOMApplication> mApplication;
|
||||
};
|
||||
|
||||
#endif // nsDOMContactChangeEvent_h__
|
@ -1,58 +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/. */
|
||||
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsDOMDeviceLightEvent.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
|
||||
NS_IMPL_RELEASE_INHERITED(nsDOMDeviceLightEvent, nsDOMEvent)
|
||||
|
||||
DOMCI_DATA(DeviceLightEvent, nsDOMDeviceLightEvent)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDOMDeviceLightEvent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceLightEvent)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceLightEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceLightEvent::InitDeviceLightEvent(const nsAString & aEventTypeArg,
|
||||
bool aCanBubbleArg,
|
||||
bool aCancelableArg,
|
||||
double aValue)
|
||||
{
|
||||
nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mValue = aValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceLightEvent::GetValue(double *aValue)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aValue);
|
||||
*aValue = mValue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMDeviceLightEvent::InitFromCtor(const nsAString& aType,
|
||||
JSContext* aCx, jsval* aVal)
|
||||
{
|
||||
mozilla::dom::DeviceLightEventInit d;
|
||||
nsresult rv = d.Init(aCx, aVal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return InitDeviceLightEvent(aType, d.bubbles, d.cancelable, d.value);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewDOMDeviceLightEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
nsPresContext* aPresContext,
|
||||
nsEvent *aEvent)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aInstancePtrResult);
|
||||
nsDOMDeviceLightEvent* it = new nsDOMDeviceLightEvent(aPresContext, aEvent);
|
||||
return CallQueryInterface(it, aInstancePtrResult);
|
||||
}
|
@ -1,36 +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/. */
|
||||
|
||||
#ifndef nsDOMDeviceLightEvent_h__
|
||||
#define nsDOMDeviceLightEvent_h__
|
||||
|
||||
#include "nsIDOMDeviceLightEvent.h"
|
||||
#include "nsDOMEvent.h"
|
||||
|
||||
class nsDOMDeviceLightEvent
|
||||
: public nsDOMEvent
|
||||
, public nsIDOMDeviceLightEvent
|
||||
{
|
||||
public:
|
||||
|
||||
nsDOMDeviceLightEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
||||
: nsDOMEvent(aPresContext, aEvent),
|
||||
mValue(0) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// Forward to nsDOMEvent
|
||||
NS_FORWARD_TO_NSDOMEVENT
|
||||
|
||||
// nsIDOMDeviceLightEvent Interface
|
||||
NS_DECL_NSIDOMDEVICELIGHTEVENT
|
||||
|
||||
virtual nsresult InitFromCtor(const nsAString& aType,
|
||||
JSContext* aCx,
|
||||
jsval* aVal);
|
||||
protected:
|
||||
double mValue;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,81 +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/. */
|
||||
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "nsDOMDeviceOrientationEvent.h"
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(nsDOMDeviceOrientationEvent, nsDOMEvent)
|
||||
NS_IMPL_RELEASE_INHERITED(nsDOMDeviceOrientationEvent, nsDOMEvent)
|
||||
|
||||
DOMCI_DATA(DeviceOrientationEvent, nsDOMDeviceOrientationEvent)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsDOMDeviceOrientationEvent)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceOrientationEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
|
||||
|
||||
NS_IMETHODIMP nsDOMDeviceOrientationEvent::InitDeviceOrientationEvent(const nsAString & aEventTypeArg,
|
||||
bool aCanBubbleArg,
|
||||
bool aCancelableArg,
|
||||
double aAlpha,
|
||||
double aBeta,
|
||||
double aGamma,
|
||||
bool aAbsolute)
|
||||
{
|
||||
nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mAlpha = aAlpha;
|
||||
mBeta = aBeta;
|
||||
mGamma = aGamma;
|
||||
mAbsolute = aAbsolute;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetAlpha(double *aAlpha)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aAlpha);
|
||||
|
||||
*aAlpha = mAlpha;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetBeta(double *aBeta)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBeta);
|
||||
|
||||
*aBeta = mBeta;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetGamma(double *aGamma)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aGamma);
|
||||
|
||||
*aGamma = mGamma;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDOMDeviceOrientationEvent::GetAbsolute(bool *aAbsolute)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aAbsolute);
|
||||
|
||||
*aAbsolute = mAbsolute;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
nsPresContext* aPresContext,
|
||||
nsEvent *aEvent)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aInstancePtrResult);
|
||||
|
||||
nsDOMDeviceOrientationEvent* it = new nsDOMDeviceOrientationEvent(aPresContext, aEvent);
|
||||
if (nsnull == it) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return CallQueryInterface(it, aInstancePtrResult);
|
||||
}
|
@ -1,36 +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/. */
|
||||
|
||||
#ifndef nsDOMDeviceOrientationEvent_h__
|
||||
#define nsDOMDeviceOrientationEvent_h__
|
||||
|
||||
#include "nsIDOMDeviceOrientationEvent.h"
|
||||
#include "nsDOMEvent.h"
|
||||
|
||||
class nsDOMDeviceOrientationEvent : public nsDOMEvent,
|
||||
public nsIDOMDeviceOrientationEvent
|
||||
{
|
||||
public:
|
||||
|
||||
nsDOMDeviceOrientationEvent(nsPresContext* aPresContext, nsEvent* aEvent)
|
||||
: nsDOMEvent(aPresContext, aEvent),
|
||||
mAlpha(0),
|
||||
mBeta(0),
|
||||
mGamma(0),
|
||||
mAbsolute(true) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// Forward to nsDOMEvent
|
||||
NS_FORWARD_TO_NSDOMEVENT
|
||||
|
||||
// nsIDOMDeviceOrientationEvent Interface
|
||||
NS_DECL_NSIDOMDEVICEORIENTATIONEVENT
|
||||
|
||||
protected:
|
||||
double mAlpha, mBeta, mGamma;
|
||||
bool mAbsolute;
|
||||
};
|
||||
|
||||
#endif
|
@ -425,6 +425,24 @@ is(e.value, 1, "value should be 1");
|
||||
document.dispatchEvent(e);
|
||||
is(receivedEvent, e, "Wrong event!");
|
||||
|
||||
// DeviceOrientationEvent
|
||||
e = new DeviceOrientationEvent("hello");
|
||||
ok(e.type, "hello", "Wrong event type!");
|
||||
ok(!e.isTrusted, "Event should not be trusted");
|
||||
is(e.alpha, 0);
|
||||
is(e.beta, 0);
|
||||
is(e.gamma, 0);
|
||||
is(e.absolute, false);
|
||||
|
||||
e = new DeviceOrientationEvent("hello", { alpha: 1, beta: 2, gamma: 3, absolute: true } );
|
||||
ok(e.type, "hello", "Wrong event type!");
|
||||
ok(!e.isTrusted, "Event should not be trusted");
|
||||
is(e.alpha, 1);
|
||||
is(e.beta, 2);
|
||||
is(e.gamma, 3);
|
||||
is(e.absolute, true);
|
||||
document.dispatchEvent(e);
|
||||
is(receivedEvent, e, "Wrong event!");
|
||||
|
||||
// MouseEvent
|
||||
|
||||
|
@ -298,8 +298,6 @@
|
||||
#define MOZ_GENERATED_EVENTS_INCLUDES
|
||||
#include "GeneratedEvents.h"
|
||||
#undef MOZ_GENERATED_EVENTS_INCLUDES
|
||||
#include "nsIDOMDeviceLightEvent.h"
|
||||
#include "nsIDOMDeviceOrientationEvent.h"
|
||||
#include "nsIDOMDeviceMotionEvent.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIDOMNodeIterator.h"
|
||||
@ -815,9 +813,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(PopupBlockedEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
// Device Light
|
||||
NS_DEFINE_CLASSINFO_DATA(DeviceLightEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
#define MOZ_GENERATED_EVENT_LIST
|
||||
#define MOZ_GENERATED_EVENT(_event_interface) \
|
||||
@ -826,9 +821,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
#include "GeneratedEvents.h"
|
||||
#undef MOZ_GENERATED_EVENT_LIST
|
||||
|
||||
// Device Orientation
|
||||
NS_DEFINE_CLASSINFO_DATA(DeviceOrientationEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(DeviceMotionEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH,
|
||||
@ -1641,8 +1633,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(MozSettingsEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(MozApplicationEvent, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
NS_DEFINE_CLASSINFO_DATA(MozWifiStatusChangeEvent, nsDOMGenericSH,
|
||||
@ -1727,10 +1717,8 @@ static const nsContractIDMapData kConstructorMap[] =
|
||||
|
||||
NS_DEFINE_EVENT_CTOR(Event)
|
||||
NS_DEFINE_EVENT_CTOR(MozSettingsEvent)
|
||||
NS_DEFINE_EVENT_CTOR(MozApplicationEvent)
|
||||
NS_DEFINE_EVENT_CTOR(UIEvent)
|
||||
NS_DEFINE_EVENT_CTOR(MouseEvent)
|
||||
NS_DEFINE_EVENT_CTOR(DeviceLightEvent)
|
||||
#ifdef MOZ_B2G_RIL
|
||||
NS_DEFINE_EVENT_CTOR(MozWifiStatusChangeEvent)
|
||||
NS_DEFINE_EVENT_CTOR(MozWifiConnectionInfoEvent)
|
||||
@ -1775,10 +1763,8 @@ static const nsConstructorFuncMapData kConstructorFuncMap[] =
|
||||
NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozSettingsEvent)
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozApplicationEvent)
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(DeviceLightEvent)
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(StorageEvent)
|
||||
#ifdef MOZ_B2G_RIL
|
||||
NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiStatusChangeEvent)
|
||||
@ -2600,11 +2586,6 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_EVENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DeviceLightEvent, nsIDOMDeviceLightEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceLightEvent)
|
||||
DOM_CLASSINFO_EVENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
#define MOZ_GENERATED_EVENT_LIST
|
||||
#define MOZ_GENERATED_EVENT(_event_interface) \
|
||||
DOM_CLASSINFO_MAP_BEGIN(_event_interface, nsIDOM##_event_interface) \
|
||||
@ -2614,11 +2595,6 @@ nsDOMClassInfo::Init()
|
||||
#include "GeneratedEvents.h"
|
||||
#undef MOZ_GENERATED_EVENT_LIST
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DeviceOrientationEvent, nsIDOMDeviceOrientationEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceOrientationEvent)
|
||||
DOM_CLASSINFO_EVENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DeviceMotionEvent, nsIDOMDeviceMotionEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceMotionEvent)
|
||||
DOM_CLASSINFO_EVENT_MAP_ENTRIES
|
||||
@ -4409,11 +4385,6 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_EVENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(MozApplicationEvent, nsIDOMMozApplicationEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozApplicationEvent)
|
||||
DOM_CLASSINFO_EVENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
DOM_CLASSINFO_MAP_BEGIN(MozWifiStatusChangeEvent, nsIDOMMozWifiStatusChangeEvent)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozWifiStatusChangeEvent)
|
||||
|
@ -43,12 +43,10 @@ DOMCI_CLASS(DragEvent)
|
||||
DOMCI_CLASS(KeyboardEvent)
|
||||
DOMCI_CLASS(CompositionEvent)
|
||||
DOMCI_CLASS(PopupBlockedEvent)
|
||||
DOMCI_CLASS(DeviceLightEvent)
|
||||
#define MOZ_GENERATED_EVENT_LIST
|
||||
#define MOZ_GENERATED_EVENT(_event_interface) DOMCI_CLASS(_event_interface)
|
||||
#include "GeneratedEvents.h"
|
||||
#undef MOZ_GENERATED_EVENT_LIST
|
||||
DOMCI_CLASS(DeviceOrientationEvent)
|
||||
DOMCI_CLASS(DeviceMotionEvent)
|
||||
DOMCI_CLASS(DeviceAcceleration)
|
||||
DOMCI_CLASS(DeviceRotationRate)
|
||||
@ -509,8 +507,6 @@ DOMCI_CLASS(MutationRecord)
|
||||
|
||||
DOMCI_CLASS(MozSettingsEvent)
|
||||
|
||||
DOMCI_CLASS(MozApplicationEvent)
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
DOMCI_CLASS(MozWifiStatusChangeEvent)
|
||||
DOMCI_CLASS(MozWifiConnectionInfoEvent)
|
||||
|
@ -17,6 +17,7 @@ GRE_MODULE = 1
|
||||
XPIDLSRCS = \
|
||||
nsIDOMApplicationRegistry.idl \
|
||||
nsIAppsService.idl \
|
||||
nsIDOMMozApplicationEvent.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -3,7 +3,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "domstubs.idl"
|
||||
#include "nsIDOMEvent.idl"
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
|
||||
interface nsIDOMDOMRequest;
|
||||
@ -43,22 +42,6 @@ interface mozIDOMApplication : nsISupports
|
||||
nsIDOMDOMRequest uninstall();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(8f2bfba8-f10e-4f63-a5e0-7a7056e1dbe6)]
|
||||
interface nsIDOMMozApplicationEvent : nsIDOMEvent
|
||||
{
|
||||
readonly attribute mozIDOMApplication application;
|
||||
|
||||
[noscript] void initMozApplicationEvent(in DOMString aType,
|
||||
in boolean aCanBubble,
|
||||
in boolean aCancelable,
|
||||
in mozIDOMApplication aApplication);
|
||||
};
|
||||
|
||||
dictionary MozApplicationEventInit : EventInit
|
||||
{
|
||||
mozIDOMApplication application;
|
||||
};
|
||||
|
||||
[scriptable, uuid(bd304874-d532-4e13-8034-544211445583)]
|
||||
interface mozIDOMApplicationMgmt : nsISupports
|
||||
{
|
||||
|
23
dom/interfaces/apps/nsIDOMMozApplicationEvent.idl
Normal file
23
dom/interfaces/apps/nsIDOMMozApplicationEvent.idl
Normal file
@ -0,0 +1,23 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "nsIDOMEvent.idl"
|
||||
|
||||
interface mozIDOMApplication;
|
||||
|
||||
[scriptable, builtinclass, uuid(8f2bfba8-f10e-4f63-a5e0-7a7056e1dbe6)]
|
||||
interface nsIDOMMozApplicationEvent : nsIDOMEvent
|
||||
{
|
||||
readonly attribute mozIDOMApplication application;
|
||||
|
||||
[noscript] void initMozApplicationEvent(in DOMString aType,
|
||||
in boolean aCanBubble,
|
||||
in boolean aCancelable,
|
||||
in mozIDOMApplication aApplication);
|
||||
};
|
||||
|
||||
dictionary MozApplicationEventInit : EventInit
|
||||
{
|
||||
mozIDOMApplication application;
|
||||
};
|
@ -41,3 +41,10 @@ interface nsIDOMDeviceOrientationEvent : nsIDOMEvent
|
||||
readonly attribute boolean absolute;
|
||||
};
|
||||
|
||||
dictionary DeviceOrientationEventInit : EventInit
|
||||
{
|
||||
double alpha;
|
||||
double beta;
|
||||
double gamma;
|
||||
boolean absolute;
|
||||
};
|
||||
|
@ -204,10 +204,6 @@ NS_NewDOMMutationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class
|
||||
nsresult
|
||||
NS_NewDOMPopupBlockedEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
|
||||
nsresult
|
||||
NS_NewDOMDeviceOrientationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
|
||||
nsresult
|
||||
NS_NewDOMDeviceLightEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
|
||||
nsresult
|
||||
NS_NewDOMDeviceMotionEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, nsEvent* aEvent);
|
||||
nsresult
|
||||
NS_NewDOMTextEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsTextEvent* aEvent);
|
||||
|
@ -16,8 +16,6 @@ dictionaries = [
|
||||
[ 'WifiConnectionInfoEventInit', 'nsIWifiEventInits.idl' ],
|
||||
[ 'WifiStatusChangeEventInit', 'nsIWifiEventInits.idl' ],
|
||||
[ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
|
||||
[ 'DeviceLightEventInit', 'nsIDOMDeviceLightEvent.idl' ],
|
||||
[ 'MozApplicationEventInit', 'nsIDOMApplicationRegistry.idl' ],
|
||||
[ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
|
||||
[ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
|
||||
[ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ]
|
||||
@ -26,7 +24,8 @@ dictionaries = [
|
||||
# include file names
|
||||
special_includes = [
|
||||
'nsContentUtils.h',
|
||||
'XPCQuickStubs.h'
|
||||
'XPCQuickStubs.h',
|
||||
'nsIDOMApplicationRegistry.h'
|
||||
]
|
||||
|
||||
# name of the type to not include using #include "typename.h"
|
||||
|
@ -304,6 +304,8 @@ def write_getter(a, iface, fd):
|
||||
fd.write(" JSBool b;\n")
|
||||
fd.write(" MOZ_ALWAYS_TRUE(JS_ValueToBoolean(aCx, v, &b));\n")
|
||||
fd.write(" aDict.%s = b;\n" % a.name)
|
||||
elif realtype.count("PRUint32"):
|
||||
fd.write(" NS_ENSURE_STATE(JS_ValueToECMAUint32(aCx, v, &aDict.%s));\n" % a.name)
|
||||
elif realtype.count("PRInt32"):
|
||||
fd.write(" NS_ENSURE_STATE(JS_ValueToECMAInt32(aCx, v, &aDict.%s));\n" % a.name)
|
||||
elif realtype.count("double"):
|
||||
|
@ -15,16 +15,21 @@ simple_events = [
|
||||
'PopStateEvent',
|
||||
'HashChangeEvent',
|
||||
'CloseEvent',
|
||||
'MozContactChangeEvent'
|
||||
'MozContactChangeEvent',
|
||||
'DeviceOrientationEvent',
|
||||
'DeviceLightEvent',
|
||||
'MozApplicationEvent'
|
||||
]
|
||||
|
||||
""" include file names """
|
||||
special_includes = [
|
||||
'DictionaryHelpers.h',
|
||||
'nsContentUtils.h'
|
||||
'nsContentUtils.h',
|
||||
'nsIDOMApplicationRegistry.h'
|
||||
]
|
||||
|
||||
""" name of the type to not include using #include "typename.h" """
|
||||
exclude_automatic_type_include = [
|
||||
'nsISupports'
|
||||
'nsISupports',
|
||||
'mozIDOMApplication'
|
||||
]
|
||||
|
@ -6098,6 +6098,7 @@ var RemoteDebugger = {
|
||||
try {
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init(this._allowConnection);
|
||||
DebuggerServer.addBrowserActors();
|
||||
DebuggerServer.addActors("chrome://browser/content/dbg-browser-actors.js");
|
||||
}
|
||||
|
||||
|
@ -5,14 +5,16 @@
|
||||
|
||||
"use strict";
|
||||
/**
|
||||
* Fennec-specific actors.
|
||||
* Fennec-specific root actor that extends BrowserRootActor and overrides some
|
||||
* of its methods.
|
||||
*/
|
||||
|
||||
var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
|
||||
/**
|
||||
* The function that creates the root actor. DebuggerServer expects to find this
|
||||
* function in the loaded actors in order to initialize properly.
|
||||
*/
|
||||
function createRootActor(aConnection) {
|
||||
return new BrowserRootActor(aConnection);
|
||||
return new FennecRootActor(aConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -24,412 +26,94 @@ function createRootActor(aConnection) {
|
||||
* @param aConnection DebuggerServerConnection
|
||||
* The conection to the client.
|
||||
*/
|
||||
function BrowserRootActor(aConnection) {
|
||||
this.conn = aConnection;
|
||||
this._tabActors = new WeakMap();
|
||||
this._tabActorPool = null;
|
||||
this._actorFactories = null;
|
||||
|
||||
this.onTabClosed = this.onTabClosed.bind(this);
|
||||
windowMediator.addListener(this);
|
||||
function FennecRootActor(aConnection) {
|
||||
BrowserRootActor.call(this, aConnection);
|
||||
}
|
||||
|
||||
BrowserRootActor.prototype = {
|
||||
/**
|
||||
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
|
||||
*/
|
||||
sayHello: function BRA_sayHello() {
|
||||
return { from: "root",
|
||||
applicationType: "browser",
|
||||
traits: [] };
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnects the actor from the browser window.
|
||||
*/
|
||||
disconnect: function BRA_disconnect() {
|
||||
windowMediator.removeListener(this);
|
||||
|
||||
// We may have registered event listeners on browser windows to
|
||||
// watch for tab closes, remove those.
|
||||
let win = windowMediator.getMostRecentWindow("navigator:browser");
|
||||
this.unwatchWindow(win);
|
||||
|
||||
// Signal our imminent shutdown.
|
||||
let evt = win.document.createEvent("Event");
|
||||
evt.initEvent("Debugger:Shutdown", true, false);
|
||||
win.document.documentElement.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the listTabs request. Builds a list of actors
|
||||
* for the tabs running in the process. The actors will survive
|
||||
* until at least the next listTabs request.
|
||||
*/
|
||||
onListTabs: function BRA_onListTabs() {
|
||||
// Get actors for all the currently-running tabs (reusing
|
||||
// existing actors where applicable), and store them in
|
||||
// an ActorPool.
|
||||
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
let actorList = [];
|
||||
|
||||
let win = windowMediator.getMostRecentWindow("navigator:browser");
|
||||
this.browser = win.BrowserApp.selectedBrowser;
|
||||
|
||||
// Watch the window for tab closes so we can invalidate
|
||||
// actors as needed.
|
||||
this.watchWindow(win);
|
||||
|
||||
let tabs = win.BrowserApp.tabs;
|
||||
let selected;
|
||||
|
||||
for each (let tab in tabs) {
|
||||
let browser = tab.browser;
|
||||
|
||||
if (browser == this.browser) {
|
||||
selected = actorList.length;
|
||||
}
|
||||
|
||||
let actor = this._tabActors.get(browser);
|
||||
if (!actor) {
|
||||
actor = new BrowserTabActor(this.conn, browser);
|
||||
actor.parentID = this.actorID;
|
||||
this._tabActors.set(browser, actor);
|
||||
}
|
||||
|
||||
actorPool.addActor(actor);
|
||||
actorList.push(actor);
|
||||
}
|
||||
|
||||
// Now drop the old actorID -> actor map. Actors that still
|
||||
// mattered were added to the new map, others will go
|
||||
// away.
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
return { "from": "root",
|
||||
"selected": selected,
|
||||
"tabs": [actor.grip()
|
||||
for each (actor in actorList)] };
|
||||
},
|
||||
|
||||
/**
|
||||
* Watch a window that was visited during onListTabs for
|
||||
* tab closures.
|
||||
*/
|
||||
watchWindow: function BRA_watchWindow(aWindow) {
|
||||
let tabContainer = aWindow.document.getElementById("browsers");
|
||||
tabContainer.addEventListener("TabClose",
|
||||
this.onTabClosed,
|
||||
false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stop watching a window for tab closes.
|
||||
*/
|
||||
unwatchWindow: function BRA_unwatchWindow(aWindow) {
|
||||
let tabContainer = aWindow.document.getElementById("browsers");
|
||||
tabContainer.removeEventListener("TabClose", this.onTabClosed);
|
||||
this.exitTabActor(aWindow);
|
||||
},
|
||||
|
||||
/**
|
||||
* When a tab is closed, exit its tab actor. The actor
|
||||
* will be dropped at the next listTabs request.
|
||||
*/
|
||||
onTabClosed: function BRA_onTabClosed(aEvent) {
|
||||
this.exitTabActor(aEvent.target.browser);
|
||||
},
|
||||
|
||||
/**
|
||||
* Exit the tab actor of the specified tab.
|
||||
*/
|
||||
exitTabActor: function BRA_exitTabActor(aWindow) {
|
||||
let actor = this._tabActors.get(aWindow);
|
||||
if (actor) {
|
||||
actor.exit();
|
||||
}
|
||||
},
|
||||
|
||||
// nsIWindowMediatorListener
|
||||
onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { },
|
||||
onOpenWindow: function BRA_onOpenWindow(aWindow) { },
|
||||
onCloseWindow: function BRA_onCloseWindow(aWindow) {
|
||||
if (aWindow.BrowserApp) {
|
||||
this.unwatchWindow(aWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
FennecRootActor.prototype = new BrowserRootActor();
|
||||
|
||||
/**
|
||||
* The request types this actor can handle.
|
||||
* Handles the listTabs request. Builds a list of actors
|
||||
* for the tabs running in the process. The actors will survive
|
||||
* until at least the next listTabs request.
|
||||
*/
|
||||
BrowserRootActor.prototype.requestTypes = {
|
||||
"listTabs": BrowserRootActor.prototype.onListTabs
|
||||
FennecRootActor.prototype.onListTabs = function FRA_onListTabs() {
|
||||
// Get actors for all the currently-running tabs (reusing
|
||||
// existing actors where applicable), and store them in
|
||||
// an ActorPool.
|
||||
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
let actorList = [];
|
||||
|
||||
let win = windowMediator.getMostRecentWindow("navigator:browser");
|
||||
this.browser = win.BrowserApp.selectedBrowser;
|
||||
|
||||
// Watch the window for tab closes so we can invalidate
|
||||
// actors as needed.
|
||||
this.watchWindow(win);
|
||||
|
||||
let tabs = win.BrowserApp.tabs;
|
||||
let selected;
|
||||
|
||||
for each (let tab in tabs) {
|
||||
let browser = tab.browser;
|
||||
|
||||
if (browser == this.browser) {
|
||||
selected = actorList.length;
|
||||
}
|
||||
|
||||
let actor = this._tabActors.get(browser);
|
||||
if (!actor) {
|
||||
actor = new BrowserTabActor(this.conn, browser);
|
||||
actor.parentID = this.actorID;
|
||||
this._tabActors.set(browser, actor);
|
||||
}
|
||||
|
||||
actorPool.addActor(actor);
|
||||
actorList.push(actor);
|
||||
}
|
||||
|
||||
// Now drop the old actorID -> actor map. Actors that still
|
||||
// mattered were added to the new map, others will go
|
||||
// away.
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
}
|
||||
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
return { "from": "root",
|
||||
"selected": selected,
|
||||
"tabs": [actor.grip()
|
||||
for each (actor in actorList)] };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a tab actor for handling requests to a browser tab, like attaching
|
||||
* and detaching.
|
||||
*
|
||||
* @param aConnection DebuggerServerConnection
|
||||
* The conection to the client.
|
||||
* @param aBrowser browser
|
||||
* The browser instance that contains this tab.
|
||||
* Return the tab container for the specified window.
|
||||
*/
|
||||
function BrowserTabActor(aConnection, aBrowser)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this._browser = aBrowser;
|
||||
FennecRootActor.prototype.getTabContainer = function FRA_getTabContainer(aWindow) {
|
||||
return aWindow.document.getElementById("browsers");
|
||||
};
|
||||
|
||||
this._onWindowCreated = this.onWindowCreated.bind(this);
|
||||
}
|
||||
/**
|
||||
* When a tab is closed, exit its tab actor. The actor
|
||||
* will be dropped at the next listTabs request.
|
||||
*/
|
||||
FennecRootActor.prototype.onTabClosed = function FRA_onTabClosed(aEvent) {
|
||||
this.exitTabActor(aEvent.target.browser);
|
||||
};
|
||||
|
||||
// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a
|
||||
// *complete* mess, needs to be rethought asap.
|
||||
|
||||
BrowserTabActor.prototype = {
|
||||
get browser() { return this._browser; },
|
||||
|
||||
get exited() { return !this._browser; },
|
||||
get attached() { return !!this._attached },
|
||||
|
||||
_tabPool: null,
|
||||
get tabActorPool() { return this._tabPool; },
|
||||
|
||||
_contextPool: null,
|
||||
get contextActorPool() { return this._contextPool; },
|
||||
|
||||
/**
|
||||
* Add the specified breakpoint to the default actor pool connection, in order
|
||||
* to be alive as long as the server is.
|
||||
*
|
||||
* @param BreakpointActor aActor
|
||||
* The actor object.
|
||||
*/
|
||||
addToBreakpointPool: function BTA_addToBreakpointPool(aActor) {
|
||||
this.conn.addActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the specified breakpint from the default actor pool.
|
||||
*
|
||||
* @param string aActor
|
||||
* The actor ID.
|
||||
*/
|
||||
removeFromBreakpointPool: function BTA_removeFromBreakpointPool(aActor) {
|
||||
this.conn.removeActor(aActor);
|
||||
},
|
||||
|
||||
actorPrefix: "tab",
|
||||
|
||||
grip: function BTA_grip() {
|
||||
dbg_assert(!this.exited,
|
||||
"grip() shouldn't be called on exited browser actor.");
|
||||
dbg_assert(this.actorID,
|
||||
"tab should have an actorID.");
|
||||
return { actor: this.actorID,
|
||||
title: this._browser.contentTitle,
|
||||
url: this._browser.currentURI.spec }
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the actor is removed from the connection.
|
||||
*/
|
||||
disconnect: function BTA_disconnect() {
|
||||
this._detach();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by the root actor when the underlying tab is closed.
|
||||
*/
|
||||
exit: function BTA_exit() {
|
||||
if (this.exited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.attached) {
|
||||
this._detach();
|
||||
this.conn.send({ from: this.actorID,
|
||||
type: "tabDetached" });
|
||||
}
|
||||
|
||||
this._browser = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the actual work of attching to a tab.
|
||||
*/
|
||||
_attach: function BTA_attach() {
|
||||
if (this._attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a pool for tab-lifetime actors.
|
||||
dbg_assert(!this._tabPool, "Shouldn't have a tab pool if we weren't attached.");
|
||||
this._tabPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._tabPool);
|
||||
|
||||
// ... and a pool for context-lifetime actors.
|
||||
this._pushContext();
|
||||
|
||||
// Watch for globals being created in this tab.
|
||||
this._browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
||||
|
||||
this._attached = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a thread actor and a pool for context-lifetime actors. It then sets
|
||||
* up the content window for debugging.
|
||||
*/
|
||||
_pushContext: function BTA_pushContext() {
|
||||
dbg_assert(!this._contextPool, "Can't push multiple contexts");
|
||||
|
||||
this._contextPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
|
||||
this.threadActor = new ThreadActor(this);
|
||||
this._addDebuggees(this._browser.contentWindow.wrappedJSObject);
|
||||
this._contextPool.addActor(this.threadActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the provided window and all windows in its frame tree as debuggees.
|
||||
*/
|
||||
_addDebuggees: function BTA__addDebuggees(aWindow) {
|
||||
this.threadActor.addDebuggee(aWindow);
|
||||
let frames = aWindow.frames;
|
||||
for (let i = 0; i < frames.length; i++) {
|
||||
this._addDebuggees(frames[i]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Exits the current thread actor and removes the context-lifetime actor pool.
|
||||
* The content window is no longer being debugged after this call.
|
||||
*/
|
||||
_popContext: function BTA_popContext() {
|
||||
dbg_assert(!!this._contextPool, "No context to pop.");
|
||||
|
||||
this.conn.removeActorPool(this._contextPool);
|
||||
this._contextPool = null;
|
||||
this.threadActor.exit();
|
||||
this.threadActor = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the actual work of detaching from a tab.
|
||||
*/
|
||||
_detach: function BTA_detach() {
|
||||
if (!this.attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
||||
|
||||
this._popContext();
|
||||
|
||||
// Shut down actors that belong to this tab's pool.
|
||||
this.conn.removeActorPool(this._tabPool);
|
||||
this._tabPool = null;
|
||||
|
||||
this._attached = false;
|
||||
},
|
||||
|
||||
// Protocol Request Handlers
|
||||
|
||||
onAttach: function BTA_onAttach(aRequest) {
|
||||
if (this.exited) {
|
||||
return { type: "exited" };
|
||||
}
|
||||
|
||||
this._attach();
|
||||
|
||||
return { type: "tabAttached", threadActor: this.threadActor.actorID };
|
||||
},
|
||||
|
||||
onDetach: function BTA_onDetach(aRequest) {
|
||||
if (!this.attached) {
|
||||
return { error: "wrongState" };
|
||||
}
|
||||
|
||||
this._detach();
|
||||
|
||||
return { type: "detached" };
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to enter a nested event loop by disabling debuggee events.
|
||||
*/
|
||||
preNest: function BTA_preNest() {
|
||||
if (!this._browser) {
|
||||
// The tab is already closed.
|
||||
return;
|
||||
}
|
||||
let windowUtils = this._browser.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.suppressEventHandling(true);
|
||||
windowUtils.suspendTimeouts();
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to exit a nested event loop by enabling debuggee events.
|
||||
*/
|
||||
postNest: function BTA_postNest(aNestData) {
|
||||
if (!this._browser) {
|
||||
// The tab is already closed.
|
||||
return;
|
||||
}
|
||||
let windowUtils = this._browser.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.resumeTimeouts();
|
||||
windowUtils.suppressEventHandling(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle location changes, by sending a tabNavigated notification to the
|
||||
* client.
|
||||
*/
|
||||
onWindowCreated: function BTA_onWindowCreated(evt) {
|
||||
if (evt.target === this._browser.contentDocument) {
|
||||
if (this._attached) {
|
||||
this.conn.send({ from: this.actorID, type: "tabNavigated",
|
||||
url: this._browser.contentDocument.URL });
|
||||
}
|
||||
}
|
||||
// nsIWindowMediatorListener
|
||||
FennecRootActor.prototype.onCloseWindow = function FRA_onCloseWindow(aWindow) {
|
||||
if (aWindow.BrowserApp) {
|
||||
this.unwatchWindow(aWindow);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The request types this actor can handle.
|
||||
*/
|
||||
BrowserTabActor.prototype.requestTypes = {
|
||||
"attach": BrowserTabActor.prototype.onAttach,
|
||||
"detach": BrowserTabActor.prototype.onDetach
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers handlers for new request types defined dynamically. This is used
|
||||
* for example by add-ons to augment the functionality of the tab actor.
|
||||
*
|
||||
* @param aName string
|
||||
* The name of the new request type.
|
||||
* @param aFunction function
|
||||
* The handler for this request type.
|
||||
*/
|
||||
DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) {
|
||||
BrowserTabActor.prototype.requestTypes[aName] = function(aRequest) {
|
||||
if (!this.attached) {
|
||||
return { error: "wrongState" };
|
||||
}
|
||||
return aFunction(this, aRequest);
|
||||
}
|
||||
FennecRootActor.prototype.requestTypes = {
|
||||
"listTabs": FennecRootActor.prototype.onListTabs
|
||||
};
|
||||
|
@ -132,13 +132,25 @@ ServerBSO.prototype = {
|
||||
}
|
||||
|
||||
if (request.hasHeader("x-if-modified-since")) {
|
||||
let headerModified = parseInt(request.getHeader("x-if-modified-since"));
|
||||
let headerModified = parseInt(request.getHeader("x-if-modified-since"),
|
||||
10);
|
||||
CommonUtils.ensureMillisecondsTimestamp(headerModified);
|
||||
|
||||
if (headerModified >= this.modified) {
|
||||
code = 304;
|
||||
status = "Not Modified";
|
||||
|
||||
sendResponse();
|
||||
return;
|
||||
}
|
||||
} else if (request.hasHeader("x-if-unmodified-since")) {
|
||||
let requestModified = parseInt(request.getHeader("x-if-unmodified-since"),
|
||||
10);
|
||||
let serverModified = this.modified;
|
||||
|
||||
if (serverModified > requestModified) {
|
||||
code = 412;
|
||||
status = "Precondition Failed";
|
||||
sendResponse();
|
||||
return;
|
||||
}
|
||||
@ -411,26 +423,6 @@ StorageServerCollection.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.index_above) {
|
||||
if (bso.sortindex === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bso.sortindex <= options.index_above) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.index_below) {
|
||||
if (bso.sortindex === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bso.sortindex >= options.index_below) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
@ -612,10 +604,11 @@ StorageServerCollection.prototype = {
|
||||
continue;
|
||||
}
|
||||
chunk = chunk.split("=");
|
||||
let key = decodeURIComponent(chunk[0]);
|
||||
if (chunk.length == 1) {
|
||||
options[chunk[0]] = "";
|
||||
options[key] = "";
|
||||
} else {
|
||||
options[chunk[0]] = chunk[1];
|
||||
options[key] = decodeURIComponent(chunk[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -641,18 +634,6 @@ StorageServerCollection.prototype = {
|
||||
options.older = parseInt(options.older, 10);
|
||||
}
|
||||
|
||||
if (options.index_above) {
|
||||
if (!isInteger(options.index_above)) {
|
||||
throw HTTP_400;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.index_below) {
|
||||
if (!isInteger(options.index_below)) {
|
||||
throw HTTP_400;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.limit) {
|
||||
if (!isInteger(options.limit)) {
|
||||
throw HTTP_400;
|
||||
@ -683,6 +664,16 @@ StorageServerCollection.prototype = {
|
||||
response.setStatusLine(request.httpVersion, 304, "Not Modified");
|
||||
return;
|
||||
}
|
||||
} else if (request.hasHeader("x-if-unmodified-since")) {
|
||||
let requestModified = parseInt(request.getHeader("x-if-unmodified-since"),
|
||||
10);
|
||||
let serverModified = this.timestamp;
|
||||
|
||||
if (serverModified > requestModified) {
|
||||
response.setHeader("X-Last-Modified", "" + serverModified);
|
||||
response.setStatusLine(request.httpVersion, 412, "Precondition Failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.full) {
|
||||
@ -710,9 +701,7 @@ StorageServerCollection.prototype = {
|
||||
if (newlines) {
|
||||
response.setHeader("Content-Type", "application/newlines", false);
|
||||
let normalized = data.map(function map(d) {
|
||||
let result = JSON.stringify(d);
|
||||
|
||||
return result.replace("\n", "\\u000a");
|
||||
return JSON.stringify(d);
|
||||
});
|
||||
|
||||
body = normalized.join("\n") + "\n";
|
||||
@ -755,10 +744,9 @@ StorageServerCollection.prototype = {
|
||||
}
|
||||
} else if (inputMediaType == "application/newlines") {
|
||||
for each (let line in inputBody.split("\n")) {
|
||||
let json = line.replace("\\u000a", "\n");
|
||||
let record;
|
||||
try {
|
||||
record = JSON.parse(json);
|
||||
record = JSON.parse(line);
|
||||
} catch (ex) {
|
||||
this._log.info("JSON parse error on line!");
|
||||
return sendMozSvcError(request, response, "8");
|
||||
|
@ -870,9 +870,12 @@ StorageServiceRequest.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.status == 503) {
|
||||
if (response.status >= 500 && response.status <= 599) {
|
||||
this._log.error(response.status + " seen from server!");
|
||||
this._error = new StorageServiceRequestError();
|
||||
this._error.server = new Error("503 Received.");
|
||||
this._error.server = new Error(response.status + " status code.");
|
||||
callOnComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
callOnComplete();
|
||||
@ -993,20 +996,6 @@ StorageCollectionGetRequest.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Only retrieve BSOs whose sortindex is higher than this integer value.
|
||||
*/
|
||||
set index_above(value) {
|
||||
this._namedArgs.index_above = value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Only retrieve BSOs whose sortindex is lower than this integer value.
|
||||
*/
|
||||
set index_below(value) {
|
||||
this._namedArgs.index_below = value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Limit the max number of returned BSOs to this integer number.
|
||||
*/
|
||||
@ -1084,15 +1073,21 @@ StorageCollectionGetRequest.prototype = {
|
||||
function StorageCollectionSetRequest() {
|
||||
StorageServiceRequest.call(this);
|
||||
|
||||
this._lines = [];
|
||||
this._size = 0;
|
||||
this.size = 0;
|
||||
|
||||
this.successfulIDs = new Set();
|
||||
this.failures = new Map();
|
||||
// TODO Bug 775781 convert to Set and Map once iterable.
|
||||
this.successfulIDs = [];
|
||||
this.failures = {};
|
||||
|
||||
this._lines = [];
|
||||
}
|
||||
StorageCollectionSetRequest.prototype = {
|
||||
__proto__: StorageServiceRequest.prototype,
|
||||
|
||||
get count() {
|
||||
return this._lines.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a BasicStorageObject to this request.
|
||||
*
|
||||
@ -1112,33 +1107,384 @@ StorageCollectionSetRequest.prototype = {
|
||||
throw new Error("Passed BSO must have id defined.");
|
||||
}
|
||||
|
||||
let line = JSON.stringify(bso).replace("\n", "\u000a");
|
||||
this.addLine(JSON.stringify(bso));
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a BSO (represented by its serialized newline-delimited form).
|
||||
*
|
||||
* You probably shouldn't use this. It is used for batching.
|
||||
*/
|
||||
addLine: function addLine(line) {
|
||||
// This is off by 1 in the larger direction. We don't care.
|
||||
this._size += line.length + "\n".length;
|
||||
this.size += line.length + 1;
|
||||
this._lines.push(line);
|
||||
},
|
||||
|
||||
_onDispatch: function _onDispatch() {
|
||||
this._data = this._lines.join("\n");
|
||||
this.size = this._data.length;
|
||||
},
|
||||
|
||||
_completeParser: function _completeParser(response) {
|
||||
let result = JSON.parse(response.body);
|
||||
|
||||
for (let id of result.success) {
|
||||
this.successfulIDs.add(id);
|
||||
this.successfulIDs.push(id);
|
||||
}
|
||||
|
||||
this.allSucceeded = true;
|
||||
|
||||
for (let [id, reasons] in result.failed) {
|
||||
for (let [id, reasons] in Iterator(result.failed)) {
|
||||
this.failures[id] = reasons;
|
||||
this.allSucceeded = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a batch upload of BSOs to an individual collection.
|
||||
*
|
||||
* This is a more intelligent way to upload may BSOs to the server. It will
|
||||
* split the uploaded data into multiple requests so size limits, etc aren't
|
||||
* exceeded.
|
||||
*
|
||||
* Once a client obtains an instance of this type, it calls `addBSO` for each
|
||||
* BSO to be uploaded. When the client is done providing BSOs to be uploaded,
|
||||
* it calls `finish`. When `finish` is called, no more BSOs can be added to the
|
||||
* batch. When all requests created from this batch have finished, the callback
|
||||
* provided to `finish` will be invoked.
|
||||
*
|
||||
* Clients can also explicitly flush pending outgoing BSOs via `flush`. This
|
||||
* allows callers to control their own batching/chunking.
|
||||
*
|
||||
* Interally, this maintains a queue of StorageCollectionSetRequest to be
|
||||
* issued. At most one request is allowed to be in-flight at once. This is to
|
||||
* avoid potential conflicts on the server. And, in the case of conditional
|
||||
* requests, it prevents requests from being declined due to the server being
|
||||
* updated by another request issued by us.
|
||||
*
|
||||
* If a request errors for any reason, all queued uploads are abandoned and the
|
||||
* `finish` callback is invoked as soon as possible. The `successfulIDs` and
|
||||
* `failures` properties will contain data from all requests that had this
|
||||
* response data. In other words, the IDs have BSOs that were never sent to the
|
||||
* server are not lumped in to either property.
|
||||
*
|
||||
* Requests can be made conditional by setting `locallyModifiedVersion` to the
|
||||
* most recent version of server data. As responses from the server are seen,
|
||||
* the last server version is carried forward to subsequent requests.
|
||||
*
|
||||
* The server version from the last request is available in the
|
||||
* `serverModifiedVersion` property. It should only be accessed during or
|
||||
* after the callback passed to `finish`.
|
||||
*
|
||||
* @param client
|
||||
* (StorageServiceClient) Client instance to use for uploading.
|
||||
*
|
||||
* @param collection
|
||||
* (string) Collection the batch operation will upload to.
|
||||
*/
|
||||
function StorageCollectionBatchedSet(client, collection) {
|
||||
this.client = client;
|
||||
this.collection = collection;
|
||||
|
||||
this._log = client._log;
|
||||
|
||||
this.locallyModifiedVersion = null;
|
||||
this.serverModifiedVersion = null;
|
||||
|
||||
// TODO Bug 775781 convert to Set and Map once iterable.
|
||||
this.successfulIDs = [];
|
||||
this.failures = {};
|
||||
|
||||
// Request currently being populated.
|
||||
this._stagingRequest = client.setBSOs(this.collection);
|
||||
|
||||
// Requests ready to be sent over the wire.
|
||||
this._outgoingRequests = [];
|
||||
|
||||
// Whether we are waiting for a response.
|
||||
this._requestInFlight = false;
|
||||
|
||||
this._onFinishCallback = null;
|
||||
this._finished = false;
|
||||
this._errorEncountered = false;
|
||||
}
|
||||
StorageCollectionBatchedSet.prototype = {
|
||||
/**
|
||||
* Add a BSO to be uploaded as part of this batch.
|
||||
*/
|
||||
addBSO: function addBSO(bso) {
|
||||
if (this._errorEncountered) {
|
||||
return;
|
||||
}
|
||||
|
||||
let line = JSON.stringify(bso);
|
||||
|
||||
if (line.length > this.client.REQUEST_SIZE_LIMIT) {
|
||||
throw new Error("BSO is larger than allowed limit: " + line.length +
|
||||
" > " + this.client.REQUEST_SIZE_LIMIT);
|
||||
}
|
||||
|
||||
if (this._stagingRequest.size + line.length > this.client.REQUEST_SIZE_LIMIT) {
|
||||
this._log.debug("Sending request because payload size would be exceeded");
|
||||
this._finishStagedRequest();
|
||||
|
||||
this._stagingRequest.addLine(line);
|
||||
return;
|
||||
}
|
||||
|
||||
// We are guaranteed to fit within size limits.
|
||||
this._stagingRequest.addLine(line);
|
||||
|
||||
if (this._stagingRequest.count >= this.client.REQUEST_BSO_COUNT_LIMIT) {
|
||||
this._log.debug("Sending request because BSO count threshold reached.");
|
||||
this._finishStagedRequest();
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
finish: function finish(cb) {
|
||||
if (this._finished) {
|
||||
throw new Error("Batch request has already been finished.");
|
||||
}
|
||||
|
||||
this.flush();
|
||||
|
||||
this._onFinishCallback = cb;
|
||||
this._finished = true;
|
||||
this._stagingRequest = null;
|
||||
},
|
||||
|
||||
flush: function flush() {
|
||||
if (this._finished) {
|
||||
throw new Error("Batch request has been finished.");
|
||||
}
|
||||
|
||||
if (!this._stagingRequest.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._finishStagedRequest();
|
||||
},
|
||||
|
||||
_finishStagedRequest: function _finishStagedRequest() {
|
||||
this._outgoingRequests.push(this._stagingRequest);
|
||||
this._sendOutgoingRequest();
|
||||
this._stagingRequest = this.client.setBSOs(this.collection);
|
||||
},
|
||||
|
||||
_sendOutgoingRequest: function _sendOutgoingRequest() {
|
||||
if (this._requestInFlight || this._errorEncountered) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._outgoingRequests.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let request = this._outgoingRequests.shift();
|
||||
|
||||
if (this.locallyModifiedVersion) {
|
||||
request.locallyModifiedVersion = this.locallyModifiedVersion;
|
||||
}
|
||||
|
||||
request.dispatch(this._onBatchComplete.bind(this));
|
||||
this._requestInFlight = true;
|
||||
},
|
||||
|
||||
_onBatchComplete: function _onBatchComplete(error, request) {
|
||||
this._requestInFlight = false;
|
||||
|
||||
this.serverModifiedVersion = request.serverTime;
|
||||
|
||||
// Only update if we had a value before. Otherwise, this breaks
|
||||
// unconditional requests!
|
||||
if (this.locallyModifiedVersion) {
|
||||
this.locallyModifiedVersion = request.serverTime;
|
||||
}
|
||||
|
||||
for (let id of request.successfulIDs) {
|
||||
this.successfulIDs.push(id);
|
||||
}
|
||||
|
||||
for (let [id, reason] in Iterator(request.failures)) {
|
||||
this.failures[id] = reason;
|
||||
}
|
||||
|
||||
if (request.error) {
|
||||
this._errorEncountered = true;
|
||||
}
|
||||
|
||||
this._checkFinish();
|
||||
},
|
||||
|
||||
_checkFinish: function _checkFinish() {
|
||||
if (this._outgoingRequests.length && !this._errorEncountered) {
|
||||
this._sendOutgoingRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._onFinishCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._onFinishCallback(this);
|
||||
} catch (ex) {
|
||||
this._log.warn("Exception when calling finished callback: " +
|
||||
CommonUtils.exceptionStr(ex));
|
||||
}
|
||||
},
|
||||
};
|
||||
Object.freeze(StorageCollectionBatchedSet.prototype);
|
||||
|
||||
/**
|
||||
* Manages a batch of BSO deletion requests.
|
||||
*
|
||||
* A single instance of this virtual request allows deletion of many individual
|
||||
* BSOs without having to worry about server limits.
|
||||
*
|
||||
* Instances are obtained by calling `deleteBSOsBatching` on
|
||||
* StorageServiceClient.
|
||||
*
|
||||
* Usage is roughly the same as StorageCollectionBatchedSet. Callers obtain
|
||||
* an instance and select individual BSOs for deletion by calling `addID`.
|
||||
* When the caller is finished marking BSOs for deletion, they call `finish`
|
||||
* with a callback which will be invoked when all deletion requests finish.
|
||||
*
|
||||
* When the finished callback is invoked, any encountered errors will be stored
|
||||
* in the `errors` property of this instance (which is passed to the callback).
|
||||
* This will be an empty array if no errors were encountered. Else, it will
|
||||
* contain the errors from the `onComplete` handler of request instances. The
|
||||
* set of succeeded and failed IDs is not currently available.
|
||||
*
|
||||
* Deletes can be made conditional by setting `locallyModifiedVersion`. The
|
||||
* behavior is the same as request types. The only difference is that the
|
||||
* updated version from the server as a result of requests is carried forward
|
||||
* to subsequent requests.
|
||||
*
|
||||
* The server version from the last request is stored in the
|
||||
* `serverModifiedVersion` property. It is not safe to access this until the
|
||||
* callback from `finish`.
|
||||
*
|
||||
* Like StorageCollectionBatchedSet, requests are issued serially to avoid
|
||||
* race conditions on the server.
|
||||
*
|
||||
* @param client
|
||||
* (StorageServiceClient) Client request is associated with.
|
||||
* @param collection
|
||||
* (string) Collection being operated on.
|
||||
*/
|
||||
function StorageCollectionBatchedDelete(client, collection) {
|
||||
this.client = client;
|
||||
this.collection = collection;
|
||||
|
||||
this._log = client._log;
|
||||
|
||||
this.locallyModifiedVersion = null;
|
||||
this.serverModifiedVersion = null;
|
||||
this.errors = [];
|
||||
|
||||
this._pendingIDs = [];
|
||||
this._requestInFlight = false;
|
||||
this._finished = false;
|
||||
this._finishedCallback = null;
|
||||
}
|
||||
StorageCollectionBatchedDelete.prototype = {
|
||||
addID: function addID(id) {
|
||||
if (this._finished) {
|
||||
throw new Error("Cannot add IDs to a finished instance.");
|
||||
}
|
||||
|
||||
// If we saw errors already, don't do any work. This is an optimization
|
||||
// and isn't strictly required, as _sendRequest() should no-op.
|
||||
if (this.errors.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._pendingIDs.push(id);
|
||||
|
||||
if (this._pendingIDs.length >= this.client.REQUEST_BSO_DELETE_LIMIT) {
|
||||
this._sendRequest();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Finish this batch operation.
|
||||
*
|
||||
* No more IDs can be added to this operation. Existing IDs are flushed as
|
||||
* a request. The passed callback will be called when all requests have
|
||||
* finished.
|
||||
*/
|
||||
finish: function finish(cb) {
|
||||
if (this._finished) {
|
||||
throw new Error("Batch delete instance has already been finished.");
|
||||
}
|
||||
|
||||
this._finished = true;
|
||||
this._finishedCallback = cb;
|
||||
|
||||
if (this._pendingIDs.length) {
|
||||
this._sendRequest();
|
||||
}
|
||||
},
|
||||
|
||||
_sendRequest: function _sendRequest() {
|
||||
// Only allow 1 active request at a time and don't send additional
|
||||
// requests if one has failed.
|
||||
if (this._requestInFlight || this.errors.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ids = this._pendingIDs.splice(0, this.client.REQUEST_BSO_DELETE_LIMIT);
|
||||
let request = this.client.deleteBSOs(this.collection, ids);
|
||||
|
||||
if (this.locallyModifiedVersion) {
|
||||
request.locallyModifiedVersion = this.locallyModifiedVersion;
|
||||
}
|
||||
|
||||
request.dispatch(this._onRequestComplete.bind(this));
|
||||
this._requestInFlight = true;
|
||||
},
|
||||
|
||||
_onRequestComplete: function _onRequestComplete(error, request) {
|
||||
this._requestInFlight = false;
|
||||
|
||||
if (error) {
|
||||
// We don't currently track metadata of what failed. This is an obvious
|
||||
// feature that could be added.
|
||||
this._log.warn("Error received from server: " + error);
|
||||
this.errors.push(error);
|
||||
}
|
||||
|
||||
this.serverModifiedVersion = request.serverTime;
|
||||
|
||||
// If performing conditional requests, carry forward the new server version
|
||||
// so subsequent conditional requests work.
|
||||
if (this.locallyModifiedVersion) {
|
||||
this.locallyModifiedVersion = request.serverTime;
|
||||
}
|
||||
|
||||
if (this._pendingIDs.length && !this.errors.length) {
|
||||
this._sendRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._finishedCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._finishedCallback(this);
|
||||
} catch (ex) {
|
||||
this._log.warn("Exception when invoking finished callback: " +
|
||||
CommonUtils.exceptionStr(ex));
|
||||
}
|
||||
},
|
||||
};
|
||||
Object.freeze(StorageCollectionBatchedDelete.prototype);
|
||||
|
||||
/**
|
||||
* Construct a new client for the SyncStorage API, version 2.0.
|
||||
*
|
||||
@ -1195,6 +1541,27 @@ StorageServiceClient.prototype = {
|
||||
*/
|
||||
userAgent: "StorageServiceClient",
|
||||
|
||||
/**
|
||||
* Maximum size of entity bodies.
|
||||
*
|
||||
* TODO this should come from the server somehow. See bug 769759.
|
||||
*/
|
||||
REQUEST_SIZE_LIMIT: 512000,
|
||||
|
||||
/**
|
||||
* Maximum number of BSOs in requests.
|
||||
*
|
||||
* TODO this should come from the server somehow. See bug 769759.
|
||||
*/
|
||||
REQUEST_BSO_COUNT_LIMIT: 100,
|
||||
|
||||
/**
|
||||
* Maximum number of BSOs that can be deleted in a single DELETE.
|
||||
*
|
||||
* TODO this should come from the server. See bug 769759.
|
||||
*/
|
||||
REQUEST_BSO_DELETE_LIMIT: 100,
|
||||
|
||||
_baseURI: null,
|
||||
_log: null,
|
||||
|
||||
@ -1584,11 +1951,9 @@ StorageServiceClient.prototype = {
|
||||
* has additional functions and properties specific to this operation. See
|
||||
* its documentation for more.
|
||||
*
|
||||
* Future improvement: support streaming of uploaded records. Currently, data
|
||||
* is buffered in the client before going over the wire. Ideally, we'd support
|
||||
* sending over the wire as soon as data is available. This will require
|
||||
* support in RESTRequest, which doesn't support streaming on requests, only
|
||||
* responses.
|
||||
* Most consumers interested in submitting multiple BSOs to the server will
|
||||
* want to use `setBSOsBatching` instead. That API intelligently splits up
|
||||
* requests as necessary, etc.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
@ -1635,6 +2000,30 @@ StorageServiceClient.prototype = {
|
||||
return request;
|
||||
},
|
||||
|
||||
/**
|
||||
* This is a batching variant of setBSOs.
|
||||
*
|
||||
* Whereas `setBSOs` is a 1:1 mapping between function calls and HTTP
|
||||
* requests issued, this one is a 1:N mapping. It will intelligently break
|
||||
* up outgoing BSOs into multiple requests so size limits, etc aren't
|
||||
* exceeded.
|
||||
*
|
||||
* Please see the documentation for `StorageCollectionBatchedSet` for
|
||||
* usage info.
|
||||
*
|
||||
* @param collection
|
||||
* (string) Collection to operate on.
|
||||
* @return
|
||||
* (StorageCollectionBatchedSet) Batched set instance.
|
||||
*/
|
||||
setBSOsBatching: function setBSOsBatching(collection) {
|
||||
if (!collection) {
|
||||
throw new Error("collection argument must be defined.");
|
||||
}
|
||||
|
||||
return new StorageCollectionBatchedSet(this, collection);
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes a single BSO from a collection.
|
||||
*
|
||||
@ -1670,6 +2059,10 @@ StorageServiceClient.prototype = {
|
||||
* The request can be made conditional by setting `locallyModifiedVersion`
|
||||
* on the returned request instance.
|
||||
*
|
||||
* If the number of BSOs to delete is potentially large, it is preferred to
|
||||
* use `deleteBSOsBatching`. That API automatically splits the operation into
|
||||
* multiple requests so server limits aren't exceeded.
|
||||
*
|
||||
* @param collection
|
||||
* (string) Name of collection to delete BSOs from.
|
||||
* @param ids
|
||||
@ -1688,6 +2081,24 @@ StorageServiceClient.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Bulk deletion of BSOs with no size limit.
|
||||
*
|
||||
* This allows a large amount of BSOs to be deleted easily. It will formulate
|
||||
* multiple `deleteBSOs` queries so the client does not exceed server limits.
|
||||
*
|
||||
* @param collection
|
||||
* (string) Name of collection to delete BSOs from.
|
||||
* @return StorageCollectionBatchedDelete
|
||||
*/
|
||||
deleteBSOsBatching: function deleteBSOsBatching(collection) {
|
||||
if (!collection) {
|
||||
throw new Error("collection argument must be defined.");
|
||||
}
|
||||
|
||||
return new StorageCollectionBatchedDelete(this, collection);
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes a single collection from the server.
|
||||
*
|
||||
|
@ -253,6 +253,28 @@ add_test(function test_bso_get_existing() {
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_percent_decoding() {
|
||||
_("Ensure query string arguments with percent encoded are handled.");
|
||||
|
||||
let server = new StorageServer();
|
||||
server.registerUser("123", "password");
|
||||
server.startSynchronous(PORT);
|
||||
|
||||
let coll = server.user("123").createCollection("test");
|
||||
coll.insert("001", {foo: "bar"});
|
||||
coll.insert("002", {bar: "foo"});
|
||||
|
||||
let request = localRequest("/2.0/123/storage/test?ids=001%2C002", "123",
|
||||
"password");
|
||||
let error = doGetRequest(request);
|
||||
do_check_null(error);
|
||||
do_check_eq(request.response.status, 200);
|
||||
let items = JSON.parse(request.response.body).items;
|
||||
do_check_attribute_count(items, 2);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_bso_404() {
|
||||
_("Ensure the server responds with a 404 if a BSO does not exist.");
|
||||
|
||||
@ -442,6 +464,60 @@ add_test(function test_bso_delete_unmodified() {
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_collection_get_unmodified_since() {
|
||||
_("Ensure conditional unmodified get on collection works when it should.");
|
||||
|
||||
let server = new StorageServer();
|
||||
server.registerUser("123", "password");
|
||||
server.startSynchronous(PORT);
|
||||
let collection = server.user("123").createCollection("testcoll");
|
||||
collection.insert("bso0", {foo: "bar"});
|
||||
|
||||
let serverModified = collection.timestamp;
|
||||
|
||||
let request1 = localRequest("/2.0/123/storage/testcoll", "123", "password");
|
||||
request1.setHeader("X-If-Unmodified-Since", serverModified);
|
||||
let error = doGetRequest(request1);
|
||||
do_check_null(error);
|
||||
do_check_eq(request1.response.status, 200);
|
||||
|
||||
let request2 = localRequest("/2.0/123/storage/testcoll", "123", "password");
|
||||
request2.setHeader("X-If-Unmodified-Since", serverModified - 1);
|
||||
let error = doGetRequest(request2);
|
||||
do_check_null(error);
|
||||
do_check_eq(request2.response.status, 412);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_bso_get_unmodified_since() {
|
||||
_("Ensure conditional unmodified get on BSO works appropriately.");
|
||||
|
||||
let server = new StorageServer();
|
||||
server.registerUser("123", "password");
|
||||
server.startSynchronous(PORT);
|
||||
let collection = server.user("123").createCollection("testcoll");
|
||||
let bso = collection.insert("bso0", {foo: "bar"});
|
||||
|
||||
let serverModified = bso.modified;
|
||||
|
||||
let request1 = localRequest("/2.0/123/storage/testcoll/bso0", "123",
|
||||
"password");
|
||||
request1.setHeader("X-If-Unmodified-Since", serverModified);
|
||||
let error = doGetRequest(request1);
|
||||
do_check_null(error);
|
||||
do_check_eq(request1.response.status, 200);
|
||||
|
||||
let request2 = localRequest("/2.0/123/storage/testcoll/bso0", "123",
|
||||
"password");
|
||||
request2.setHeader("X-If-Unmodified-Since", serverModified - 1);
|
||||
let error = doGetRequest(request2);
|
||||
do_check_null(error);
|
||||
do_check_eq(request2.response.status, 412);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_missing_collection_404() {
|
||||
_("Ensure a missing collection returns a 404.");
|
||||
|
||||
|
@ -12,7 +12,11 @@ function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function getEmptyServer(user="765", password="password") {
|
||||
function getRandomUser() {
|
||||
return "" + (Math.floor(Math.random() * 100000) + 1);
|
||||
}
|
||||
|
||||
function getEmptyServer(user=getRandomUser(), password="password") {
|
||||
let users = {};
|
||||
users[user] = password;
|
||||
|
||||
@ -23,7 +27,7 @@ function getEmptyServer(user="765", password="password") {
|
||||
});
|
||||
}
|
||||
|
||||
function getClient(user="765", password="password") {
|
||||
function getClient(user=getRandomUser(), password="password") {
|
||||
let client = new StorageServiceClient(BASE_URI + "/" + user);
|
||||
client.addListener({
|
||||
onDispatch: function onDispatch(request) {
|
||||
@ -35,7 +39,7 @@ function getClient(user="765", password="password") {
|
||||
return client;
|
||||
}
|
||||
|
||||
function getServerAndClient(user="765", password="password") {
|
||||
function getServerAndClient(user=getRandomUser(), password="password") {
|
||||
let server = getEmptyServer(user, password);
|
||||
let client = getClient(user, password);
|
||||
|
||||
@ -644,9 +648,9 @@ add_test(function test_set_bsos_simple() {
|
||||
do_check_null(error);
|
||||
|
||||
let successful = req.successfulIDs;
|
||||
do_check_eq(successful.size(), 2);
|
||||
do_check_true(successful.has(bso0.id));
|
||||
do_check_true(successful.has(bso1.id));
|
||||
do_check_eq(successful.length, 2);
|
||||
do_check_eq(successful.indexOf(bso0.id), 0);
|
||||
do_check_true(successful.indexOf(bso1.id), 1);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
@ -701,7 +705,7 @@ add_test(function test_set_bsos_newline() {
|
||||
|
||||
request.dispatch(function onComplete(error, request) {
|
||||
do_check_null(error);
|
||||
do_check_eq(request.successfulIDs.size(), 2);
|
||||
do_check_eq(request.successfulIDs.length, 2);
|
||||
|
||||
let coll = user.collection("testcoll");
|
||||
do_check_eq(coll.bso("bso0").payload, bso0.payload);
|
||||
@ -965,3 +969,410 @@ add_test(function test_network_error_listener() {
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_too_large() {
|
||||
_("Ensure we throw when attempting to add a BSO that is too large to fit.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
let payload = "";
|
||||
|
||||
// The actual length of the payload is a little less. But, this ensures we
|
||||
// exceed it.
|
||||
for (let i = 0; i < client.REQUEST_SIZE_LIMIT; i++) {
|
||||
payload += i;
|
||||
}
|
||||
|
||||
let bso = new BasicStorageObject("bso");
|
||||
bso.payload = payload;
|
||||
do_check_throws(function add() { request.addBSO(bso); });
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_basic() {
|
||||
_("Ensure batching set works with single requests.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
for (let i = 0; i < 10; i++) {
|
||||
let bso = new BasicStorageObject("bso" + i);
|
||||
bso.payload = "payload" + i;
|
||||
request.addBSO(bso);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(request.successfulIDs.length, 10);
|
||||
|
||||
let collection = server.user(username).collection("testcoll");
|
||||
do_check_eq(collection.timestamp, request.serverModifiedVersion);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_batch_count() {
|
||||
_("Ensure multiple outgoing request batching works when count is exceeded.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
}
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
for (let i = 1; i <= 300; i++) {
|
||||
let bso = new BasicStorageObject("bso" + i);
|
||||
bso.payload = "XXXXXXX";
|
||||
request.addBSO(bso);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(request.successfulIDs.length, 300);
|
||||
do_check_eq(requestCount, 3);
|
||||
|
||||
let collection = server.user(username).collection("testcoll");
|
||||
do_check_eq(collection.timestamp, request.serverModifiedVersion);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_batch_size() {
|
||||
_("Ensure outgoing requests batch when size is exceeded.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
};
|
||||
|
||||
let limit = client.REQUEST_SIZE_LIMIT;
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
|
||||
// JavaScript: Y U NO EASY REPETITION FUNCTIONALITY?
|
||||
let data = [];
|
||||
for (let i = (limit / 2) - 100; i; i -= 1) {
|
||||
data.push("X");
|
||||
}
|
||||
|
||||
let payload = data.join("");
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let bso = new BasicStorageObject("bso" + i);
|
||||
bso.payload = payload;
|
||||
request.addBSO(bso);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(request.successfulIDs.length, 4);
|
||||
do_check_eq(requestCount, 2);
|
||||
|
||||
let collection = server.user(username).collection("testcoll");
|
||||
do_check_eq(collection.timestamp, request.serverModifiedVersion);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_flush() {
|
||||
_("Ensure flushing batch sets works.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
}
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
for (let i = 1; i < 101; i++) {
|
||||
let bso = new BasicStorageObject("bso" + i);
|
||||
bso.payload = "foo";
|
||||
request.addBSO(bso);
|
||||
|
||||
if (i % 10 == 0) {
|
||||
request.flush();
|
||||
}
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(request.successfulIDs.length, 100);
|
||||
do_check_eq(requestCount, 10);
|
||||
|
||||
let collection = server.user(username).collection("testcoll");
|
||||
do_check_eq(collection.timestamp, request.serverModifiedVersion);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_conditional_success() {
|
||||
_("Ensure conditional requests for batched sets work properly.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
|
||||
let collection = server.user(username).createCollection("testcoll");
|
||||
|
||||
let lastServerVersion = Date.now();
|
||||
collection.insertBSO(new ServerBSO("foo", "bar", lastServerVersion));
|
||||
collection.timestamp = lastServerVersion;
|
||||
do_check_eq(collection.timestamp, lastServerVersion);
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
}
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
request.locallyModifiedVersion = collection.timestamp;
|
||||
|
||||
for (let i = 1; i < 251; i++) {
|
||||
let bso = new BasicStorageObject("bso" + i);
|
||||
bso.payload = "foo" + i;
|
||||
request.addBSO(bso);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 3);
|
||||
|
||||
do_check_eq(collection.timestamp, request.serverModifiedVersion);
|
||||
do_check_eq(collection.timestamp, request.locallyModifiedVersion);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_initial_failure() {
|
||||
_("Ensure that an initial request failure setting BSOs is handled properly.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
|
||||
let collection = server.user(username).createCollection("testcoll");
|
||||
collection.timestamp = Date.now();
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
}
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
request.locallyModifiedVersion = collection.timestamp - 1;
|
||||
|
||||
for (let i = 1; i < 250; i++) {
|
||||
let bso = new BasicStorageObject("bso" + i);
|
||||
bso.payload = "foo" + i;
|
||||
request.addBSO(bso);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 1);
|
||||
|
||||
do_check_eq(request.successfulIDs.length, 0);
|
||||
do_check_eq(Object.keys(request.failures).length, 0);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batching_set_subsequent_failure() {
|
||||
_("Ensure a non-initial failure during batching set is handled properly.");
|
||||
|
||||
let [server, client, username] = getServerAndClient();
|
||||
let collection = server.user(username).createCollection("testcoll");
|
||||
collection.timestamp = Date.now();
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
|
||||
if (requestCount == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
collection.timestamp++;
|
||||
}
|
||||
|
||||
let request = client.setBSOsBatching("testcoll");
|
||||
request.locallyModifiedVersion = collection.timestamp;
|
||||
|
||||
for (let i = 0; i < 250; i++) {
|
||||
let bso = new BasicStorageObject("bso" + i);
|
||||
bso.payload = "foo" + i;
|
||||
request.addBSO(bso);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 2);
|
||||
do_check_eq(request.successfulIDs.length, 100);
|
||||
do_check_eq(Object.keys(request.failures).length, 0);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
function getBatchedDeleteData(collection="testcoll") {
|
||||
let [server, client, username] = getServerAndClient();
|
||||
|
||||
let serverBSOs = {};
|
||||
for (let i = 1000; i; i -= 1) {
|
||||
serverBSOs["bso" + i] = new ServerBSO("bso" + i, "payload" + i);
|
||||
}
|
||||
|
||||
let user = server.user(username);
|
||||
user.createCollection(collection, serverBSOs);
|
||||
|
||||
return [server, client, username, collection];
|
||||
}
|
||||
|
||||
add_test(function test_batched_delete_single() {
|
||||
_("Ensure batched delete with single request works.");
|
||||
|
||||
let [server, client, username, collection] = getBatchedDeleteData();
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount += 1;
|
||||
}
|
||||
|
||||
let request = client.deleteBSOsBatching(collection);
|
||||
for (let i = 1; i < 51; i += 1) {
|
||||
request.addID("bso" + i);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 1);
|
||||
do_check_eq(request.errors.length, 0);
|
||||
|
||||
let coll = server.user(username).collection(collection);
|
||||
do_check_eq(coll.count(), 950);
|
||||
|
||||
do_check_eq(request.serverModifiedVersion, coll.timestamp);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batched_delete_multiple() {
|
||||
_("Ensure batched delete splits requests properly.");
|
||||
|
||||
let [server, client, username, collection] = getBatchedDeleteData();
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount += 1;
|
||||
}
|
||||
|
||||
let request = client.deleteBSOsBatching(collection);
|
||||
for (let i = 1; i < 251; i += 1) {
|
||||
request.addID("bso" + i);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 3);
|
||||
do_check_eq(request.errors.length, 0);
|
||||
|
||||
let coll = server.user(username).collection(collection);
|
||||
do_check_eq(coll.count(), 750);
|
||||
|
||||
do_check_eq(request.serverModifiedVersion, coll.timestamp);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batched_delete_conditional_success() {
|
||||
_("Ensure conditional batched delete all work.");
|
||||
|
||||
let [server, client, username, collection] = getBatchedDeleteData();
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
}
|
||||
|
||||
let serverCollection = server.user(username).collection(collection);
|
||||
let initialTimestamp = serverCollection.timestamp;
|
||||
|
||||
let request = client.deleteBSOsBatching(collection);
|
||||
request.locallyModifiedVersion = initialTimestamp;
|
||||
|
||||
for (let i = 1; i < 251; i += 1) {
|
||||
request.addID("bso" + 1);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 3);
|
||||
do_check_eq(request.errors.length, 0);
|
||||
|
||||
do_check_true(request.locallyModifiedVersion > initialTimestamp);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batched_delete_conditional_initial_failure() {
|
||||
_("Ensure conditional batched delete failure on initial request works.");
|
||||
|
||||
// The client needs to issue multiple requests but the first one was
|
||||
// rejected. The client should only issue that initial request.
|
||||
let [server, client, username, collection] = getBatchedDeleteData();
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
}
|
||||
|
||||
let serverCollection = server.user(username).collection(collection);
|
||||
let request = client.deleteBSOsBatching(collection);
|
||||
request.locallyModifiedVersion = serverCollection.timestamp - 1;
|
||||
|
||||
for (let i = 1; i < 251; i += 1) {
|
||||
request.addID("bso" + i);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 1);
|
||||
do_check_eq(request.errors.length, 1);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_batched_delete_conditional_subsequent_failure() {
|
||||
_("Ensure conditional batched delete failure on non-initial request.");
|
||||
|
||||
let [server, client, username, collection] = getBatchedDeleteData();
|
||||
|
||||
let serverCollection = server.user(username).collection(collection);
|
||||
|
||||
let requestCount = 0;
|
||||
server.callback.onRequest = function onRequest() {
|
||||
requestCount++;
|
||||
|
||||
if (requestCount <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Advance collection's timestamp on subsequent requests so request is
|
||||
// rejected.
|
||||
serverCollection.timestamp++;
|
||||
}
|
||||
|
||||
let request = client.deleteBSOsBatching(collection);
|
||||
request.locallyModifiedVersion = serverCollection.timestamp;
|
||||
|
||||
for (let i = 1; i < 251; i += 1) {
|
||||
request.addID("bso" + i);
|
||||
}
|
||||
|
||||
request.finish(function onFinish(request) {
|
||||
do_check_eq(requestCount, 2);
|
||||
do_check_eq(request.errors.length, 1);
|
||||
|
||||
server.stop(run_next_test);
|
||||
});
|
||||
});
|
||||
|
@ -128,20 +128,27 @@ BrowserRootActor.prototype = {
|
||||
* tab closures.
|
||||
*/
|
||||
watchWindow: function BRA_watchWindow(aWindow) {
|
||||
aWindow.getBrowser().tabContainer.addEventListener("TabClose",
|
||||
this.onTabClosed,
|
||||
false);
|
||||
this.getTabContainer(aWindow).addEventListener("TabClose",
|
||||
this.onTabClosed,
|
||||
false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stop watching a window for tab closes.
|
||||
*/
|
||||
unwatchWindow: function BRA_unwatchWindow(aWindow) {
|
||||
aWindow.getBrowser().tabContainer.removeEventListener("TabClose",
|
||||
this.onTabClosed);
|
||||
this.getTabContainer(aWindow).removeEventListener("TabClose",
|
||||
this.onTabClosed);
|
||||
this.exitTabActor(aWindow);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tab container for the specified window.
|
||||
*/
|
||||
getTabContainer: function BRA_getTabContainer(aWindow) {
|
||||
return aWindow.getBrowser().tabContainer;
|
||||
},
|
||||
|
||||
/**
|
||||
* When a tab is closed, exit its tab actor. The actor
|
||||
* will be dropped at the next listTabs request.
|
||||
|
@ -6807,10 +6807,10 @@ nsWindow::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, PRUint32 aModifie
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL WINAPI EnumFirstChild(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
*((HWND*)lParam) = hwnd;
|
||||
return FALSE;
|
||||
static BOOL WINAPI EnumFirstChild(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
*((HWND*)lParam) = hwnd;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void InvalidatePluginAsWorkaround(nsWindow *aWindow, const nsIntRect &aRect)
|
||||
|
Loading…
Reference in New Issue
Block a user