layout/style/xbl-marquee/xbl-marquee.xml

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

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>

mercurial