!import
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1 <?xml version="1.0"?>
2
3 <!DOCTYPE bindings [
4 <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
5 %globalDTD;
6 ]>
7
8 <bindings id="arrowscrollboxBindings"
9 xmlns="http://www.mozilla.org/xbl"
10 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
11 xmlns:xbl="http://www.mozilla.org/xbl">
12
13 <binding id="scrollbox-base" extends="chrome://global/content/bindings/general.xml#basecontrol">
14 <resources>
15 <stylesheet src="chrome://global/skin/scrollbox.css"/>
16 </resources>
17 </binding>
18
19 <binding id="scrollbox" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
20 <content>
21 <xul:box class="box-inherit scrollbox-innerbox" xbl:inherits="orient,align,pack,dir" flex="1">
22 <children/>
23 </xul:box>
24 </content>
25 </binding>
26
27 <binding id="arrowscrollbox" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
28 <content>
29 <xul:autorepeatbutton class="autorepeatbutton-up"
30 anonid="scrollbutton-up"
31 collapsed="true"
32 xbl:inherits="orient"
33 oncommand="_autorepeatbuttonScroll(event);"/>
34 <xul:scrollbox xbl:inherits="orient,align,pack,dir" flex="1" anonid="scrollbox">
35 <children/>
36 </xul:scrollbox>
37 <xul:autorepeatbutton class="autorepeatbutton-down"
38 anonid="scrollbutton-down"
39 collapsed="true"
40 xbl:inherits="orient"
41 oncommand="_autorepeatbuttonScroll(event);"/>
42 </content>
43
44 <implementation>
field__scrollbox
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
45 <field name="_scrollbox">
46 document.getAnonymousElementByAttribute(this, "anonid", "scrollbox");
47 </field>
field__scrollButtonUp
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
48 <field name="_scrollButtonUp">
49 document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-up");
50 </field>
field__scrollButtonDown
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
51 <field name="_scrollButtonDown">
52 document.getAnonymousElementByAttribute(this, "anonid", "scrollbutton-down");
53 </field>
54
field___prefBranch
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
55 <field name="__prefBranch">null</field>
56 <property name="_prefBranch" readonly="true">
get__prefBranch
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
57 <getter><![CDATA[
58 if (this.__prefBranch === null) {
59 this.__prefBranch = Components.classes['@mozilla.org/preferences-service;1']
60 .getService(Components.interfaces.nsIPrefBranch2);
61 }
62 return this.__prefBranch;
63 ]]></getter>
64 </property>
65
field__scrollIncrement
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
66 <field name="_scrollIncrement">null</field>
67 <property name="scrollIncrement" readonly="true">
get_scrollIncrement
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
68 <getter><![CDATA[
69 if (this._scrollIncrement === null) {
70 try {
71 this._scrollIncrement = this._prefBranch
72 .getIntPref("toolkit.scrollbox.scrollIncrement");
73 }
74 catch (ex) {
75 this._scrollIncrement = 20;
76 }
77 }
78 return this._scrollIncrement;
79 ]]></getter>
80 </property>
81
field__smoothScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
82 <field name="_smoothScroll">null</field>
83 <property name="smoothScroll">
get_smoothScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
84 <getter><![CDATA[
85 if (this._smoothScroll === null) {
86 if (this.hasAttribute("smoothscroll")) {
87 this._smoothScroll = (this.getAttribute("smoothscroll") == "true");
88 } else {
89 try {
90 this._smoothScroll = this._prefBranch
91 .getBoolPref("toolkit.scrollbox.smoothScroll");
92 }
93 catch (ex) {
94 this._smoothScroll = true;
95 }
96 }
97 }
98 return this._smoothScroll;
99 ]]></getter>
set_smoothScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
100 <setter><![CDATA[
101 this._smoothScroll = val;
102 return val;
103 ]]></setter>
104 </property>
105
field__scrollBoxObject
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
106 <field name="_scrollBoxObject">null</field>
107 <property name="scrollBoxObject" readonly="true">
get_scrollBoxObject
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
108 <getter><![CDATA[
109 if (!this._scrollBoxObject) {
110 this._scrollBoxObject =
111 this._scrollbox.boxObject
112 .QueryInterface(Components.interfaces.nsIScrollBoxObject);
113 }
114 return this._scrollBoxObject;
115 ]]></getter>
116 </property>
117
field__isLTRScrollbox
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
118 <field name="_isLTRScrollbox">
119 document.defaultView.getComputedStyle(this._scrollbox, "").direction == "ltr";
120 </field>
121
122 <method name="ensureElementIsVisible">
123 <parameter name="element"/>
ensureElementIsVisible
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
124 <body><![CDATA[
125 if (!this.smoothScroll || this.getAttribute("orient") == "vertical") {
126 this.scrollBoxObject.ensureElementIsVisible(element);
127 return;
128 }
129
130 var rect = this._scrollbox.getBoundingClientRect();
131 var containerStart = rect.left;
132 var containerEnd = rect.right;
133 rect = element.getBoundingClientRect();
134 var elementStart = rect.left;
135 var elementEnd = rect.right;
136 var amountToScroll;
137
138 if (elementStart < containerStart) {
139 amountToScroll = elementStart - containerStart;
140 } else if (containerEnd < elementEnd) {
141 amountToScroll = elementEnd - containerEnd;
142 } else if (this._isScrolling) {
143 // decelerate if a currently-visible element is selected during the scroll
144 const STOP_DISTANCE = 15;
145 if (this._isScrolling == -1 && elementStart - STOP_DISTANCE < containerStart)
146 amountToScroll = elementStart - containerStart;
147 else if (this._isScrolling == 1 && containerEnd - STOP_DISTANCE < elementEnd)
148 amountToScroll = elementEnd - containerEnd;
149 else
150 amountToScroll = this._isScrolling * STOP_DISTANCE;
151 } else {
152 return;
153 }
154
155 this._smoothScrollByPixels(amountToScroll);
156 ]]></body>
157 </method>
158
159 <method name="_smoothScrollByPixels">
160 <parameter name="amountToScroll"/>
_smoothScrollByPixels
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
161 <body><![CDATA[
162 this._stopSmoothScroll();
163
164 // Positive amountToScroll makes us scroll right (elements fly left), negative scrolls left.
165 var round;
166 if (amountToScroll < 0) {
167 this._isScrolling = -1;
168 round = Math.floor;
169 } else {
170 this._isScrolling = 1;
171 round = Math.ceil;
172 }
173
174 const FRAME_LENGTH = 60;
175
processFrame
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
176 function processFrame(self, scrollAmounts, off) {
177 var distance = scrollAmounts.shift();
178
179 // Skip frames if we aren't getting the desired frame rate.
180 if (off > 0) {
181 for (var i = Math.round(off / FRAME_LENGTH); i > 0; i--)
182 distance += scrollAmounts.shift() || 0;
183 }
184
185 self.scrollBoxObject.scrollBy(distance, 0);
186 if (!scrollAmounts.length)
187 self._stopSmoothScroll();
188 }
189
190 // amountToScroll: total distance to scroll
191 // scrollAmount: distance to move during the particular effect frame (60ms)
192 var scrollAmount, scrollAmounts = [];
193 if (amountToScroll > 2 || amountToScroll < -2) {
194 scrollAmount = round(amountToScroll * 0.2);
195 scrollAmounts.push(scrollAmount, scrollAmount, scrollAmount);
196 amountToScroll -= 3 * scrollAmount;
197 }
198 while (this._isScrolling < 0 && amountToScroll < 0 ||
199 this._isScrolling > 0 && amountToScroll > 0) {
200 amountToScroll -= (scrollAmount = round(amountToScroll * 0.5));
201 scrollAmounts.push(scrollAmount);
202 }
203 this._smoothScrollTimer = setInterval(processFrame, FRAME_LENGTH, this, scrollAmounts);
204 processFrame(this, scrollAmounts, 0);
205 ]]></body>
206 </method>
207
208 <method name="scrollByIndex">
209 <parameter name="index"/>
scrollByIndex
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
210 <body><![CDATA[
211 if (index == 0)
212 return;
213 if (this.getAttribute("orient") == "vertical") {
214 this.scrollBoxObject.scrollByIndex(index);
215 return;
216 }
217
218 var x;
219 if (index > 0)
220 x = this._scrollbox.getBoundingClientRect().right + 1;
221 else
222 x = this._scrollbox.getBoundingClientRect().left - 1;
223 var nextElement = this._elementFromPoint(x);
224 if (!nextElement)
225 return;
226
227 var targetElement;
228 if (!this._isLTRScrollbox)
229 index *= -1;
230
231 while (index < 0 && nextElement) {
232 targetElement = nextElement;
233 nextElement = nextElement.previousSibling;
234 index++;
235 }
236 while (index > 0 && nextElement) {
237 targetElement = nextElement;
238 nextElement = nextElement.nextSibling;
239 index--;
240 }
241
242 this.ensureElementIsVisible(targetElement);
243 ]]></body>
244 </method>
245
246 <method name="_elementFromPoint">
247 <parameter name="aX"/>
_elementFromPoint
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
248 <body><![CDATA[
249 var elements = this.hasChildNodes() ?
250 this.childNodes :
251 document.getBindingParent(this).childNodes;
252 if (!this._isLTRScrollbox) {
253 elements = Array.slice(elements);
254 elements.reverse();
255 }
256 var low = 0;
257 var high = elements.length - 1;
258
259 while (low <= high) {
260 var mid = Math.floor((low + high) / 2);
261 var element = elements[mid];
262 var rect = element.getBoundingClientRect();
263 if (rect.left > aX)
264 high = mid - 1;
265 else if (rect.right < aX)
266 low = mid + 1;
267 else
268 return element;
269 }
270
271 return null;
272 ]]></body>
273 </method>
274
275 <method name="_autorepeatbuttonScroll">
276 <parameter name="event"/>
_autorepeatbuttonScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
277 <body><![CDATA[
278 var dir = event.originalTarget == this._scrollButtonUp ? -1 : 1;
279 if (this.getAttribute("orient") == "horizontal" && !this._isLTRScrollbox)
280 dir *= -1;
281
282 this.scrollByPixels(this.scrollIncrement * dir);
283
284 event.stopPropagation();
285 ]]></body>
286 </method>
287
288 <method name="scrollByPixels">
289 <parameter name="px"/>
scrollByPixels
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
290 <body><![CDATA[
291 if (this.getAttribute("orient") == "horizontal")
292 this.scrollBoxObject.scrollBy(px, 0);
293 else
294 this.scrollBoxObject.scrollBy(0, px);
295 ]]></body>
296 </method>
297
298 <!-- 0: idle
299 1: scrolling right
300 -1: scrolling left -->
field__isScrolling
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
301 <field name="_isScrolling">0</field>
field__smoothScrollTimer
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
302 <field name="_smoothScrollTimer">0</field>
303
304 <method name="_stopSmoothScroll">
_stopSmoothScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
305 <body><![CDATA[
306 clearInterval(this._smoothScrollTimer);
307 this._isScrolling = 0;
308 ]]></body>
309 </method>
310
311 <method name="_updateScrollButtonsDisabledState">
_updateScrollButtonsDisabledState
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
312 <body><![CDATA[
313 var disableUpButton = false;
314 var disableDownButton = false;
315
316 if (this.getAttribute("orient") == "horizontal") {
317 var width = {};
318 this.scrollBoxObject.getScrolledSize(width, {});
319 var xPos = {};
320 this.scrollBoxObject.getPosition(xPos, {});
321 if (xPos.value == 0) {
322 // In the RTL case, this means the _last_ element in the
323 // scrollbox is visible
324 if (this._isLTRScrollbox)
325 disableUpButton = true;
326 else
327 disableDownButton = true;
328 }
329 else if (this._scrollbox.boxObject.width + xPos.value == width.value) {
330 // In the RTL case, this means the _first_ element in the
331 // scrollbox is visible
332 if (this._isLTRScrollbox)
333 disableDownButton = true;
334 else
335 disableUpButton = true;
336 }
337 }
338 else { // vertical scrollbox
339 var height = {};
340 this.scrollBoxObject.getScrolledSize({}, height);
341 var yPos = {};
342 this.scrollBoxObject.getPosition({}, yPos);
343 if (yPos.value == 0)
344 disableUpButton = true;
345 else if (this._scrollbox.boxObject.height + yPos.value == height.value)
346 disableDownButton = true;
347 }
348
349 if (this._scrollButtonUp.disabled != disableUpButton ||
350 this._scrollButtonDown.disabled != disableDownButton) {
351 this._scrollButtonUp.disabled = disableUpButton;
352 this._scrollButtonDown.disabled = disableDownButton;
353
354 var event = document.createEvent("Events");
355 event.initEvent("UpdatedScrollButtonsDisabledState", true, false);
356 this.dispatchEvent(event);
357 }
358 ]]></body>
359 </method>
360 </implementation>
361
362 <handlers>
onDOMMouseScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
363 <handler event="DOMMouseScroll" action="this.scrollByIndex(event.detail); event.stopPropagation();"/>
364
onunderflow
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
365 <handler event="underflow"><![CDATA[
366 // filter underflow events which were dispatched on nested scrollboxes
367 if (event.target != this)
368 return;
369
370 // Ignore events that doesn't match our orientation.
371 // Scrollport event orientation:
372 // 0: vertical
373 // 1: horizontal
374 // 2: both
375 if (this.getAttribute("orient") == "horizontal") {
376 if (event.detail == 0) {
377 return;
378 }
379 }
380 else { // vertical scrollbox
381 if (event.detail == 1) {
382 return;
383 }
384 }
385
386 this._scrollButtonUp.collapsed = true;
387 this._scrollButtonDown.collapsed = true;
388 try {
389 // See bug 341047 and comments in overflow handler as to why
390 // try..catch is needed here
391 var childNodes = document.getAnonymousNodes(this._scrollbox);
392 if (childNodes && childNodes.length)
393 this.scrollBoxObject.ensureElementIsVisible(childNodes[0]);
394 }
395 catch(e) {
396 this._scrollButtonUp.collapsed = false;
397 this._scrollButtonDown.collapsed = false;
398 }
399 ]]></handler>
400
onoverflow
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
401 <handler event="overflow"><![CDATA[
402 // filter underflow events which were dispatched on nested scrollboxes
403 if (event.target != this)
404 return;
405
406 // Ignore events that doesn't match our orientation.
407 // Scrollport event orientation:
408 // 0: vertical
409 // 1: horizontal
410 // 2: both
411 if (this.getAttribute("orient") == "horizontal") {
412 if (event.detail == 0) {
413 return;
414 }
415 }
416 else { // vertical scrollbox
417 if (event.detail == 1) {
418 return;
419 }
420 }
421
422 this._scrollButtonUp.collapsed = false;
423 this._scrollButtonDown.collapsed = false;
424 try {
425 // See bug 341047, the overflow event is dispatched when the
426 // scrollbox already is mostly destroyed. This causes some code in
427 // _updateScrollButtonsDisabledState() to throw an error. It also
428 // means that the scrollbarbuttons were uncollapsed when that should
429 // not be happening, because the whole overflow event should not be
430 // happening in that case.
431 this._updateScrollButtonsDisabledState();
432 }
433 catch(e) {
434 this._scrollButtonUp.collapsed = true;
435 this._scrollButtonDown.collapsed = true;
436 }
437 ]]></handler>
438
onscroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
439 <handler event="scroll" action="this._updateScrollButtonsDisabledState()"/>
440 </handlers>
441 </binding>
442
443 <binding id="autorepeatbutton" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
444 <content repeat="hover" chromedir="&locale.dir;">
445 <xul:image class="autorepeatbutton-icon"/>
446 </content>
447 </binding>
448
449 <binding id="arrowscrollbox-clicktoscroll" extends="chrome://global/content/bindings/scrollbox.xml#arrowscrollbox">
450 <content>
451 <xul:toolbarbutton class="scrollbutton-up" collapsed="true"
452 xbl:inherits="orient"
453 anonid="scrollbutton-up"
454 onclick="_distanceScroll(event);"
455 onmousedown="_startScroll(-1);"
456 onmouseover="_continueScroll(-1);"
457 onmouseup="_stopScroll();"
458 onmouseout="_pauseScroll();"
459 chromedir="&locale.dir;"/>
460 <xul:scrollbox xbl:inherits="orient,align,pack,dir" flex="1" anonid="scrollbox">
461 <children/>
462 </xul:scrollbox>
463 <xul:toolbarbutton class="scrollbutton-down" collapsed="true"
464 xbl:inherits="orient"
465 anonid="scrollbutton-down"
466 onclick="_distanceScroll(event);"
467 onmousedown="_startScroll(1);"
468 onmouseover="_continueScroll(1);"
469 onmouseup="_stopScroll();"
470 onmouseout="_pauseScroll();"
471 chromedir="&locale.dir;"/>
472 </content>
473 <implementation implements="nsITimerCallback, nsIDOMEventListener">
constructor
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
474 <constructor><![CDATA[
475 try {
476 this._scrollDelay = this._prefBranch
477 .getIntPref("toolkit.scrollbox.clickToScroll.scrollDelay");
478 }
479 catch (ex) {
480 }
481 ]]></constructor>
482
destructor
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
483 <destructor><![CDATA[
484 // Release timer to avoid reference cycles.
485 if (this._scrollTimer) {
486 this._scrollTimer.cancel();
487 this._scrollTimer = null;
488 }
489 ]]></destructor>
490
field__scrollIndex
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
491 <field name="_scrollIndex">0</field>
field__scrollDelay
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
492 <field name="_scrollDelay">150</field>
493
494 <method name="notify">
495 <parameter name="aTimer"/>
notify
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
496 <body>
497 <![CDATA[
498 if (!document)
499 aTimer.cancel();
500
501 if (this.smoothScroll)
502 this.scrollByPixels(25 * this._scrollIndex);
503 else
504 this.scrollBoxObject.scrollByIndex(this._scrollIndex);
505 ]]>
506 </body>
507 </method>
508
509 <method name="_startScroll">
510 <parameter name="index"/>
_startScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
511 <body><![CDATA[
512 if (this.getAttribute("orient") == "horizontal" && !this._isLTRScrollbox)
513 index *= -1;
514 this._scrollIndex = index;
515 var scrollDelay = this.smoothScroll ? 60 : this._scrollDelay;
516 if (!this._scrollTimer)
517 this._scrollTimer =
518 Components.classes["@mozilla.org/timer;1"]
519 .createInstance(Components.interfaces.nsITimer);
520 else
521 this._scrollTimer.cancel();
522
523 this._scrollTimer.initWithCallback(this, scrollDelay,
524 this._scrollTimer.TYPE_REPEATING_SLACK);
525 this.notify(this._scrollTimer);
526 this._mousedown = true;
527 ]]>
528 </body>
529 </method>
530
531 <method name="_stopScroll">
_stopScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
532 <body><![CDATA[
533 if (this._scrollTimer)
534 this._scrollTimer.cancel();
535 this._mousedown = false;
536 if (!this._scrollIndex || !this.smoothScroll)
537 return;
538
539 this.scrollByIndex(this._scrollIndex);
540 this._scrollIndex = 0;
541 ]]></body>
542 </method>
543
544 <method name="_pauseScroll">
_pauseScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
545 <body><![CDATA[
546 if (this._mousedown) {
547 this._stopScroll();
548 this._mousedown = true;
549 document.addEventListener("mouseup", this, false);
550 document.addEventListener("blur", this, true);
551 }
552 ]]></body>
553 </method>
554
555 <method name="_continueScroll">
556 <parameter name="index"/>
_continueScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
557 <body><![CDATA[
558 if (this._mousedown)
559 this._startScroll(index);
560 ]]></body>
561 </method>
562
563 <method name="handleEvent">
564 <parameter name="aEvent"/>
handleEvent
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
565 <body><![CDATA[
566 if (aEvent.type == "mouseup" ||
567 aEvent.type == "blur" && aEvent.target == document) {
568 this._mousedown = false;
569 document.removeEventListener("mouseup", this, false);
570 document.removeEventListener("blur", this, true);
571 }
572 ]]></body>
573 </method>
574
575 <method name="_distanceScroll">
576 <parameter name="aEvent"/>
_distanceScroll
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
577 <body><![CDATA[
578 if (this.getAttribute("orient") == "vertical" ||
579 aEvent.detail < 2 || aEvent.detail > 3)
580 return;
581
582 var scrollLeft = (aEvent.originalTarget == this._scrollButtonUp);
583 if (!this._isLTRScrollbox)
584 scrollLeft = !scrollLeft;
585 var targetElement;
586
587 if (aEvent.detail == 2) {
588 // scroll by the width of the scrollbox; make sure that the next
589 // partly-hidden element will become fully visible.
590 var rect = this._scrollbox.getBoundingClientRect();
591 var x;
592 if (scrollLeft)
593 x = rect.left - (rect.right - rect.left);
594 else
595 x = rect.right + (rect.right - rect.left);
596 targetElement = this._elementFromPoint(x);
597
598 if (targetElement)
599 targetElement = scrollLeft ?
600 targetElement.nextSibling :
601 targetElement.previousSibling;
602 }
603
604 if (!targetElement) {
605 // scroll to the first resp. last element
606 var container = this.hasChildNodes() ? this : document.getBindingParent(this);
607 targetElement = (this._isLTRScrollbox ? scrollLeft : !scrollLeft) ?
608 container.firstChild :
609 container.lastChild;
610 }
611
612 this.ensureElementIsVisible(targetElement);
613 ]]></body>
614 </method>
615
616 </implementation>
617 </binding>
618 </bindings>