LCOV - code coverage report
Current view: top level - modules/script/tweener - tweener.js (source / functions) Hit Total Coverage
Test: gjs- Code Coverage Lines: 369 438 84.2 %
Date: 2023-09-17 02:39:54 Functions: 35 42 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 199 252 79.0 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil; -*- */
       2                 :            : /* eslint-disable block-scoped-var, eqeqeq, no-shadow, prefer-rest-params */
       3                 :            : // SPDX-License-Identifier: MIT
       4                 :            : // SPDX-FileCopyrightText: 2006-2007 Zeh Fernando and Nate Chatellier
       5                 :            : // SPDX-FileCopyrightText: 2008 litl, LLC.
       6                 :            : 
       7                 :            : /**
       8                 :            :  * Tweener
       9                 :            :  * Transition controller for movieclips, sounds, textfields and other objects
      10                 :            :  *
      11                 :            :  * @author              Zeh Fernando, Nate Chatellier, Arthur Debert
      12                 :            :  * @version             1.31.71
      13                 :            :  */
      14                 :            : /* exported addCaller, addTween, FrameTicker, getTweenCount, getTimeScale,
      15                 :            : pauseAllTweens, pauseTweens, PropertyList, registerSpecialProperty,
      16                 :            : registerSpecialPropertyModifier, registerSpecialPropertySplitter,
      17                 :            : removeAllTweens, removeTweens, restrictedWords, resumeAllTweens, resumeTweens,
      18                 :            : setFrameTicker, setTimeScale */
      19                 :            : 
      20                 :            : /*
      21                 :            :  http://code.google.com/p/tweener/
      22                 :            :  http://code.google.com/p/tweener/wiki/License
      23                 :            :  */
      24                 :            : 
      25                 :          1 : const GLib = imports.gi.GLib;
      26                 :            : 
      27                 :          1 : const TweenList = imports.tweener.tweenList;
      28                 :          1 : const Signals = imports.signals;
      29                 :            : 
      30                 :          1 : var _inited = false;
      31                 :          1 : var _engineExists = false;
      32                 :          1 : var _tweenList = null;
      33                 :            : 
      34                 :          1 : var _timeScale = 1;
      35                 :            : 
      36                 :          1 : var _specialPropertyList = [];
      37                 :          1 : var _specialPropertyModifierList = [];
      38                 :          1 : var _specialPropertySplitterList = [];
      39                 :            : 
      40                 :            : /*
      41                 :            :  * Ticker should implement:
      42                 :            :  *
      43                 :            :  * property FRAME_RATE
      44                 :            :  * start()
      45                 :            :  * stop()
      46                 :            :  * getTime() gets time in milliseconds from start()
      47                 :            :  * signal prepare-frame
      48                 :            :  *
      49                 :            :  */
      50                 :          1 : var _ticker = null;
      51                 :            : 
      52                 :          1 : var _prepareFrameId = 0;
      53                 :            : 
      54                 :            : /* default frame ticker */
      55                 :            : function FrameTicker() {
      56                 :          1 :     this._init();
      57                 :            : }
      58                 :            : 
      59                 :          1 : FrameTicker.prototype = {
      60                 :          1 :     FRAME_RATE: 65,
      61                 :            : 
      62                 :          1 :     _init() {
      63                 :            :     },
      64                 :            : 
      65                 :          1 :     start() {
      66                 :          0 :         this._currentTime = 0;
      67                 :            : 
      68                 :          0 :         let me = this;
      69                 :            : 
      70                 :          0 :         this._timeoutID = GLib.timeout_add(
      71                 :          0 :             GLib.PRIORITY_DEFAULT,
      72                 :          0 :             Math.floor(1000 / me.FRAME_RATE),
      73                 :            :             function () {
      74                 :          0 :                 me._currentTime += 1000 / me.FRAME_RATE;
      75                 :          0 :                 me.emit('prepare-frame');
      76                 :          0 :                 return true;
      77                 :            :             });
      78                 :            :     },
      79                 :            : 
      80                 :          1 :     stop() {
      81         [ #  # ]:          0 :         if ('_timeoutID' in this) {
      82                 :          0 :             GLib.source_remove(this._timeoutID);
      83                 :          0 :             delete this._timeoutID;
      84                 :            :         }
      85                 :            : 
      86                 :          0 :         this._currentTime = 0;
      87                 :            :     },
      88                 :            : 
      89                 :          1 :     getTime() {
      90                 :          0 :         return this._currentTime;
      91                 :            :     },
      92                 :            : };
      93                 :          1 : Signals.addSignalMethods(FrameTicker.prototype);
      94                 :            : 
      95                 :          1 : _ticker = new FrameTicker();
      96                 :            : 
      97                 :            : /* TODOs:
      98                 :            :  *
      99                 :            :  * Special properties:
     100                 :            :  *
     101                 :            :  * Special properties are 'proxy' properties used in Tweener to tween
     102                 :            :  * (animate) things that are not proper properties per se. One example
     103                 :            :  * given is the 'frame' of an object in ActionScript, which is not an
     104                 :            :  * object property. Using the special property '_frame' you could animate
     105                 :            :  * it like this:
     106                 :            :  *
     107                 :            :  * Tweener.addTween(myMovieClip, {_frame:20, time:1});
     108                 :            :  *
     109                 :            :  * which would be equivalent to applying a fast-forward to it.
     110                 :            :  *
     111                 :            :  * This properties need a special support in the code, and I've removed it
     112                 :            :  * for now until we see the need for it in our clutter based stuff.
     113                 :            :  */
     114                 :            : 
     115                 :            : /* This is a bit pointless now, but let's keep it anyway... */
     116                 :            : function _init() {
     117         [ +  - ]:          1 :     if (_inited)
     118                 :          0 :         return;
     119                 :            : 
     120                 :          1 :     _inited = true;
     121                 :            : }
     122                 :            : 
     123                 :            : function setFrameTicker(ticker) {
     124                 :          1 :     _ticker = ticker;
     125                 :            : }
     126                 :            : 
     127                 :            : function _startEngine() {
     128         [ +  - ]:          2 :     if (_engineExists)
     129                 :          0 :         return;
     130                 :            : 
     131                 :          2 :     _engineExists = true;
     132                 :          2 :     _tweenList = [];
     133                 :            : 
     134         [ +  - ]:          2 :     if (!_ticker)
     135                 :          0 :         throw new Error('Must call setFrameTicker()');
     136                 :            : 
     137                 :          4 :     _prepareFrameId = _ticker.connect('prepare-frame',
     138                 :          2 :         _onEnterFrame);
     139                 :          2 :     _ticker.start();
     140                 :            : }
     141                 :            : 
     142                 :            : function _stopEngine() {
     143         [ +  - ]:          1 :     if (!_engineExists)
     144                 :          0 :         return;
     145                 :            : 
     146                 :          1 :     _engineExists = false;
     147                 :          1 :     _tweenList = false;
     148                 :            : 
     149                 :          1 :     _ticker.disconnect(_prepareFrameId);
     150                 :          1 :     _prepareFrameId = 0;
     151                 :          1 :     _ticker.stop();
     152                 :            : }
     153                 :            : 
     154                 :            : function _getCurrentTweeningTime() {
     155                 :        471 :     return _ticker.getTime();
     156                 :            : }
     157                 :            : 
     158                 :            : function _removeTweenByIndex(i) {
     159                 :         73 :     _tweenList[i] = null;
     160                 :            : 
     161                 :         73 :     var finalRemoval = arguments[1];
     162                 :            : 
     163 [ +  + ][ +  + ]:         73 :     if (finalRemoval != undefined && finalRemoval)
     164                 :         32 :         _tweenList.splice(i, 1);
     165                 :            : 
     166                 :         73 :     return true;
     167                 :            : }
     168                 :            : 
     169                 :            : function _resumeTweenByIndex(i) {
     170                 :          4 :     var tweening = _tweenList[i];
     171                 :            : 
     172 [ -  + ][ +  - ]:          4 :     if (tweening == null || !tweening.isPaused)
     173                 :          0 :         return false;
     174                 :            : 
     175                 :          4 :     var currentTime = _getCurrentTweeningTime(tweening);
     176                 :            : 
     177                 :          4 :     tweening.timeStart += currentTime - tweening.timePaused;
     178                 :          4 :     tweening.timeComplete += currentTime - tweening.timePaused;
     179                 :          4 :     tweening.timePaused = undefined;
     180                 :          4 :     tweening.isPaused = false;
     181                 :            : 
     182                 :          4 :     return true;
     183                 :            : }
     184                 :            : 
     185                 :            : /* FIXME: any way to get the function name from the fn itself? */
     186                 :            : function _callOnFunction(fn, fnname, scope, fallbackScope, params) {
     187         [ +  + ]:        466 :     if (fn) {
     188         [ +  - ]:         75 :         var eventScope = scope ? scope : fallbackScope;
     189                 :         75 :         try {
     190                 :         75 :             fn.apply(eventScope, params);
     191                 :          0 :         } catch (e) {
     192                 :          0 :             logError(e, `Error calling ${fnname}`);
     193                 :            :         }
     194                 :            :     }
     195                 :            : }
     196                 :            : 
     197                 :            : function _updateTweenByIndex(i) {
     198                 :        472 :     var tweening = _tweenList[i];
     199                 :            : 
     200 [ +  + ][ +  + ]:        472 :     if (tweening == null || !tweening.scope)
     201                 :          9 :         return false;
     202                 :            : 
     203                 :        463 :     var currentTime = _getCurrentTweeningTime(tweening);
     204                 :            : 
     205         [ +  + ]:        463 :     if (currentTime < tweening.timeStart)
     206                 :         52 :         return true; // Hasn't started, so return true
     207                 :            : 
     208                 :        411 :     var scope = tweening.scope;
     209                 :            :     var t, b, c, d, nv;
     210                 :            : 
     211                 :        411 :     var isOver = false;
     212                 :            : 
     213         [ +  + ]:        411 :     if (tweening.isCaller) {
     214                 :          5 :         do {
     215                 :         14 :             t = (tweening.timeComplete - tweening.timeStart) / tweening.count *
     216                 :         14 :                 (tweening.timesCalled + 1);
     217                 :         14 :             b = tweening.timeStart;
     218                 :         14 :             c = tweening.timeComplete - tweening.timeStart;
     219                 :         14 :             d = tweening.timeComplete - tweening.timeStart;
     220                 :         14 :             nv = tweening.transition(t, b, c, d);
     221                 :            : 
     222         [ +  + ]:         14 :             if (currentTime >= nv) {
     223                 :         20 :                 _callOnFunction(tweening.onUpdate, 'onUpdate', tweening.onUpdateScope,
     224                 :         10 :                     scope, tweening.onUpdateParams);
     225                 :            : 
     226                 :         10 :                 tweening.timesCalled++;
     227         [ +  + ]:         10 :                 if (tweening.timesCalled >= tweening.count) {
     228                 :          1 :                     isOver = true;
     229                 :            :                     break;
     230                 :            :                 }
     231                 :            : 
     232         [ +  - ]:          9 :                 if (tweening.waitFrames)
     233                 :            :                     break;
     234                 :            :             }
     235         [ +  + ]:         13 :         } while (currentTime >= nv);
     236                 :            :     } else {
     237                 :            :         var mustUpdate, name;
     238                 :            : 
     239         [ +  + ]:        406 :         if (currentTime >= tweening.timeComplete) {
     240                 :         22 :             isOver = true;
     241                 :         22 :             mustUpdate = true;
     242                 :            :         } else {
     243         [ -  + ]:        384 :             mustUpdate = tweening.skipUpdates < 1 ||
     244         [ +  - ]:        384 :                 !tweening.skipUpdates ||
     245                 :          0 :                 tweening.updatesSkipped >= tweening.skipUpdates;
     246                 :            :         }
     247                 :            : 
     248         [ +  + ]:        406 :         if (!tweening.hasStarted) {
     249                 :         48 :             _callOnFunction(tweening.onStart, 'onStart', tweening.onStartScope,
     250                 :         24 :                 scope, tweening.onStartParams);
     251                 :            : 
     252         [ +  + ]:         59 :             for (name in tweening.properties) {
     253                 :            :                 var pv;
     254                 :            : 
     255         [ +  + ]:         35 :                 if (tweening.properties[name].isSpecialProperty) {
     256                 :            :                     // It's a special property, tunnel via the special property function
     257         [ +  - ]:          1 :                     if (_specialPropertyList[name].preProcess != undefined)
     258                 :          0 :                         tweening.properties[name].valueComplete = _specialPropertyList[name].preProcess(scope, _specialPropertyList[name].parameters, tweening.properties[name].originalValueComplete, tweening.properties[name].extra);
     259                 :          1 :                     pv = _specialPropertyList[name].getValue(scope, _specialPropertyList[name].parameters, tweening.properties[name].extra);
     260                 :            :                 } else {
     261                 :            :                     // Directly read property
     262                 :         34 :                     pv = scope[name];
     263                 :            :                 }
     264         [ +  - ]:         35 :                 tweening.properties[name].valueStart = isNaN(pv) ? tweening.properties[name].valueComplete : pv;
     265                 :            :             }
     266                 :            : 
     267                 :         24 :             mustUpdate = true;
     268                 :         24 :             tweening.hasStarted = true;
     269                 :            :         }
     270                 :            : 
     271         [ -  + ]:        406 :         if (mustUpdate) {
     272         [ +  + ]:       1166 :             for (name in tweening.properties) {
     273                 :        760 :                 var property = tweening.properties[name];
     274                 :            : 
     275         [ +  + ]:        760 :                 if (isOver) {
     276                 :            :                     // Tweening time has finished, just set it to the final value
     277                 :         33 :                     nv = property.valueComplete;
     278         [ +  + ]:        727 :                 } else if (property.hasModifier) {
     279                 :            :                     // Modified
     280                 :         49 :                     t = currentTime - tweening.timeStart;
     281                 :         49 :                     d = tweening.timeComplete - tweening.timeStart;
     282                 :         49 :                     nv = tweening.transition(t, 0, 1, d, tweening.transitionParams);
     283                 :         49 :                     nv = property.modifierFunction(property.valueStart, property.valueComplete, nv, property.modifierParameters);
     284                 :            :                 } else {
     285                 :            :                     // Normal update
     286                 :        678 :                     t = currentTime - tweening.timeStart;
     287                 :        678 :                     b = property.valueStart;
     288                 :        678 :                     c = property.valueComplete - property.valueStart;
     289                 :        678 :                     d = tweening.timeComplete - tweening.timeStart;
     290                 :        678 :                     nv = tweening.transition(t, b, c, d, tweening.transitionParams);
     291                 :            :                 }
     292                 :            : 
     293         [ +  - ]:        760 :                 if (tweening.rounded)
     294                 :          0 :                     nv = Math.round(nv);
     295                 :            : 
     296 [ +  + ][ +  + ]:        760 :                 if (tweening.min !== undefined && nv < tweening.min)
     297                 :         50 :                     nv = tweening.min;
     298 [ +  + ][ +  + ]:        760 :                 if (tweening.max !== undefined && nv > tweening.max)
     299                 :         16 :                     nv = tweening.max;
     300                 :            : 
     301         [ +  + ]:        760 :                 if (property.isSpecialProperty) {
     302                 :            :                     // It's a special property, tunnel via the special property method
     303                 :         50 :                     _specialPropertyList[name].setValue(scope, nv, _specialPropertyList[name].parameters, tweening.properties[name].extra);
     304                 :            :                 } else {
     305                 :            :                     // Directly set property
     306                 :        710 :                     scope[name] = nv;
     307                 :            :                 }
     308                 :            :             }
     309                 :            : 
     310                 :        406 :             tweening.updatesSkipped = 0;
     311                 :            : 
     312                 :        812 :             _callOnFunction(tweening.onUpdate, 'onUpdate', tweening.onUpdateScope,
     313                 :        406 :                 scope, tweening.onUpdateParams);
     314                 :            :         } else {
     315                 :          0 :             tweening.updatesSkipped++;
     316                 :            :         }
     317                 :            :     }
     318                 :            : 
     319         [ +  + ]:        411 :     if (isOver) {
     320                 :         46 :         _callOnFunction(tweening.onComplete, 'onComplete', tweening.onCompleteScope,
     321                 :         23 :             scope, tweening.onCompleteParams);
     322                 :            :     }
     323                 :            : 
     324                 :        411 :     return !isOver;
     325                 :            : }
     326                 :            : 
     327                 :            : function _updateTweens() {
     328         [ +  + ]:        308 :     if (_tweenList.length == 0)
     329                 :          1 :         return false;
     330                 :            : 
     331         [ +  + ]:        803 :     for (let i = 0; i < _tweenList.length; i++) {
     332 [ +  + ][ +  + ]:        496 :         if (_tweenList[i] == undefined || !_tweenList[i].isPaused) {
     333         [ +  + ]:        471 :             if (!_updateTweenByIndex(i))
     334                 :         31 :                 _removeTweenByIndex(i);
     335                 :            : 
     336         [ +  + ]:        471 :             if (_tweenList[i] == null) {
     337                 :         32 :                 _removeTweenByIndex(i, true);
     338                 :         32 :                 i--;
     339                 :            :             }
     340                 :            :         }
     341                 :            :     }
     342                 :            : 
     343                 :        307 :     return true;
     344                 :            : }
     345                 :            : 
     346                 :            : /* Ran once every 'frame'. It's the main engine, updates all existing tweenings */
     347                 :            : function _onEnterFrame() {
     348         [ +  + ]:        308 :     if (!_updateTweens())
     349                 :          1 :         _stopEngine();
     350                 :            : 
     351                 :        308 :     return true;
     352                 :            : }
     353                 :            : 
     354                 :          1 : var restrictedWords = {
     355                 :          1 :     time: true,
     356                 :          1 :     delay: true,
     357                 :          1 :     userFrames: true,
     358                 :          1 :     skipUpdates: true,
     359                 :          1 :     transition: true,
     360                 :          1 :     transitionParams: true,
     361                 :          1 :     onStart: true,
     362                 :          1 :     onUpdate: true,
     363                 :          1 :     onComplete: true,
     364                 :          1 :     onOverwrite: true,
     365                 :          1 :     onError: true,
     366                 :          1 :     rounded: true,
     367                 :          1 :     min: true,
     368                 :          1 :     max: true,
     369                 :          1 :     onStartParams: true,
     370                 :          1 :     onUpdateParams: true,
     371                 :          1 :     onCompleteParams: true,
     372                 :          1 :     onOverwriteParams: true,
     373                 :          1 :     onStartScope: true,
     374                 :          1 :     onUpdateScope: true,
     375                 :          1 :     onCompleteScope: true,
     376                 :          1 :     onOverwriteScope: true,
     377                 :          1 :     onErrorScope: true,
     378                 :            : };
     379                 :            : 
     380                 :            : function _constructPropertyList(obj) {
     381                 :         32 :     var properties = {};
     382                 :         32 :     var modifiedProperties = {};
     383                 :            : 
     384         [ +  + ]:        144 :     for (let istr in obj) {
     385         [ +  + ]:        112 :         if (restrictedWords[istr])
     386                 :            :             continue;
     387                 :            : 
     388         [ +  + ]:         50 :         if (_specialPropertySplitterList[istr] != undefined) {
     389                 :            :             // Special property splitter
     390                 :          1 :             var splitProperties = _specialPropertySplitterList[istr].splitValues(obj[istr], _specialPropertySplitterList[istr].parameters);
     391         [ +  + ]:          3 :             for (let i = 0; i < splitProperties.length; i++) {
     392         [ +  - ]:          2 :                 if (_specialPropertySplitterList[splitProperties[i].name] != undefined) {
     393                 :          0 :                     var splitProperties2 = _specialPropertySplitterList[splitProperties[i].name].splitValues(splitProperties[i].value, _specialPropertySplitterList[splitProperties[i].name].parameters);
     394         [ #  # ]:          0 :                     for (let j = 0; j < splitProperties2.length; j++) {
     395                 :          0 :                         properties[splitProperties2[j].name] = {
     396                 :          0 :                             valueStart: undefined,
     397                 :          0 :                             valueComplete: splitProperties2[j].value,
     398                 :          0 :                             arrayIndex: splitProperties2[j].arrayIndex,
     399                 :          0 :                             isSpecialProperty: false,
     400                 :            :                         };
     401                 :            :                     }
     402                 :            :                 } else {
     403                 :          2 :                     properties[splitProperties[i].name] = {
     404                 :          2 :                         valueStart: undefined,
     405                 :          2 :                         valueComplete: splitProperties[i].value,
     406                 :          2 :                         arrayIndex: splitProperties[i].arrayIndex,
     407                 :          2 :                         isSpecialProperty: false,
     408                 :            :                     };
     409                 :            :                 }
     410                 :            :             }
     411         [ +  + ]:         49 :         } else if (_specialPropertyModifierList[istr] != undefined) {
     412                 :            :             // Special property modifier
     413                 :          1 :             let tempModifiedProperties = _specialPropertyModifierList[istr].modifyValues(obj[istr]);
     414         [ +  + ]:          2 :             for (let i = 0; i < tempModifiedProperties.length; i++) {
     415                 :          1 :                 modifiedProperties[tempModifiedProperties[i].name] = {
     416                 :          1 :                     modifierParameters: tempModifiedProperties[i].parameters,
     417                 :          1 :                     modifierFunction: _specialPropertyModifierList[istr].getValue,
     418                 :            :                 };
     419                 :            :             }
     420                 :            :         } else {
     421                 :         48 :             properties[istr] = {
     422                 :         48 :                 valueStart: undefined,
     423                 :         48 :                 valueComplete: obj[istr],
     424                 :            :             };
     425                 :            :         }
     426                 :            :     }
     427                 :            : 
     428                 :            :     // Adds the modifiers to the list of properties
     429         [ +  + ]:         33 :     for (let istr in modifiedProperties) {
     430         [ -  + ]:          1 :         if (properties[istr]) {
     431                 :          1 :             properties[istr].modifierParameters = modifiedProperties[istr].modifierParameters;
     432                 :          1 :             properties[istr].modifierFunction = modifiedProperties[istr].modifierFunction;
     433                 :            :         }
     434                 :            :     }
     435                 :            : 
     436                 :         32 :     return properties;
     437                 :            : }
     438                 :            : 
     439                 :            : function PropertyInfo(valueStart, valueComplete, originalValueComplete,
     440                 :            :     arrayIndex, extra, isSpecialProperty,
     441                 :            :     modifierFunction, modifierParameters) {
     442                 :        100 :     this._init(valueStart, valueComplete, originalValueComplete,
     443                 :         50 :         arrayIndex, extra, isSpecialProperty,
     444                 :         50 :         modifierFunction, modifierParameters);
     445                 :            : }
     446                 :            : 
     447                 :          1 : PropertyInfo.prototype = {
     448                 :          1 :     _init(valueStart, valueComplete, originalValueComplete,
     449                 :            :         arrayIndex, extra, isSpecialProperty,
     450                 :            :         modifierFunction, modifierParameters) {
     451                 :         50 :         this.valueStart             =       valueStart;
     452                 :         50 :         this.valueComplete          =       valueComplete;
     453                 :         50 :         this.originalValueComplete  =       originalValueComplete;
     454                 :         50 :         this.arrayIndex             =       arrayIndex;
     455                 :         50 :         this.extra                  =       extra;
     456                 :         50 :         this.isSpecialProperty      =       isSpecialProperty;
     457                 :         50 :         this.hasModifier            =       Boolean(modifierFunction);
     458                 :         50 :         this.modifierFunction       =       modifierFunction;
     459                 :         50 :         this.modifierParameters     =       modifierParameters;
     460                 :            :     },
     461                 :            : };
     462                 :            : 
     463                 :            : function _addTweenOrCaller(target, tweeningParameters, isCaller) {
     464         [ +  - ]:         33 :     if (!target)
     465                 :          0 :         return false;
     466                 :            : 
     467                 :            :     var scopes; // List of objects to tween
     468         [ +  - ]:         33 :     if (Array.isArray(target)) {
     469                 :            :         // The first argument is an array
     470                 :          0 :         scopes = target.concat(); // XXX: To copy the array I guess
     471                 :            :     } else {
     472                 :            :         // The first argument(s) is(are) object(s)
     473                 :         33 :         scopes = new Array(target);
     474                 :            :     }
     475                 :            : 
     476                 :            :     var obj, istr;
     477                 :            : 
     478         [ +  + ]:         33 :     if (isCaller) {
     479                 :          1 :         obj = tweeningParameters;
     480                 :            :     } else {
     481                 :         32 :         obj = TweenList.makePropertiesChain(tweeningParameters);
     482                 :            : 
     483                 :         32 :         var properties = _constructPropertyList(obj);
     484                 :            : 
     485                 :            :         // Verifies whether the properties exist or not, for warning messages
     486         [ +  + ]:         82 :         for (istr in properties) {
     487         [ +  + ]:         50 :             if (_specialPropertyList[istr] != undefined) {
     488                 :          1 :                 properties[istr].isSpecialProperty = true;
     489                 :            :             } else {
     490         [ +  + ]:         98 :                 for (var i = 0; i < scopes.length; i++) {
     491         [ +  - ]:         49 :                     if (scopes[i][istr] == undefined) {
     492                 :          0 :                         log(`The property ${istr} doesn't seem to be a ` +
     493                 :          0 :                             `normal object property of ${scopes[i]} or a ` +
     494                 :          0 :                             'registered special property');
     495                 :            :                     }
     496                 :            :                 }
     497                 :            :             }
     498                 :            :         }
     499                 :            :     }
     500                 :            : 
     501                 :            :     // Creates the main engine if it isn't active
     502         [ +  + ]:         33 :     if (!_inited)
     503                 :          1 :         _init();
     504         [ +  + ]:         33 :     if (!_engineExists)
     505                 :          2 :         _startEngine();
     506                 :            : 
     507                 :            :     // Creates a "safer", more strict tweening object
     508         [ +  + ]:         33 :     var time = obj.time || 0;
     509         [ +  + ]:         33 :     var delay = obj.delay || 0;
     510                 :            : 
     511                 :            :     var transition;
     512                 :            : 
     513                 :            :     // FIXME: Tweener allows you to use functions with an all lower-case name
     514         [ +  + ]:         33 :     if (typeof obj.transition == 'string')
     515                 :          7 :         transition = imports.tweener.equations[obj.transition];
     516                 :            :     else
     517                 :         26 :         transition = obj.transition;
     518                 :            : 
     519         [ +  + ]:         33 :     if (!transition)
     520                 :         26 :         transition = imports.tweener.equations['easeOutExpo'];
     521                 :            : 
     522                 :            :     var tween;
     523                 :            : 
     524         [ +  + ]:         66 :     for (let i = 0; i < scopes.length; i++) {
     525         [ +  + ]:         33 :         if (!isCaller) {
     526                 :            :             // Make a copy of the properties
     527                 :         32 :             var copyProperties = {};
     528         [ +  + ]:         82 :             for (istr in properties) {
     529                 :        100 :                 copyProperties[istr] = new PropertyInfo(properties[istr].valueStart,
     530                 :         50 :                     properties[istr].valueComplete,
     531                 :         50 :                     properties[istr].valueComplete,
     532         [ -  + ]:         50 :                     properties[istr].arrayIndex || 0,
     533                 :         50 :                     {},
     534         [ +  + ]:         50 :                     properties[istr].isSpecialProperty || false,
     535         [ +  + ]:         50 :                     properties[istr].modifierFunction || null,
     536         [ -  + ]:         50 :                     properties[istr].modifierParameters || null);
     537                 :            :             }
     538                 :            :         }
     539                 :            : 
     540                 :         66 :         tween = new TweenList.TweenList(scopes[i],
     541                 :         33 :             _ticker.getTime() + delay * 1000 / _timeScale,
     542                 :         33 :             _ticker.getTime() + (delay * 1000 + time * 1000) / _timeScale,
     543                 :         33 :             false,
     544                 :         33 :             transition,
     545         [ -  + ]:         33 :             obj.transitionParams || null);
     546                 :            : 
     547         [ +  + ]:         33 :         tween.properties               =       isCaller ? null : copyProperties;
     548                 :         33 :         tween.onStart                  =       obj.onStart;
     549                 :         33 :         tween.onUpdate                 =       obj.onUpdate;
     550                 :         33 :         tween.onComplete               =       obj.onComplete;
     551                 :         33 :         tween.onOverwrite              =       obj.onOverwrite;
     552                 :         33 :         tween.onError                  =       obj.onError;
     553                 :         33 :         tween.onStartParams            =       obj.onStartParams;
     554                 :         33 :         tween.onUpdateParams           =       obj.onUpdateParams;
     555                 :         33 :         tween.onCompleteParams         =       obj.onCompleteParams;
     556                 :         33 :         tween.onOverwriteParams        =       obj.onOverwriteParams;
     557                 :         33 :         tween.onStartScope             =       obj.onStartScope;
     558                 :         33 :         tween.onUpdateScope            =       obj.onUpdateScope;
     559                 :         33 :         tween.onCompleteScope          =       obj.onCompleteScope;
     560                 :         33 :         tween.onOverwriteScope         =       obj.onOverwriteScope;
     561                 :         33 :         tween.onErrorScope             =       obj.onErrorScope;
     562                 :         33 :         tween.rounded                  =       obj.rounded;
     563                 :         33 :         tween.min                      =       obj.min;
     564                 :         33 :         tween.max                      =       obj.max;
     565                 :         33 :         tween.skipUpdates              =       obj.skipUpdates;
     566                 :         33 :         tween.isCaller                 =       isCaller;
     567                 :            : 
     568         [ +  + ]:         33 :         if (isCaller) {
     569                 :          1 :             tween.count = obj.count;
     570                 :          1 :             tween.waitFrames = obj.waitFrames;
     571                 :            :         }
     572                 :            : 
     573         [ +  + ]:         33 :         if (!isCaller) {
     574                 :            :             // Remove other tweenings that occur at the same time
     575                 :         32 :             removeTweensByTime(tween.scope, tween.properties, tween.timeStart, tween.timeComplete);
     576                 :            :         }
     577                 :            : 
     578                 :            :         // And finally adds it to the list
     579                 :         33 :         _tweenList.push(tween);
     580                 :            : 
     581                 :            :         // Immediate update and removal if it's an immediate tween
     582                 :            :         // If not deleted, it executes at the end of this frame execution
     583 [ +  + ][ +  + ]:         33 :         if (time == 0 && delay == 0) {
     584                 :          1 :             var myT = _tweenList.length - 1;
     585                 :          1 :             _updateTweenByIndex(myT);
     586                 :          1 :             _removeTweenByIndex(myT);
     587                 :            :         }
     588                 :            :     }
     589                 :            : 
     590                 :         33 :     return true;
     591                 :            : }
     592                 :            : 
     593                 :            : function addTween(target, tweeningParameters) {
     594                 :         32 :     return _addTweenOrCaller(target, tweeningParameters, false);
     595                 :            : }
     596                 :            : 
     597                 :            : function addCaller(target, tweeningParameters) {
     598                 :          1 :     return _addTweenOrCaller(target, tweeningParameters, true);
     599                 :            : }
     600                 :            : 
     601                 :            : function _getNumberOfProperties(object) {
     602                 :         21 :     var totalProperties = 0;
     603                 :            : 
     604                 :            :     // the following line is disabled because eslint was picking up the following error: the variable name is defined but never used, however since it is required to search the object it is used and we'll allow the line to be ignored to get rid of the error message
     605                 :            :     /* eslint-disable-next-line */
     606         [ +  + ]:         39 :     for (let name in object) {
     607                 :         18 :         totalProperties++;
     608                 :            :     }
     609                 :            : 
     610                 :            : 
     611                 :         21 :     return totalProperties;
     612                 :            : }
     613                 :            : 
     614                 :            : function removeTweensByTime(scope, properties, timeStart, timeComplete) {
     615                 :         32 :     var removed = false;
     616                 :            :     var removedLocally;
     617                 :            :     var name;
     618                 :            : 
     619         [ +  + ]:         77 :     for (let i = 0; i < _tweenList.length; i++) {
     620                 :         45 :         removedLocally = false;
     621                 :            : 
     622         [ +  + ]:         45 :         if (_tweenList[i] &&
     623         [ +  + ]:         42 :             scope == _tweenList[i].scope &&
     624         [ -  + ]:         13 :             timeComplete > _tweenList[i].timeStart &&
     625         [ +  + ]:         13 :             timeStart < _tweenList[i].timeComplete) {
     626         [ +  + ]:         30 :             for (name in _tweenList[i].properties) {
     627         [ +  + ]:         18 :                 if (properties[name]) {
     628         [ +  + ]:          9 :                     if (!removedLocally) {
     629                 :          6 :                         _callOnFunction(_tweenList[i].onOverwrite, 'onOverwrite', _tweenList[i].onOverwriteScope,
     630                 :          3 :                             _tweenList[i].scope, _tweenList[i].onOverwriteParams);
     631                 :            :                     }
     632                 :            : 
     633                 :          9 :                     _tweenList[i].properties[name] = undefined;
     634                 :          9 :                     delete _tweenList[i].properties[name];
     635                 :          9 :                     removedLocally = true;
     636                 :          9 :                     removed = true;
     637                 :            :                 }
     638                 :            :             }
     639                 :            : 
     640         [ +  + ]:         12 :             if (removedLocally &&
     641         [ +  + ]:          3 :                 _getNumberOfProperties(_tweenList[i].properties) == 0)
     642                 :          3 :                 _removeTweenByIndex(i);
     643                 :            :         }
     644                 :            :     }
     645                 :            : 
     646                 :         32 :     return removed;
     647                 :            : }
     648                 :            : 
     649                 :            : function _pauseTweenByIndex(i) {
     650                 :          5 :     var tweening = _tweenList[i];
     651                 :            : 
     652 [ -  + ][ +  + ]:          5 :     if (tweening == null || tweening.isPaused)
     653                 :          1 :         return false;
     654                 :            : 
     655                 :          4 :     tweening.timePaused = _getCurrentTweeningTime(tweening);
     656                 :          4 :     tweening.isPaused = true;
     657                 :            : 
     658                 :          4 :     return true;
     659                 :            : }
     660                 :            : 
     661                 :            : function _splitTweens(tween, properties) {
     662                 :          0 :     var originalTween = _tweenList[tween];
     663                 :          0 :     var newTween = originalTween.clone();
     664                 :            :     var name;
     665                 :            : 
     666         [ #  # ]:          0 :     for (let i = 0; i < properties.length; i++) {
     667                 :          0 :         name = properties[i];
     668         [ #  # ]:          0 :         if (originalTween.properties[name]) {
     669                 :          0 :             originalTween.properties[name] = undefined;
     670                 :          0 :             delete originalTween.properties[name];
     671                 :            :         }
     672                 :            :     }
     673                 :            : 
     674                 :          0 :     var found = false;
     675         [ #  # ]:          0 :     for (name in newTween.properties) {
     676                 :          0 :         found = false;
     677         [ #  # ]:          0 :         for (let i = 0; i < properties.length; i++) {
     678         [ #  # ]:          0 :             if (properties[i] == name) {
     679                 :          0 :                 found = true;
     680                 :            :                 break;
     681                 :            :             }
     682                 :            :         }
     683                 :            : 
     684         [ #  # ]:          0 :         if (!found) {
     685                 :          0 :             newTween.properties[name] = undefined;
     686                 :          0 :             delete newTween.properties[name];
     687                 :            :         }
     688                 :            :     }
     689                 :            : 
     690                 :          0 :     _tweenList.push(newTween);
     691                 :          0 :     return _tweenList.length - 1;
     692                 :            : }
     693                 :            : 
     694                 :            : function _affectTweens(affectFunction, scope, properties) {
     695                 :          6 :     var affected = false;
     696                 :            : 
     697         [ +  - ]:          6 :     if (!_tweenList)
     698                 :          0 :         return false;
     699                 :            : 
     700         [ +  + ]:         31 :     for (let i = 0; i < _tweenList.length; i++) {
     701 [ -  + ][ +  + ]:         25 :         if (!_tweenList[i] || _tweenList[i].scope != scope)
     702                 :            :             continue;
     703                 :            : 
     704         [ +  + ]:         11 :         if (properties.length == 0) {
     705                 :            :             // Can check everything
     706                 :          1 :             affectFunction(i);
     707                 :          1 :             affected = true;
     708                 :            :         } else {
     709                 :            :             // Must check whether this tween must have specific properties affected
     710                 :         10 :             var affectedProperties = [];
     711         [ +  + ]:         27 :             for (let j = 0; j < properties.length; j++) {
     712         [ +  + ]:         17 :                 if (_tweenList[i].properties[properties[j]])
     713                 :          6 :                     affectedProperties.push(properties[j]);
     714                 :            :             }
     715                 :            : 
     716         [ +  + ]:         10 :             if (affectedProperties.length > 0) {
     717                 :          6 :                 var objectProperties = _getNumberOfProperties(_tweenList[i].properties);
     718         [ -  + ]:          6 :                 if (objectProperties == affectedProperties.length) {
     719                 :            :                     // The list of properties is the same as all properties, so affect it all
     720                 :          6 :                     affectFunction(i);
     721                 :          6 :                     affected = true;
     722                 :            :                 } else {
     723                 :            :                     // The properties are mixed, so split the tween and affect only certain specific
     724                 :            :                     // properties
     725                 :          0 :                     var splicedTweenIndex = _splitTweens(i, affectedProperties);
     726                 :          0 :                     affectFunction(splicedTweenIndex);
     727                 :          0 :                     affected = true;
     728                 :            :                 }
     729                 :            :             }
     730                 :            :         }
     731                 :            :     }
     732                 :            : 
     733                 :          6 :     return affected;
     734                 :            : }
     735                 :            : 
     736                 :            : function _isInArray(string, array) {
     737                 :          7 :     var l = array.length;
     738                 :            : 
     739         [ +  + ]:          9 :     for (let i = 0; i < l; i++) {
     740         [ +  - ]:          2 :         if (array[i] == string)
     741                 :          0 :             return true;
     742                 :            :     }
     743                 :            : 
     744                 :          7 :     return false;
     745                 :          0 : }
     746                 :            : 
     747                 :            : function _affectTweensWithFunction(func, args) {
     748                 :          6 :     var properties = [];
     749                 :          6 :     var scope = args[0];
     750                 :          6 :     var affected = false;
     751                 :            :     var scopes;
     752                 :            : 
     753         [ +  - ]:          6 :     if (Array.isArray(scope))
     754                 :          0 :         scopes = scope.concat();
     755                 :            :     else
     756                 :          6 :         scopes = new Array(scope);
     757                 :            : 
     758         [ +  + ]:         13 :     for (let i = 1; args[i] != undefined; i++) {
     759 [ -  + ][ -  + ]:          7 :         if (typeof args[i] == 'string' && !_isInArray(args[i], properties)) {
     760         [ +  - ]:          7 :             if (_specialPropertySplitterList[args[i]]) {
     761                 :            :                 // special property, get splitter array first
     762                 :          0 :                 var sps = _specialPropertySplitterList[arguments[i]];
     763                 :          0 :                 var specialProps = sps.splitValues(scope, null);
     764         [ #  # ]:          0 :                 for (let j = 0; j < specialProps.length; j++)
     765                 :          0 :                     properties.push(specialProps[j].name);
     766                 :            :             } else {
     767                 :          7 :                 properties.push(args[i]);
     768                 :            :             }
     769                 :            :         }
     770                 :            :     }
     771                 :            : 
     772                 :            :     // the return now value means: "affect at least one tween"
     773         [ +  + ]:         12 :     for (let i = 0; i < scopes.length; i++)
     774         [ -  + ]:          6 :         affected = affected || _affectTweens(func, scopes[i], properties);
     775                 :            : 
     776                 :          6 :     return affected;
     777                 :            : }
     778                 :            : 
     779                 :            : function resumeTweens() {
     780                 :          1 :     return _affectTweensWithFunction(_resumeTweenByIndex, arguments);
     781                 :            : }
     782                 :            : 
     783                 :            : function pauseTweens() {
     784                 :          3 :     return _affectTweensWithFunction(_pauseTweenByIndex, arguments);
     785                 :            : }
     786                 :            : 
     787                 :            : function removeTweens() {
     788                 :          2 :     return _affectTweensWithFunction(_removeTweenByIndex, arguments);
     789                 :            : }
     790                 :            : 
     791                 :            : function _mapOverTweens(func) {
     792                 :          3 :     var rv = false;
     793                 :            : 
     794         [ +  - ]:          3 :     if (_tweenList == null)
     795                 :          0 :         return false;
     796                 :            : 
     797         [ +  + ]:         11 :     for (let i = 0; i < _tweenList.length; i++) {
     798         [ +  + ]:          8 :         if (func(i))
     799                 :          7 :             rv = true;
     800                 :            :     }
     801                 :            : 
     802                 :          3 :     return rv;
     803                 :            : }
     804                 :            : 
     805                 :            : function pauseAllTweens() {
     806                 :          1 :     return _mapOverTweens(_pauseTweenByIndex);
     807                 :            : }
     808                 :            : 
     809                 :            : function resumeAllTweens() {
     810                 :          1 :     return _mapOverTweens(_resumeTweenByIndex);
     811                 :            : }
     812                 :            : 
     813                 :            : function removeAllTweens() {
     814                 :          1 :     return _mapOverTweens(_removeTweenByIndex);
     815                 :            : }
     816                 :            : 
     817                 :            : function getTweenCount(scope) {
     818         [ +  - ]:          6 :     if (!_tweenList)
     819                 :          0 :         return 0;
     820                 :            : 
     821                 :          6 :     var c = 0;
     822                 :            : 
     823         [ +  + ]:         20 :     for (let i = 0; i < _tweenList.length; i++) {
     824 [ +  + ][ +  + ]:         14 :         if (_tweenList[i] && _tweenList[i].scope == scope)
     825                 :         12 :             c += _getNumberOfProperties(_tweenList[i].properties);
     826                 :            :     }
     827                 :            : 
     828                 :          6 :     return c;
     829                 :            : }
     830                 :            : 
     831                 :            : function registerSpecialProperty(name, getFunction, setFunction,
     832                 :            :     parameters, preProcessFunction) {
     833                 :          1 :     _specialPropertyList[name] = {
     834                 :          1 :         getValue: getFunction,
     835                 :          1 :         setValue: setFunction,
     836                 :          1 :         parameters,
     837                 :          1 :         preProcess: preProcessFunction,
     838                 :            :     };
     839                 :            : }
     840                 :            : 
     841                 :            : function registerSpecialPropertyModifier(name, modifyFunction, getFunction) {
     842                 :          1 :     _specialPropertyModifierList[name] = {
     843                 :          1 :         modifyValues: modifyFunction,
     844                 :          1 :         getValue: getFunction,
     845                 :            :     };
     846                 :            : }
     847                 :            : 
     848                 :            : function registerSpecialPropertySplitter(name, splitFunction, parameters) {
     849                 :          1 :     _specialPropertySplitterList[name] = {
     850                 :          1 :         splitValues: splitFunction,
     851                 :          1 :         parameters,
     852                 :            :     };
     853                 :            : }
     854                 :            : 
     855                 :            : function setTimeScale(scale) {
     856                 :          0 :     _timeScale = scale;
     857                 :            : }
     858                 :            : 
     859                 :            : function getTimeScale() {
     860                 :          0 :     return _timeScale;
     861                 :            : }

Generated by: LCOV version 1.14