home *** CD-ROM | disk | FTP | other *** search
- <?xml version="1.0"?>
-
- <!DOCTYPE bindings [
- <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
- %globalDTD;
- ]>
-
- <bindings id="arrowscrollboxBindings"
- xmlns="http://www.mozilla.org/xbl"
- xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- xmlns:xbl="http://www.mozilla.org/xbl">
-
- <binding id="scrollbox-base" extends="chrome://global/content/bindings/general.xml#basecontrol">
- <resources>
- <stylesheet src="chrome://global/skin/scrollbox.css"/>
- </resources>
- </binding>
-
- <binding id="scrollbox" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
- <content>
- <xul:box class="box-inherit scrollbox-innerbox" xbl:inherits="orient,align,pack,dir" flex="1">
- <children/>
- </xul:box>
- </content>
- </binding>
-
- <binding id="arrowscrollbox" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
- <content>
- <xul:autorepeatbutton class="autorepeatbutton-up"
- anonid="scrollbutton-up"
- collapsed="true"
- xbl:inherits="orient"
- oncommand="_autorepeatbuttonScroll(event);"/>
- <xul:scrollbox xbl:inherits="orient,align,pack,dir" flex="1" anonid="scrollbox">
- <children/>
- </xul:scrollbox>
- <xul:autorepeatbutton class="autorepeatbutton-down"
- anonid="scrollbutton-down"
- collapsed="true"
- xbl:inherits="orient"
- oncommand="_autorepeatbuttonScroll(event);"/>
- </content>
-
- <implementation>
- <field name="_scrollbox">
- document.getAnonymousElementByAttribute(this, "anonid", "scrollbox");
- </field>
- <field name="_scrollButtonUp">
- document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-up");
- </field>
- <field name="_scrollButtonDown">
- document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-down");
- </field>
-
- <field name="__prefBranch">null</field>
- <property name="_prefBranch" readonly="true">
- <getter><![CDATA[
- if (this.__prefBranch === null) {
- this.__prefBranch = Components.classes['@mozilla.org/preferences-service;1']
- .getService(Components.interfaces.nsIPrefBranch2);
- }
- return this.__prefBranch;
- ]]></getter>
- </property>
-
- <field name="_scrollIncrement">null</field>
- <property name="scrollIncrement" readonly="true">
- <getter><![CDATA[
- if (this._scrollIncrement === null) {
- try {
- this._scrollIncrement = this._prefBranch
- .getIntPref("toolkit.scrollbox.scrollIncrement");
- }
- catch (ex) {
- this._scrollIncrement = 20;
- }
- }
- return this._scrollIncrement;
- ]]></getter>
- </property>
-
- <field name="_smoothScroll">null</field>
- <property name="smoothScroll">
- <getter><![CDATA[
- if (this._smoothScroll === null) {
- if (this.hasAttribute("smoothscroll")) {
- this._smoothScroll = (this.getAttribute("smoothscroll") == "true");
- } else {
- try {
- this._smoothScroll = this._prefBranch
- .getBoolPref("toolkit.scrollbox.smoothScroll");
- }
- catch (ex) {
- this._smoothScroll = true;
- }
- }
- }
- return this._smoothScroll;
- ]]></getter>
- <setter><![CDATA[
- this._smoothScroll = val;
- return val;
- ]]></setter>
- </property>
-
- <field name="_scrollBoxObject">null</field>
- <property name="scrollBoxObject" readonly="true">
- <getter><![CDATA[
- if (!this._scrollBoxObject) {
- this._scrollBoxObject =
- this._scrollbox.boxObject
- .QueryInterface(Components.interfaces.nsIScrollBoxObject);
- }
- return this._scrollBoxObject;
- ]]></getter>
- </property>
-
- <field name="_isLTRScrollbox">
- document.defaultView.getComputedStyle(this._scrollbox, "").direction == "ltr";
- </field>
-
- <method name="ensureElementIsVisible">
- <parameter name="element"/>
- <body><![CDATA[
- if (!this.smoothScroll || this.getAttribute("orient") == "vertical") {
- this.scrollBoxObject.ensureElementIsVisible(element);
- return;
- }
-
- var rect = this._scrollbox.getBoundingClientRect();
- var containerStart = rect.left;
- var containerEnd = rect.right;
- rect = element.getBoundingClientRect();
- var elementStart = rect.left;
- var elementEnd = rect.right;
- var amountToScroll;
-
- if (elementStart < containerStart) {
- amountToScroll = elementStart - containerStart;
- } else if (containerEnd < elementEnd) {
- amountToScroll = elementEnd - containerEnd;
- } else if (this._isScrolling) {
- // decelerate if a currently-visible element is selected during the scroll
- const STOP_DISTANCE = 15;
- if (this._isScrolling == -1 && elementStart - STOP_DISTANCE < containerStart)
- amountToScroll = elementStart - containerStart;
- else if (this._isScrolling == 1 && containerEnd - STOP_DISTANCE < elementEnd)
- amountToScroll = elementEnd - containerEnd;
- else
- amountToScroll = this._isScrolling * STOP_DISTANCE;
- } else {
- return;
- }
-
- this._smoothScrollByPixels(amountToScroll);
- ]]></body>
- </method>
-
- <method name="_smoothScrollByPixels">
- <parameter name="amountToScroll"/>
- <body><![CDATA[
- this._stopSmoothScroll();
-
- // Positive amountToScroll makes us scroll right (elements fly left), negative scrolls left.
- var round;
- if (amountToScroll < 0) {
- this._isScrolling = -1;
- round = Math.floor;
- } else {
- this._isScrolling = 1;
- round = Math.ceil;
- }
-
- const FRAME_LENGTH = 60;
-
- function processFrame(self, scrollAmounts, off) {
- var distance = scrollAmounts.shift();
-
- // Skip frames if we aren't getting the desired frame rate.
- if (off > 0) {
- for (var i = Math.round(off / FRAME_LENGTH); i > 0; i--)
- distance += scrollAmounts.shift() || 0;
- }
-
- self.scrollBoxObject.scrollBy(distance, 0);
- if (!scrollAmounts.length)
- self._stopSmoothScroll();
- }
-
- // amountToScroll: total distance to scroll
- // scrollAmount: distance to move during the particular effect frame (60ms)
- var scrollAmount, scrollAmounts = [];
- if (amountToScroll > 2 || amountToScroll < -2) {
- scrollAmount = round(amountToScroll * 0.2);
- scrollAmounts.push(scrollAmount, scrollAmount, scrollAmount);
- amountToScroll -= 3 * scrollAmount;
- }
- while (this._isScrolling < 0 && amountToScroll < 0 ||
- this._isScrolling > 0 && amountToScroll > 0) {
- amountToScroll -= (scrollAmount = round(amountToScroll * 0.5));
- scrollAmounts.push(scrollAmount);
- }
- this._smoothScrollTimer = setInterval(processFrame, FRAME_LENGTH, this, scrollAmounts);
- processFrame(this, scrollAmounts, 0);
- ]]></body>
- </method>
-
- <method name="scrollByIndex">
- <parameter name="index"/>
- <body><![CDATA[
- if (index == 0)
- return;
- if (this.getAttribute("orient") == "vertical") {
- this.scrollBoxObject.scrollByIndex(index);
- return;
- }
-
- var x;
- if (index > 0)
- x = this._scrollbox.getBoundingClientRect().right + 1;
- else
- x = this._scrollbox.getBoundingClientRect().left - 1;
- var nextElement = this._elementFromPoint(x);
- if (!nextElement)
- return;
-
- var targetElement;
- if (!this._isLTRScrollbox)
- index *= -1;
-
- while (index < 0 && nextElement) {
- targetElement = nextElement;
- nextElement = nextElement.previousSibling;
- index++;
- }
- while (index > 0 && nextElement) {
- targetElement = nextElement;
- nextElement = nextElement.nextSibling;
- index--;
- }
-
- this.ensureElementIsVisible(targetElement);
- ]]></body>
- </method>
-
- <method name="_elementFromPoint">
- <parameter name="aX"/>
- <body><![CDATA[
- var elements = this.hasChildNodes() ?
- this.childNodes :
- document.getBindingParent(this).childNodes;
- if (!this._isLTRScrollbox) {
- elements = Array.slice(elements);
- elements.reverse();
- }
- var low = 0;
- var high = elements.length - 1;
-
- while (low <= high) {
- var mid = Math.floor((low + high) / 2);
- var element = elements[mid];
- var rect = element.getBoundingClientRect();
- if (rect.left > aX)
- high = mid - 1;
- else if (rect.right < aX)
- low = mid + 1;
- else
- return element;
- }
-
- return null;
- ]]></body>
- </method>
-
- <method name="_autorepeatbuttonScroll">
- <parameter name="event"/>
- <body><![CDATA[
- var dir = event.originalTarget == this._scrollButtonUp ? -1 : 1;
- if (this.getAttribute("orient") == "horizontal" && !this._isLTRScrollbox)
- dir *= -1;
-
- this.scrollByPixels(this.scrollIncrement * dir);
-
- event.stopPropagation();
- ]]></body>
- </method>
-
- <method name="scrollByPixels">
- <parameter name="px"/>
- <body><![CDATA[
- if (this.getAttribute("orient") == "horizontal")
- this.scrollBoxObject.scrollBy(px, 0);
- else
- this.scrollBoxObject.scrollBy(0, px);
- ]]></body>
- </method>
-
- <!-- 0: idle
- 1: scrolling right
- -1: scrolling left -->
- <field name="_isScrolling">0</field>
- <field name="_smoothScrollTimer">0</field>
-
- <method name="_stopSmoothScroll">
- <body><![CDATA[
- clearInterval(this._smoothScrollTimer);
- this._isScrolling = 0;
- ]]></body>
- </method>
-
- <method name="_updateScrollButtonsDisabledState">
- <body><![CDATA[
- var disableUpButton = false;
- var disableDownButton = false;
-
- if (this.getAttribute("orient") == "horizontal") {
- var width = {};
- this.scrollBoxObject.getScrolledSize(width, {});
- var xPos = {};
- this.scrollBoxObject.getPosition(xPos, {});
- if (xPos.value == 0) {
- // In the RTL case, this means the _last_ element in the
- // scrollbox is visible
- if (this._isLTRScrollbox)
- disableUpButton = true;
- else
- disableDownButton = true;
- }
- else if (this._scrollbox.boxObject.width + xPos.value == width.value) {
- // In the RTL case, this means the _first_ element in the
- // scrollbox is visible
- if (this._isLTRScrollbox)
- disableDownButton = true;
- else
- disableUpButton = true;
- }
- }
- else { // vertical scrollbox
- var height = {};
- this.scrollBoxObject.getScrolledSize({}, height);
- var yPos = {};
- this.scrollBoxObject.getPosition({}, yPos);
- if (yPos.value == 0)
- disableUpButton = true;
- else if (this._scrollbox.boxObject.height + yPos.value == height.value)
- disableDownButton = true;
- }
-
- if (this._scrollButtonUp.disabled != disableUpButton ||
- this._scrollButtonDown.disabled != disableDownButton) {
- this._scrollButtonUp.disabled = disableUpButton;
- this._scrollButtonDown.disabled = disableDownButton;
-
- var event = document.createEvent("Events");
- event.initEvent("UpdatedScrollButtonsDisabledState", true, false);
- this.dispatchEvent(event);
- }
- ]]></body>
- </method>
- </implementation>
-
- <handlers>
- <handler event="DOMMouseScroll" action="this.scrollByIndex(event.detail); event.stopPropagation();"/>
-
- <handler event="underflow"><![CDATA[
- // filter underflow events which were dispatched on nested scrollboxes
- if (event.target != this)
- return;
-
- // Ignore events that doesn't match our orientation.
- // Scrollport event orientation:
- // 0: vertical
- // 1: horizontal
- // 2: both
- if (this.getAttribute("orient") == "horizontal") {
- if (event.detail == 0) {
- return;
- }
- }
- else { // vertical scrollbox
- if (event.detail == 1) {
- return;
- }
- }
-
- this._scrollButtonUp.collapsed = true;
- this._scrollButtonDown.collapsed = true;
- try {
- // See bug 341047 and comments in overflow handler as to why
- // try..catch is needed here
- var childNodes = document.getAnonymousNodes(this._scrollbox);
- if (childNodes && childNodes.length)
- this.scrollBoxObject.ensureElementIsVisible(childNodes[0]);
- }
- catch(e) {
- this._scrollButtonUp.collapsed = false;
- this._scrollButtonDown.collapsed = false;
- }
- ]]></handler>
-
- <handler event="overflow"><![CDATA[
- // filter underflow events which were dispatched on nested scrollboxes
- if (event.target != this)
- return;
-
- // Ignore events that doesn't match our orientation.
- // Scrollport event orientation:
- // 0: vertical
- // 1: horizontal
- // 2: both
- if (this.getAttribute("orient") == "horizontal") {
- if (event.detail == 0) {
- return;
- }
- }
- else { // vertical scrollbox
- if (event.detail == 1) {
- return;
- }
- }
-
- this._scrollButtonUp.collapsed = false;
- this._scrollButtonDown.collapsed = false;
- try {
- // See bug 341047, the overflow event is dispatched when the
- // scrollbox already is mostly destroyed. This causes some code in
- // _updateScrollButtonsDisabledState() to throw an error. It also
- // means that the scrollbarbuttons were uncollapsed when that should
- // not be happening, because the whole overflow event should not be
- // happening in that case.
- this._updateScrollButtonsDisabledState();
- }
- catch(e) {
- this._scrollButtonUp.collapsed = true;
- this._scrollButtonDown.collapsed = true;
- }
- ]]></handler>
-
- <handler event="scroll" action="this._updateScrollButtonsDisabledState()"/>
- </handlers>
- </binding>
-
- <binding id="autorepeatbutton" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
- <content repeat="hover" chromedir="&locale.dir;">
- <xul:image class="autorepeatbutton-icon"/>
- </content>
- </binding>
-
- <binding id="arrowscrollbox-clicktoscroll" extends="chrome://global/content/bindings/scrollbox.xml#arrowscrollbox">
- <content>
- <xul:toolbarbutton class="scrollbutton-up" collapsed="true"
- xbl:inherits="orient"
- anonid="scrollbutton-up"
- onclick="_distanceScroll(event);"
- onmousedown="_startScroll(-1);"
- onmouseover="_continueScroll(-1);"
- onmouseup="_stopScroll();"
- onmouseout="_pauseScroll();"
- chromedir="&locale.dir;"/>
- <xul:scrollbox xbl:inherits="orient,align,pack,dir" flex="1" anonid="scrollbox">
- <children/>
- </xul:scrollbox>
- <xul:toolbarbutton class="scrollbutton-down" collapsed="true"
- xbl:inherits="orient"
- anonid="scrollbutton-down"
- onclick="_distanceScroll(event);"
- onmousedown="_startScroll(1);"
- onmouseover="_continueScroll(1);"
- onmouseup="_stopScroll();"
- onmouseout="_pauseScroll();"
- chromedir="&locale.dir;"/>
- </content>
- <implementation implements="nsITimerCallback, nsIDOMEventListener">
- <constructor><![CDATA[
- try {
- this._scrollDelay = this._prefBranch
- .getIntPref("toolkit.scrollbox.clickToScroll.scrollDelay");
- }
- catch (ex) {
- }
- ]]></constructor>
-
- <destructor><![CDATA[
- // Release timer to avoid reference cycles.
- if (this._scrollTimer) {
- this._scrollTimer.cancel();
- this._scrollTimer = null;
- }
- ]]></destructor>
-
- <field name="_scrollIndex">0</field>
- <field name="_scrollDelay">150</field>
-
- <method name="notify">
- <parameter name="aTimer"/>
- <body>
- <![CDATA[
- if (!document)
- aTimer.cancel();
-
- if (this.smoothScroll)
- this.scrollByPixels(25 * this._scrollIndex);
- else
- this.scrollBoxObject.scrollByIndex(this._scrollIndex);
- ]]>
- </body>
- </method>
-
- <method name="_startScroll">
- <parameter name="index"/>
- <body><![CDATA[
- if (this.getAttribute("orient") == "horizontal" && !this._isLTRScrollbox)
- index *= -1;
- this._scrollIndex = index;
- var scrollDelay = this.smoothScroll ? 60 : this._scrollDelay;
- if (!this._scrollTimer)
- this._scrollTimer =
- Components.classes["@mozilla.org/timer;1"]
- .createInstance(Components.interfaces.nsITimer);
- else
- this._scrollTimer.cancel();
-
- this._scrollTimer.initWithCallback(this, scrollDelay,
- this._scrollTimer.TYPE_REPEATING_SLACK);
- this.notify(this._scrollTimer);
- this._mousedown = true;
- ]]>
- </body>
- </method>
-
- <method name="_stopScroll">
- <body><![CDATA[
- if (this._scrollTimer)
- this._scrollTimer.cancel();
- this._mousedown = false;
- if (!this._scrollIndex || !this.smoothScroll)
- return;
-
- this.scrollByIndex(this._scrollIndex);
- this._scrollIndex = 0;
- ]]></body>
- </method>
-
- <method name="_pauseScroll">
- <body><![CDATA[
- if (this._mousedown) {
- this._stopScroll();
- this._mousedown = true;
- document.addEventListener("mouseup", this, false);
- document.addEventListener("blur", this, true);
- }
- ]]></body>
- </method>
-
- <method name="_continueScroll">
- <parameter name="index"/>
- <body><![CDATA[
- if (this._mousedown)
- this._startScroll(index);
- ]]></body>
- </method>
-
- <method name="handleEvent">
- <parameter name="aEvent"/>
- <body><![CDATA[
- if (aEvent.type == "mouseup" ||
- aEvent.type == "blur" && aEvent.target == document) {
- this._mousedown = false;
- document.removeEventListener("mouseup", this, false);
- document.removeEventListener("blur", this, true);
- }
- ]]></body>
- </method>
-
- <method name="_distanceScroll">
- <parameter name="aEvent"/>
- <body><![CDATA[
- if (this.getAttribute("orient") == "vertical" ||
- aEvent.detail < 2 || aEvent.detail > 3)
- return;
-
- var scrollLeft = (aEvent.originalTarget == this._scrollButtonUp);
- if (!this._isLTRScrollbox)
- scrollLeft = !scrollLeft;
- var targetElement;
-
- if (aEvent.detail == 2) {
- // scroll by the width of the scrollbox; make sure that the next
- // partly-hidden element will become fully visible.
- var rect = this._scrollbox.getBoundingClientRect();
- var x;
- if (scrollLeft)
- x = rect.left - (rect.right - rect.left);
- else
- x = rect.right + (rect.right - rect.left);
- targetElement = this._elementFromPoint(x);
-
- if (targetElement)
- targetElement = scrollLeft ?
- targetElement.nextSibling :
- targetElement.previousSibling;
- }
-
- if (!targetElement) {
- // scroll to the first resp. last element
- var container = this.hasChildNodes() ? this : document.getBindingParent(this);
- targetElement = (this._isLTRScrollbox ? scrollLeft : !scrollLeft) ?
- container.firstChild :
- container.lastChild;
- }
-
- this.ensureElementIsVisible(targetElement);
- ]]></body>
- </method>
-
- </implementation>
- </binding>
- </bindings>
-