Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
1 <?xml version="1.0"?>
2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
3 - License, v. 2.0. If a copy of the MPL was not distributed with this
4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
6 <bindings id="marqueeBindings"
7 xmlns="http://www.mozilla.org/xbl"
8 xmlns:html="http://www.w3.org/1999/xhtml"
9 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
10 xmlns:xbl="http://www.mozilla.org/xbl">
13 <binding id="marquee">
15 <resources>
16 <stylesheet src="chrome://xbl-marquee/content/xbl-marquee.css"/>
17 </resources>
18 <implementation>
20 <property name="scrollAmount" exposeToUntrustedContent="true">
21 <getter>
22 <![CDATA[
23 var val = parseInt(this.getAttribute("scrollamount"));
25 if (val <= 0 || isNaN(val))
26 return this._scrollAmount;
28 return val;
29 ]]>
30 </getter>
31 <setter>
32 this.setAttribute("scrollamount", val);
33 </setter>
34 </property>
36 <property name="scrollDelay" exposeToUntrustedContent="true">
37 <getter>
38 <![CDATA[
39 var val = parseInt(this.getAttribute("scrolldelay"));
41 if (val <= 0 || isNaN(val))
42 return this._scrollDelay;
44 return val;
45 ]]>
46 </getter>
47 <setter>
48 this.setAttribute("scrolldelay", val);
49 </setter>
50 </property>
52 <property name="trueSpeed" exposeToUntrustedContent="true">
53 <getter>
54 <![CDATA[
55 if (!this.hasAttribute("truespeed"))
56 return false;
58 return true;
59 ]]>
60 </getter>
61 <setter>
62 <![CDATA[
63 if (val)
64 this.setAttribute("truespeed", "truespeed");
65 else
66 this.removeAttribute('truespeed');
67 ]]>
68 </setter>
69 </property>
71 <property name="direction" exposeToUntrustedContent="true">
72 <getter>
73 return this.getAttribute("direction");
74 </getter>
75 <setter>
76 this.setAttribute("direction", val);
77 </setter>
78 </property>
80 <property name="behavior" exposeToUntrustedContent="true">
81 <getter>
82 return this._behavior;
83 </getter>
84 <setter>
85 this.setAttribute("behavior", val);
86 </setter>
87 </property>
90 <property name="loop" exposeToUntrustedContent="true">
91 <getter>
92 <![CDATA[
93 var val = parseInt(this.getAttribute('loop'));
95 if (val < -1 || isNaN(val))
96 return this._loop;
98 return val;
99 ]]>
100 </getter>
101 <setter>
102 this.setAttribute("loop", val);
103 </setter>
104 </property>
107 <property name="onstart" exposeToUntrustedContent="true">
108 <getter>
109 return this.getAttribute("onstart");
110 </getter>
111 <setter>
112 this._setEventListener("start", val, true);
113 this.setAttribute("onstart", val);
114 </setter>
115 </property>
117 <property name="onfinish" exposeToUntrustedContent="true">
118 <getter>
119 return this.getAttribute("onfinish");
120 </getter>
121 <setter>
122 this._setEventListener("finish", val, true);
123 this.setAttribute("onfinish", val);
124 </setter>
125 </property>
127 <property name="onbounce" exposeToUntrustedContent="true">
128 <getter>
129 return this.getAttribute("onbounce");
130 </getter>
131 <setter>
132 this._setEventListener("bounce", val, true);
133 this.setAttribute("onbounce", val);
134 </setter>
135 </property>
137 <property name="outerDiv"
138 onget="return document.getAnonymousNodes(this)[0]"
139 />
141 <property name="innerDiv"
142 onget="return document.getAnonymousElementByAttribute(this, 'class', 'innerDiv');"
143 />
145 <property name="height" exposeToUntrustedContent="true"
146 onget="return this.getAttribute('height');"
147 onset="this.setAttribute('height', val);"
148 />
150 <property name="width" exposeToUntrustedContent="true"
151 onget="return this.getAttribute('width');"
152 onset="this.setAttribute('width', val);"
153 />
155 <method name="_set_scrollDelay">
156 <parameter name="aValue"/>
157 <body>
158 <![CDATA[
159 if (aValue <= 0 || isNaN(aValue) || aValue == null)
160 return false;
162 if (aValue < 60) {
163 if (this.trueSpeed == true)
164 this._scrollDelay = aValue;
165 else
166 this._scrollDelay = 60;
167 }
168 else {
169 this._scrollDelay = aValue;
170 }
171 return true;
172 ]]>
173 </body>
174 </method>
176 <method name="_set_scrollAmount">
177 <parameter name="aValue"/>
178 <body>
179 <![CDATA[
180 if (aValue < 0 || isNaN(aValue) || aValue == null)
181 return false;
183 this._scrollAmount = aValue;
184 return true;
185 ]]>
186 </body>
187 </method>
189 <method name="_set_behavior">
190 <parameter name="aValue"/>
191 <body>
192 <![CDATA[
193 if (typeof aValue == 'string')
194 aValue = aValue.toLowerCase();
195 if (aValue != 'alternate' && aValue != 'slide' && aValue != 'scroll')
196 return false;
198 this._behavior = aValue;
199 return true;
200 ]]>
201 </body>
202 </method>
204 <method name="_set_direction">
205 <parameter name="aValue"/>
206 <body>
207 <![CDATA[
208 if (typeof aValue == 'string')
209 aValue = aValue.toLowerCase();
210 if (aValue != 'left' && aValue != 'right' && aValue != 'up' && aValue != 'down')
211 return false;
213 if (aValue != this._direction)
214 this.startNewDirection = true;
215 this._direction = aValue;
216 return true;
217 ]]>
218 </body>
219 </method>
221 <method name="_set_loop">
222 <parameter name="aValue"/>
223 <body>
224 <![CDATA[
225 if (!aValue || isNaN(aValue))
226 return false;
228 if (aValue < -1)
229 aValue = -1;
231 this._loop = aValue;
232 return true;
233 ]]>
234 </body>
235 </method>
237 <method name="_setEventListener">
238 <parameter name="aName"/>
239 <parameter name="aValue"/>
240 <parameter name="aIgnoreNextCall"/>
241 <body>
242 <![CDATA[
243 if (this._ignoreNextCall)
244 return this._ignoreNextCall = false;
246 if (aIgnoreNextCall)
247 this._ignoreNextCall = true;
249 if (typeof this["_on" + aName] == 'function')
250 this.removeEventListener(aName, this["_on" + aName], false);
252 switch (typeof aValue)
253 {
254 case "function":
255 this["_on" + aName] = aValue;
256 this.addEventListener(aName, this["_on" + aName], false);
257 break;
259 case "string":
260 if (!aIgnoreNextCall) {
261 try {
262 // Things to watch out for here:
263 // * Weird |new| precedence.
264 // * Getting the correct constructor (via Xrays).
265 // * Waiving the constructor before invoking it, so that we can
266 // call it (since XBL gets opaque non-callable wrappers to content).
267 // * The fact that contentFn is transitively waived, which we need
268 // in order to be able to invoke it.
269 this["_on" + aName] = new (XPCNativeWrapper.unwrap(window.Function))("event", aValue);
270 }
271 catch(e) {
272 return false;
273 }
274 this.addEventListener(aName, this["_on" + aName], false);
275 }
276 else {
277 this["_on" + aName] = aValue;
278 }
279 break;
281 case "object":
282 this["_on" + aName] = aValue;
283 break;
285 default:
286 this._ignoreNextCall = false;
287 throw new Error("Invalid argument for Marquee::on" + aName);
288 }
289 return true;
290 ]]>
291 </body>
292 </method>
294 <method name="_fireEvent">
295 <parameter name="aName"/>
296 <parameter name="aBubbles"/>
297 <parameter name="aCancelable"/>
298 <body>
299 <![CDATA[
300 var e = document.createEvent("Events");
301 e.initEvent(aName, aBubbles, aCancelable);
302 this.dispatchEvent(e);
303 ]]>
304 </body>
305 </method>
307 <method name="start" exposeToUntrustedContent="true">
308 <body>
309 <![CDATA[
310 if (this.runId == 0) {
311 var myThis = this;
312 var lambda = function myTimeOutFunction(){myThis._doMove(false);}
313 this.runId = window.setTimeout(lambda, this._scrollDelay - this._deltaStartStop);
314 this._deltaStartStop = 0;
315 }
316 ]]>
317 </body>
318 </method>
320 <method name="stop" exposeToUntrustedContent="true">
321 <body>
322 <![CDATA[
323 if (this.runId != 0) {
324 this._deltaStartStop = Date.now()- this._lastMoveDate;
325 clearTimeout(this.runId);
326 }
328 this.runId = 0;
329 ]]>
330 </body>
331 </method>
333 <method name="_doMove">
334 <parameter name="aResetPosition"/>
335 <body>
336 <![CDATA[
337 this._lastMoveDate = Date.now();
339 //startNewDirection is true at first load and whenever the direction is changed
340 if (this.startNewDirection) {
341 this.startNewDirection = false; //we only want this to run once every scroll direction change
343 var corrvalue = 0;
345 switch (this._direction)
346 {
347 case "up":
348 var height = document.defaultView.getComputedStyle(this, "").height;
349 this.outerDiv.style.height = height;
350 if (this.originalHeight > this.outerDiv.offsetHeight)
351 corrvalue = this.originalHeight - this.outerDiv.offsetHeight;
352 this.innerDiv.style.padding = height + " 0";
353 this.dirsign = 1;
354 this.startAt = (this._behavior == 'alternate') ? (this.originalHeight - corrvalue) : 0;
355 this.stopAt = (this._behavior == 'alternate' || this._behavior == 'slide') ?
356 (parseInt(height) + corrvalue) : (this.originalHeight + parseInt(height));
357 break;
359 case "down":
360 var height = document.defaultView.getComputedStyle(this, "").height;
361 this.outerDiv.style.height = height;
362 if (this.originalHeight > this.outerDiv.offsetHeight)
363 corrvalue = this.originalHeight - this.outerDiv.offsetHeight;
364 this.innerDiv.style.padding = height + " 0";
365 this.dirsign = -1;
366 this.startAt = (this._behavior == 'alternate') ?
367 (parseInt(height) + corrvalue) : (this.originalHeight + parseInt(height));
368 this.stopAt = (this._behavior == 'alternate' || this._behavior == 'slide') ?
369 (this.originalHeight - corrvalue) : 0;
370 break;
372 case "right":
373 if (this.innerDiv.offsetWidth > this.outerDiv.offsetWidth)
374 corrvalue = this.innerDiv.offsetWidth - this.outerDiv.offsetWidth;
375 this.dirsign = -1;
376 this.stopAt = (this._behavior == 'alternate' || this._behavior == 'slide') ?
377 (this.innerDiv.offsetWidth - corrvalue) : 0;
378 this.startAt = this.outerDiv.offsetWidth + ((this._behavior == 'alternate') ?
379 corrvalue : (this.innerDiv.offsetWidth + this.stopAt));
380 break;
382 case "left":
383 default:
384 if (this.innerDiv.offsetWidth > this.outerDiv.offsetWidth)
385 corrvalue = this.innerDiv.offsetWidth - this.outerDiv.offsetWidth;
386 this.dirsign = 1;
387 this.startAt = (this._behavior == 'alternate') ? (this.innerDiv.offsetWidth - corrvalue) : 0;
388 this.stopAt = this.outerDiv.offsetWidth +
389 ((this._behavior == 'alternate' || this._behavior == 'slide') ?
390 corrvalue : (this.innerDiv.offsetWidth + this.startAt));
391 }
393 if (aResetPosition) {
394 this.newPosition = this.startAt;
395 this._fireEvent("start", false, false);
396 }
397 } //end if
399 this.newPosition = this.newPosition + (this.dirsign * this._scrollAmount);
401 if ((this.dirsign == 1 && this.newPosition > this.stopAt) ||
402 (this.dirsign == -1 && this.newPosition < this.stopAt))
403 {
404 switch (this._behavior)
405 {
406 case 'alternate':
407 // lets start afresh
408 this.startNewDirection = true;
410 // swap direction
411 const swap = {left: "right", down: "up", up: "down", right: "left"};
412 this._direction = swap[this._direction];
413 this.newPosition = this.stopAt;
415 if ((this._direction == "up") || (this._direction == "down"))
416 this.outerDiv.scrollTop = this.newPosition;
417 else
418 this.outerDiv.scrollLeft = this.newPosition;
420 if (this._loop != 1)
421 this._fireEvent("bounce", false, true);
422 break;
424 case 'slide':
425 if (this._loop > 1)
426 this.newPosition = this.startAt;
427 break;
429 default:
430 this.newPosition = this.startAt;
432 if ((this._direction == "up") || (this._direction == "down"))
433 this.outerDiv.scrollTop = this.newPosition;
434 else
435 this.outerDiv.scrollLeft = this.newPosition;
437 //dispatch start event, even when this._loop == 1, comp. with IE6
438 this._fireEvent("start", false, false);
439 }
441 if (this._loop > 1)
442 this._loop--;
443 else if (this._loop == 1) {
444 if ((this._direction == "up") || (this._direction == "down"))
445 this.outerDiv.scrollTop = this.stopAt;
446 else
447 this.outerDiv.scrollLeft = this.stopAt;
448 this.stop();
449 this._fireEvent("finish", false, true);
450 return;
451 }
452 }
453 else {
454 if ((this._direction == "up") || (this._direction == "down"))
455 this.outerDiv.scrollTop = this.newPosition;
456 else
457 this.outerDiv.scrollLeft = this.newPosition;
458 }
460 var myThis = this;
461 var lambda = function myTimeOutFunction(){myThis._doMove(false);}
462 this.runId = window.setTimeout(lambda, this._scrollDelay);
463 ]]>
464 </body>
465 </method>
467 <method name="init">
468 <body>
469 <![CDATA[
470 this.stop();
472 if ((this._direction != "up") && (this._direction != "down")) {
473 var width = window.getComputedStyle(this, "").width;
474 this.innerDiv.parentNode.style.margin = '0 ' + width;
476 //XXX Adding the margin sometimes causes the marquee to widen,
477 // see testcase from bug bug 364434:
478 // https://bugzilla.mozilla.org/attachment.cgi?id=249233
479 // Just add a fixed width with current marquee's width for now
480 if (width != window.getComputedStyle(this, "").width) {
481 var width = window.getComputedStyle(this, "").width;
482 this.outerDiv.style.width = width;
483 this.innerDiv.parentNode.style.margin = '0 ' + width;
484 }
485 }
486 else {
487 // store the original height before we add padding
488 this.innerDiv.style.padding = 0;
489 this.originalHeight = this.innerDiv.offsetHeight;
490 }
492 this._doMove(true);
493 ]]>
494 </body>
495 </method>
497 <constructor>
498 <![CDATA[
499 // Set up state.
500 this._scrollAmount = 6;
501 this._scrollDelay = 85;
502 this._direction = "left";
503 this._behavior = "scroll";
504 this._loop = -1;
505 this.dirsign = 1;
506 this.startAt = 0;
507 this.stopAt = 0;
508 this.newPosition = 0;
509 this.runId = 0;
510 this.originalHeight = 0;
511 this.startNewDirection = true;
513 // hack needed to fix js error, see bug 386470
514 var myThis = this;
515 var lambda = function myScopeFunction() { if (myThis.init) myThis.init(); }
517 this._set_direction(this.getAttribute('direction'));
518 this._set_behavior(this.getAttribute('behavior'));
519 this._set_scrollDelay(this.getAttribute('scrolldelay'));
520 this._set_scrollAmount(this.getAttribute('scrollamount'));
521 this._set_loop(this.getAttribute('loop'));
522 this._setEventListener("start", this.getAttribute("onstart"));
523 this._setEventListener("finish", this.getAttribute("onfinish"));
524 this._setEventListener("bounce", this.getAttribute("onbounce"));
525 this.startNewDirection = true;
527 // init needs to be run after the page has loaded in order to calculate
528 // the correct height/width
529 if (document.readyState == "complete")
530 lambda();
531 else
532 window.addEventListener("load", lambda, false);
533 ]]>
534 </constructor>
535 </implementation>
537 <handlers>
538 <handler event="DOMAttrModified" phase="target">
539 <![CDATA[
540 var attrName = event.attrName.toLowerCase();
541 var oldValue = event.prevValue.toLowerCase();
542 var newValue = event.newValue.toLowerCase();
543 var attributeRemoval = false;
544 if (event.attrChange == event.REMOVAL) {
545 newValue = null;
546 attributeRemoval = true;
547 };
549 if (oldValue != newValue) {
550 switch (attrName) {
551 case "loop":
552 if (!this._set_loop(newValue)) {
553 if (attributeRemoval) {
554 this._loop = -1;
555 if (this.runId == 0)
556 this.start();
557 }
558 else
559 throw new Error("Invalid argument for Marquee::loop");
560 }
561 if (this.rundId == 0)
562 this.start();
563 break;
564 case "scrollamount":
565 if (!this._set_scrollAmount(newValue)) {
566 if (attributeRemoval)
567 this._scrollAmount = 6;
568 else
569 throw new Error("Invalid argument for Marquee::scrollAmount");
570 }
571 break;
572 case "scrolldelay":
573 if (!this._set_scrollDelay(newValue)) {
574 if (attributeRemoval)
575 this._scrollDelay = 85;
576 else
577 throw new Error("Invalid argument for Marquee::scrollDelay");
578 }
579 this.stop();
580 this.start();
581 break;
582 case "truespeed":
583 //needed to update this._scrollDelay
584 var myThis = this;
585 var lambda = function() {myThis._set_scrollDelay(myThis.getAttribute('scrolldelay'));}
586 window.setTimeout(lambda, 0);
587 break;
588 case "behavior":
589 if (!this._set_behavior(newValue)) {
590 if (attributeRemoval)
591 this._behavior = "scroll";
592 else
593 throw new Error("Invalid argument for Marquee::behavior");
594 }
596 this.startNewDirection = true;
597 if ((oldValue == "slide" && this.newPosition == this.stopAt) ||
598 newValue == "alternate" || newValue == "slide") {
599 this.stop();
600 this._doMove(true);
601 }
602 break;
603 case "direction":
604 if (!this._set_direction(newValue)) {
605 if (attributeRemoval)
606 this._direction = "left";
607 else
608 throw new Error("Invalid argument for Marquee::direction");
609 }
610 break;
611 case "width":
612 case "height":
613 this.startNewDirection = true;
614 break;
615 case "onstart":
616 this._setEventListener("start", newValue);
617 break;
618 case "onfinish":
619 this._setEventListener("finish", newValue);
620 break;
621 case "onbounce":
622 this._setEventListener("bounce", newValue);
623 break;
624 }
625 }
626 ]]>
627 </handler>
628 </handlers>
630 </binding>
632 <binding id="marquee-horizontal"
633 extends="chrome://xbl-marquee/content/xbl-marquee.xml#marquee"
634 inheritstyle="false">
636 <!-- White-space isn't allowed because a marquee could be
637 inside 'white-space: pre' -->
638 <content>
639 <html:div style="display: -moz-box; overflow: hidden; width: -moz-available;"
640 ><html:div style="display: -moz-box;"
641 ><html:div class="innerDiv" style="display: table; border-spacing: 0;"
642 ><html:div
643 ><children
644 /></html:div
645 ></html:div
646 ></html:div
647 ></html:div>
648 </content>
650 </binding>
652 <binding id="marquee-vertical"
653 extends="chrome://xbl-marquee/content/xbl-marquee.xml#marquee"
654 inheritstyle="false">
656 <!-- White-space isn't allowed because a marquee could be
657 inside 'white-space: pre' -->
658 <content>
659 <html:div style="overflow: hidden; width: -moz-available;"
660 ><html:div class="innerDiv"
661 ><children
662 /></html:div
663 ></html:div>
664 </content>
666 </binding>
668 <binding id="marquee-horizontal-editable"
669 inheritstyle="false">
671 <!-- White-space isn't allowed because a marquee could be
672 inside 'white-space: pre' -->
673 <content>
674 <html:div style="display: inline-block; overflow: auto; width: -moz-available;"
675 ><children
676 /></html:div>
677 </content>
679 </binding>
681 <binding id="marquee-vertical-editable"
682 inheritstyle="false">
684 <!-- White-space isn't allowed because a marquee could be
685 inside 'white-space: pre' -->
686 <content>
687 <html:div style="overflow: auto; height: inherit; width: -moz-available;"
688 ><children/></html:div>
689 </content>
691 </binding>
693 </bindings>