Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 908cd81ccf
Fetching contributors…

Cannot retrieve contributors at this time

798 lines (639 sloc) 24.777 kb
<?xml version="1.0"?>
<!DOCTYPE bindings [
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
]>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="chattabbox">
<resources>
<stylesheet src="chrome://oneteam/skin/chattabbox/chattabbox.css"/>
</resources>
<content>
<xul:tabbox flex="1">
<xul:tabs class="with-scroll" setfocus="false" anonid="tabs"/>
<xul:tabpanels anonid="tabpanels" flex="1"
onselect="if (event.originalTarget==this) this.selectedPanel.controller.focus()"/>
</xul:tabbox>
</content>
<implementation>
<property name="selectedTab" onget="return this._selectedTab"
readonly="true"/>
<property name="unseenCount" onget="return this._unseenCount || 0">
<setter><![CDATA[
if (val == this._unseenCount)
return val;
this._unseenCount = val;
if (val)
window.getAttention();
document.title = document.title.replace(/^(?:\* |\[\d+\] )?/,
val == 0 ? "" : val == 1 ? "* " : "["+val+"] ");
if (window.top.changeFavIcon)
window.top.changeFavIcon(val ? account.style.defaultSet.iconsMap["psi/message"] : null);
return val;
]]></setter>
</property>
<constructor><![CDATA[
this._tabs = document.getAnonymousElementByAttribute(this, "anonid", "tabs");
this._tabpanels = document.getAnonymousElementByAttribute(this, "anonid", "tabpanels");
this._inSelectTab = 0;
var _this = this;
recoverSetters(this);
window.addEventListener("focus", function(event) {
_this._windowFocusHandler(_this, event)
}, true);
window.addEventListener("blur", function(event) {
_this._windowBlurHandler(_this, event)
}, true);
window.addEventListener("keypress", function(event) {
if (event.charCode && _this._selectedTab) {
if (event.target.localName != "textbox" &&
event.target.localName != "chattabbox" &&
_this._selectedTab.controller._replayEventInInput(event)) {
_this._selectedTab.controller.focus();
event.preventDefault();
}
}
}, false);
]]></constructor>
<method name="openTab">
<parameter name="thread"/>
<body><![CDATA[
// Search for tab with this same jid (contact may lost track of chatpane
// after resource disconnection/connection
var tab, tabpanel;
var content = document.createElementNS(XULNS, "chattab-content");
content._tabbox = this;
tabpanel = content._tabpanel = document.createElementNS(XULNS, "tabpanel");
tabpanel.setAttribute("flex", "1");
this._tabpanels.appendChild(tabpanel);
tabpanel.appendChild(content);
tab = content._tab = document.createElementNS(XULNS, "tab");
tab.setAttribute("hasclosebutton", "true");
tab.setAttribute("oncommand", "this.controller.close()");
tab.maxWidth = 250;
tab.minWidth = 100;
tab.width = 0;
this._tabs.appendChild(tab);
// XXX: TEAM-63 hack
tab.setAttribute("last-tab", "true");
if (!tab.previousSibling)
tab.setAttribute("first-tab", "true");
else
tab.previousSibling.removeAttribute("last-tab");
content.thread = thread;
tabpanel.controller = content;
tab.controller = content;
this._selectTab(content);
var ev = document.createEvent("Events");
ev.initEvent("tab-added", true, false);
this.dispatchEvent(ev);
content.focus();
return content;
]]></body>
</method>
<method name="closeTabs">
<body><![CDATA[
this._inCloseTabs = true;
for (var i = this._tabs.childNodes.length-1; i >= 0; i--)
this._tabs.childNodes[i].controller.close();
this._selectedTab = null;
this._inCloseTabs = false;
]]></body>
</method>
<method name="_removeTab">
<parameter name="content"/>
<body><![CDATA[
if (!content._tab.parentNode)
return;
content.destroy();
if (this._inCloseTabs) {
content._tabpanel.parentNode.removeChild(content._tabpanel);
content._tab.parentNode.removeChild(content._tab);
var ev = document.createEvent("Events");
ev.initEvent("tab-removed", true, false);
this.dispatchEvent(ev);
return;
}
var nextTab = content._tab.selected ?
content._tab.nextSibling || content._tab.previousSibling :
content._tab.parentNode.selectedItem;
if (nextTab)
nextTab.controller.focus();
// XXX: TEAM-63 hack
if (content._tab.nextSibling) {
if (!content._tab.previousSibling)
content._tab.nextSibling.setAttribute("first-tab", "true");
} else if (content._tab.previousSibling)
content._tab.previousSibling.setAttribute("last-tab", "true");
content._tabpanel.parentNode.removeChild(content._tabpanel);
content._tab.parentNode.removeChild(content._tab);
if (nextTab)
nextTab.controller.focus();
else
this._selectedTab = null;
this._tabs._fixupScrollPosition();
var ev = document.createEvent("Events");
ev.initEvent("tab-removed", true, false);
this.dispatchEvent(ev);
]]></body>
</method>
<method name="_selectTab">
<parameter name="content"/>
<body><![CDATA[
if (this._inSelectTab)
return;
this._inSelectTab++;
// XXXpfx Tabbox doesn't fixup styles after focusing tab, we need
// to do this ourself.
for (var i = 0; i < this._tabs.childNodes.length; i++)
if (this._tabs.childNodes[i] == content._tab) {
this._tabs.selectedIndex = i;
this._tabpanels.selectedIndex = i;
break;
}
content._tab.controller.onActivate();
if (content._tab == this._selectedTab) {
this._tabs.scrollToTab(null, 1);
this._inSelectTab--;
return;
}
if (this._selectedTab) {
this._selectedTab.removeAttribute("selected");
if (this._selectedTab.previousSibling)
this._selectedTab.previousSibling.removeAttribute("beforeselected");
if (this._selectedTab.nextSibling)
this._selectedTab.nextSibling.removeAttribute("afterselected");
this._selectedTab.controller.onDeactivate();
}
this._selectedTab = content._tab;
content._tab.setAttribute("selected", "true");
if (content._tab.previousSibling)
content._tab.previousSibling.setAttribute("beforeselected", "true");
if (content._tab.nextSibling)
content._tab.nextSibling.setAttribute("afterselected", "true");
this._inSelectTab--;
this._tabs.scrollToTab(null, 1);
]]></body>
</method>
<method name="_windowFocusHandler">
<parameter name="_this"/>
<parameter name="event"/>
<body><![CDATA[
if (!("nodeType" in event.target) || event.target.nodeType != 9)
return;
if (_this._blurTimeout) {
clearTimeout(_this._blurTimeout);
_this._blurTimeout = null;
}
if (!_this._windowHasFocus && !_this._focusTimeout)
_this._focusTimeout = setTimeout(function(_this) {
_this._focusTimeout = null;
_this._windowHasFocus = true;
_this._onWindowFocus();
}, 50, _this);
]]></body>
</method>
<method name="_windowBlurHandler">
<parameter name="_this"/>
<parameter name="event"/>
<body><![CDATA[
if (!("nodeType" in event.target) || event.target.nodeType != 9 || _this._blurTimeout)
return;
_this._blurTimeout = setTimeout(function(_this) {
if (_this._focusTimeout) {
clearTimeout(_this._focusTimeout);
_this._focusTimeout = null;
}
_this._blurTimeout = null;
if (_this._windowHasFocus) {
_this._windowHasFocus = false;
_this._onWindowBlur();
}
}, 50, _this);
]]></body>
</method>
<method name="_onWindowFocus">
<body><![CDATA[
if (this._selectedTab)
this._selectedTab.controller.focused();
]]></body>
</method>
<method name="_onWindowBlur">
<body><![CDATA[
if (this._selectedTab)
this._selectedTab.controller.blured();
]]></body>
</method>
</implementation>
</binding>
<binding id="chattab-content" display="xul:vbox">
<content flex="1">
<xul:chatpane anonid="chatpane" flex="1"/>
</content>
<implementation>
<property name="thread" onget="return this._thread">
<setter><![CDATA[
if (this._thread == val)
return;
if (this._thread && this._thread.unseenCount)
this._onUnseenCountChange(null, null, {diff: -this._thread.unseenCount});
this._thread = val;
this._chatpane.model = val;
if (val && val.unseenCount)
this._onUnseenCountChange(null, null, {diff: val.unseenCount});
if (val && this._chatpane.visible)
val.visible = true;
this._onNameChange();
this._onPeerChatStateChange();
this._regBundle.unregister();
if (val) {
this._regBundle.register(val.contact, this._onNameChange, "visibleName");
this._regBundle.register(val, this._onUnseenCountChange, "unseenCount");
this._regBundle.register(val, this._onPeerChatStateChange, "peerChatState");
}
]]></setter>
</property>
<constructor><![CDATA[
this._regBundle = new RegsBundle(this);
this._chatpane = document.getAnonymousElementByAttribute(this, "anonid", "chatpane");
this._chatpane.focusHandler = this._tabbox;
recoverSetters(this);
this.closed = false;
]]></constructor>
<destructor><![CDATA[
this.destroy();
]]></destructor>
<method name="destroy">
<body><![CDATA[
this._regBundle.unregister();
this._chatpane.model = null;
]]></body>
</method>
<method name="close">
<body><![CDATA[
this.closed = true;
if (this._activateTimer) {
clearTimeout(this._activateTimer);
delete this._activateTimer;
}
if (this.thread)
this.thread._onChatPaneClosed();
this._updateChatState("gone");
if (this.thread && this.thread.contact instanceof Conference)
this.thread.contact.exitRoom();
this._tabbox._removeTab(this);
]]></body>
</method>
<method name="focus">
<body><![CDATA[
if (this.closed || this._inFocus)
return;
this.focused();
this._chatpane.focus();
]]></body>
</method>
<method name="focused">
<body><![CDATA[
if (this.closed || this._inFocus)
return;
this._inFocus = true;
this._tabbox._selectTab(this);
delete this._inFocus;
this.onActivate();
]]></body>
</method>
<method name="blured">
<body><![CDATA[
this.onDeactivate();
]]></body>
</method>
<method name="onActivate">
<body><![CDATA[
if (this.closed)
return;
try {
this._chatpane.visible = true;
} catch (ex) {}
if (!this._activateTimer) {
this._activateTimer = setTimeout(function(_this) {
delete _this._activateTimer;
if (!_this.closed)
_this._updateChatState("active");
}, 1000, this);
}
]]></body>
</method>
<method name="onDeactivate">
<body><![CDATA[
if (this._activateTimer) {
clearTimeout(this._activateTimer);
delete this._activateTimer;
}
if (this.closed)
return;
try {
this._chatpane.visible = false;
} catch (ex) {}
]]></body>
</method>
<method name="_updateChatState">
<parameter name="state"/>
<parameter name="_this"/>
<body><![CDATA[
if (!_this)
_this = this;
if (!_this.thread || !_this.thread.peerHandlesChatState)
return;
if (_this._chatStateTimeout) {
clearTimeout(_this._chatStateTimeout);
this._chatStateTimeout = null;
}
if (state == "composing")
_this._chatStateTimeout = setTimeout(_this._updateChatState, 5000, "paused", _this);
if (state == "active" || state == "paused")
_this._chatStateTimeout = setTimeout(_this._updateChatState, 30000, "inactive", _this);
_this.thread.chatState = state;
]]></body>
</method>
<method name="_onPeerChatStateChange">
<body><![CDATA[
if (this._chatpane._contactInfo && this._chatpane._contactInfo.updateChatState)
this._chatpane._contactInfo.updateChatState((this._thread && this._thread.peerChatState) || "");
this._syncTabColor();
]]></body>
</method>
<method name="_appendToInput">
<parameter name="str"/>
<body><![CDATA[
this._chatpane._input._append(str);
]]></body>
</method>
<method name="_replayEventInInput">
<parameter name="event"/>
<body><![CDATA[
return this._chatpane._input._replayEvent(event);
]]></body>
</method>
<method name="_onNameChange">
<body><![CDATA[
var count = this._thread ? this._thread.unseenCount : 0;
var countStr = !count ? "" : count == 1 ?
"* " : "["+count+"] ";
this._tab.setAttribute("label", countStr + (this._thread ? this._thread.contact.visibleName : ""));
]]></body>
</method>
<method name="_syncTabColor">
<body><![CDATA[
if (this._thread.unseenCount)
this._tab.setAttribute("chatstate", "modified");
else if (this._thread.peerChatState == "composing")
this._tab.setAttribute("chatstate", "composing");
else
this._tab.removeAttribute("chatstate");
]]></body>
</method>
<method name="_onUnseenCountChange">
<parameter name="model"/>
<parameter name="name"/>
<parameter name="arg"/>
<body><![CDATA[
this._tabbox.unseenCount += arg.diff;
this._syncTabColor();
this._onNameChange();
return this._tabbox.unseenCount;
]]></body>
</method>
</implementation>
<handlers>
<handler event="userTyping"><![CDATA[
this._updateChatState(event.originalTarget.isEmpty ? "active" : "composing");
]]></handler>
</handlers>
</binding>
<binding id="tabs-with-scroll"
extends="chrome://global/content/bindings/tabbox.xml#tabs">
<resources>
<stylesheet src="chrome://oneteam/skin/chattabbox/chattabbox.css"/>
</resources>
<content>
<xul:toolbarbutton id="scroll-left-button" collapsed="true"
onmousedown="this.parentNode._startScrolling(-1)"
onmouseup="this.parentNode._stopScrolling()"
onmouseout="this.parentNode._stopScrolling()"/>
<xul:scrollbox anonid="scrollbox" orient="horizontal" flex="1" style="min-width: 1px;">
<children includes="tab"/>
</xul:scrollbox>
<xul:toolbarbutton id="scroll-right-button" collapsed="true"
onmousedown="this.parentNode._startScrolling(1)"
onmouseup="this.parentNode._stopScrolling()"
onmouseout="this.parentNode._stopScrolling()"/>
</content>
<implementation>
<property name="_scrollBoxObject" readonly="true"
onget="return this._scrollBox.boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject)"/>
<constructor><![CDATA[
this._scrollLeft = document.getAnonymousElementByAttribute(this, "id", "scroll-left-button");
this._scrollRight = document.getAnonymousElementByAttribute(this, "id", "scroll-right-button");
this._scrollBox = document.getAnonymousElementByAttribute(this, "anonid", "scrollbox");
var me = this;
window.addEventListener("resize", function(){me.scrollToTab(null, 2)}, false);
]]></constructor>
<method name="scrollToTab">
<parameter name="tab"/>
<parameter name="scrollMode"/>
<body><![CDATA[
var pos = {}, size = {};
this._scrollBoxObject.getPosition(pos, {});
this._scrollBoxObject.getScrolledSize(size, {});
pos = pos.value;
size = size.value;
var posw = pos + this._scrollBox.boxObject.width;
if (!tab && this.selectedIndex >= 0)
tab = this.childNodes[this.selectedIndex];
if (!tab) {
this._fixupScrollPosition();
return;
}
var x = tab.boxObject.x - this.childNodes[0].boxObject.x;
var xw = x + tab.boxObject.width;
var endPos;
if (xw > posw)
endPos = xw + pos - posw;
else if (x < pos)
endPos = x - 3;
if (endPos == null) {
this._fixupScrollPosition();
return;
}
if (scrollMode == 2 || scrollMode == 1 && Math.abs(pos-endPos) > 150)
this._scrollTo(endPos);
else {
this._startScrollPos = pos;
this._endScrollPos = endPos;
if (!this._scrolling) {
this._scrollSpeed = pos < endPos ? 1 : -1;
this._scrollFun(this);
}
}
]]></body>
</method>
<method name="_startScrolling">
<parameter name="direction"/>
<body><![CDATA[
var pos = {}, size = {};
this._scrollBoxObject.getPosition(pos, {});
this._scrollBoxObject.getScrolledSize(size, {});
if (direction > 0) {
if (size.value == pos.value)
return;
} else if (pos.value == 0)
return;
this._startScrollPos = pos.value;
this._endScrollPos = direction > 0 ?
size.value - this._scrollBox.boxObject.width : 0;
this._userScrolling = true;
if (!this._scrolling) {
this._scrollSpeed = direction > 0 ? 1 : -1;
this._scrollFun(this);
}
]]></body>
</method>
<method name="_stopScrolling">
<body><![CDATA[
if (!this._userScrolling)
return;
var pos = {}, newPos, size = {};
this._scrollBoxObject.getPosition(pos, {});
pos = pos.value;
this._userScrolling = false;
var tabs = this.childNodes;
var leftMargin = tabs[0].boxObject.x + 3;
for (var i = 0; i < tabs.length; i++)
if (tabs[i].boxObject.x-leftMargin > pos) {
this._endScrollPos = this._scrollSpeed > 0 ?
tabs[i].boxObject.x-leftMargin : i > 0 ?
tabs[i-1].boxObject.x-leftMargin : 0;
break;
}
]]></body>
</method>
<method name="_scrollFun">
<parameter name="me"/>
<body><![CDATA[
var pos = {}, newPos, size = {};
me._scrollBoxObject.getPosition(pos, {});
pos = pos.value;
newPos = pos + Math.ceil(me._scrollSpeed);
if ((me._scrollSpeed > 0 && newPos >= me._endScrollPos) ||
(me._scrollSpeed < 0 && newPos <= me._endScrollPos))
{
me._scrolling = false;
me._scrollTo(me._endScrollPos);
return;
}
if (me._scrollTo(newPos, 0)) {
me._scrolling = false;
return;
}
var ds = newPos - me._startScrollPos, de = me._endScrollPos - newPos;
var accel = (ds*de/(ds+de)/(ds+de)*4*5)*(ds > 0 ? 1 : -1);
var newSpeed = me._scrollSpeed + accel;
if (newSpeed < 12 && newSpeed > -12 && newSpeed != 0)
me._scrollSpeed = newSpeed;
me._scrolling = true;
setTimeout(me._scrollFun, 10, me);
]]></body>
</method>
<method name="_scrollTo">
<parameter name="position"/>
<body><![CDATA[
var pos = {}, size = {};
this._scrollBoxObject.scrollTo(position, 0);
this._scrollBoxObject.getPosition(pos, {});
this._scrollBoxObject.getScrolledSize(size, {});
this._scrollLeft.disabled = pos.value == 0;
this._scrollRight.disabled = pos.value + this._scrollBox.boxObject.width == size.value;
var onEdge = this._scrollLeft.disabled || this._scrollRight.disabled;
if (onEdge)
this._userScrolling = false;
return onEdge;
]]></body>
</method>
<method name="_fixupScrollPosition">
<body><![CDATA[
try {
var pos = {}, size = {}, posw;
this._scrollBoxObject.getPosition(pos, {});
this._scrollBoxObject.getScrolledSize(size, {});
pos = pos.value;
posw = pos + this._scrollBox.boxObject.width;
size = size.value;
if (posw > size)
this._scrollTo(size);
else if (size < posw - pos)
this._scrollTo(0, 0);
} catch (ex) {}
]]></body>
</method>
<method name="handleEvent">
<parameter name="event"/>
<body><![CDATA[
this.fixupScrollPosition();
]]></body>
</method>
</implementation>
<handlers>
<handler event="overflow"><![CDATA[
if (event.originalTarget != this._scrollBox || event.detail == 0)
return;
try {
this._scrollLeft.collapsed = false;
this._scrollRight.collapsed = false;
this.scrollToTab(null, 2);
} catch (ex) {}
]]></handler>
<handler event="underflow"><![CDATA[
if (event.originalTarget != this._scrollBox || event.detail == 0)
return;
try {
this._scrollLeft.collapsed = true;
this._scrollRight.collapsed = true;
} catch(ex) {}
]]></handler>
</handlers>
</binding>
<binding id="tab-with-close-button" extends="chrome://global/content/bindings/tabbox.xml#tab"
display="xul:box">
<resources>
<stylesheet src="chrome://oneteam/skin/chattabbox/chattabbox.css"/>
</resources>
<content chromedir="&locale.dir;" class="tab-content" flex="100">
<xul:hbox class="tab-middle box-inherit" xbl:inherits="align,dir,pack,orient,selected"
flex="1">
<xul:image class="tab-icon" xbl:inherits="validate,src=image"/>
<xul:label class="tab-text" crop="end" xbl:inherits="value=label,accesskey,crop,disabled"
flex="100"/>
</xul:hbox>
<xul:toolbarbutton tabindex="-1" class="closebutton"/>
</content>
<implementation>
<constructor><![CDATA[
this._closebutton = document.getAnonymousElementByAttribute(this, "class", "closebutton");
]]></constructor>
</implementation>
<handlers>
<handler event="mousedown" button="0" phase="capturing"><![CDATA[
if (event.originalTarget == this._closebutton) {
event.stopPropagation();
}
]]></handler>
<handler event="mouseup"><![CDATA[
if (event.button == 1 || event.button == 0 && event.ctrlKey)
this._closebutton.doCommand();
]]></handler>
</handlers>
</binding>
</bindings>
Jump to Line
Something went wrong with that request. Please try again.