зеркало из https://github.com/mozilla/gecko-dev.git
Bug 779686 - implement docked chat content areas, r=felipe
--HG-- extra : transplant_source : c%29h%B5%89%27%F3S%C0%B6%CB%82%A27%3C%0D%AEL%14V
This commit is contained in:
Родитель
decc5c0f98
Коммит
5cc0f50e62
|
@ -40,6 +40,7 @@ let SocialUI = {
|
||||||
SocialShareButton.updateButtonHiddenState();
|
SocialShareButton.updateButtonHiddenState();
|
||||||
SocialToolbar.updateButtonHiddenState();
|
SocialToolbar.updateButtonHiddenState();
|
||||||
SocialSidebar.updateSidebar();
|
SocialSidebar.updateSidebar();
|
||||||
|
SocialChatBar.update();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Components.utils.reportError(e);
|
Components.utils.reportError(e);
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -157,6 +158,27 @@ let SocialUI = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let SocialChatBar = {
|
||||||
|
get chatbar() {
|
||||||
|
return document.getElementById("pinnedchats");
|
||||||
|
},
|
||||||
|
// Whether the chats can be shown for this window.
|
||||||
|
get canShow() {
|
||||||
|
let docElem = document.documentElement;
|
||||||
|
let chromeless = docElem.getAttribute("disablechrome") ||
|
||||||
|
docElem.getAttribute("chromehidden").indexOf("extrachrome") >= 0;
|
||||||
|
return Social.uiVisible && !chromeless;
|
||||||
|
},
|
||||||
|
newChat: function(aProvider, aURL, aCallback) {
|
||||||
|
if (this.canShow)
|
||||||
|
this.chatbar.newChat(aProvider, aURL, aCallback);
|
||||||
|
},
|
||||||
|
update: function() {
|
||||||
|
if (!this.canShow)
|
||||||
|
this.chatbar.removeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let SocialShareButton = {
|
let SocialShareButton = {
|
||||||
// Called once, after window load, when the Social.provider object is initialized
|
// Called once, after window load, when the Social.provider object is initialized
|
||||||
init: function SSB_init() {
|
init: function SSB_init() {
|
||||||
|
|
|
@ -615,3 +615,12 @@ stack[anonid=browserStack][responsivemode] {
|
||||||
stack[anonid=browserStack][responsivemode][notransition] {
|
stack[anonid=browserStack][responsivemode][notransition] {
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chatbox {
|
||||||
|
-moz-binding: url("chrome://browser/content/socialchat.xml#chatbox");
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar {
|
||||||
|
-moz-binding: url("chrome://browser/content/socialchat.xml#chatbar");
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
|
@ -3161,6 +3161,52 @@ const DOMLinkHandler = {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getLinkIconURI: function(aLink) {
|
||||||
|
let targetDoc = aLink.ownerDocument;
|
||||||
|
var uri = makeURI(aLink.href, targetDoc.characterSet);
|
||||||
|
|
||||||
|
// Verify that the load of this icon is legal.
|
||||||
|
// Some error or special pages can load their favicon.
|
||||||
|
// To be on the safe side, only allow chrome:// favicons.
|
||||||
|
var isAllowedPage = [
|
||||||
|
/^about:neterror\?/,
|
||||||
|
/^about:blocked\?/,
|
||||||
|
/^about:certerror\?/,
|
||||||
|
/^about:home$/,
|
||||||
|
].some(function (re) re.test(targetDoc.documentURI));
|
||||||
|
|
||||||
|
if (!isAllowedPage || !uri.schemeIs("chrome")) {
|
||||||
|
var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].
|
||||||
|
getService(Ci.nsIScriptSecurityManager);
|
||||||
|
try {
|
||||||
|
ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
|
||||||
|
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
||||||
|
} catch(e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"].
|
||||||
|
getService(Ci.nsIContentPolicy);
|
||||||
|
} catch(e) {
|
||||||
|
return null; // Refuse to load if we can't do a security check.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security says okay, now ask content policy
|
||||||
|
if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||||
|
uri, targetDoc.documentURIObject,
|
||||||
|
aLink, aLink.type, null)
|
||||||
|
!= Ci.nsIContentPolicy.ACCEPT)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
uri.userPass = "";
|
||||||
|
} catch(e) {
|
||||||
|
// some URIs are immutable
|
||||||
|
}
|
||||||
|
return uri;
|
||||||
|
},
|
||||||
onLinkAdded: function (event) {
|
onLinkAdded: function (event) {
|
||||||
var link = event.originalTarget;
|
var link = event.originalTarget;
|
||||||
var rel = link.rel && link.rel.toLowerCase();
|
var rel = link.rel && link.rel.toLowerCase();
|
||||||
|
@ -3194,54 +3240,20 @@ const DOMLinkHandler = {
|
||||||
if (!gPrefService.getBoolPref("browser.chrome.site_icons"))
|
if (!gPrefService.getBoolPref("browser.chrome.site_icons"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var targetDoc = link.ownerDocument;
|
var uri = this.getLinkIconURI(link);
|
||||||
var uri = makeURI(link.href, targetDoc.characterSet);
|
if (!uri)
|
||||||
|
break;
|
||||||
|
|
||||||
if (gBrowser.isFailedIcon(uri))
|
if (gBrowser.isFailedIcon(uri))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Verify that the load of this icon is legal.
|
var browserIndex = gBrowser.getBrowserIndexForDocument(link.ownerDocument);
|
||||||
// Some error or special pages can load their favicon.
|
|
||||||
// To be on the safe side, only allow chrome:// favicons.
|
|
||||||
var isAllowedPage = [
|
|
||||||
/^about:neterror\?/,
|
|
||||||
/^about:blocked\?/,
|
|
||||||
/^about:certerror\?/,
|
|
||||||
/^about:home$/,
|
|
||||||
].some(function (re) re.test(targetDoc.documentURI));
|
|
||||||
|
|
||||||
if (!isAllowedPage || !uri.schemeIs("chrome")) {
|
|
||||||
var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].
|
|
||||||
getService(Ci.nsIScriptSecurityManager);
|
|
||||||
try {
|
|
||||||
ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
|
|
||||||
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
|
||||||
} catch(e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"].
|
|
||||||
getService(Ci.nsIContentPolicy);
|
|
||||||
} catch(e) {
|
|
||||||
break; // Refuse to load if we can't do a security check.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Security says okay, now ask content policy
|
|
||||||
if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
|
||||||
uri, targetDoc.documentURIObject,
|
|
||||||
link, link.type, null)
|
|
||||||
!= Ci.nsIContentPolicy.ACCEPT)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var browserIndex = gBrowser.getBrowserIndexForDocument(targetDoc);
|
|
||||||
// no browser? no favicon.
|
// no browser? no favicon.
|
||||||
if (browserIndex == -1)
|
if (browserIndex == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
let tab = gBrowser.tabs[browserIndex];
|
let tab = gBrowser.tabs[browserIndex];
|
||||||
gBrowser.setIcon(tab, link.href);
|
gBrowser.setIcon(tab, uri.spec);
|
||||||
iconAdded = true;
|
iconAdded = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1051,6 +1051,7 @@
|
||||||
contentcontextmenu="contentAreaContextMenu"
|
contentcontextmenu="contentAreaContextMenu"
|
||||||
autocompletepopup="PopupAutoComplete"
|
autocompletepopup="PopupAutoComplete"
|
||||||
onclick="contentAreaClick(event, false);"/>
|
onclick="contentAreaClick(event, false);"/>
|
||||||
|
<chatbar id="pinnedchats" layer="true" mousethrough="always"/>
|
||||||
<statuspanel id="statusbar-display" inactive="true"/>
|
<statuspanel id="statusbar-display" inactive="true"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
<splitter id="devtools-side-splitter" hidden="true"/>
|
<splitter id="devtools-side-splitter" hidden="true"/>
|
||||||
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<bindings id="socialChatBindings"
|
||||||
|
xmlns="http://www.mozilla.org/xbl"
|
||||||
|
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||||
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
|
|
||||||
|
<binding id="chatbox">
|
||||||
|
<content orient="vertical" mousethrough="never">
|
||||||
|
<xul:hbox class="chat-titlebar" xbl:inherits="minimized">
|
||||||
|
<xul:image class="chat-status-icon" xbl:inherits="src=image"/>
|
||||||
|
<xul:label class="chat-title" flex="1" xbl:inherits="value=label,crop"/>
|
||||||
|
<xul:toolbarbutton class="chat-toggle-button chat-toolbarbutton"
|
||||||
|
xbl:inherits="minimized"
|
||||||
|
oncommand="document.getBindingParent(this).toggle();"/>
|
||||||
|
<xul:toolbarbutton class="chat-close-button chat-toolbarbutton"
|
||||||
|
oncommand="document.getBindingParent(this).close();"/>
|
||||||
|
</xul:hbox>
|
||||||
|
<xul:iframe anonid="iframe" class="chat-frame" flex="1"
|
||||||
|
xbl:inherits="src,origin,collapsed=minimized" type="content"/>
|
||||||
|
</content>
|
||||||
|
|
||||||
|
<implementation implements="nsIDOMEventListener">
|
||||||
|
<field name="iframe" readonly="true">
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "iframe");
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<method name="init">
|
||||||
|
<parameter name="aProvider"/>
|
||||||
|
<parameter name="aURL"/>
|
||||||
|
<parameter name="aCallback"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
this._callback = aCallback;
|
||||||
|
this.setAttribute("origin", aProvider.origin);
|
||||||
|
this.setAttribute("src", aURL);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="close">
|
||||||
|
<body><![CDATA[
|
||||||
|
this.parentNode.remove(this);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="toggle">
|
||||||
|
<body><![CDATA[
|
||||||
|
let type;
|
||||||
|
if (this.getAttribute("minimized") == "true") {
|
||||||
|
this.removeAttribute("minimized");
|
||||||
|
type = "socialFrameShow";
|
||||||
|
} else {
|
||||||
|
this.setAttribute("minimized", "true");
|
||||||
|
type = "socialFrameHide";
|
||||||
|
}
|
||||||
|
// let the chat frame know if it is being shown or hidden
|
||||||
|
let evt = this.iframe.contentDocument.createEvent("CustomEvent");
|
||||||
|
evt.initCustomEvent(type, true, true, {});
|
||||||
|
this.iframe.contentDocument.documentElement.dispatchEvent(evt);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
</implementation>
|
||||||
|
|
||||||
|
<handlers>
|
||||||
|
<handler event="focus" phase="capturing">
|
||||||
|
this.parentNode.selectedChat = this;
|
||||||
|
</handler>
|
||||||
|
<handler event="DOMContentLoaded" action="if (this._callback) this._callback(this.iframe.contentWindow);"/>
|
||||||
|
<handler event="DOMTitleChanged" action="this.setAttribute('label', this.iframe.contentDocument.title);"/>
|
||||||
|
<handler event="DOMLinkAdded"><![CDATA[
|
||||||
|
// much of this logic is from DOMLinkHandler in browser.js
|
||||||
|
// this sets the presence icon for a chat user, we simply use favicon style updating
|
||||||
|
let link = event.originalTarget;
|
||||||
|
let rel = link.rel && link.rel.toLowerCase();
|
||||||
|
if (!link || !link.ownerDocument || !rel || !link.href)
|
||||||
|
return;
|
||||||
|
if (link.rel.indexOf("icon") < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let uri = DOMLinkHandler.getLinkIconURI(link);
|
||||||
|
if (!uri)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// we made it this far, use it
|
||||||
|
this.setAttribute('image', uri.spec);
|
||||||
|
]]></handler>
|
||||||
|
</handlers>
|
||||||
|
</binding>
|
||||||
|
|
||||||
|
<binding id="chatbar">
|
||||||
|
<content>
|
||||||
|
<xul:hbox align="end" pack="end" anonid="innerbox" class="chatbar-innerbox" mousethrough="always" flex="1">
|
||||||
|
<xul:toolbarbutton anonid="nub" class="chatbar-button" type="menu" collapsed="true" mousethrough="never">
|
||||||
|
<xul:menupopup anonid="nubMenu" oncommand="document.getBindingParent(this).swapChat(event)"/>
|
||||||
|
</xul:toolbarbutton>
|
||||||
|
<xul:spacer flex="1" anonid="spacer" class="chatbar-overflow-spacer"/>
|
||||||
|
<children/>
|
||||||
|
</xul:hbox>
|
||||||
|
</content>
|
||||||
|
|
||||||
|
<implementation implements="nsIDOMEventListener">
|
||||||
|
|
||||||
|
<field name="innerbox" readonly="true">
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "innerbox");
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="menupopup" readonly="true">
|
||||||
|
document.getAnonymousElementByAttribute(this, "anonid", "nubMenu");
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<property name="emptyWidth">
|
||||||
|
<getter>
|
||||||
|
return document.getAnonymousElementByAttribute(this, "anonid", "spacer").boxObject.width;
|
||||||
|
</getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<field name="selectedChat"/>
|
||||||
|
|
||||||
|
<field name="menuitemMap">new WeakMap()</field>
|
||||||
|
|
||||||
|
<property name="firstCollapsedChild">
|
||||||
|
<getter><![CDATA[
|
||||||
|
let child = this.lastChild;
|
||||||
|
while (child && !child.collapsed) {
|
||||||
|
child = child.previousSibling;
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
]]></getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property name="firstVisibleChild">
|
||||||
|
<getter><![CDATA[
|
||||||
|
let child = this.firstChild;
|
||||||
|
while (child && child.collapsed) {
|
||||||
|
child = child.nextSibling;
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
]]></getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property name="firstRemovableChild">
|
||||||
|
<getter><![CDATA[
|
||||||
|
let child = this.firstChild;
|
||||||
|
// find the first visible non-focused chatbox, always keep one visible if we
|
||||||
|
// have enough width to do so.
|
||||||
|
while (child &&
|
||||||
|
(child.collapsed || child == this.selectedChat)) {
|
||||||
|
child = child.nextSibling;
|
||||||
|
}
|
||||||
|
if (!child && this.selectedChat) {
|
||||||
|
child = this.selectedChat;
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
]]></getter>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<method name="resize">
|
||||||
|
<body><![CDATA[
|
||||||
|
let child = this.firstCollapsedChild;
|
||||||
|
if (child && this.emptyWidth > 200) {
|
||||||
|
this.showChat(child);
|
||||||
|
}
|
||||||
|
if (!this.firstCollapsedChild) {
|
||||||
|
window.removeEventListener("resize", this);
|
||||||
|
this.menupopup.parentNode.collapsed = true;
|
||||||
|
}
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="handleEvent">
|
||||||
|
<parameter name="aEvent"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
if (aEvent.type == "resize") {
|
||||||
|
this.resize();
|
||||||
|
}
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="swapChat">
|
||||||
|
<parameter name="aEvent"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
let menuitem = aEvent.target;
|
||||||
|
let newChat = menuitem.chat;
|
||||||
|
let oldChat = this.firstVisibleChild;
|
||||||
|
if (oldChat)
|
||||||
|
this.collapseChat(oldChat);
|
||||||
|
if (newChat)
|
||||||
|
this.showChat(newChat);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="collapseChat">
|
||||||
|
<parameter name="aChatbox"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
aChatbox.collapsed = true;
|
||||||
|
let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
|
||||||
|
menu.setAttribute("label", aChatbox.iframe.contentDocument.title);
|
||||||
|
menu.chat = aChatbox;
|
||||||
|
this.menuitemMap.set(aChatbox, menu);
|
||||||
|
this.menupopup.appendChild(menu);
|
||||||
|
this.menupopup.parentNode.collapsed = false;
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="showChat">
|
||||||
|
<parameter name="aChatbox"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
let menuitem = this.menuitemMap.get(aChatbox);
|
||||||
|
this.menuitemMap.delete(aChatbox);
|
||||||
|
this.menupopup.removeChild(menuitem);
|
||||||
|
aChatbox.collapsed = false;
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="remove">
|
||||||
|
<parameter name="aChatbox"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
if (this.selectedChat == aChatbox) {
|
||||||
|
this.selectedChat = aChatbox.previousSibling ? aChatbox.previousSibling : aChatbox.nextSibling
|
||||||
|
}
|
||||||
|
this.removeChild(aChatbox);
|
||||||
|
this.resize();
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="removeAll">
|
||||||
|
<body><![CDATA[
|
||||||
|
while (this.firstChild) {
|
||||||
|
this.removeChild(this.firstChild);
|
||||||
|
}
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="newChat">
|
||||||
|
<parameter name="aProvider"/>
|
||||||
|
<parameter name="aURL"/>
|
||||||
|
<parameter name="aCallback"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
let cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
|
||||||
|
this.selectedChat = cb;
|
||||||
|
this.appendChild(cb);
|
||||||
|
cb.init(aProvider, aURL, aCallback);
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
</implementation>
|
||||||
|
<handlers>
|
||||||
|
<handler event="overflow"><![CDATA[
|
||||||
|
// make sure we're not getting an overflow from content
|
||||||
|
if (event.originalTarget != this.innerbox)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let hasHidden = this.firstCollapsedChild;
|
||||||
|
let child = this.firstRemovableChild;
|
||||||
|
if (child)
|
||||||
|
this.collapseChat(child);
|
||||||
|
if (!hasHidden) {
|
||||||
|
window.addEventListener("resize", this);
|
||||||
|
}
|
||||||
|
]]></handler>
|
||||||
|
</handlers>
|
||||||
|
</binding>
|
||||||
|
|
||||||
|
</bindings>
|
|
@ -264,8 +264,10 @@ _BROWSER_FILES = \
|
||||||
browser_social_sidebar.js \
|
browser_social_sidebar.js \
|
||||||
browser_social_mozSocial_API.js \
|
browser_social_mozSocial_API.js \
|
||||||
browser_social_isVisible.js \
|
browser_social_isVisible.js \
|
||||||
|
browser_social_chatwindow.js \
|
||||||
social_panel.html \
|
social_panel.html \
|
||||||
social_sidebar.html \
|
social_sidebar.html \
|
||||||
|
social_chat.html \
|
||||||
social_window.html \
|
social_window.html \
|
||||||
social_worker.js \
|
social_worker.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* 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() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
let manifest = { // normal provider
|
||||||
|
name: "provider 1",
|
||||||
|
origin: "https://example.com",
|
||||||
|
sidebarURL: "https://example.com/browser/browser/base/content/test/social_sidebar.html",
|
||||||
|
workerURL: "https://example.com/browser/browser/base/content/test/social_worker.js",
|
||||||
|
iconURL: "chrome://branding/content/icon48.png"
|
||||||
|
};
|
||||||
|
runSocialTestWithProvider(manifest, function (finishcb) {
|
||||||
|
runSocialTests(tests, undefined, undefined, function () {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
ok(chats.children.length == 0, "no chatty children left behind");
|
||||||
|
finishcb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = {
|
||||||
|
testOpenCloseChat: function(next) {
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
let port = Social.provider.port;
|
||||||
|
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":
|
||||||
|
if (e.data.result == "hidden") {
|
||||||
|
ok(true, "chatbox got minimized");
|
||||||
|
chats.selectedChat.toggle();
|
||||||
|
} else if (e.data.result == "shown") {
|
||||||
|
ok(true, "chatbox got shown");
|
||||||
|
// close it now
|
||||||
|
let iframe = chats.selectedChat.iframe;
|
||||||
|
iframe.addEventListener("unload", function chatUnload() {
|
||||||
|
iframe.removeEventListener("unload", chatUnload, true);
|
||||||
|
ok(true, "got chatbox unload on close");
|
||||||
|
next();
|
||||||
|
}, true);
|
||||||
|
chats.selectedChat.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
port.postMessage({topic: "test-init"});
|
||||||
|
},
|
||||||
|
testManyChats: function(next) {
|
||||||
|
// open enough chats to overflow the window, then check
|
||||||
|
// if the menupopup is visible
|
||||||
|
let port = Social.provider.port;
|
||||||
|
ok(port, "provider has a port");
|
||||||
|
let width = document.documentElement.boxObject.width;
|
||||||
|
let numToOpen = (width / 200) + 1;
|
||||||
|
port.onmessage = function (e) {
|
||||||
|
let topic = e.data.topic;
|
||||||
|
switch (topic) {
|
||||||
|
case "got-chatbox-message":
|
||||||
|
numToOpen--;
|
||||||
|
if (numToOpen >= 0) {
|
||||||
|
// we're waiting for all to open
|
||||||
|
ok(true, "got a chat window opened");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// close our chats now
|
||||||
|
let chats = document.getElementById("pinnedchats");
|
||||||
|
ok(!chats.menupopup.parentNode.collapsed, "menu selection is visible");
|
||||||
|
while (chats.selectedChat) {
|
||||||
|
chats.selectedChat.close();
|
||||||
|
}
|
||||||
|
ok(!chats.selectedChat, "chats are all closed");
|
||||||
|
next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let num = numToOpen;
|
||||||
|
while (num-- > 0) {
|
||||||
|
port.postMessage({topic: "test-chatbox-open"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script>
|
||||||
|
function pingWorker() {
|
||||||
|
var port = navigator.mozSocial.getWorker().port;
|
||||||
|
port.postMessage({topic: "chatbox-message", result: "ok"});
|
||||||
|
}
|
||||||
|
window.addEventListener("socialFrameShow", function(e) {
|
||||||
|
var port = navigator.mozSocial.getWorker().port;
|
||||||
|
port.postMessage({topic: "chatbox-visibility", result: "shown"});
|
||||||
|
}, false);
|
||||||
|
window.addEventListener("socialFrameHide", function(e) {
|
||||||
|
var port = navigator.mozSocial.getWorker().port;
|
||||||
|
port.postMessage({topic: "chatbox-visibility", result: "hidden"});
|
||||||
|
}, false);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="pingWorker();">
|
||||||
|
<p>This is a test social chat window.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -8,6 +8,11 @@
|
||||||
port.onmessage = function(e) {
|
port.onmessage = function(e) {
|
||||||
var topic = e.data.topic;
|
var topic = e.data.topic;
|
||||||
switch (topic) {
|
switch (topic) {
|
||||||
|
case "test-chatbox-open":
|
||||||
|
navigator.mozSocial.openChatWindow("social_chat.html", function(chatwin) {
|
||||||
|
port.postMessage({topic: "chatbox-opened", result: chatwin ? "ok" : "failed"});
|
||||||
|
});
|
||||||
|
break;
|
||||||
case "test-service-window":
|
case "test-service-window":
|
||||||
win = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "width=300,height=300");
|
win = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "width=300,height=300");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -39,6 +39,15 @@ onconnect = function(e) {
|
||||||
if (testPort && event.data.result == "ok")
|
if (testPort && event.data.result == "ok")
|
||||||
testPort.postMessage({topic:"got-panel-message"});
|
testPort.postMessage({topic:"got-panel-message"});
|
||||||
break;
|
break;
|
||||||
|
case "test-chatbox-open":
|
||||||
|
sidebarPort.postMessage({topic:"test-chatbox-open"});
|
||||||
|
break;
|
||||||
|
case "chatbox-message":
|
||||||
|
testPort.postMessage({topic:"got-chatbox-message", result: event.data.result});
|
||||||
|
break;
|
||||||
|
case "chatbox-visibility":
|
||||||
|
testPort.postMessage({topic:"got-chatbox-visibility", result: event.data.result});
|
||||||
|
break;
|
||||||
case "social.initialize":
|
case "social.initialize":
|
||||||
// This is the workerAPI port, respond and set up a notification icon.
|
// This is the workerAPI port, respond and set up a notification icon.
|
||||||
port.postMessage({topic: "social.initialize-response"});
|
port.postMessage({topic: "social.initialize-response"});
|
||||||
|
|
|
@ -102,6 +102,7 @@ browser.jar:
|
||||||
content/browser/win6BrowserOverlay.xul (content/win6BrowserOverlay.xul)
|
content/browser/win6BrowserOverlay.xul (content/win6BrowserOverlay.xul)
|
||||||
#endif
|
#endif
|
||||||
content/browser/social-icon.png (content/social-icon.png)
|
content/browser/social-icon.png (content/social-icon.png)
|
||||||
|
content/browser/socialchat.xml (content/socialchat.xml)
|
||||||
# the following files are browser-specific overrides
|
# the following files are browser-specific overrides
|
||||||
* content/browser/license.html (/toolkit/content/license.html)
|
* content/browser/license.html (/toolkit/content/license.html)
|
||||||
% override chrome://global/content/license.html chrome://browser/content/license.html
|
% override chrome://global/content/license.html chrome://browser/content/license.html
|
||||||
|
|
|
@ -2748,3 +2748,126 @@ stack[anonid=browserStack][responsivemode] {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chat-status-icon {
|
||||||
|
max-height: 16px;
|
||||||
|
max-width: 16px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toolbarbutton {
|
||||||
|
-moz-appearance: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toolbarbutton > .toolbarbutton-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button {
|
||||||
|
list-style-image: url("chrome://global/skin/icons/close.png");
|
||||||
|
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button:hover {
|
||||||
|
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button:hover:active {
|
||||||
|
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chat-toggle-button {
|
||||||
|
/* XXX get a real image for this */
|
||||||
|
list-style-image: url("chrome://global/skin/icons/checkbox.png");
|
||||||
|
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button:hover {
|
||||||
|
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button[minimized="true"] {
|
||||||
|
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button[minimized="true"]:hover {
|
||||||
|
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-title {
|
||||||
|
font-weight: bold;
|
||||||
|
color: -moz-dialogtext;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-titlebar {
|
||||||
|
background-image: linear-gradient(white, #ddd);
|
||||||
|
height: 20px;
|
||||||
|
min-height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-titlebar[minimized="true"] {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-frame {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-button {
|
||||||
|
/* XXX get a real image for this */
|
||||||
|
list-style-image: url("chrome://browser/skin/social/social.png");
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
height: 21px;
|
||||||
|
width: 21px;
|
||||||
|
border-top: 1px solid gray;
|
||||||
|
-moz-border-end: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-button[open="true"],
|
||||||
|
.chatbar-button:active:hover {
|
||||||
|
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* toolbarbutton-icon */
|
||||||
|
.chatbar-button > .toolbarbutton-text,
|
||||||
|
.chatbar-button > .toolbarbutton-menu-dropmarker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-innerbox {
|
||||||
|
background: transparent;
|
||||||
|
margin: -200px -1px 0 -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox {
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid gray;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox[minimized="true"] {
|
||||||
|
width: 100px;
|
||||||
|
height: 20px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox + chatbox {
|
||||||
|
-moz-margin-start: -1px;
|
||||||
|
}
|
||||||
|
|
|
@ -3519,3 +3519,129 @@ stack[anonid=browserStack][responsivemode] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === end of social toolbar panels === */
|
/* === end of social toolbar panels === */
|
||||||
|
|
||||||
|
|
||||||
|
.chat-status-icon {
|
||||||
|
max-height: 16px;
|
||||||
|
max-width: 16px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toolbarbutton {
|
||||||
|
-moz-appearance: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toolbarbutton > .toolbarbutton-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button {
|
||||||
|
list-style-image: url("chrome://global/skin/icons/close.png");
|
||||||
|
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button:hover {
|
||||||
|
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button:hover:active {
|
||||||
|
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chat-toggle-button {
|
||||||
|
/* XXX get a real image for this */
|
||||||
|
list-style-image: url("chrome://global/skin/icons/checkbox.png");
|
||||||
|
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button:hover {
|
||||||
|
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button[minimized="true"] {
|
||||||
|
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button[minimized="true"]:hover {
|
||||||
|
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-title {
|
||||||
|
font-weight: bold;
|
||||||
|
color: -moz-dialogtext;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-titlebar {
|
||||||
|
background-image: linear-gradient(white, #ddd);
|
||||||
|
height: 20px;
|
||||||
|
min-height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #404040;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-titlebar[minimized="true"] {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-frame {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-button {
|
||||||
|
/* XXX get a real image for this */
|
||||||
|
background-image: linear-gradient(white, #ddd);
|
||||||
|
list-style-image: url("chrome://browser/skin/social/social.png");
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
height: 21px;
|
||||||
|
width: 21px;
|
||||||
|
border-top: 1px solid #404040;
|
||||||
|
-moz-border-end: 1px solid #404040;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-button[open="true"],
|
||||||
|
.chatbar-button:active:hover {
|
||||||
|
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* toolbarbutton-icon */
|
||||||
|
.chatbar-button > .toolbarbutton-text,
|
||||||
|
.chatbar-button > .toolbarbutton-menu-dropmarker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-innerbox {
|
||||||
|
background: transparent;
|
||||||
|
margin: -200px -1px 0 -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox {
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid #404040;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox[minimized="true"] {
|
||||||
|
width: 100px;
|
||||||
|
height: 20px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox + chatbox {
|
||||||
|
-moz-margin-start: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,12 @@
|
||||||
.menu-iconic-accel {
|
.menu-iconic-accel {
|
||||||
color: graytext;
|
color: graytext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chatbar-button,
|
||||||
|
chatbar > chatbox {
|
||||||
|
border-color: #A9B7C9;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (-moz-windows-compositor) {
|
@media (-moz-windows-compositor) {
|
||||||
|
|
|
@ -3450,3 +3450,136 @@ stack[anonid=browserStack][responsivemode] {
|
||||||
max-height: 600px;
|
max-height: 600px;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chat-status-icon {
|
||||||
|
max-height: 16px;
|
||||||
|
max-width: 16px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toolbarbutton {
|
||||||
|
-moz-appearance: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toolbarbutton > .toolbarbutton-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button {
|
||||||
|
list-style-image: url("chrome://global/skin/icons/Close.gif");
|
||||||
|
padding: 2px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button:hover {
|
||||||
|
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-close-button:hover:active {
|
||||||
|
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chat-toggle-button {
|
||||||
|
/* XXX get a real image for this */
|
||||||
|
list-style-image: url("chrome://global/skin/icons/expand.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button:hover {
|
||||||
|
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button[minimized="true"] {
|
||||||
|
list-style-image: url("chrome://global/skin/icons/collapse.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-toggle-button[minimized="true"]:hover {
|
||||||
|
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-title {
|
||||||
|
font-weight: bold;
|
||||||
|
color: -moz-dialogtext;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-titlebar {
|
||||||
|
background-image: linear-gradient(white, #ddd);
|
||||||
|
height: 20px;
|
||||||
|
min-height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-titlebar[minimized="true"] {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-frame {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-button {
|
||||||
|
/* XXX get a real image for this */
|
||||||
|
-moz-appearance: none;
|
||||||
|
list-style-image: url("chrome://browser/skin/social/social.png");
|
||||||
|
background-image: linear-gradient(white, #ddd);
|
||||||
|
border: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
height: 21px;
|
||||||
|
width: 21px;
|
||||||
|
border-top: 1px solid gray;
|
||||||
|
-moz-border-end: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-button > .button-box > .box-inherit > .button-icon {
|
||||||
|
max-height: 16px;
|
||||||
|
max-width: 16px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-button[open="true"],
|
||||||
|
.chatbar-button:hover,
|
||||||
|
.chatbar-button:active:hover {
|
||||||
|
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* toolbarbutton-icon */
|
||||||
|
.chatbar-button > .toolbarbutton-text,
|
||||||
|
.chatbar-button > .toolbarbutton-menu-dropmarker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chatbar-innerbox {
|
||||||
|
background: transparent;
|
||||||
|
margin: -200px -1px 0 -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox {
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid gray;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox[minimized="true"] {
|
||||||
|
width: 100px;
|
||||||
|
height: 20px;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatbar > chatbox + chatbox {
|
||||||
|
-moz-margin-start: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,17 @@ function attachToWindow(provider, targetWindow) {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
writable: true,
|
writable: true,
|
||||||
value: function(toURL, name, options) {
|
value: function(toURL, name, options) {
|
||||||
return openServiceWindow(provider, targetWindow, toURL, name, options);
|
let url = targetWindow.document.documentURIObject.resolve(toURL);
|
||||||
|
return openServiceWindow(provider, targetWindow, url, name, options);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openChatWindow: {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
value: function(toURL, callback) {
|
||||||
|
let url = targetWindow.document.documentURIObject.resolve(toURL);
|
||||||
|
openChatWindow(getChromeWindow(targetWindow), provider, url, callback);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getAttention: {
|
getAttention: {
|
||||||
|
@ -107,13 +117,7 @@ function attachToWindow(provider, targetWindow) {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
writable: true,
|
writable: true,
|
||||||
value: function() {
|
value: function() {
|
||||||
let mainWindow = targetWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
getChromeWindow(targetWindow).getAttention();
|
||||||
.getInterface(Components.interfaces.nsIWebNavigation)
|
|
||||||
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
|
|
||||||
.rootTreeItem
|
|
||||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Components.interfaces.nsIDOMWindow);
|
|
||||||
mainWindow.getAttention();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isVisible: {
|
isVisible: {
|
||||||
|
@ -152,12 +156,21 @@ function schedule(callback) {
|
||||||
Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
|
Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openServiceWindow(provider, contentWindow, url, name, options) {
|
function getChromeWindow(contentWin) {
|
||||||
|
return contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||||
|
.rootTreeItem
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureProviderOrigin(provider, url) {
|
||||||
// resolve partial URLs and check prePath matches
|
// resolve partial URLs and check prePath matches
|
||||||
let uri;
|
let uri;
|
||||||
let fullURL;
|
let fullURL;
|
||||||
try {
|
try {
|
||||||
fullURL = contentWindow.document.documentURIObject.resolve(url);
|
fullURL = Services.io.newURI(provider.origin, null, null).resolve(url);
|
||||||
uri = Services.io.newURI(fullURL, null, null);
|
uri = Services.io.newURI(fullURL, null, null);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
Cu.reportError("openServiceWindow: failed to resolve window URL: " + url + "; " + ex);
|
Cu.reportError("openServiceWindow: failed to resolve window URL: " + url + "; " + ex);
|
||||||
|
@ -169,25 +182,33 @@ function openServiceWindow(provider, contentWindow, url, name, options) {
|
||||||
provider.origin + " != " + uri.prePath);
|
provider.origin + " != " + uri.prePath);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return fullURL;
|
||||||
|
}
|
||||||
|
|
||||||
function getChromeWindow(contentWin) {
|
function openChatWindow(chromeWindow, provider, url, callback) {
|
||||||
return contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
if (!chromeWindow.SocialChatBar)
|
||||||
.getInterface(Ci.nsIWebNavigation)
|
return;
|
||||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
let fullURL = ensureProviderOrigin(provider, url);
|
||||||
.rootTreeItem
|
if (!fullURL)
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
return;
|
||||||
.getInterface(Ci.nsIDOMWindow);
|
chromeWindow.SocialChatBar.newChat(provider, fullURL, callback);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
function openServiceWindow(provider, contentWindow, url, name, options) {
|
||||||
let chromeWindow = Services.ww.getWindowByName("social-service-window-" + name,
|
// resolve partial URLs and check prePath matches
|
||||||
getChromeWindow(contentWindow));
|
let fullURL = ensureProviderOrigin(provider, url);
|
||||||
|
if (!fullURL)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let windowName = provider.origin + name;
|
||||||
|
let chromeWindow = Services.ww.getWindowByName(windowName, null);
|
||||||
let tabbrowser = chromeWindow && chromeWindow.gBrowser;
|
let tabbrowser = chromeWindow && chromeWindow.gBrowser;
|
||||||
if (tabbrowser &&
|
if (tabbrowser &&
|
||||||
tabbrowser.selectedBrowser.getAttribute("origin") == provider.origin) {
|
tabbrowser.selectedBrowser.getAttribute("origin") == provider.origin) {
|
||||||
return tabbrowser.contentWindow;
|
return tabbrowser.contentWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
let serviceWindow = contentWindow.openDialog(fullURL, name,
|
let serviceWindow = contentWindow.openDialog(fullURL, windowName,
|
||||||
"chrome=no,dialog=no" + options);
|
"chrome=no,dialog=no" + options);
|
||||||
|
|
||||||
// Get the newly opened window's containing XUL window
|
// Get the newly opened window's containing XUL window
|
||||||
|
@ -195,7 +216,7 @@ function openServiceWindow(provider, contentWindow, url, name, options) {
|
||||||
|
|
||||||
// set the window's name and origin attribute on its browser, so that it can
|
// set the window's name and origin attribute on its browser, so that it can
|
||||||
// be found via getWindowByName
|
// be found via getWindowByName
|
||||||
chromeWindow.name = "social-service-window-" + name;
|
chromeWindow.name = windowName;
|
||||||
chromeWindow.gBrowser.selectedBrowser.setAttribute("origin", provider.origin);
|
chromeWindow.gBrowser.selectedBrowser.setAttribute("origin", provider.origin);
|
||||||
|
|
||||||
// we dont want the default title the browser produces, we'll fixup whenever
|
// we dont want the default title the browser produces, we'll fixup whenever
|
||||||
|
|
Загрузка…
Ссылка в новой задаче