/* Animation Task Manager Usage: window['piro.sakura.ne.jp'].animationManager.addTask( function(aTime, aBeginningValue, aTotalChange, aDuration) { // some animation task runned by interval var current = someEasingFunction(aTime, aBeginningValue, aTotalChange, aDuration); target.style.left = current+'px'; return aTime > aDuration; // return true if the animation finished. }, 100, // beginning 200, // total change (so, the final value will be 100+200=300) 250, // msec, duration window // the window (used by Firefox 4 animation frame API) ); // stop all window['piro.sakura.ne.jp'].animationManager.stop(); // restart after doing something window['piro.sakura.ne.jp'].animationManager.start(); license: The MIT License, Copyright (c) 2009-2012 YUKI "Piro" Hiroshi http://github.com/piroor/fxaddonlibs/blob/master/license.txt original: http://github.com/piroor/fxaddonlibs/blob/master/animationManager.js */ /* To work as a JS Code Module (*require jstimer.jsm) http://github.com/piroor/fxaddonlibs/blob/master/jstimer.jsm */ if (typeof window == 'undefined' || (window && typeof window.constructor == 'function')) { this.EXPORTED_SYMBOLS = ['animationManager']; // If namespace.jsm is available, export symbols to the shared namespace. // See: http://github.com/piroor/fxaddonlibs/blob/master/namespace.jsm let ns = {}; try { Components.utils.import('resource://treestyletab-modules/lib/namespace.jsm', ns); /* var */ window = ns.getNamespaceFor('piro.sakura.ne.jp'); } catch(e) { window = {}; } if (!('setInterval' in window)) Components.utils.import('resource://treestyletab-modules/lib/jstimer.jsm', window); } (function() { const currentRevision = 16; if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {}; var loadedRevision = 'animationManager' in window['piro.sakura.ne.jp'] ? window['piro.sakura.ne.jp'].animationManager.revision : 0 ; var tasks = !loadedRevision ? [] : window['piro.sakura.ne.jp'].animationManager.tasks ; var windows = !loadedRevision ? [] : window['piro.sakura.ne.jp'].animationManager._windows || [] ; if (loadedRevision && loadedRevision > currentRevision) { return; } var Cc = Components.classes; var Ci = Components.interfaces; if (tasks.length) window['piro.sakura.ne.jp'].animationManager.stop(); window['piro.sakura.ne.jp'].animationManager = { revision : currentRevision, running : false, addTask : function(aTask, aBeginningValue, aTotalChange, aDuration, aRelatedWindow) { if (!aRelatedWindow && window instanceof Ci.nsIDOMWindow) aRelatedWindow = window; if (!aTask || !aRelatedWindow) return; if (this._windows.indexOf(aRelatedWindow) < 0) this._windows.push(aRelatedWindow); this.tasks.push({ task : aTask, start : aRelatedWindow ? aRelatedWindow.mozAnimationStartTime : Date.now(), beginning : aBeginningValue, change : aTotalChange, duration : aDuration, window : aRelatedWindow }); this.start(); }, removeTask : function(aTask) { if (!aTask) return; for (let i = this.tasks.length - 1; i > -1; i--) { let registeredTask = this.tasks[i]; if (registeredTask) { if (registeredTask.task != aTask) continue; delete registeredTask.task; delete registeredTask.start; delete registeredTask.beginning; delete registeredTask.change; delete registeredTask.duration; delete registeredTask.window; } this.tasks.splice(i, 1); } this._cleanUpWindows(); }, start : function() { if (!this._windows.length) return; this._windows.forEach(function(aWindow) { if (this._animatingWindows.indexOf(aWindow) > -1) return; this._animatingWindows.push(aWindow); let self = this; aWindow.mozRequestAnimationFrame(function() { self.processAnimationFrame(aWindow); }); }, this); }, stop : function() { this._animatingWindows = []; }, removeAllTasks : function() { this.stop(); this.tasks = []; this._windows = []; }, tasks : tasks, _windows : windows, _animatingWindows : [], _cleanUpWindows : function() { for (let i = this._windows.length - 1; i > -1; i--) { let w = this._windows[i]; if (this.tasks.some(function(aTask) { return aTask && aTask.window == w; })) continue; let index = this._animatingWindows.indexOf(w); if (index > -1) this._animatingWindows.splice(index, 1); this._windows.splice(i, 1); } }, processAnimationFrame : function(aWindow) { if (this._animatingWindows.indexOf(aWindow) > -1) { this.onAnimation(aWindow); } this._cleanUpWindows(); if (this._animatingWindows.indexOf(aWindow) > -1) { let self = this; aWindow.mozRequestAnimationFrame(function() { self.processAnimationFrame(aWindow); }); } }, onAnimation : function(aWindow) { // task should return true if it finishes. var now = Date.now(); for (let i = this.tasks.length - 1; i > -1; i--) { let task = this.tasks[i]; try { if (task && !task.window.closed) { if (task.window != aWindow) continue; let time = Math.min(task.duration, now - task.start); let finished = task.task( time, task.beginning, task.change, task.duration ); if (!finished && (time < task.duration)) continue; } } catch(e) { dump(e+'\n'+e.stack+'\n'); } this.tasks.splice(i, 1); } } }; if (tasks.length) window['piro.sakura.ne.jp'].animationManager.start(); })(); if (window != this) { // work as a JS Code Module this.animationManager = window['piro.sakura.ne.jp'].animationManager; }