mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changesets 2f3f35b8cea3 and 7824a3826963 (bug 1002914) for intermittent mochitest-bc failures.
This commit is contained in:
parent
b7ee6ee34a
commit
3c1768e7a4
@ -119,8 +119,8 @@
|
|||||||
<command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
|
<command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
|
||||||
<command id="Social:ToggleSidebar" oncommand="SocialSidebar.toggleSidebar();" hidden="true"/>
|
<command id="Social:ToggleSidebar" oncommand="SocialSidebar.toggleSidebar();" hidden="true"/>
|
||||||
<command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
|
<command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
|
||||||
|
<command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/>
|
||||||
<command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
|
<command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
|
||||||
<command id="Chat:Focus" oncommand="Cu.import('resource:///modules/Chat.jsm', {}).Chat.focus(window);"/>
|
|
||||||
</commandset>
|
</commandset>
|
||||||
|
|
||||||
<commandset id="placesCommands">
|
<commandset id="placesCommands">
|
||||||
@ -380,15 +380,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
<!--<key id="markPage" key="&markPageCmd.commandkey;" command="Social:TogglePageMark" modifiers="accel,shift"/>-->
|
<!--<key id="markPage" key="&markPageCmd.commandkey;" command="Social:TogglePageMark" modifiers="accel,shift"/>-->
|
||||||
<key id="focusChatBar" key="&social.chatBar.commandkey;" command="Chat:Focus"
|
<key id="focusChatBar" key="&social.chatBar.commandkey;" command="Social:FocusChat" modifiers="accel,shift"/>
|
||||||
#ifdef XP_MACOSX
|
|
||||||
# Sadly the devtools uses shift-accel-c on non-mac and alt-accel-c everywhere else
|
|
||||||
# So we just use the other
|
|
||||||
modifiers="accel,shift"
|
|
||||||
#else
|
|
||||||
modifiers="accel,alt"
|
|
||||||
#endif
|
|
||||||
/>
|
|
||||||
|
|
||||||
<key id="key_stop" keycode="VK_ESCAPE" command="Browser:Stop"/>
|
<key id="key_stop" keycode="VK_ESCAPE" command="Browser:Stop"/>
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
// the "exported" symbols
|
// the "exported" symbols
|
||||||
let SocialUI,
|
let SocialUI,
|
||||||
|
SocialChatBar,
|
||||||
SocialFlyout,
|
SocialFlyout,
|
||||||
SocialMarks,
|
SocialMarks,
|
||||||
SocialShare,
|
SocialShare,
|
||||||
@ -172,6 +173,7 @@ SocialUI = {
|
|||||||
_providersChanged: function() {
|
_providersChanged: function() {
|
||||||
SocialSidebar.clearProviderMenus();
|
SocialSidebar.clearProviderMenus();
|
||||||
SocialSidebar.update();
|
SocialSidebar.update();
|
||||||
|
SocialChatBar.update();
|
||||||
SocialShare.populateProviderMenu();
|
SocialShare.populateProviderMenu();
|
||||||
SocialStatus.populateToolbarPalette();
|
SocialStatus.populateToolbarPalette();
|
||||||
SocialMarks.populateToolbarPalette();
|
SocialMarks.populateToolbarPalette();
|
||||||
@ -295,6 +297,45 @@ SocialUI = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SocialChatBar = {
|
||||||
|
get chatbar() {
|
||||||
|
return document.getElementById("pinnedchats");
|
||||||
|
},
|
||||||
|
// Whether the chatbar is available for this window. Note that in full-screen
|
||||||
|
// mode chats are available, but not shown.
|
||||||
|
get isAvailable() {
|
||||||
|
return SocialUI.enabled;
|
||||||
|
},
|
||||||
|
// Does this chatbar have any chats (whether minimized, collapsed or normal)
|
||||||
|
get hasChats() {
|
||||||
|
return !!this.chatbar.firstElementChild;
|
||||||
|
},
|
||||||
|
openChat: function(aProvider, aURL, aCallback, aMode) {
|
||||||
|
this.update();
|
||||||
|
if (!this.isAvailable)
|
||||||
|
return false;
|
||||||
|
this.chatbar.openChat(aProvider, aURL, aCallback, aMode);
|
||||||
|
// We only want to focus the chat if it is as a result of user input.
|
||||||
|
let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
|
if (dwu.isHandlingUserInput)
|
||||||
|
this.chatbar.focus();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
update: function() {
|
||||||
|
let command = document.getElementById("Social:FocusChat");
|
||||||
|
if (!this.isAvailable) {
|
||||||
|
this.chatbar.hidden = command.hidden = true;
|
||||||
|
} else {
|
||||||
|
this.chatbar.hidden = command.hidden = false;
|
||||||
|
}
|
||||||
|
command.setAttribute("disabled", command.hidden ? "true" : "false");
|
||||||
|
},
|
||||||
|
focus: function SocialChatBar_focus() {
|
||||||
|
this.chatbar.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SocialFlyout = {
|
SocialFlyout = {
|
||||||
get panel() {
|
get panel() {
|
||||||
return document.getElementById("social-flyout-panel");
|
return document.getElementById("social-flyout-panel");
|
||||||
|
@ -30,43 +30,50 @@
|
|||||||
|
|
||||||
<implementation implements="nsIDOMEventListener">
|
<implementation implements="nsIDOMEventListener">
|
||||||
<constructor><![CDATA[
|
<constructor><![CDATA[
|
||||||
|
let Social = Components.utils.import("resource:///modules/Social.jsm", {}).Social;
|
||||||
this.content.__defineGetter__("popupnotificationanchor",
|
this.content.__defineGetter__("popupnotificationanchor",
|
||||||
() => document.getAnonymousElementByAttribute(this, "anonid", "notification-icon"));
|
() => document.getAnonymousElementByAttribute(this, "anonid", "notification-icon"));
|
||||||
|
Social.setErrorListener(this.content, function(aBrowser) {
|
||||||
|
aBrowser.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
|
||||||
|
encodeURIComponent(aBrowser.getAttribute("origin")),
|
||||||
|
null, null, null, null);
|
||||||
|
});
|
||||||
if (!this.chatbar) {
|
if (!this.chatbar) {
|
||||||
document.getAnonymousElementByAttribute(this, "anonid", "minimize").hidden = true;
|
document.getAnonymousElementByAttribute(this, "anonid", "minimize").hidden = true;
|
||||||
document.getAnonymousElementByAttribute(this, "anonid", "close").hidden = true;
|
document.getAnonymousElementByAttribute(this, "anonid", "close").hidden = true;
|
||||||
}
|
}
|
||||||
let contentWindow = this.contentWindow;
|
let contentWindow = this.contentWindow;
|
||||||
// process this._callbacks, then set to null so the chatbox creator
|
|
||||||
// knows to make new callbacks immediately.
|
|
||||||
if (this._callbacks) {
|
|
||||||
for (let callback of this._callbacks) {
|
|
||||||
callback(this);
|
|
||||||
}
|
|
||||||
this._callbacks = null;
|
|
||||||
}
|
|
||||||
this.addEventListener("DOMContentLoaded", function DOMContentLoaded(event) {
|
this.addEventListener("DOMContentLoaded", function DOMContentLoaded(event) {
|
||||||
if (event.target != this.contentDocument)
|
if (event.target != this.contentDocument)
|
||||||
return;
|
return;
|
||||||
this.removeEventListener("DOMContentLoaded", DOMContentLoaded, true);
|
this.removeEventListener("DOMContentLoaded", DOMContentLoaded, true);
|
||||||
this.isActive = !this.minimized;
|
this.isActive = !this.minimized;
|
||||||
this._deferredChatLoaded.resolve(this);
|
// process this._callbacks, then set to null so the chatbox creator
|
||||||
|
// knows to make new callbacks immediately.
|
||||||
|
if (this._callbacks) {
|
||||||
|
for (let callback of this._callbacks) {
|
||||||
|
if (callback)
|
||||||
|
callback(contentWindow);
|
||||||
|
}
|
||||||
|
this._callbacks = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// content can send a socialChatActivity event to have the UI update.
|
||||||
|
let chatActivity = function() {
|
||||||
|
this.setAttribute("activity", true);
|
||||||
|
if (this.chatbar)
|
||||||
|
this.chatbar.updateTitlebar(this);
|
||||||
|
}.bind(this);
|
||||||
|
contentWindow.addEventListener("socialChatActivity", chatActivity);
|
||||||
|
contentWindow.addEventListener("unload", function unload() {
|
||||||
|
contentWindow.removeEventListener("unload", unload);
|
||||||
|
contentWindow.removeEventListener("socialChatActivity", chatActivity);
|
||||||
|
});
|
||||||
}, true);
|
}, true);
|
||||||
if (this.src)
|
if (this.src)
|
||||||
this.setAttribute("src", this.src);
|
this.setAttribute("src", this.src);
|
||||||
]]></constructor>
|
]]></constructor>
|
||||||
|
|
||||||
<field name="_deferredChatLoaded" readonly="true">
|
|
||||||
Promise.defer();
|
|
||||||
</field>
|
|
||||||
|
|
||||||
<property name="promiseChatLoaded">
|
|
||||||
<getter>
|
|
||||||
return this._deferredChatLoaded.promise;
|
|
||||||
</getter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<field name="content" readonly="true">
|
<field name="content" readonly="true">
|
||||||
document.getAnonymousElementByAttribute(this, "anonid", "content");
|
document.getAnonymousElementByAttribute(this, "anonid", "content");
|
||||||
</field>
|
</field>
|
||||||
@ -141,7 +148,15 @@
|
|||||||
aTarget.src = this.src;
|
aTarget.src = this.src;
|
||||||
aTarget.content.setAttribute("origin", this.content.getAttribute("origin"));
|
aTarget.content.setAttribute("origin", this.content.getAttribute("origin"));
|
||||||
aTarget.content.popupnotificationanchor.className = this.content.popupnotificationanchor.className;
|
aTarget.content.popupnotificationanchor.className = this.content.popupnotificationanchor.className;
|
||||||
|
this.content.socialErrorListener.remove();
|
||||||
|
aTarget.content.socialErrorListener.remove();
|
||||||
this.content.swapDocShells(aTarget.content);
|
this.content.swapDocShells(aTarget.content);
|
||||||
|
Social.setErrorListener(this.content, function(aBrowser) {}); // 'this' will be destroyed soon.
|
||||||
|
Social.setErrorListener(aTarget.content, function(aBrowser) {
|
||||||
|
aBrowser.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
|
||||||
|
encodeURIComponent(aBrowser.getAttribute("origin")),
|
||||||
|
null, null, null, null);
|
||||||
|
});
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
@ -171,40 +186,31 @@
|
|||||||
|
|
||||||
<method name="swapWindows">
|
<method name="swapWindows">
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
let deferred = Promise.defer();
|
let provider = Social._getProviderFromOrigin(this.content.getAttribute("origin"));
|
||||||
let title = this.getAttribute("label");
|
|
||||||
if (this.chatbar) {
|
if (this.chatbar) {
|
||||||
this.chatbar.detachChatbox(this, { "centerscreen": "yes" }).then(
|
this.chatbar.detachChatbox(this, { "centerscreen": "yes" }, win => {
|
||||||
chatbox => {
|
win.document.title = provider.name;
|
||||||
chatbox.contentWindow.document.title = title;
|
});
|
||||||
deferred.resolve(chatbox);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// attach this chatbox to the topmost browser window
|
// attach this chatbox to the topmost browser window
|
||||||
let Chat = Cu.import("resource:///modules/Chat.jsm").Chat;
|
let findChromeWindowForChats = Cu.import("resource://gre/modules/MozSocialAPI.jsm").findChromeWindowForChats;
|
||||||
let win = Chat.findChromeWindowForChats();
|
let win = findChromeWindowForChats();
|
||||||
let chatbar = win.document.getElementById("pinnedchats");
|
let chatbar = win.SocialChatBar.chatbar;
|
||||||
let origin = this.content.getAttribute("origin");
|
chatbar.openChat(provider, "about:blank", win => {
|
||||||
let cb = chatbar.openChat(origin, title, "about:blank");
|
let cb = chatbar.selectedChat;
|
||||||
cb.promiseChatLoaded.then(
|
this.swapDocShells(cb);
|
||||||
() => {
|
|
||||||
this.swapDocShells(cb);
|
|
||||||
|
|
||||||
// chatboxForURL is a map of URL -> chatbox used to avoid opening
|
// chatboxForURL is a map of URL -> chatbox used to avoid opening
|
||||||
// duplicate chat windows. Ensure reattached chat windows aren't
|
// duplicate chat windows. Ensure reattached chat windows aren't
|
||||||
// registered with about:blank as their URL, otherwise reattaching
|
// registered with about:blank as their URL, otherwise reattaching
|
||||||
// more than one chat window isn't possible.
|
// more than one chat window isn't possible.
|
||||||
chatbar.chatboxForURL.delete("about:blank");
|
chatbar.chatboxForURL.delete("about:blank");
|
||||||
chatbar.chatboxForURL.set(this.src, Cu.getWeakReference(cb));
|
chatbar.chatboxForURL.set(this.src, Cu.getWeakReference(cb));
|
||||||
|
|
||||||
chatbar.focus();
|
chatbar.focus();
|
||||||
this.close();
|
this.close();
|
||||||
deferred.resolve(cb);
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return deferred.promise;
|
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
@ -504,6 +510,7 @@
|
|||||||
<method name="_remove">
|
<method name="_remove">
|
||||||
<parameter name="aChatbox"/>
|
<parameter name="aChatbox"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
|
aChatbox.content.socialErrorListener.remove();
|
||||||
this.removeChild(aChatbox);
|
this.removeChild(aChatbox);
|
||||||
// child might have been collapsed.
|
// child might have been collapsed.
|
||||||
let menuitem = this.menuitemMap.get(aChatbox);
|
let menuitem = this.menuitemMap.get(aChatbox);
|
||||||
@ -515,12 +522,22 @@
|
|||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<method name="removeAll">
|
||||||
|
<body><![CDATA[
|
||||||
|
this.selectedChat = null;
|
||||||
|
while (this.firstElementChild) {
|
||||||
|
this._remove(this.firstElementChild);
|
||||||
|
}
|
||||||
|
// and the nub/popup must also die.
|
||||||
|
this.nub.collapsed = true;
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
<method name="openChat">
|
<method name="openChat">
|
||||||
<parameter name="aOrigin"/>
|
<parameter name="aProvider"/>
|
||||||
<parameter name="aTitle"/>
|
|
||||||
<parameter name="aURL"/>
|
<parameter name="aURL"/>
|
||||||
<parameter name="aMode"/>
|
|
||||||
<parameter name="aCallback"/>
|
<parameter name="aCallback"/>
|
||||||
|
<parameter name="aMode"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
let cb = this.chatboxForURL.get(aURL);
|
let cb = this.chatboxForURL.get(aURL);
|
||||||
if (cb) {
|
if (cb) {
|
||||||
@ -529,35 +546,30 @@
|
|||||||
this.showChat(cb, aMode);
|
this.showChat(cb, aMode);
|
||||||
if (aCallback) {
|
if (aCallback) {
|
||||||
if (cb._callbacks == null) {
|
if (cb._callbacks == null) {
|
||||||
// Chatbox has already been created, so callback now.
|
// DOMContentLoaded has already fired, so callback now.
|
||||||
aCallback(cb);
|
aCallback(cb.contentWindow);
|
||||||
} else {
|
} else {
|
||||||
// Chatbox is yet to have bindings created...
|
// DOMContentLoaded for this chat is yet to fire...
|
||||||
cb._callbacks.push(aCallback);
|
cb._callbacks.push(aCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cb;
|
return;
|
||||||
}
|
}
|
||||||
this.chatboxForURL.delete(aURL);
|
this.chatboxForURL.delete(aURL);
|
||||||
}
|
}
|
||||||
cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
|
cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
|
||||||
cb._callbacks = [];
|
// _callbacks is a javascript property instead of a <field> as it
|
||||||
if (aCallback) {
|
// must exist before the (possibly delayed) bindings are created.
|
||||||
// _callbacks is a javascript property instead of a <field> as it
|
cb._callbacks = [aCallback];
|
||||||
// must exist before the (possibly delayed) bindings are created.
|
|
||||||
cb._callbacks.push(aCallback);
|
|
||||||
}
|
|
||||||
// src also a javascript property; the src attribute is set in the ctor.
|
// src also a javascript property; the src attribute is set in the ctor.
|
||||||
cb.src = aURL;
|
cb.src = aURL;
|
||||||
if (aMode == "minimized")
|
if (aMode == "minimized")
|
||||||
cb.setAttribute("minimized", "true");
|
cb.setAttribute("minimized", "true");
|
||||||
cb.setAttribute("origin", aOrigin);
|
cb.setAttribute("origin", aProvider.origin);
|
||||||
cb.setAttribute("label", aTitle);
|
|
||||||
this.insertBefore(cb, this.firstChild);
|
this.insertBefore(cb, this.firstChild);
|
||||||
this.selectedChat = cb;
|
this.selectedChat = cb;
|
||||||
this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
|
this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
|
||||||
this.resize();
|
this.resize();
|
||||||
return cb;
|
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
@ -636,14 +648,12 @@
|
|||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<!-- Moves a chatbox to a new window. Returns a promise that is resolved
|
<!-- Moves a chatbox to a new window. -->
|
||||||
once the move to the other window is complete.
|
|
||||||
-->
|
|
||||||
<method name="detachChatbox">
|
<method name="detachChatbox">
|
||||||
<parameter name="aChatbox"/>
|
<parameter name="aChatbox"/>
|
||||||
<parameter name="aOptions"/>
|
<parameter name="aOptions"/>
|
||||||
|
<parameter name="aCallback"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
let deferred = Promise.defer();
|
|
||||||
let options = "";
|
let options = "";
|
||||||
for (let name in aOptions)
|
for (let name in aOptions)
|
||||||
options += "," + name + "=" + aOptions[name];
|
options += "," + name + "=" + aOptions[name];
|
||||||
@ -659,9 +669,9 @@
|
|||||||
let otherChatbox = otherWin.document.getElementById("chatter");
|
let otherChatbox = otherWin.document.getElementById("chatter");
|
||||||
aChatbox.swapDocShells(otherChatbox);
|
aChatbox.swapDocShells(otherChatbox);
|
||||||
aChatbox.close();
|
aChatbox.close();
|
||||||
deferred.resolve(otherChatbox);
|
if (aCallback)
|
||||||
|
aCallback(otherWin);
|
||||||
}, true);
|
}, true);
|
||||||
return deferred.promise;
|
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
@ -740,12 +750,11 @@
|
|||||||
let top = Math.min(Math.max(eY, sY.value),
|
let top = Math.min(Math.max(eY, sY.value),
|
||||||
sY.value + sHeight.value - winHeight);
|
sY.value + sHeight.value - winHeight);
|
||||||
|
|
||||||
let title = draggedChat.content.getAttribute("title");
|
let provider = Social._getProviderFromOrigin(draggedChat.content.getAttribute("origin"));
|
||||||
this.detachChatbox(draggedChat, { screenX: left, screenY: top }).then(
|
this.detachChatbox(draggedChat, { screenX: left, screenY: top }, win => {
|
||||||
chatbox => {
|
win.document.title = provider.name;
|
||||||
chatbox.contentWindow.document.title = title;
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
]]></handler>
|
]]></handler>
|
||||||
</handlers>
|
</handlers>
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
support-files =
|
|
||||||
head.js
|
|
||||||
chat.html
|
|
||||||
|
|
||||||
[browser_chatwindow.js]
|
|
||||||
[browser_focus.js]
|
|
||||||
[browser_tearoff.js]
|
|
@ -1,135 +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/. */
|
|
||||||
|
|
||||||
let chatbar = document.getElementById("pinnedchats");
|
|
||||||
|
|
||||||
add_chat_task(function* testOpenCloseChat() {
|
|
||||||
let chatbox = yield promiseOpenChat("http://example.com");
|
|
||||||
Assert.strictEqual(chatbox, chatbar.selectedChat);
|
|
||||||
// we requested a "normal" chat, so shouldn't be minimized
|
|
||||||
Assert.ok(!chatbox.minimized, "chat is not minimized");
|
|
||||||
Assert.equal(chatbar.childNodes.length, 1, "should be 1 chat open");
|
|
||||||
|
|
||||||
|
|
||||||
// now request the same URL again - we should get the same chat.
|
|
||||||
let chatbox2 = yield promiseOpenChat("http://example.com");
|
|
||||||
Assert.strictEqual(chatbox2, chatbox, "got the same chat");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
|
|
||||||
|
|
||||||
chatbox.toggle();
|
|
||||||
is(chatbox.minimized, true, "chat is now minimized");
|
|
||||||
// was no other chat to select, so selected becomes null.
|
|
||||||
is(chatbar.selectedChat, null);
|
|
||||||
|
|
||||||
// We check the content gets an unload event as we close it.
|
|
||||||
let promiseClosed = promiseOneEvent(chatbox.content, "unload", true);
|
|
||||||
chatbox.close();
|
|
||||||
yield promiseClosed;
|
|
||||||
});
|
|
||||||
|
|
||||||
// In this case we open a chat minimized, then request the same chat again
|
|
||||||
// without specifying minimized. On that second call the chat should open,
|
|
||||||
// selected, and no longer minimized.
|
|
||||||
add_chat_task(function* testMinimized() {
|
|
||||||
let chatbox = yield promiseOpenChat("http://example.com", "minimized");
|
|
||||||
Assert.strictEqual(chatbox, chatbar.selectedChat);
|
|
||||||
Assert.ok(chatbox.minimized, "chat is minimized");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
|
|
||||||
yield promiseOpenChat("http://example.com");
|
|
||||||
Assert.ok(!chatbox.minimized, false, "chat is no longer minimized");
|
|
||||||
});
|
|
||||||
|
|
||||||
// open enough chats to overflow the window, then check
|
|
||||||
// if the menupopup is visible
|
|
||||||
add_chat_task(function* testManyChats() {
|
|
||||||
Assert.ok(chatbar.menupopup.parentNode.collapsed, "popup nub collapsed at start");
|
|
||||||
// we should *never* find a test box that needs more than this to cause
|
|
||||||
// an overflow!
|
|
||||||
let maxToOpen = 20;
|
|
||||||
let numOpened = 0;
|
|
||||||
for (let i = 0; i < maxToOpen; i++) {
|
|
||||||
yield promiseOpenChat("http://example.com#" + i);
|
|
||||||
if (!chatbar.menupopup.parentNode.collapsed) {
|
|
||||||
info("the menu popup appeared");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Assert.ok(false, "We didn't find a collapsed chat after " + maxToOpen + "chats!");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check that closeAll works as expected.
|
|
||||||
add_chat_task(function* testOpenTwiceCallbacks() {
|
|
||||||
yield promiseOpenChat("http://example.com#1");
|
|
||||||
yield promiseOpenChat("http://example.com#2");
|
|
||||||
yield promiseOpenChat("http://test2.example.com");
|
|
||||||
Assert.equal(numChatsInWindow(window), 3, "should be 3 chats open");
|
|
||||||
Chat.closeAll("http://example.com");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should have closed 2 chats");
|
|
||||||
Chat.closeAll("http://test2.example.com");
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "should have closed last chat");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check that when we open the same chat twice, the callbacks are called back
|
|
||||||
// twice.
|
|
||||||
add_chat_task(function* testOpenTwiceCallbacks() {
|
|
||||||
yield promiseOpenChatCallback("http://example.com");
|
|
||||||
yield promiseOpenChatCallback("http://example.com");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Bug 817782 - check chats work in new top-level windows.
|
|
||||||
add_chat_task(function* testSecondTopLevelWindow() {
|
|
||||||
const chatUrl = "http://example.com";
|
|
||||||
let secondWindow = OpenBrowserWindow();
|
|
||||||
yield promiseOneEvent(secondWindow, "load");
|
|
||||||
yield promiseOpenChat(chatUrl);
|
|
||||||
// the chat was created - let's make sure it was created in the second window.
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "main window has no chats");
|
|
||||||
Assert.equal(numChatsInWindow(secondWindow), 1, "second window has 1 chat");
|
|
||||||
secondWindow.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Test that chats are created in the correct window.
|
|
||||||
add_chat_task(function* testChatWindowChooser() {
|
|
||||||
let chat = yield promiseOpenChat("http://example.com");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "first window has the chat");
|
|
||||||
// create a second window - this will be the "most recent" and will
|
|
||||||
// therefore be the window that hosts the new chat (see bug 835111)
|
|
||||||
let secondWindow = OpenBrowserWindow();
|
|
||||||
yield promiseOneEvent(secondWindow, "load");
|
|
||||||
Assert.equal(numChatsInWindow(secondWindow), 0, "second window starts with no chats");
|
|
||||||
yield promiseOpenChat("http://example.com#2");
|
|
||||||
Assert.equal(numChatsInWindow(secondWindow), 1, "second window now has chats");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "first window still has 1 chat");
|
|
||||||
chat.close();
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "first window now has no chats");
|
|
||||||
// now open another chat - it should still open in the second.
|
|
||||||
yield promiseOpenChat("http://example.com#3");
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "first window still has no chats");
|
|
||||||
Assert.equal(numChatsInWindow(secondWindow), 2, "second window has both chats");
|
|
||||||
|
|
||||||
// focus the first window, and open yet another chat - it
|
|
||||||
// should open in the first window.
|
|
||||||
window.focus();
|
|
||||||
yield promiseWaitForFocus();
|
|
||||||
chat = yield promiseOpenChat("http://example.com#4");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "first window got new chat");
|
|
||||||
chat.close();
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "first window has no chats");
|
|
||||||
|
|
||||||
let privateWindow = OpenBrowserWindow({private: true});
|
|
||||||
yield promiseOneEvent(privateWindow, "load")
|
|
||||||
|
|
||||||
// open a last chat - the focused window can't accept
|
|
||||||
// chats (it's a private window), so the chat should open
|
|
||||||
// in the window that was selected before. This is known
|
|
||||||
// to be broken on Linux.
|
|
||||||
chat = yield promiseOpenChat("http://example.com#5");
|
|
||||||
let os = Services.appinfo.OS;
|
|
||||||
const BROKEN_WM_Z_ORDER = os != "WINNT" && os != "Darwin";
|
|
||||||
let fn = BROKEN_WM_Z_ORDER ? todo : ok;
|
|
||||||
fn(numChatsInWindow(window) == 1, "first window got the chat");
|
|
||||||
chat.close();
|
|
||||||
privateWindow.close();
|
|
||||||
secondWindow.close();
|
|
||||||
});
|
|
@ -1,226 +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/. */
|
|
||||||
|
|
||||||
// Tests the focus functionality.
|
|
||||||
|
|
||||||
const CHAT_URL = "https://example.com/browser/browser/base/content/test/chat/chat.html";
|
|
||||||
|
|
||||||
// Is the currently opened tab focused?
|
|
||||||
function isTabFocused() {
|
|
||||||
let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
|
||||||
return Services.focus.focusedWindow == tabb.contentWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is the specified chat focused?
|
|
||||||
function isChatFocused(chat) {
|
|
||||||
return chat.chatbar._isChatFocused(chat);
|
|
||||||
}
|
|
||||||
|
|
||||||
let chatbar = document.getElementById("pinnedchats");
|
|
||||||
|
|
||||||
function* setUp() {
|
|
||||||
// Note that (probably) due to bug 604289, if a tab is focused but the
|
|
||||||
// focused element is null, our chat windows can "steal" focus. This is
|
|
||||||
// avoided if we explicitly focus an element in the tab.
|
|
||||||
// So we load a page with an <input> field and focus that before testing.
|
|
||||||
let html = '<input id="theinput"><button id="chat-opener"></button>';
|
|
||||||
let url = "data:text/html;charset=utf-8," + encodeURI(html);
|
|
||||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true});
|
|
||||||
yield promiseOneEvent(tab.linkedBrowser, "load", true);
|
|
||||||
tab.linkedBrowser.contentDocument.getElementById("theinput").focus();
|
|
||||||
registerCleanupFunction(function() {
|
|
||||||
gBrowser.removeTab(tab);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test default focus - not user input.
|
|
||||||
add_chat_task(function* testDefaultFocus() {
|
|
||||||
yield setUp();
|
|
||||||
let chat = yield promiseOpenChat("http://example.com");
|
|
||||||
// we used the default focus behaviour, which means that because this was
|
|
||||||
// not the direct result of user action the chat should not be focused.
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
|
|
||||||
Assert.ok(isTabFocused(), "the tab should remain focused.");
|
|
||||||
Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Test default focus via user input.
|
|
||||||
add_chat_task(function* testDefaultFocus() {
|
|
||||||
yield setUp();
|
|
||||||
let tab = gBrowser.selectedTab;
|
|
||||||
let deferred = Promise.defer();
|
|
||||||
let button = tab.linkedBrowser.contentDocument.getElementById("chat-opener");
|
|
||||||
button.addEventListener("click", function onclick() {
|
|
||||||
button.removeEventListener("click", onclick);
|
|
||||||
promiseOpenChat("http://example.com").then(
|
|
||||||
chat => deferred.resolve(chat)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
// Note we must use synthesizeMouseAtCenter() rather than calling
|
|
||||||
// .click() directly as this causes nsIDOMWindowUtils.isHandlingUserInput
|
|
||||||
// to be true.
|
|
||||||
EventUtils.synthesizeMouseAtCenter(button, {}, button.ownerDocument.defaultView);
|
|
||||||
let chat = yield deferred.promise;
|
|
||||||
|
|
||||||
// we use the default focus behaviour but the chat was opened via user input,
|
|
||||||
// so the chat should be focused.
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
|
|
||||||
Assert.ok(!isTabFocused(), "the tab should have lost focus.");
|
|
||||||
Assert.ok(isChatFocused(chat), "the chat should have got focus.");
|
|
||||||
});
|
|
||||||
|
|
||||||
// We explicitly ask for the chat to be focused.
|
|
||||||
add_chat_task(function* testExplicitFocus() {
|
|
||||||
yield setUp();
|
|
||||||
let chat = yield promiseOpenChat("http://example.com", undefined, true);
|
|
||||||
// we use the default focus behaviour, which means that because this was
|
|
||||||
// not the direct result of user action the chat should not be focused.
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
|
|
||||||
Assert.ok(!isTabFocused(), "the tab should have lost focus.");
|
|
||||||
Assert.ok(isChatFocused(chat), "the chat should have got focus.");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open a minimized chat via default focus behaviour - it will open and not
|
|
||||||
// have focus. Then open the same chat without 'minimized' - it will be
|
|
||||||
// restored but should still not have grabbed focus.
|
|
||||||
add_chat_task(function* testNoFocusOnAutoRestore() {
|
|
||||||
yield setUp();
|
|
||||||
let chat = yield promiseOpenChat("http://example.com", "minimized");
|
|
||||||
Assert.ok(chat.minimized, "chat is minimized");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
|
|
||||||
Assert.ok(isTabFocused(), "the tab should remain focused.");
|
|
||||||
Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
|
|
||||||
yield promiseOpenChat("http://example.com");
|
|
||||||
Assert.ok(!chat.minimized, "chat should be restored");
|
|
||||||
Assert.ok(isTabFocused(), "the tab should remain focused.");
|
|
||||||
Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Here we open a chat, which will not be focused. Then we minimize it and
|
|
||||||
// restore it via a titlebar clock - it should get focus at that point.
|
|
||||||
add_chat_task(function* testFocusOnExplicitRestore() {
|
|
||||||
yield setUp();
|
|
||||||
let chat = yield promiseOpenChat("http://example.com");
|
|
||||||
Assert.ok(!chat.minimized, "chat should have been opened restored");
|
|
||||||
Assert.ok(isTabFocused(), "the tab should remain focused.");
|
|
||||||
Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
|
|
||||||
chat.minimized = true;
|
|
||||||
Assert.ok(isTabFocused(), "tab should still be focused");
|
|
||||||
Assert.ok(!isChatFocused(chat), "the chat should not be focused.");
|
|
||||||
|
|
||||||
let promise = promiseOneEvent(chat.contentWindow, "focus");
|
|
||||||
// pretend we clicked on the titlebar
|
|
||||||
chat.onTitlebarClick({button: 0});
|
|
||||||
yield promise; // wait for focus event.
|
|
||||||
Assert.ok(!chat.minimized, "chat should have been restored");
|
|
||||||
Assert.ok(isChatFocused(chat), "chat should be focused");
|
|
||||||
Assert.strictEqual(chat, chatbar.selectedChat, "chat is marked selected");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open 2 chats and give 1 focus. Minimize the focused one - the second
|
|
||||||
// should get focus.
|
|
||||||
add_chat_task(function* testMinimizeFocused() {
|
|
||||||
yield setUp();
|
|
||||||
let chat1 = yield promiseOpenChat("http://example.com#1");
|
|
||||||
let chat2 = yield promiseOpenChat("http://example.com#2");
|
|
||||||
Assert.equal(numChatsInWindow(window), 2, "2 chats open");
|
|
||||||
Assert.strictEqual(chatbar.selectedChat, chat2, "chat2 is selected");
|
|
||||||
let promise = promiseOneEvent(chat1.contentWindow, "focus");
|
|
||||||
chatbar.selectedChat = chat1;
|
|
||||||
chatbar.focus();
|
|
||||||
yield promise; // wait for chat1 to get focus.
|
|
||||||
Assert.strictEqual(chat1, chatbar.selectedChat, "chat1 is marked selected");
|
|
||||||
Assert.notStrictEqual(chat2, chatbar.selectedChat, "chat2 is not marked selected");
|
|
||||||
promise = promiseOneEvent(chat2.contentWindow, "focus");
|
|
||||||
chat1.minimized = true;
|
|
||||||
yield promise; // wait for chat2 to get focus.
|
|
||||||
Assert.notStrictEqual(chat1, chatbar.selectedChat, "chat1 is not marked selected");
|
|
||||||
Assert.strictEqual(chat2, chatbar.selectedChat, "chat2 is marked selected");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open 2 chats, select and focus the second. Pressing the TAB key should
|
|
||||||
// cause focus to move between all elements in our chat window before moving
|
|
||||||
// to the next chat window.
|
|
||||||
add_chat_task(function* testTab() {
|
|
||||||
yield setUp();
|
|
||||||
|
|
||||||
function sendTabAndWaitForFocus(chat, eltid) {
|
|
||||||
let doc = chat.contentDocument;
|
|
||||||
EventUtils.sendKey("tab");
|
|
||||||
// ideally we would use the 'focus' event here, but that doesn't work
|
|
||||||
// as expected for the iframe - the iframe itself never gets the focus
|
|
||||||
// event (apparently the sub-document etc does.)
|
|
||||||
// So just poll for the correct element getting focus...
|
|
||||||
let deferred = Promise.defer();
|
|
||||||
let tries = 0;
|
|
||||||
let interval = setInterval(function() {
|
|
||||||
if (tries >= 30) {
|
|
||||||
clearInterval(interval);
|
|
||||||
deferred.reject("never got focus");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tries ++;
|
|
||||||
let elt = eltid ? doc.getElementById(eltid) : doc.documentElement;
|
|
||||||
if (doc.activeElement == elt) {
|
|
||||||
clearInterval(interval);
|
|
||||||
deferred.resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
let chat1 = yield promiseOpenChat(CHAT_URL + "#1");
|
|
||||||
let chat2 = yield promiseOpenChat(CHAT_URL + "#2");
|
|
||||||
chatbar.selectedChat = chat2;
|
|
||||||
let promise = promiseOneEvent(chat2.contentWindow, "focus");
|
|
||||||
chatbar.focus();
|
|
||||||
yield promise;
|
|
||||||
|
|
||||||
// Our chats have 3 focusable elements, so it takes 4 TABs to move
|
|
||||||
// to the new chat.
|
|
||||||
yield sendTabAndWaitForFocus(chat2, "input1");
|
|
||||||
Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input1",
|
|
||||||
"first input field has focus");
|
|
||||||
Assert.ok(isChatFocused(chat2), "new chat still focused after first tab");
|
|
||||||
|
|
||||||
yield sendTabAndWaitForFocus(chat2, "input2");
|
|
||||||
Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
|
|
||||||
Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "input2",
|
|
||||||
"second input field has focus");
|
|
||||||
|
|
||||||
yield sendTabAndWaitForFocus(chat2, "iframe");
|
|
||||||
Assert.ok(isChatFocused(chat2), "new chat still focused after tab");
|
|
||||||
Assert.equal(chat2.contentDocument.activeElement.getAttribute("id"), "iframe",
|
|
||||||
"iframe has focus");
|
|
||||||
|
|
||||||
// this tab now should move to the next chat, but focus the
|
|
||||||
// document element itself (hence the null eltid)
|
|
||||||
yield sendTabAndWaitForFocus(chat1, null);
|
|
||||||
Assert.ok(isChatFocused(chat1), "first chat is focused");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open a chat and focus an element other than the first. Move focus to some
|
|
||||||
// other item (the tab itself in this case), then focus the chatbar - the
|
|
||||||
// same element that was previously focused should still have focus.
|
|
||||||
add_chat_task(function* testFocusedElement() {
|
|
||||||
yield setUp();
|
|
||||||
|
|
||||||
// open a chat with focus requested.
|
|
||||||
let chat = yield promiseOpenChat(CHAT_URL, undefined, true);
|
|
||||||
|
|
||||||
chat.contentDocument.getElementById("input2").focus();
|
|
||||||
|
|
||||||
// set focus to the tab.
|
|
||||||
let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
|
||||||
let promise = promiseOneEvent(tabb.contentWindow, "focus");
|
|
||||||
Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
|
|
||||||
yield promise;
|
|
||||||
|
|
||||||
promise = promiseOneEvent(chat.contentWindow, "focus");
|
|
||||||
chatbar.focus();
|
|
||||||
yield promise;
|
|
||||||
|
|
||||||
Assert.equal(chat.contentDocument.activeElement.getAttribute("id"), "input2",
|
|
||||||
"correct input field still has focus");
|
|
||||||
});
|
|
@ -1,128 +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/. */
|
|
||||||
|
|
||||||
let chatbar = document.getElementById("pinnedchats");
|
|
||||||
|
|
||||||
function promiseNewWindowLoaded() {
|
|
||||||
let deferred = Promise.defer();
|
|
||||||
Services.wm.addListener({
|
|
||||||
onWindowTitleChange: function() {},
|
|
||||||
onCloseWindow: function(xulwindow) {},
|
|
||||||
onOpenWindow: function(xulwindow) {
|
|
||||||
var domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Components.interfaces.nsIDOMWindow);
|
|
||||||
Services.wm.removeListener(this);
|
|
||||||
// wait for load to ensure the window is ready for us to test
|
|
||||||
domwindow.addEventListener("load", function _load(event) {
|
|
||||||
let doc = domwindow.document;
|
|
||||||
if (event.target != doc)
|
|
||||||
return;
|
|
||||||
domwindow.removeEventListener("load", _load);
|
|
||||||
deferred.resolve(domwindow);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_chat_task(function* testTearoffChat() {
|
|
||||||
let chatbox = yield promiseOpenChat("http://example.com");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "should be 1 chat open");
|
|
||||||
|
|
||||||
let chatDoc = chatbox.contentDocument;
|
|
||||||
let chatTitle = chatDoc.title;
|
|
||||||
|
|
||||||
Assert.equal(chatbox.getAttribute("label"), chatTitle,
|
|
||||||
"the new chatbox should show the title of the chat window");
|
|
||||||
|
|
||||||
// mutate the chat document a bit before we tear it off.
|
|
||||||
let div = chatDoc.createElement("div");
|
|
||||||
div.setAttribute("id", "testdiv");
|
|
||||||
div.setAttribute("test", "1");
|
|
||||||
chatDoc.body.appendChild(div);
|
|
||||||
|
|
||||||
// chatbox is open, lets detach. The new chat window will be caught in
|
|
||||||
// the window watcher below
|
|
||||||
let promise = promiseNewWindowLoaded();
|
|
||||||
|
|
||||||
let swap = document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
|
|
||||||
swap.click();
|
|
||||||
|
|
||||||
// and wait for the new window.
|
|
||||||
let domwindow = yield promise;
|
|
||||||
|
|
||||||
Assert.equal(domwindow.document.documentElement.getAttribute("windowtype"), "Social:Chat", "Social:Chat window opened");
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "should be no chats in the chat bar");
|
|
||||||
|
|
||||||
// get the chatbox from the new window.
|
|
||||||
chatbox = domwindow.document.getElementById("chatter")
|
|
||||||
Assert.equal(chatbox.getAttribute("label"), chatTitle, "window should have same title as chat");
|
|
||||||
|
|
||||||
div = chatbox.contentDocument.getElementById("testdiv");
|
|
||||||
Assert.equal(div.getAttribute("test"), "1", "docshell should have been swapped");
|
|
||||||
div.setAttribute("test", "2");
|
|
||||||
|
|
||||||
// swap the window back to the chatbar
|
|
||||||
promise = promiseOneEvent(domwindow, "unload");
|
|
||||||
swap = domwindow.document.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
|
|
||||||
swap.click();
|
|
||||||
|
|
||||||
yield promise;
|
|
||||||
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "chat should be docked back in the window");
|
|
||||||
chatbox = chatbar.selectedChat;
|
|
||||||
Assert.equal(chatbox.getAttribute("label"), chatTitle,
|
|
||||||
"the new chatbox should show the title of the chat window again");
|
|
||||||
|
|
||||||
div = chatbox.contentDocument.getElementById("testdiv");
|
|
||||||
Assert.equal(div.getAttribute("test"), "2", "docshell should have been swapped");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Similar test but with 2 chats.
|
|
||||||
add_chat_task(function* testReattachTwice() {
|
|
||||||
let chatbox1 = yield promiseOpenChat("http://example.com#1");
|
|
||||||
let chatbox2 = yield promiseOpenChat("http://example.com#2");
|
|
||||||
Assert.equal(numChatsInWindow(window), 2, "both chats should be docked in the window");
|
|
||||||
|
|
||||||
info("chatboxes are open, detach from window");
|
|
||||||
let promise = promiseNewWindowLoaded();
|
|
||||||
document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
|
|
||||||
let domwindow1 = yield promise;
|
|
||||||
chatbox1 = domwindow1.document.getElementById("chatter");
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "only second chat should be docked in the window");
|
|
||||||
|
|
||||||
promise = promiseNewWindowLoaded();
|
|
||||||
document.getAnonymousElementByAttribute(chatbox2, "anonid", "swap").click();
|
|
||||||
let domwindow2 = yield promise;
|
|
||||||
chatbox2 = domwindow2.document.getElementById("chatter");
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "should be no docked chats");
|
|
||||||
|
|
||||||
promise = promiseOneEvent(domwindow2, "unload");
|
|
||||||
domwindow2.document.getAnonymousElementByAttribute(chatbox2, "anonid", "swap").click();
|
|
||||||
yield promise;
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "one chat should be docked back in the window");
|
|
||||||
|
|
||||||
promise = promiseOneEvent(domwindow1, "unload");
|
|
||||||
domwindow1.document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
|
|
||||||
yield promise;
|
|
||||||
Assert.equal(numChatsInWindow(window), 2, "both chats should be docked back in the window");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check that Chat.closeAll() also closes detached windows.
|
|
||||||
add_chat_task(function* testCloseAll() {
|
|
||||||
let chatbox1 = yield promiseOpenChat("http://example.com#1");
|
|
||||||
let chatbox2 = yield promiseOpenChat("http://example.com#2");
|
|
||||||
|
|
||||||
let promise = promiseNewWindowLoaded();
|
|
||||||
document.getAnonymousElementByAttribute(chatbox1, "anonid", "swap").click();
|
|
||||||
let domwindow = yield promise;
|
|
||||||
chatbox1 = domwindow.document.getElementById("chatter");
|
|
||||||
|
|
||||||
let promiseWindowUnload = promiseOneEvent(domwindow, "unload");
|
|
||||||
|
|
||||||
Assert.equal(numChatsInWindow(window), 1, "second chat should still be docked");
|
|
||||||
Chat.closeAll("http://example.com");
|
|
||||||
yield promiseWindowUnload;
|
|
||||||
Assert.equal(numChatsInWindow(window), 0, "should be no chats left");
|
|
||||||
});
|
|
@ -1,14 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>test chat window</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>This is a test chat window.</p>
|
|
||||||
<!-- a couple of input fields to help with focus testing -->
|
|
||||||
<input id="input1"/>
|
|
||||||
<input id="input2"/>
|
|
||||||
<!-- an iframe here so this one page generates multiple load events -->
|
|
||||||
<iframe id="iframe" src="data:text/plain:this is an iframe"></iframe>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,74 +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/. */
|
|
||||||
|
|
||||||
// Utility functions for Chat tests.
|
|
||||||
|
|
||||||
let Chat = Cu.import("resource:///modules/Chat.jsm", {}).Chat;
|
|
||||||
|
|
||||||
function promiseOpenChat(url, mode, focus) {
|
|
||||||
let uri = Services.io.newURI(url, null, null);
|
|
||||||
let origin = uri.prePath;
|
|
||||||
let title = origin;
|
|
||||||
let chatbox = Chat.open(null, origin, title, url, mode, focus);
|
|
||||||
return chatbox.promiseChatLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opens a chat, returns a promise resolved when the chat callback fired.
|
|
||||||
function promiseOpenChatCallback(url, mode) {
|
|
||||||
let uri = Services.io.newURI(url, null, null);
|
|
||||||
let origin = uri.prePath;
|
|
||||||
let title = origin;
|
|
||||||
let deferred = Promise.defer();
|
|
||||||
let callback = deferred.resolve;
|
|
||||||
Chat.open(null, origin, title, url, mode, undefined, callback);
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opens a chat, returns the chat window's promise which fires when the chat
|
|
||||||
// starts loading.
|
|
||||||
function promiseOneEvent(target, eventName, capture) {
|
|
||||||
let deferred = Promise.defer();
|
|
||||||
target.addEventListener(eventName, function handler(event) {
|
|
||||||
target.removeEventListener(eventName, handler, capture);
|
|
||||||
deferred.resolve();
|
|
||||||
}, capture);
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the number of chats in a browser window.
|
|
||||||
function numChatsInWindow(win) {
|
|
||||||
let chatbar = win.document.getElementById("pinnedchats");
|
|
||||||
return chatbar.childElementCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
function promiseWaitForFocus() {
|
|
||||||
let deferred = Promise.defer();
|
|
||||||
waitForFocus(deferred.resolve);
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A simple way to clean up after each test.
|
|
||||||
function add_chat_task(genFunction) {
|
|
||||||
add_task(function* () {
|
|
||||||
info("Starting chat test " + genFunction.name);
|
|
||||||
try {
|
|
||||||
yield genFunction();
|
|
||||||
} finally {
|
|
||||||
info("Finished chat test " + genFunction.name + " - cleaning up.");
|
|
||||||
// close all docked chats.
|
|
||||||
while (chatbar.childNodes.length) {
|
|
||||||
chatbar.childNodes[0].close();
|
|
||||||
}
|
|
||||||
// and non-docked chats.
|
|
||||||
let winEnum = Services.wm.getEnumerator("Social:Chat");
|
|
||||||
while (winEnum.hasMoreElements()) {
|
|
||||||
let win = winEnum.getNext();
|
|
||||||
if (win.closed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
win.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
@ -26,6 +26,7 @@ support-files =
|
|||||||
|
|
||||||
[browser_addons.js]
|
[browser_addons.js]
|
||||||
[browser_blocklist.js]
|
[browser_blocklist.js]
|
||||||
|
[browser_chat_tearoff.js]
|
||||||
[browser_defaults.js]
|
[browser_defaults.js]
|
||||||
[browser_share.js]
|
[browser_share.js]
|
||||||
[browser_social_activation.js]
|
[browser_social_activation.js]
|
||||||
|
308
browser/base/content/test/social/browser_chat_tearoff.js
Normal file
308
browser/base/content/test/social/browser_chat_tearoff.js
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
requestLongerTimeout(2); // only debug builds seem to need more time...
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
let manifest = { // normal provider
|
||||||
|
name: "provider 1",
|
||||||
|
origin: "https://example.com",
|
||||||
|
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
|
||||||
|
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||||
|
iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
let postSubTest = function(cb) {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
ok(chats.children.length == 0, "no chatty children left behind");
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
runSocialTestWithProvider(manifest, function (finishcb) {
|
||||||
|
SocialSidebar.show();
|
||||||
|
ok(SocialSidebar.provider, "sidebar provider exists");
|
||||||
|
runSocialTests(tests, undefined, postSubTest, function() {
|
||||||
|
finishcb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = {
|
||||||
|
testTearoffChat: function(next) {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
let chatTitle;
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
ok(port, "provider has a port");
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "got-sidebar-message":
|
||||||
|
port.postMessage({topic: "test-chatbox-open"});
|
||||||
|
break;
|
||||||
|
case "got-chatbox-visibility":
|
||||||
|
// chatbox is open, lets detach. The new chat window will be caught in
|
||||||
|
// the window watcher below
|
||||||
|
let doc = chats.selectedChat.contentDocument;
|
||||||
|
// This message is (sometimes!) received a second time
|
||||||
|
// before we start our tests from the onCloseWindow
|
||||||
|
// callback.
|
||||||
|
if (doc.location == "about:blank")
|
||||||
|
return;
|
||||||
|
chatTitle = doc.title;
|
||||||
|
ok(chats.selectedChat.getAttribute("label") == chatTitle,
|
||||||
|
"the new chatbox should show the title of the chat window");
|
||||||
|
let div = doc.createElement("div");
|
||||||
|
div.setAttribute("id", "testdiv");
|
||||||
|
div.setAttribute("test", "1");
|
||||||
|
doc.body.appendChild(div);
|
||||||
|
let swap = document.getAnonymousElementByAttribute(chats.selectedChat, "anonid", "swap");
|
||||||
|
swap.click();
|
||||||
|
port.close();
|
||||||
|
break;
|
||||||
|
case "got-chatbox-message":
|
||||||
|
ok(true, "got chatbox message");
|
||||||
|
ok(e.data.result == "ok", "got chatbox windowRef result: "+e.data.result);
|
||||||
|
chats.selectedChat.toggle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Services.wm.addListener({
|
||||||
|
onWindowTitleChange: function() {},
|
||||||
|
onCloseWindow: function(xulwindow) {},
|
||||||
|
onOpenWindow: function(xulwindow) {
|
||||||
|
var domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Components.interfaces.nsIDOMWindow);
|
||||||
|
Services.wm.removeListener(this);
|
||||||
|
// wait for load to ensure the window is ready for us to test
|
||||||
|
domwindow.addEventListener("load", function _load(event) {
|
||||||
|
let doc = domwindow.document;
|
||||||
|
if (event.target != doc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
domwindow.removeEventListener("load", _load, false);
|
||||||
|
|
||||||
|
domwindow.addEventListener("unload", function _close(event) {
|
||||||
|
if (event.target != doc)
|
||||||
|
return;
|
||||||
|
domwindow.removeEventListener("unload", _close, false);
|
||||||
|
info("window has been closed");
|
||||||
|
waitForCondition(function() {
|
||||||
|
return chats.selectedChat && chats.selectedChat.contentDocument &&
|
||||||
|
chats.selectedChat.contentDocument.readyState == "complete";
|
||||||
|
},function () {
|
||||||
|
ok(chats.selectedChat, "should have a chatbox in our window again");
|
||||||
|
ok(chats.selectedChat.getAttribute("label") == chatTitle,
|
||||||
|
"the new chatbox should show the title of the chat window again");
|
||||||
|
let testdiv = chats.selectedChat.contentDocument.getElementById("testdiv");
|
||||||
|
is(testdiv.getAttribute("test"), "2", "docshell should have been swapped");
|
||||||
|
chats.selectedChat.close();
|
||||||
|
waitForCondition(function() {
|
||||||
|
return chats.children.length == 0;
|
||||||
|
},function () {
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
is(doc.documentElement.getAttribute("windowtype"), "Social:Chat", "Social:Chat window opened");
|
||||||
|
// window is loaded, but the docswap does not happen until after load,
|
||||||
|
// and we have no event to wait on, so we'll wait for document state
|
||||||
|
// to be ready
|
||||||
|
let chatbox = doc.getElementById("chatter");
|
||||||
|
waitForCondition(function() {
|
||||||
|
return chats.selectedChat == null &&
|
||||||
|
chatbox.contentDocument &&
|
||||||
|
chatbox.contentDocument.readyState == "complete";
|
||||||
|
},function() {
|
||||||
|
ok(chatbox.getAttribute("label") == chatTitle,
|
||||||
|
"detached window should show the title of the chat window");
|
||||||
|
let testdiv = chatbox.contentDocument.getElementById("testdiv");
|
||||||
|
is(testdiv.getAttribute("test"), "1", "docshell should have been swapped");
|
||||||
|
testdiv.setAttribute("test", "2");
|
||||||
|
// swap the window back to the chatbar
|
||||||
|
let swap = doc.getAnonymousElementByAttribute(chatbox, "anonid", "swap");
|
||||||
|
swap.click();
|
||||||
|
}, domwindow);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
port.postMessage({topic: "test-init", data: { id: 1 }});
|
||||||
|
},
|
||||||
|
|
||||||
|
testCloseOnLogout: function(next) {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
ok(port, "provider has a port");
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "got-chatbox-visibility":
|
||||||
|
// chatbox is open, lets detach. The new chat window will be caught in
|
||||||
|
// the window watcher below
|
||||||
|
let doc = chats.selectedChat.contentDocument;
|
||||||
|
// This message is (sometimes!) received a second time
|
||||||
|
// before we start our tests from the onCloseWindow
|
||||||
|
// callback.
|
||||||
|
if (doc.location == "about:blank")
|
||||||
|
return;
|
||||||
|
info("chatbox is open, detach from window");
|
||||||
|
let swap = document.getAnonymousElementByAttribute(chats.selectedChat, "anonid", "swap");
|
||||||
|
swap.click();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Services.wm.addListener({
|
||||||
|
onWindowTitleChange: function() {},
|
||||||
|
onCloseWindow: function(xulwindow) {},
|
||||||
|
onOpenWindow: function(xulwindow) {
|
||||||
|
let domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Components.interfaces.nsIDOMWindow);
|
||||||
|
Services.wm.removeListener(this);
|
||||||
|
// wait for load to ensure the window is ready for us to test, make sure
|
||||||
|
// we're not getting called for about:blank
|
||||||
|
domwindow.addEventListener("load", function _load(event) {
|
||||||
|
let doc = domwindow.document;
|
||||||
|
if (event.target != doc)
|
||||||
|
return;
|
||||||
|
domwindow.removeEventListener("load", _load, false);
|
||||||
|
|
||||||
|
domwindow.addEventListener("unload", function _close(event) {
|
||||||
|
if (event.target != doc)
|
||||||
|
return;
|
||||||
|
domwindow.removeEventListener("unload", _close, false);
|
||||||
|
ok(true, "window has been closed");
|
||||||
|
next();
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
is(doc.documentElement.getAttribute("windowtype"), "Social:Chat", "Social:Chat window opened");
|
||||||
|
// window is loaded, but the docswap does not happen until after load,
|
||||||
|
// and we have no event to wait on, so we'll wait for document state
|
||||||
|
// to be ready
|
||||||
|
let chatbox = doc.getElementById("chatter");
|
||||||
|
waitForCondition(function() {
|
||||||
|
return chats.children.length == 0 &&
|
||||||
|
chatbox.contentDocument &&
|
||||||
|
chatbox.contentDocument.readyState == "complete";
|
||||||
|
},function() {
|
||||||
|
// logout, we should get unload next
|
||||||
|
port.postMessage({topic: "test-logout"});
|
||||||
|
port.close();
|
||||||
|
}, domwindow);
|
||||||
|
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
port.postMessage({topic: "test-worker-chat", data: chatUrl});
|
||||||
|
},
|
||||||
|
|
||||||
|
testReattachTwice: function(next) {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
||||||
|
let chatBoxCount = 0, reattachCount = 0;
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
ok(port, "provider has a port");
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "got-chatbox-visibility":
|
||||||
|
// chatbox is open, lets detach. The new chat window will be caught in
|
||||||
|
// the window watcher below
|
||||||
|
let doc = chats.selectedChat.contentDocument;
|
||||||
|
// This message is (sometimes!) received a second time
|
||||||
|
// before we start our tests from the onCloseWindow
|
||||||
|
// callback.
|
||||||
|
if (doc.location == "about:blank")
|
||||||
|
return;
|
||||||
|
if (++chatBoxCount != 2) {
|
||||||
|
// open the second chat window
|
||||||
|
port.postMessage({topic: "test-worker-chat", data: chatUrl + "?id=2"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
info("chatbox is open, detach from window");
|
||||||
|
let chat1 = chats.firstChild;
|
||||||
|
let chat2 = chat1.nextSibling;
|
||||||
|
document.getAnonymousElementByAttribute(chat1, "anonid", "swap").click();
|
||||||
|
document.getAnonymousElementByAttribute(chat2, "anonid", "swap").click();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let firstChatWindowDoc;
|
||||||
|
Services.wm.addListener({
|
||||||
|
onWindowTitleChange: function() {},
|
||||||
|
onCloseWindow: function(xulwindow) {},
|
||||||
|
onOpenWindow: function(xulwindow) {
|
||||||
|
let listener = this;
|
||||||
|
let domwindow = xulwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Components.interfaces.nsIDOMWindow);
|
||||||
|
// wait for load to ensure the window is ready for us to test, make sure
|
||||||
|
// we're not getting called for about:blank
|
||||||
|
domwindow.addEventListener("load", function _load(event) {
|
||||||
|
let doc = domwindow.document;
|
||||||
|
if (event.target != doc)
|
||||||
|
return;
|
||||||
|
domwindow.removeEventListener("load", _load, false);
|
||||||
|
|
||||||
|
domwindow.addEventListener("unload", function _close(event) {
|
||||||
|
if (event.target != doc)
|
||||||
|
return;
|
||||||
|
domwindow.removeEventListener("unload", _close, false);
|
||||||
|
ok(true, "window has been closed");
|
||||||
|
waitForCondition(function() {
|
||||||
|
return chats.selectedChat && chats.selectedChat.contentDocument &&
|
||||||
|
chats.selectedChat.contentDocument.readyState == "complete";
|
||||||
|
}, function () {
|
||||||
|
++reattachCount;
|
||||||
|
if (reattachCount == 1) {
|
||||||
|
info("reattaching second chat window");
|
||||||
|
let chatbox = firstChatWindowDoc.getElementById("chatter");
|
||||||
|
firstChatWindowDoc.getAnonymousElementByAttribute(chatbox, "anonid", "swap").click();
|
||||||
|
firstChatWindowDoc = null;
|
||||||
|
}
|
||||||
|
else if (reattachCount == 2) {
|
||||||
|
is(chats.children.length, 2, "both chat windows should be reattached");
|
||||||
|
chats.removeAll();
|
||||||
|
waitForCondition(() => chats.children.length == 0, function () {
|
||||||
|
info("no chat window left");
|
||||||
|
is(chats.chatboxForURL.size, 0, "chatboxForURL map should be empty");
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, "waited too long for the window to reattach");
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
is(doc.documentElement.getAttribute("windowtype"), "Social:Chat", "Social:Chat window opened");
|
||||||
|
if (!firstChatWindowDoc) {
|
||||||
|
firstChatWindowDoc = doc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Services.wm.removeListener(listener);
|
||||||
|
|
||||||
|
// window is loaded, but the docswap does not happen until after load,
|
||||||
|
// and we have no event to wait on, so we'll wait for document state
|
||||||
|
// to be ready
|
||||||
|
let chatbox = doc.getElementById("chatter");
|
||||||
|
waitForCondition(function() {
|
||||||
|
return chats.children.length == 0 &&
|
||||||
|
chatbox.contentDocument &&
|
||||||
|
chatbox.contentDocument.readyState == "complete";
|
||||||
|
},function() {
|
||||||
|
info("reattaching chat window");
|
||||||
|
doc.getAnonymousElementByAttribute(chatbox, "anonid", "swap").click();
|
||||||
|
}, "waited too long for the chat window to be detached");
|
||||||
|
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
port.postMessage({topic: "test-worker-chat", data: chatUrl + "?id=1"});
|
||||||
|
}
|
||||||
|
};
|
@ -44,10 +44,6 @@ function openChat(provider, callback) {
|
|||||||
gURLsNotRemembered.push(url);
|
gURLsNotRemembered.push(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
function windowHasChats(win) {
|
|
||||||
return !!getChatBar().firstElementChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
requestLongerTimeout(2); // only debug builds seem to need more time...
|
requestLongerTimeout(2); // only debug builds seem to need more time...
|
||||||
waitForExplicitFinish();
|
waitForExplicitFinish();
|
||||||
@ -111,6 +107,85 @@ var tests = {
|
|||||||
}
|
}
|
||||||
port.postMessage({topic: "test-init", data: { id: 1 }});
|
port.postMessage({topic: "test-init", data: { id: 1 }});
|
||||||
},
|
},
|
||||||
|
testOpenMinimized: function(next) {
|
||||||
|
// In this case the sidebar opens a chat (without specifying minimized).
|
||||||
|
// We then minimize it and have the sidebar reopen the chat (again without
|
||||||
|
// minimized). On that second call the chat should open and no longer
|
||||||
|
// be minimized.
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
let seen_opened = false;
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "test-init-done":
|
||||||
|
port.postMessage({topic: "test-chatbox-open"});
|
||||||
|
break;
|
||||||
|
case "chatbox-opened":
|
||||||
|
is(e.data.result, "ok", "the sidebar says it got a chatbox");
|
||||||
|
if (!seen_opened) {
|
||||||
|
// first time we got the opened message, so minimize the chat then
|
||||||
|
// re-request the same chat to be opened - we should get the
|
||||||
|
// message again and the chat should be restored.
|
||||||
|
ok(!chats.selectedChat.minimized, "chat not initially minimized")
|
||||||
|
chats.selectedChat.minimized = true
|
||||||
|
seen_opened = true;
|
||||||
|
port.postMessage({topic: "test-chatbox-open"});
|
||||||
|
} else {
|
||||||
|
// This is the second time we've seen this message - there should
|
||||||
|
// be exactly 1 chat open and it should no longer be minimized.
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
ok(!chats.selectedChat.minimized, "chat no longer minimized")
|
||||||
|
chats.selectedChat.close();
|
||||||
|
is(chats.selectedChat, null, "should only have been one chat open");
|
||||||
|
port.close();
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.postMessage({topic: "test-init", data: { id: 1 }});
|
||||||
|
},
|
||||||
|
testManyChats: function(next) {
|
||||||
|
// open enough chats to overflow the window, then check
|
||||||
|
// if the menupopup is visible
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
ok(port, "provider has a port");
|
||||||
|
ok(chats.menupopup.parentNode.collapsed, "popup nub collapsed at start");
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
// we should *never* find a test box that needs more than this to cause
|
||||||
|
// an overflow!
|
||||||
|
let maxToOpen = 20;
|
||||||
|
let numOpened = 0;
|
||||||
|
let maybeOpenAnother = function() {
|
||||||
|
if (numOpened++ >= maxToOpen) {
|
||||||
|
ok(false, "We didn't find a collapsed chat after " + maxToOpen + "chats!");
|
||||||
|
closeAllChats();
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
port.postMessage({topic: "test-chatbox-open", data: { id: numOpened }});
|
||||||
|
}
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "got-chatbox-message":
|
||||||
|
if (!chats.menupopup.parentNode.collapsed) {
|
||||||
|
maybeOpenAnother();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ok(true, "popup nub became visible");
|
||||||
|
// close our chats now
|
||||||
|
while (chats.selectedChat) {
|
||||||
|
chats.selectedChat.close();
|
||||||
|
}
|
||||||
|
ok(!chats.selectedChat, "chats are all closed");
|
||||||
|
port.close();
|
||||||
|
next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maybeOpenAnother();
|
||||||
|
},
|
||||||
testWorkerChatWindow: function(next) {
|
testWorkerChatWindow: function(next) {
|
||||||
const chatUrl = SocialSidebar.provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
const chatUrl = SocialSidebar.provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
let chats = document.getElementById("pinnedchats");
|
let chats = document.getElementById("pinnedchats");
|
||||||
@ -164,10 +239,61 @@ var tests = {
|
|||||||
}
|
}
|
||||||
port.postMessage({topic: "test-init", data: { id: 1 }});
|
port.postMessage({topic: "test-init", data: { id: 1 }});
|
||||||
},
|
},
|
||||||
|
testSameChatCallbacks: function(next) {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
let seen_opened = false;
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "test-init-done":
|
||||||
|
port.postMessage({topic: "test-chatbox-open"});
|
||||||
|
break;
|
||||||
|
case "chatbox-opened":
|
||||||
|
is(e.data.result, "ok", "the sidebar says it got a chatbox");
|
||||||
|
if (seen_opened) {
|
||||||
|
// This is the second time we've seen this message - there should
|
||||||
|
// be exactly 1 chat open.
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
chats.selectedChat.close();
|
||||||
|
is(chats.selectedChat, null, "should only have been one chat open");
|
||||||
|
port.close();
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
// first time we got the opened message, so re-request the same
|
||||||
|
// chat to be opened - we should get the message again.
|
||||||
|
seen_opened = true;
|
||||||
|
port.postMessage({topic: "test-chatbox-open"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.postMessage({topic: "test-init", data: { id: 1 }});
|
||||||
|
},
|
||||||
|
|
||||||
|
// check removeAll does the right thing
|
||||||
|
testRemoveAll: function(next, mode) {
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
get3ChatsForCollapsing(mode || "normal", function() {
|
||||||
|
let chatbar = window.SocialChatBar.chatbar;
|
||||||
|
chatbar.removeAll();
|
||||||
|
// should be no evidence of any chats left.
|
||||||
|
is(chatbar.childNodes.length, 0, "should be no chats left");
|
||||||
|
checkPopup();
|
||||||
|
is(chatbar.selectedChat, null, "nothing should be selected");
|
||||||
|
is(chatbar.chatboxForURL.size, 0, "chatboxForURL map should be empty");
|
||||||
|
port.close();
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
testRemoveAllMinimized: function(next) {
|
||||||
|
this.testRemoveAll(next, "minimized");
|
||||||
|
},
|
||||||
|
|
||||||
// Check what happens when you close the only visible chat.
|
// Check what happens when you close the only visible chat.
|
||||||
testCloseOnlyVisible: function(next) {
|
testCloseOnlyVisible: function(next) {
|
||||||
let chatbar = getChatBar();
|
let chatbar = window.SocialChatBar.chatbar;
|
||||||
let chatWidth = undefined;
|
let chatWidth = undefined;
|
||||||
let num = 0;
|
let num = 0;
|
||||||
is(chatbar.childNodes.length, 0, "chatbar starting empty");
|
is(chatbar.childNodes.length, 0, "chatbar starting empty");
|
||||||
@ -205,7 +331,7 @@ var tests = {
|
|||||||
let port = SocialSidebar.provider.getWorkerPort();
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
port.postMessage({topic: "test-init"});
|
port.postMessage({topic: "test-init"});
|
||||||
get3ChatsForCollapsing("normal", function(first, second, third) {
|
get3ChatsForCollapsing("normal", function(first, second, third) {
|
||||||
let chatbar = getChatBar();
|
let chatbar = window.SocialChatBar.chatbar;
|
||||||
chatbar.showChat(first);
|
chatbar.showChat(first);
|
||||||
ok(!first.collapsed, "first should no longer be collapsed");
|
ok(!first.collapsed, "first should no longer be collapsed");
|
||||||
ok(second.collapsed || third.collapsed, false, "one of the others should be collapsed");
|
ok(second.collapsed || third.collapsed, false, "one of the others should be collapsed");
|
||||||
@ -215,6 +341,61 @@ var tests = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testActivity: function(next) {
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
get3ChatsForCollapsing("normal", function(first, second, third) {
|
||||||
|
let chatbar = window.SocialChatBar.chatbar;
|
||||||
|
is(chatbar.selectedChat, third, "third chat should be selected");
|
||||||
|
ok(!chatbar.selectedChat.hasAttribute("activity"), "third chat should have no activity");
|
||||||
|
// send an activity message to the second.
|
||||||
|
ok(!second.hasAttribute("activity"), "second chat should have no activity");
|
||||||
|
let chat2 = second.content;
|
||||||
|
let evt = chat2.contentDocument.createEvent("CustomEvent");
|
||||||
|
evt.initCustomEvent("socialChatActivity", true, true, {});
|
||||||
|
chat2.contentDocument.documentElement.dispatchEvent(evt);
|
||||||
|
// second should have activity.
|
||||||
|
ok(second.hasAttribute("activity"), "second chat should now have activity");
|
||||||
|
// select the second - it should lose "activity"
|
||||||
|
chatbar.selectedChat = second;
|
||||||
|
ok(!second.hasAttribute("activity"), "second chat should no longer have activity");
|
||||||
|
// Now try the first - it is collapsed, so the 'nub' also gets activity attr.
|
||||||
|
ok(!first.hasAttribute("activity"), "first chat should have no activity");
|
||||||
|
let chat1 = first.content;
|
||||||
|
let evt = chat1.contentDocument.createEvent("CustomEvent");
|
||||||
|
evt.initCustomEvent("socialChatActivity", true, true, {});
|
||||||
|
chat1.contentDocument.documentElement.dispatchEvent(evt);
|
||||||
|
ok(first.hasAttribute("activity"), "first chat should now have activity");
|
||||||
|
ok(chatbar.nub.hasAttribute("activity"), "nub should also have activity");
|
||||||
|
// first is collapsed, so use openChat to get it.
|
||||||
|
chatbar.openChat(SocialSidebar.provider, first.getAttribute("src"));
|
||||||
|
ok(!first.hasAttribute("activity"), "first chat should no longer have activity");
|
||||||
|
// The nub should lose the activity flag here too
|
||||||
|
todo(!chatbar.nub.hasAttribute("activity"), "Bug 806266 - nub should no longer have activity");
|
||||||
|
// TODO: tests for bug 806266 should arrange to have 2 chats collapsed
|
||||||
|
// then open them checking the nub is updated correctly.
|
||||||
|
// Now we will go and change the embedded browser in the second chat and
|
||||||
|
// ensure the activity magic still works (ie, check that the unload for
|
||||||
|
// the browser didn't cause our event handlers to be removed.)
|
||||||
|
ok(!second.hasAttribute("activity"), "second chat should have no activity");
|
||||||
|
let subiframe = chat2.contentDocument.getElementById("iframe");
|
||||||
|
subiframe.contentWindow.addEventListener("unload", function subunload() {
|
||||||
|
subiframe.contentWindow.removeEventListener("unload", subunload);
|
||||||
|
// ensure all other unload listeners have fired.
|
||||||
|
executeSoon(function() {
|
||||||
|
let evt = chat2.contentDocument.createEvent("CustomEvent");
|
||||||
|
evt.initCustomEvent("socialChatActivity", true, true, {});
|
||||||
|
chat2.contentDocument.documentElement.dispatchEvent(evt);
|
||||||
|
ok(second.hasAttribute("activity"), "second chat still has activity after unloading sub-iframe");
|
||||||
|
closeAllChats();
|
||||||
|
port.close();
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
subiframe.setAttribute("src", "data:text/plain:new location for iframe");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
testOnlyOneCallback: function(next) {
|
testOnlyOneCallback: function(next) {
|
||||||
let chats = document.getElementById("pinnedchats");
|
let chats = document.getElementById("pinnedchats");
|
||||||
let port = SocialSidebar.provider.getWorkerPort();
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
@ -232,7 +413,7 @@ var tests = {
|
|||||||
case "pong":
|
case "pong":
|
||||||
executeSoon(function() {
|
executeSoon(function() {
|
||||||
is(numOpened, 1, "only got one open message");
|
is(numOpened, 1, "only got one open message");
|
||||||
chats.selectedChat.close();
|
chats.removeAll();
|
||||||
port.close();
|
port.close();
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@ -241,6 +422,86 @@ var tests = {
|
|||||||
port.postMessage({topic: "test-init", data: { id: 1 }});
|
port.postMessage({topic: "test-init", data: { id: 1 }});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
testSecondTopLevelWindow: function(next) {
|
||||||
|
// Bug 817782 - check chats work in new top-level windows.
|
||||||
|
const chatUrl = SocialSidebar.provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
|
let port = SocialSidebar.provider.getWorkerPort();
|
||||||
|
let secondWindow;
|
||||||
|
port.onmessage = function(e) {
|
||||||
|
if (e.data.topic == "test-init-done") {
|
||||||
|
secondWindow = OpenBrowserWindow();
|
||||||
|
secondWindow.addEventListener("load", function loadListener() {
|
||||||
|
secondWindow.removeEventListener("load", loadListener);
|
||||||
|
port.postMessage({topic: "test-worker-chat", data: chatUrl});
|
||||||
|
});
|
||||||
|
} else if (e.data.topic == "got-chatbox-message") {
|
||||||
|
// the chat was created - let's make sure it was created in the second window.
|
||||||
|
is(secondWindow.SocialChatBar.chatbar.childElementCount, 1);
|
||||||
|
secondWindow.close();
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
},
|
||||||
|
|
||||||
|
testChatWindowChooser: function(next) {
|
||||||
|
// Tests that when a worker creates a chat, it is opened in the correct
|
||||||
|
// window.
|
||||||
|
// open a chat (it will open in the main window)
|
||||||
|
ok(!window.SocialChatBar.hasChats, "first window should start with no chats");
|
||||||
|
openChat(SocialSidebar.provider, function() {
|
||||||
|
ok(window.SocialChatBar.hasChats, "first window has the chat");
|
||||||
|
// create a second window - this will be the "most recent" and will
|
||||||
|
// therefore be the window that hosts the new chat (see bug 835111)
|
||||||
|
let secondWindow = OpenBrowserWindow();
|
||||||
|
secondWindow.addEventListener("load", function loadListener() {
|
||||||
|
secondWindow.removeEventListener("load", loadListener);
|
||||||
|
ok(!secondWindow.SocialChatBar.hasChats, "second window has no chats");
|
||||||
|
openChat(SocialSidebar.provider, function() {
|
||||||
|
ok(secondWindow.SocialChatBar.hasChats, "second window now has chats");
|
||||||
|
is(window.SocialChatBar.chatbar.childElementCount, 1, "first window still has 1 chat");
|
||||||
|
window.SocialChatBar.chatbar.removeAll();
|
||||||
|
// now open another chat - it should still open in the second.
|
||||||
|
openChat(SocialSidebar.provider, function() {
|
||||||
|
ok(!window.SocialChatBar.hasChats, "first window has no chats");
|
||||||
|
ok(secondWindow.SocialChatBar.hasChats, "second window has a chat");
|
||||||
|
|
||||||
|
// focus the first window, and open yet another chat - it
|
||||||
|
// should open in the first window.
|
||||||
|
waitForFocus(function() {
|
||||||
|
openChat(SocialSidebar.provider, function() {
|
||||||
|
ok(window.SocialChatBar.hasChats, "first window has chats");
|
||||||
|
window.SocialChatBar.chatbar.removeAll();
|
||||||
|
ok(!window.SocialChatBar.hasChats, "first window has no chats");
|
||||||
|
|
||||||
|
let privateWindow = OpenBrowserWindow({private: true});
|
||||||
|
privateWindow.addEventListener("load", function loadListener() {
|
||||||
|
privateWindow.removeEventListener("load", loadListener);
|
||||||
|
|
||||||
|
// open a last chat - the focused window can't accept
|
||||||
|
// chats (it's a private window), so the chat should open
|
||||||
|
// in the window that was selected before. This is known
|
||||||
|
// to be broken on Linux.
|
||||||
|
openChat(SocialSidebar.provider, function() {
|
||||||
|
let os = Services.appinfo.OS;
|
||||||
|
const BROKEN_WM_Z_ORDER = os != "WINNT" && os != "Darwin";
|
||||||
|
let fn = BROKEN_WM_Z_ORDER ? todo : ok;
|
||||||
|
fn(window.SocialChatBar.hasChats, "first window has a chat");
|
||||||
|
window.SocialChatBar.chatbar.removeAll();
|
||||||
|
|
||||||
|
privateWindow.close();
|
||||||
|
secondWindow.close();
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
window.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
testMultipleProviderChat: function(next) {
|
testMultipleProviderChat: function(next) {
|
||||||
// test incomming chats from all providers
|
// test incomming chats from all providers
|
||||||
openChat(Social.providers[0], function() {
|
openChat(Social.providers[0], function() {
|
||||||
@ -256,7 +517,7 @@ var tests = {
|
|||||||
port.postMessage({topic: "test-logout"});
|
port.postMessage({topic: "test-logout"});
|
||||||
waitForCondition(function() chats.children.length == Social.providers.length - 1,
|
waitForCondition(function() chats.children.length == Social.providers.length - 1,
|
||||||
function() {
|
function() {
|
||||||
closeAllChats();
|
chats.removeAll();
|
||||||
waitForCondition(function() chats.children.length == 0,
|
waitForCondition(function() chats.children.length == 0,
|
||||||
function() {
|
function() {
|
||||||
ok(!chats.selectedChat, "multiprovider chats are all closed");
|
ok(!chats.selectedChat, "multiprovider chats are all closed");
|
||||||
|
@ -9,7 +9,7 @@ function isTabFocused() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isChatFocused(chat) {
|
function isChatFocused(chat) {
|
||||||
return getChatBar()._isChatFocused(chat);
|
return SocialChatBar.chatbar._isChatFocused(chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openChatViaUser() {
|
function openChatViaUser() {
|
||||||
@ -32,7 +32,7 @@ function openChatViaSidebarMessage(port, data, callback) {
|
|||||||
function openChatViaWorkerMessage(port, data, callback) {
|
function openChatViaWorkerMessage(port, data, callback) {
|
||||||
// sadly there is no message coming back to tell us when the chat has
|
// sadly there is no message coming back to tell us when the chat has
|
||||||
// been opened, so we wait until one appears.
|
// been opened, so we wait until one appears.
|
||||||
let chatbar = getChatBar();
|
let chatbar = SocialChatBar.chatbar;
|
||||||
let numExpected = chatbar.childElementCount + 1;
|
let numExpected = chatbar.childElementCount + 1;
|
||||||
port.postMessage({topic: "test-worker-chat", data: data});
|
port.postMessage({topic: "test-worker-chat", data: data});
|
||||||
waitForCondition(function() chatbar.childElementCount == numExpected,
|
waitForCondition(function() chatbar.childElementCount == numExpected,
|
||||||
@ -40,13 +40,12 @@ function openChatViaWorkerMessage(port, data, callback) {
|
|||||||
// so the child has been added, but we don't know if it
|
// so the child has been added, but we don't know if it
|
||||||
// has been intialized - re-request it and the callback
|
// has been intialized - re-request it and the callback
|
||||||
// means it's done. Minimized, same as the worker.
|
// means it's done. Minimized, same as the worker.
|
||||||
chatbar.openChat(SocialSidebar.provider.origin,
|
SocialChatBar.openChat(SocialSidebar.provider,
|
||||||
SocialSidebar.provider.name,
|
data,
|
||||||
data,
|
function() {
|
||||||
"minimized",
|
callback();
|
||||||
function() {
|
},
|
||||||
callback();
|
"minimized");
|
||||||
});
|
|
||||||
},
|
},
|
||||||
"No new chat appeared");
|
"No new chat appeared");
|
||||||
}
|
}
|
||||||
@ -110,7 +109,7 @@ function test() {
|
|||||||
waitForCondition(function() isTabFocused(), cb, "tab should have focus");
|
waitForCondition(function() isTabFocused(), cb, "tab should have focus");
|
||||||
}
|
}
|
||||||
let postSubTest = function(cb) {
|
let postSubTest = function(cb) {
|
||||||
closeAllChats();
|
window.SocialChatBar.chatbar.removeAll();
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
// and run the tests.
|
// and run the tests.
|
||||||
@ -133,22 +132,21 @@ var tests = {
|
|||||||
// Then we do it again - should still not be focused.
|
// Then we do it again - should still not be focused.
|
||||||
// Then we perform a user-initiated request - it should get focus.
|
// Then we perform a user-initiated request - it should get focus.
|
||||||
testNoFocusWhenViaWorker: function(next) {
|
testNoFocusWhenViaWorker: function(next) {
|
||||||
let chatbar = getChatBar();
|
|
||||||
startTestAndWaitForSidebar(function(port) {
|
startTestAndWaitForSidebar(function(port) {
|
||||||
openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
|
openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
|
||||||
ok(true, "got chatbox message");
|
ok(true, "got chatbox message");
|
||||||
is(chatbar.childElementCount, 1, "exactly 1 chat open");
|
is(SocialChatBar.chatbar.childElementCount, 1, "exactly 1 chat open");
|
||||||
ok(isTabFocused(), "tab should still be focused");
|
ok(isTabFocused(), "tab should still be focused");
|
||||||
// re-request the same chat via a message.
|
// re-request the same chat via a message.
|
||||||
openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
|
openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
|
||||||
is(chatbar.childElementCount, 1, "still exactly 1 chat open");
|
is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
|
||||||
ok(isTabFocused(), "tab should still be focused");
|
ok(isTabFocused(), "tab should still be focused");
|
||||||
// re-request the same chat via user event.
|
// re-request the same chat via user event.
|
||||||
openChatViaUser();
|
openChatViaUser();
|
||||||
waitForCondition(function() isChatFocused(chatbar.selectedChat),
|
waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
|
||||||
function() {
|
function() {
|
||||||
is(chatbar.childElementCount, 1, "still exactly 1 chat open");
|
is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
|
||||||
is(chatbar.selectedChat, chatbar.firstElementChild, "chat should be selected");
|
is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat should be selected");
|
||||||
next();
|
next();
|
||||||
}, "chat should be focused");
|
}, "chat should be focused");
|
||||||
});
|
});
|
||||||
@ -160,14 +158,204 @@ var tests = {
|
|||||||
// click. This should cause the new chat to be opened and focused.
|
// click. This should cause the new chat to be opened and focused.
|
||||||
testFocusWhenViaUser: function(next) {
|
testFocusWhenViaUser: function(next) {
|
||||||
startTestAndWaitForSidebar(function(port) {
|
startTestAndWaitForSidebar(function(port) {
|
||||||
let chatbar = getChatBar();
|
|
||||||
openChatViaUser();
|
openChatViaUser();
|
||||||
ok(chatbar.firstElementChild, "chat opened");
|
ok(SocialChatBar.chatbar.firstElementChild, "chat opened");
|
||||||
waitForCondition(function() isChatFocused(chatbar.selectedChat),
|
waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
|
||||||
function() {
|
function() {
|
||||||
is(chatbar.selectedChat, chatbar.firstElementChild, "chat is selected");
|
is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat is selected");
|
||||||
next();
|
next();
|
||||||
}, "chat should be focused");
|
}, "chat should be focused");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Open a chat via the worker - it will open and not have focus.
|
||||||
|
// Then open the same chat via a sidebar message - it will be restored but
|
||||||
|
// should still not have grabbed focus.
|
||||||
|
testNoFocusOnAutoRestore: function(next) {
|
||||||
|
const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html?id=1";
|
||||||
|
let chatbar = SocialChatBar.chatbar;
|
||||||
|
startTestAndWaitForSidebar(function(port) {
|
||||||
|
openChatViaWorkerMessage(port, chatUrl, function() {
|
||||||
|
is(chatbar.childElementCount, 1, "exactly 1 chat open");
|
||||||
|
// bug 865086 opening minimized still sets the window as selected
|
||||||
|
todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected");
|
||||||
|
ok(isTabFocused(), "tab should be focused");
|
||||||
|
openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
|
||||||
|
is(chatbar.childElementCount, 1, "still 1 chat open");
|
||||||
|
ok(!chatbar.firstElementChild.minimized, "chat no longer minimized");
|
||||||
|
// bug 865086 because we marked it selected on open, it still is
|
||||||
|
todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected");
|
||||||
|
ok(isTabFocused(), "tab should still be focused");
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Here we open a chat, which will not be focused. Then we minimize it and
|
||||||
|
// restore it via a titlebar clock - it should get focus at that point.
|
||||||
|
testFocusOnExplicitRestore: function(next) {
|
||||||
|
startTestAndWaitForSidebar(function(port) {
|
||||||
|
openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
|
||||||
|
ok(true, "got chatbox message");
|
||||||
|
ok(isTabFocused(), "tab should still be focused");
|
||||||
|
let chatbox = SocialChatBar.chatbar.firstElementChild;
|
||||||
|
ok(chatbox, "chat opened");
|
||||||
|
chatbox.minimized = true;
|
||||||
|
ok(isTabFocused(), "tab should still be focused");
|
||||||
|
// pretend we clicked on the titlebar
|
||||||
|
chatbox.onTitlebarClick({button: 0});
|
||||||
|
waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
|
||||||
|
function() {
|
||||||
|
ok(!chatbox.minimized, "chat should have been restored");
|
||||||
|
ok(isChatFocused(chatbox), "chat should be focused");
|
||||||
|
is(chatbox, SocialChatBar.chatbar.selectedChat, "chat is marked selected");
|
||||||
|
next();
|
||||||
|
}, "chat should have focus");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Open 2 chats and give 1 focus. Minimize the focused one - the second
|
||||||
|
// should get focus.
|
||||||
|
testMinimizeFocused: function(next) {
|
||||||
|
let chatbar = SocialChatBar.chatbar;
|
||||||
|
startTestAndWaitForSidebar(function(port) {
|
||||||
|
openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
|
||||||
|
let chat1 = chatbar.firstElementChild;
|
||||||
|
openChatViaSidebarMessage(port, {stealFocus: 1, id: 2}, function() {
|
||||||
|
is(chatbar.childElementCount, 2, "exactly 2 chats open");
|
||||||
|
let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
|
||||||
|
chatbar.selectedChat = chat1;
|
||||||
|
chatbar.focus();
|
||||||
|
waitForCondition(function() isChatFocused(chat1),
|
||||||
|
function() {
|
||||||
|
is(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is marked selected");
|
||||||
|
isnot(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is not marked selected");
|
||||||
|
chat1.minimized = true;
|
||||||
|
waitForCondition(function() isChatFocused(chat2),
|
||||||
|
function() {
|
||||||
|
// minimizing the chat with focus should give it to another.
|
||||||
|
isnot(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is not marked selected");
|
||||||
|
is(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is marked selected");
|
||||||
|
next();
|
||||||
|
}, "chat2 should have focus");
|
||||||
|
}, "chat1 should have focus");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Open 2 chats, select (but not focus) one, then re-request it be
|
||||||
|
// opened via a message. Focus should not move.
|
||||||
|
testReopenNonFocused: function(next) {
|
||||||
|
let chatbar = SocialChatBar.chatbar;
|
||||||
|
startTestAndWaitForSidebar(function(port) {
|
||||||
|
openChatViaSidebarMessage(port, {id: 1}, function() {
|
||||||
|
let chat1 = chatbar.firstElementChild;
|
||||||
|
openChatViaSidebarMessage(port, {id: 2}, function() {
|
||||||
|
let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
|
||||||
|
chatbar.selectedChat = chat2;
|
||||||
|
// tab still has focus
|
||||||
|
ok(isTabFocused(), "tab should still be focused");
|
||||||
|
// re-request the first.
|
||||||
|
openChatViaSidebarMessage(port, {id: 1}, function() {
|
||||||
|
is(chatbar.selectedChat, chat1, "chat1 now selected");
|
||||||
|
ok(isTabFocused(), "tab should still be focused");
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Open 2 chats, select and focus the second. Pressing the TAB key should
|
||||||
|
// cause focus to move between all elements in our chat window before moving
|
||||||
|
// to the next chat window.
|
||||||
|
testTab: function(next) {
|
||||||
|
function sendTabAndWaitForFocus(chat, eltid, callback) {
|
||||||
|
// ideally we would use the 'focus' event here, but that doesn't work
|
||||||
|
// as expected for the iframe - the iframe itself never gets the focus
|
||||||
|
// event (apparently the sub-document etc does.)
|
||||||
|
// So just poll for the correct element getting focus...
|
||||||
|
let doc = chat.contentDocument;
|
||||||
|
EventUtils.sendKey("tab");
|
||||||
|
waitForCondition(function() {
|
||||||
|
let elt = eltid ? doc.getElementById(eltid) : doc.documentElement;
|
||||||
|
return doc.activeElement == elt;
|
||||||
|
}, callback, "element " + eltid + " never got focus");
|
||||||
|
}
|
||||||
|
|
||||||
|
let chatbar = SocialChatBar.chatbar;
|
||||||
|
startTestAndWaitForSidebar(function(port) {
|
||||||
|
openChatViaSidebarMessage(port, {id: 1}, function() {
|
||||||
|
let chat1 = chatbar.firstElementChild;
|
||||||
|
openChatViaSidebarMessage(port, {id: 2}, function() {
|
||||||
|
let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
|
||||||
|
chatbar.selectedChat = chat2;
|
||||||
|
chatbar.focus();
|
||||||
|
waitForCondition(function() isChatFocused(chatbar.selectedChat),
|
||||||
|
function() {
|
||||||
|
// Our chats have 3 focusable elements, so it takes 4 TABs to move
|
||||||
|
// to the new chat.
|
||||||
|
sendTabAndWaitForFocus(chat2, "input1", function() {
|
||||||
|
is(chat2.contentDocument.activeElement.getAttribute("id"), "input1",
|
||||||
|
"first input field has focus");
|
||||||
|
ok(isChatFocused(chat2), "new chat still focused after first tab");
|
||||||
|
sendTabAndWaitForFocus(chat2, "input2", function() {
|
||||||
|
ok(isChatFocused(chat2), "new chat still focused after tab");
|
||||||
|
is(chat2.contentDocument.activeElement.getAttribute("id"), "input2",
|
||||||
|
"second input field has focus");
|
||||||
|
sendTabAndWaitForFocus(chat2, "iframe", function() {
|
||||||
|
ok(isChatFocused(chat2), "new chat still focused after tab");
|
||||||
|
is(chat2.contentDocument.activeElement.getAttribute("id"), "iframe",
|
||||||
|
"iframe has focus");
|
||||||
|
// this tab now should move to the next chat, but focus the
|
||||||
|
// document element itself (hence the null eltid)
|
||||||
|
sendTabAndWaitForFocus(chat1, null, function() {
|
||||||
|
ok(isChatFocused(chat1), "first chat is focused");
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, "chat should have focus");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Open a chat and focus an element other than the first. Move focus to some
|
||||||
|
// other item (the tab itself in this case), then focus the chatbar - the
|
||||||
|
// same element that was previously focused should still have focus.
|
||||||
|
testFocusedElement: function(next) {
|
||||||
|
let chatbar = SocialChatBar.chatbar;
|
||||||
|
startTestAndWaitForSidebar(function(port) {
|
||||||
|
openChatViaUser();
|
||||||
|
let chat = chatbar.firstElementChild;
|
||||||
|
// need to wait for the content to load before we can focus it.
|
||||||
|
chat.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
|
||||||
|
chat.removeEventListener("DOMContentLoaded", DOMContentLoaded);
|
||||||
|
chat.contentDocument.getElementById("input2").focus();
|
||||||
|
waitForCondition(function() isChatFocused(chat),
|
||||||
|
function() {
|
||||||
|
is(chat.contentDocument.activeElement.getAttribute("id"), "input2",
|
||||||
|
"correct input field has focus");
|
||||||
|
// set focus to the tab.
|
||||||
|
let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
|
||||||
|
Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
|
||||||
|
waitForCondition(function() isTabFocused(),
|
||||||
|
function() {
|
||||||
|
chatbar.focus();
|
||||||
|
waitForCondition(function() isChatFocused(chat),
|
||||||
|
function() {
|
||||||
|
is(chat.contentDocument.activeElement.getAttribute("id"), "input2",
|
||||||
|
"correct input field still has focus");
|
||||||
|
next();
|
||||||
|
}, "chat took focus");
|
||||||
|
}, "tab has focus");
|
||||||
|
}, "chat took focus");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -9,8 +9,6 @@ function gc() {
|
|||||||
wu.garbageCollect();
|
wu.garbageCollect();
|
||||||
}
|
}
|
||||||
|
|
||||||
let openChatWindow = Cu.import("resource://gre/modules/MozSocialAPI.jsm", {}).openChatWindow;
|
|
||||||
|
|
||||||
// Support for going on and offline.
|
// Support for going on and offline.
|
||||||
// (via browser/base/content/test/browser_bookmark_titles.js)
|
// (via browser/base/content/test/browser_bookmark_titles.js)
|
||||||
let origProxyType = Services.prefs.getIntPref('network.proxy.type');
|
let origProxyType = Services.prefs.getIntPref('network.proxy.type');
|
||||||
@ -44,10 +42,9 @@ function openPanel(url, panelCallback, loadCallback) {
|
|||||||
|
|
||||||
function openChat(url, panelCallback, loadCallback) {
|
function openChat(url, panelCallback, loadCallback) {
|
||||||
// open a chat window
|
// open a chat window
|
||||||
let chatbar = getChatBar();
|
SocialChatBar.openChat(SocialSidebar.provider, url, panelCallback);
|
||||||
openChatWindow(null, SocialSidebar.provider, url, panelCallback);
|
SocialChatBar.chatbar.firstChild.addEventListener("DOMContentLoaded", function panelLoad() {
|
||||||
chatbar.firstChild.addEventListener("DOMContentLoaded", function panelLoad() {
|
SocialChatBar.chatbar.firstChild.removeEventListener("DOMContentLoaded", panelLoad, true);
|
||||||
chatbar.firstChild.removeEventListener("DOMContentLoaded", panelLoad, true);
|
|
||||||
loadCallback();
|
loadCallback();
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
@ -157,7 +154,7 @@ var tests = {
|
|||||||
|
|
||||||
testChatWindow: function(next) {
|
testChatWindow: function(next) {
|
||||||
let panelCallbackCount = 0;
|
let panelCallbackCount = 0;
|
||||||
// go offline and open a chat.
|
// go offline and open a flyout.
|
||||||
goOffline();
|
goOffline();
|
||||||
openChat(
|
openChat(
|
||||||
"https://example.com/browser/browser/base/content/test/social/social_chat.html",
|
"https://example.com/browser/browser/base/content/test/social/social_chat.html",
|
||||||
@ -167,7 +164,7 @@ var tests = {
|
|||||||
function() { // the "load" callback.
|
function() { // the "load" callback.
|
||||||
executeSoon(function() {
|
executeSoon(function() {
|
||||||
todo_is(panelCallbackCount, 0, "Bug 833207 - should be no callback when error page loads.");
|
todo_is(panelCallbackCount, 0, "Bug 833207 - should be no callback when error page loads.");
|
||||||
let chat = getChatBar().selectedChat;
|
let chat = SocialChatBar.chatbar.selectedChat;
|
||||||
waitForCondition(function() chat.contentDocument.location.href.indexOf("about:socialerror?")==0,
|
waitForCondition(function() chat.contentDocument.location.href.indexOf("about:socialerror?")==0,
|
||||||
function() {
|
function() {
|
||||||
chat.close();
|
chat.close();
|
||||||
@ -177,36 +174,5 @@ var tests = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
|
||||||
|
|
||||||
testChatWindowAfterTearOff: function(next) {
|
|
||||||
// Ensure that the error listener survives the chat window being detached.
|
|
||||||
let url = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
|
||||||
let panelCallbackCount = 0;
|
|
||||||
// open a chat while we are still online.
|
|
||||||
openChat(
|
|
||||||
url,
|
|
||||||
null,
|
|
||||||
function() { // the "load" callback.
|
|
||||||
executeSoon(function() {
|
|
||||||
let chat = getChatBar().selectedChat;
|
|
||||||
is(chat.contentDocument.location.href, url, "correct url loaded");
|
|
||||||
// toggle to a detached window.
|
|
||||||
chat.swapWindows().then(
|
|
||||||
chat => {
|
|
||||||
// now go offline and reload the chat - about:socialerror should be loaded.
|
|
||||||
goOffline();
|
|
||||||
chat.contentDocument.location.reload();
|
|
||||||
waitForCondition(function() chat.contentDocument.location.href.indexOf("about:socialerror?")==0,
|
|
||||||
function() {
|
|
||||||
chat.close();
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
"error page didn't appear");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +237,8 @@ function checkSocialUI(win) {
|
|||||||
_is(!!a, !!b, msg);
|
_is(!!a, !!b, msg);
|
||||||
}
|
}
|
||||||
isbool(win.SocialSidebar.canShow, sidebarEnabled, "social sidebar active?");
|
isbool(win.SocialSidebar.canShow, sidebarEnabled, "social sidebar active?");
|
||||||
|
isbool(win.SocialChatBar.isAvailable, enabled, "chatbar available?");
|
||||||
|
isbool(!win.SocialChatBar.chatbar.hidden, enabled, "chatbar visible?");
|
||||||
|
|
||||||
let contextMenus = [
|
let contextMenus = [
|
||||||
{
|
{
|
||||||
@ -277,6 +279,8 @@ function checkSocialUI(win) {
|
|||||||
// and for good measure, check all the social commands.
|
// and for good measure, check all the social commands.
|
||||||
isbool(!doc.getElementById("Social:ToggleSidebar").hidden, sidebarEnabled, "Social:ToggleSidebar visible?");
|
isbool(!doc.getElementById("Social:ToggleSidebar").hidden, sidebarEnabled, "Social:ToggleSidebar visible?");
|
||||||
isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
|
isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
|
||||||
|
isbool(!doc.getElementById("Social:FocusChat").hidden, enabled, "Social:FocusChat visible?");
|
||||||
|
isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
|
||||||
|
|
||||||
// and report on overall success of failure of the various checks here.
|
// and report on overall success of failure of the various checks here.
|
||||||
is(numGoodTests, numTests, "The Social UI tests succeeded.")
|
is(numGoodTests, numTests, "The Social UI tests succeeded.")
|
||||||
@ -399,7 +403,7 @@ function get3ChatsForCollapsing(mode, cb) {
|
|||||||
// To make our life easier we don't go via the worker and ports so we get
|
// To make our life easier we don't go via the worker and ports so we get
|
||||||
// more control over creation *and* to make the code much simpler. We
|
// more control over creation *and* to make the code much simpler. We
|
||||||
// assume the worker/port stuff is individually tested above.
|
// assume the worker/port stuff is individually tested above.
|
||||||
let chatbar = getChatBar();
|
let chatbar = window.SocialChatBar.chatbar;
|
||||||
let chatWidth = undefined;
|
let chatWidth = undefined;
|
||||||
let num = 0;
|
let num = 0;
|
||||||
is(chatbar.childNodes.length, 0, "chatbar starting empty");
|
is(chatbar.childNodes.length, 0, "chatbar starting empty");
|
||||||
@ -443,21 +447,23 @@ function makeChat(mode, uniqueid, cb) {
|
|||||||
info("making a chat window '" + uniqueid +"'");
|
info("making a chat window '" + uniqueid +"'");
|
||||||
let provider = SocialSidebar.provider;
|
let provider = SocialSidebar.provider;
|
||||||
const chatUrl = provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
const chatUrl = provider.origin + "/browser/browser/base/content/test/social/social_chat.html";
|
||||||
// Note that we use promiseChatLoaded instead of the callback to ensure the
|
let isOpened = window.SocialChatBar.openChat(provider, chatUrl + "?id=" + uniqueid, function(chat) {
|
||||||
// content has started loading.
|
|
||||||
let chatbox = getChatBar().openChat(provider.origin, provider.name,
|
|
||||||
chatUrl + "?id=" + uniqueid, mode);
|
|
||||||
chatbox.promiseChatLoaded.then(
|
|
||||||
() => {
|
|
||||||
info("chat window has opened");
|
info("chat window has opened");
|
||||||
chatbox.contentDocument.title = uniqueid;
|
// we can't callback immediately or we might close the chat during
|
||||||
cb();
|
// this event which upsets the implementation - it is only 1/2 way through
|
||||||
});
|
// handling the load event.
|
||||||
|
chat.document.title = uniqueid;
|
||||||
|
executeSoon(cb);
|
||||||
|
}, mode);
|
||||||
|
if (!isOpened) {
|
||||||
|
ok(false, "unable to open chat window, no provider? more failures to come");
|
||||||
|
executeSoon(cb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkPopup() {
|
function checkPopup() {
|
||||||
// popup only showing if any collapsed popup children.
|
// popup only showing if any collapsed popup children.
|
||||||
let chatbar = getChatBar();
|
let chatbar = window.SocialChatBar.chatbar;
|
||||||
let numCollapsed = 0;
|
let numCollapsed = 0;
|
||||||
for (let chat of chatbar.childNodes) {
|
for (let chat of chatbar.childNodes) {
|
||||||
if (chat.collapsed) {
|
if (chat.collapsed) {
|
||||||
@ -476,7 +482,7 @@ function checkPopup() {
|
|||||||
// Does a callback passing |true| if the window is now big enough or false
|
// Does a callback passing |true| if the window is now big enough or false
|
||||||
// if we couldn't resize large enough to satisfy the test requirement.
|
// if we couldn't resize large enough to satisfy the test requirement.
|
||||||
function resizeWindowToChatAreaWidth(desired, cb, count = 0) {
|
function resizeWindowToChatAreaWidth(desired, cb, count = 0) {
|
||||||
let current = getChatBar().getBoundingClientRect().width;
|
let current = window.SocialChatBar.chatbar.getBoundingClientRect().width;
|
||||||
let delta = desired - current;
|
let delta = desired - current;
|
||||||
info(count + ": resizing window so chat area is " + desired + " wide, currently it is "
|
info(count + ": resizing window so chat area is " + desired + " wide, currently it is "
|
||||||
+ current + ". Screen avail is " + window.screen.availWidth
|
+ current + ". Screen avail is " + window.screen.availWidth
|
||||||
@ -509,7 +515,7 @@ function resizeWindowToChatAreaWidth(desired, cb, count = 0) {
|
|||||||
}
|
}
|
||||||
function resize_handler(event) {
|
function resize_handler(event) {
|
||||||
// we did resize - but did we get far enough to be able to continue?
|
// we did resize - but did we get far enough to be able to continue?
|
||||||
let newSize = getChatBar().getBoundingClientRect().width;
|
let newSize = window.SocialChatBar.chatbar.getBoundingClientRect().width;
|
||||||
let sizedOk = widthDeltaCloseEnough(newSize - desired);
|
let sizedOk = widthDeltaCloseEnough(newSize - desired);
|
||||||
if (!sizedOk)
|
if (!sizedOk)
|
||||||
return;
|
return;
|
||||||
@ -557,13 +563,8 @@ function resizeAndCheckWidths(first, second, third, checks, cb) {
|
|||||||
}, count);
|
}, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChatBar() {
|
|
||||||
return document.getElementById("pinnedchats");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPopupWidth() {
|
function getPopupWidth() {
|
||||||
let chatbar = getChatBar();
|
let popup = window.SocialChatBar.chatbar.menupopup;
|
||||||
let popup = chatbar.menupopup;
|
|
||||||
ok(!popup.parentNode.collapsed, "asking for popup width when it is visible");
|
ok(!popup.parentNode.collapsed, "asking for popup width when it is visible");
|
||||||
let cs = document.defaultView.getComputedStyle(popup.parentNode);
|
let cs = document.defaultView.getComputedStyle(popup.parentNode);
|
||||||
let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight);
|
let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight);
|
||||||
@ -571,8 +572,6 @@ function getPopupWidth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function closeAllChats() {
|
function closeAllChats() {
|
||||||
let chatbar = getChatBar();
|
let chatbar = window.SocialChatBar.chatbar;
|
||||||
while (chatbar.selectedChat) {
|
chatbar.removeAll();
|
||||||
chatbar.selectedChat.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ MOCHITEST_CHROME_MANIFESTS += [
|
|||||||
]
|
]
|
||||||
|
|
||||||
BROWSER_CHROME_MANIFESTS += [
|
BROWSER_CHROME_MANIFESTS += [
|
||||||
'content/test/chat/browser.ini',
|
|
||||||
'content/test/general/browser.ini',
|
'content/test/general/browser.ini',
|
||||||
'content/test/newtab/browser.ini',
|
'content/test/newtab/browser.ini',
|
||||||
'content/test/plugins/browser.ini',
|
'content/test/plugins/browser.ini',
|
||||||
|
@ -1,191 +0,0 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// A module for working with chat windows.
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["Chat"];
|
|
||||||
|
|
||||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
|
||||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
|
||||||
|
|
||||||
// A couple of internal helper function.
|
|
||||||
function isWindowChromeless(win) {
|
|
||||||
// XXX - stolen from browser-social.js, but there's no obvious place to
|
|
||||||
// put this so it can be shared.
|
|
||||||
|
|
||||||
// Is this a popup window that doesn't want chrome shown?
|
|
||||||
let docElem = win.document.documentElement;
|
|
||||||
// extrachrome is not restored during session restore, so we need
|
|
||||||
// to check for the toolbar as well.
|
|
||||||
let chromeless = docElem.getAttribute("chromehidden").contains("extrachrome") ||
|
|
||||||
docElem.getAttribute('chromehidden').contains("toolbar");
|
|
||||||
return chromeless;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isWindowGoodForChats(win) {
|
|
||||||
return !win.closed &&
|
|
||||||
!!win.document.getElementById("pinnedchats") &&
|
|
||||||
!isWindowChromeless(win) &&
|
|
||||||
!PrivateBrowsingUtils.isWindowPrivate(win);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChromeWindow(contentWin) {
|
|
||||||
return contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIWebNavigation)
|
|
||||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
|
||||||
.rootTreeItem
|
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The exported Chat object
|
|
||||||
*/
|
|
||||||
|
|
||||||
let Chat = {
|
|
||||||
/**
|
|
||||||
* Open a new chatbox.
|
|
||||||
*
|
|
||||||
* @param contentWindow [optional]
|
|
||||||
* The content window that requested this chat. May be null.
|
|
||||||
* @param origin
|
|
||||||
* The origin for the chat. This is primarily used as an identifier
|
|
||||||
* to help identify all chats from the same provider.
|
|
||||||
* @param title
|
|
||||||
* The title to be used if a new chat window is created.
|
|
||||||
* @param url
|
|
||||||
* The URL for the that. Should be under the origin. If an existing
|
|
||||||
* chatbox exists with the same URL, it will be reused and returned.
|
|
||||||
* @param mode [optional]
|
|
||||||
* May be undefined or 'minimized'
|
|
||||||
* @param focus [optional]
|
|
||||||
* Indicates if the chatbox should be focused. If undefined the chat
|
|
||||||
* will be focused if the window is currently handling user input (ie,
|
|
||||||
* if the chat is being opened as a direct result of user input)
|
|
||||||
|
|
||||||
* @return A chatbox binding. This binding has a number of promises which
|
|
||||||
* can be used to determine when the chatbox is being created and
|
|
||||||
* has loaded. Will return null if no chat can be created (Which
|
|
||||||
* should only happen in edge-cases)
|
|
||||||
*/
|
|
||||||
open: function(contentWindow, origin, title, url, mode, focus, callback) {
|
|
||||||
let chromeWindow = this.findChromeWindowForChats(contentWindow);
|
|
||||||
if (!chromeWindow) {
|
|
||||||
Cu.reportError("Failed to open a chat window - no host window could be found.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let chatbar = chromeWindow.document.getElementById("pinnedchats");
|
|
||||||
chatbar.hidden = false;
|
|
||||||
let chatbox = chatbar.openChat(origin, title, url, mode, callback);
|
|
||||||
// getAttention is ignored if the target window is already foreground, so
|
|
||||||
// we can call it unconditionally.
|
|
||||||
chromeWindow.getAttention();
|
|
||||||
// If focus is undefined we want automatic focus handling, and only focus
|
|
||||||
// if a direct result of user action.
|
|
||||||
if (focus === undefined) {
|
|
||||||
let dwu = chromeWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
focus = dwu.isHandlingUserInput;
|
|
||||||
}
|
|
||||||
if (focus) {
|
|
||||||
chatbar.focus();
|
|
||||||
}
|
|
||||||
return chatbox;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close all chats from the specified origin.
|
|
||||||
*
|
|
||||||
* @param origin
|
|
||||||
* The origin from which all chats should be closed.
|
|
||||||
*/
|
|
||||||
closeAll: function(origin) {
|
|
||||||
// close all attached chat windows
|
|
||||||
let winEnum = Services.wm.getEnumerator("navigator:browser");
|
|
||||||
while (winEnum.hasMoreElements()) {
|
|
||||||
let win = winEnum.getNext();
|
|
||||||
let chatbar = win.document.getElementById("pinnedchats");
|
|
||||||
if (!chatbar)
|
|
||||||
continue;
|
|
||||||
let chats = [c for (c of chatbar.children) if (c.content.getAttribute("origin") == origin)];
|
|
||||||
[c.close() for (c of chats)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// close all standalone chat windows
|
|
||||||
winEnum = Services.wm.getEnumerator("Social:Chat");
|
|
||||||
while (winEnum.hasMoreElements()) {
|
|
||||||
let win = winEnum.getNext();
|
|
||||||
if (win.closed)
|
|
||||||
continue;
|
|
||||||
let chatOrigin = win.document.getElementById("chatter").content.getAttribute("origin");
|
|
||||||
if (origin == chatOrigin)
|
|
||||||
win.close();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Focus the chatbar associated with a window
|
|
||||||
*
|
|
||||||
* @param window
|
|
||||||
*/
|
|
||||||
focus: function(win) {
|
|
||||||
let chatbar = win.document.getElementById("pinnedchats");
|
|
||||||
if (chatbar && !chatbar.hidden) {
|
|
||||||
chatbar.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
// This is exported as socialchat.xml needs to find a window when a chat
|
|
||||||
// is re-docked.
|
|
||||||
findChromeWindowForChats: function(preferredWindow) {
|
|
||||||
if (preferredWindow) {
|
|
||||||
preferredWindow = getChromeWindow(preferredWindow);
|
|
||||||
if (isWindowGoodForChats(preferredWindow)) {
|
|
||||||
return preferredWindow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no good - we just use the "most recent" browser window which can host
|
|
||||||
// chats (we used to try and "group" all chats in the same browser window,
|
|
||||||
// but that didn't work out so well - see bug 835111
|
|
||||||
|
|
||||||
// Try first the most recent window as getMostRecentWindow works
|
|
||||||
// even on platforms where getZOrderDOMWindowEnumerator is broken
|
|
||||||
// (ie. Linux). This will handle most cases, but won't work if the
|
|
||||||
// foreground window is a popup.
|
|
||||||
|
|
||||||
let mostRecent = Services.wm.getMostRecentWindow("navigator:browser");
|
|
||||||
if (isWindowGoodForChats(mostRecent))
|
|
||||||
return mostRecent;
|
|
||||||
|
|
||||||
let topMost, enumerator;
|
|
||||||
// *sigh* - getZOrderDOMWindowEnumerator is broken except on Mac and
|
|
||||||
// Windows. We use BROKEN_WM_Z_ORDER as that is what some other code uses
|
|
||||||
// and a few bugs recommend searching mxr for this symbol to identify the
|
|
||||||
// workarounds - we want this code to be hit in such searches.
|
|
||||||
let os = Services.appinfo.OS;
|
|
||||||
const BROKEN_WM_Z_ORDER = os != "WINNT" && os != "Darwin";
|
|
||||||
if (BROKEN_WM_Z_ORDER) {
|
|
||||||
// this is oldest to newest and no way to change the order.
|
|
||||||
enumerator = Services.wm.getEnumerator("navigator:browser");
|
|
||||||
} else {
|
|
||||||
// here we explicitly ask for bottom-to-top so we can use the same logic
|
|
||||||
// where BROKEN_WM_Z_ORDER is true.
|
|
||||||
enumerator = Services.wm.getZOrderDOMWindowEnumerator("navigator:browser", false);
|
|
||||||
}
|
|
||||||
while (enumerator.hasMoreElements()) {
|
|
||||||
let win = enumerator.getNext();
|
|
||||||
if (!win.closed && isWindowGoodForChats(win))
|
|
||||||
topMost = win;
|
|
||||||
}
|
|
||||||
return topMost;
|
|
||||||
},
|
|
||||||
}
|
|
@ -9,7 +9,6 @@ TEST_DIRS += ['test']
|
|||||||
EXTRA_JS_MODULES += [
|
EXTRA_JS_MODULES += [
|
||||||
'BrowserNewTabPreloader.jsm',
|
'BrowserNewTabPreloader.jsm',
|
||||||
'BrowserUITelemetry.jsm',
|
'BrowserUITelemetry.jsm',
|
||||||
'Chat.jsm',
|
|
||||||
'ContentClick.jsm',
|
'ContentClick.jsm',
|
||||||
'ContentLinkHandler.jsm',
|
'ContentLinkHandler.jsm',
|
||||||
'ContentSearch.jsm',
|
'ContentSearch.jsm',
|
||||||
|
@ -8,8 +8,6 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "SocialService", "resource://gre/modules/SocialService.jsm");
|
XPCOMUtils.defineLazyModuleGetter(this, "SocialService", "resource://gre/modules/SocialService.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Social", "resource:///modules/Social.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Chat", "resource:///modules/Chat.jsm");
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm");
|
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["MozSocialAPI", "openChatWindow", "findChromeWindowForChats", "closeAllChatWindows"];
|
this.EXPORTED_SYMBOLS = ["MozSocialAPI", "openChatWindow", "findChromeWindowForChats", "closeAllChatWindows"];
|
||||||
@ -127,7 +125,7 @@ function attachToWindow(provider, targetWindow) {
|
|||||||
writable: true,
|
writable: true,
|
||||||
value: function(toURL, callback) {
|
value: function(toURL, callback) {
|
||||||
let url = targetWindow.document.documentURIObject.resolve(toURL);
|
let url = targetWindow.document.documentURIObject.resolve(toURL);
|
||||||
openChatWindow(targetWindow, provider, url, callback);
|
openChatWindow(getChromeWindow(targetWindow), provider, url, callback);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openPanel: {
|
openPanel: {
|
||||||
@ -272,31 +270,92 @@ function getChromeWindow(contentWin) {
|
|||||||
.getInterface(Ci.nsIDOMWindow);
|
.getInterface(Ci.nsIDOMWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isWindowGoodForChats(win) {
|
||||||
|
return win.SocialChatBar
|
||||||
|
&& win.SocialChatBar.isAvailable
|
||||||
|
&& !PrivateBrowsingUtils.isWindowPrivate(win);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findChromeWindowForChats(preferredWindow) {
|
||||||
|
if (preferredWindow && isWindowGoodForChats(preferredWindow))
|
||||||
|
return preferredWindow;
|
||||||
|
// no good - we just use the "most recent" browser window which can host
|
||||||
|
// chats (we used to try and "group" all chats in the same browser window,
|
||||||
|
// but that didn't work out so well - see bug 835111
|
||||||
|
|
||||||
|
// Try first the most recent window as getMostRecentWindow works
|
||||||
|
// even on platforms where getZOrderDOMWindowEnumerator is broken
|
||||||
|
// (ie. Linux). This will handle most cases, but won't work if the
|
||||||
|
// foreground window is a popup.
|
||||||
|
|
||||||
|
let mostRecent = Services.wm.getMostRecentWindow("navigator:browser");
|
||||||
|
if (isWindowGoodForChats(mostRecent))
|
||||||
|
return mostRecent;
|
||||||
|
|
||||||
|
let topMost, enumerator;
|
||||||
|
// *sigh* - getZOrderDOMWindowEnumerator is broken except on Mac and
|
||||||
|
// Windows. We use BROKEN_WM_Z_ORDER as that is what some other code uses
|
||||||
|
// and a few bugs recommend searching mxr for this symbol to identify the
|
||||||
|
// workarounds - we want this code to be hit in such searches.
|
||||||
|
let os = Services.appinfo.OS;
|
||||||
|
const BROKEN_WM_Z_ORDER = os != "WINNT" && os != "Darwin";
|
||||||
|
if (BROKEN_WM_Z_ORDER) {
|
||||||
|
// this is oldest to newest and no way to change the order.
|
||||||
|
enumerator = Services.wm.getEnumerator("navigator:browser");
|
||||||
|
} else {
|
||||||
|
// here we explicitly ask for bottom-to-top so we can use the same logic
|
||||||
|
// where BROKEN_WM_Z_ORDER is true.
|
||||||
|
enumerator = Services.wm.getZOrderDOMWindowEnumerator("navigator:browser", false);
|
||||||
|
}
|
||||||
|
while (enumerator.hasMoreElements()) {
|
||||||
|
let win = enumerator.getNext();
|
||||||
|
if (!win.closed && isWindowGoodForChats(win))
|
||||||
|
topMost = win;
|
||||||
|
}
|
||||||
|
return topMost;
|
||||||
|
}
|
||||||
|
|
||||||
this.openChatWindow =
|
this.openChatWindow =
|
||||||
function openChatWindow(contentWindow, provider, url, callback, mode) {
|
function openChatWindow(chromeWindow, provider, url, callback, mode) {
|
||||||
|
chromeWindow = findChromeWindowForChats(chromeWindow);
|
||||||
|
if (!chromeWindow) {
|
||||||
|
Cu.reportError("Failed to open a social chat window - no host window could be found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let fullURI = provider.resolveUri(url);
|
let fullURI = provider.resolveUri(url);
|
||||||
if (!provider.isSameOrigin(fullURI)) {
|
if (!provider.isSameOrigin(fullURI)) {
|
||||||
Cu.reportError("Failed to open a social chat window - the requested URL is not the same origin as the provider.");
|
Cu.reportError("Failed to open a social chat window - the requested URL is not the same origin as the provider.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!chromeWindow.SocialChatBar.openChat(provider, fullURI.spec, callback, mode)) {
|
||||||
let thisCallback = function(chatbox) {
|
Cu.reportError("Failed to open a social chat window - the chatbar is not available in the target window.");
|
||||||
// All social chat windows get a special error listener.
|
return;
|
||||||
Social.setErrorListener(chatbox.content, function(aBrowser) {
|
|
||||||
aBrowser.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
|
|
||||||
encodeURIComponent(aBrowser.getAttribute("origin")),
|
|
||||||
null, null, null, null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let chatbox = Chat.open(contentWindow, provider.origin, provider.name,
|
|
||||||
fullURI.spec, mode, undefined, thisCallback);
|
|
||||||
if (callback) {
|
|
||||||
chatbox.promiseChatLoaded.then(() => {
|
|
||||||
callback(chatbox.contentWindow);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// getAttention is ignored if the target window is already foreground, so
|
||||||
|
// we can call it unconditionally.
|
||||||
|
chromeWindow.getAttention();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closeAllChatWindows = function closeAllChatWindows(provider) {
|
this.closeAllChatWindows =
|
||||||
return Chat.closeAll(provider.origin);
|
function closeAllChatWindows(provider) {
|
||||||
|
// close all attached chat windows
|
||||||
|
let winEnum = Services.wm.getEnumerator("navigator:browser");
|
||||||
|
while (winEnum.hasMoreElements()) {
|
||||||
|
let win = winEnum.getNext();
|
||||||
|
if (!win.SocialChatBar)
|
||||||
|
continue;
|
||||||
|
let chats = [c for (c of win.SocialChatBar.chatbar.children) if (c.content.getAttribute("origin") == provider.origin)];
|
||||||
|
[c.close() for (c of chats)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// close all standalone chat windows
|
||||||
|
winEnum = Services.wm.getEnumerator("Social:Chat");
|
||||||
|
while (winEnum.hasMoreElements()) {
|
||||||
|
let win = winEnum.getNext();
|
||||||
|
if (win.closed)
|
||||||
|
continue;
|
||||||
|
let origin = win.document.getElementById("chatter").content.getAttribute("origin");
|
||||||
|
if (provider.origin == origin)
|
||||||
|
win.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user