mirror of
https://github.com/flynx/PortableMag.git
synced 2025-10-29 03:00:09 +00:00
updated jli.js...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
95d35f7f3a
commit
8a8288998a
560
lib/jli.js
560
lib/jli.js
@ -9,6 +9,16 @@
|
|||||||
|
|
||||||
//var DEBUG = DEBUG != null ? DEBUG : true
|
//var DEBUG = DEBUG != null ? DEBUG : true
|
||||||
|
|
||||||
|
var POOL_SIZE = 64
|
||||||
|
|
||||||
|
var DEFAULT_TRANSITION_DURATION = 200
|
||||||
|
|
||||||
|
// XXX this affects only the innertial part, not setCurrentPage...
|
||||||
|
var USE_TRANSITIONS_FOR_ANIMATION = false
|
||||||
|
|
||||||
|
var USE_TRANSFORM = true
|
||||||
|
var USE_3D_TRANSFORM = true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
@ -33,20 +43,25 @@
|
|||||||
// - <index> : 0 for 'off' and 1 for 'on' (see below)
|
// - <index> : 0 for 'off' and 1 for 'on' (see below)
|
||||||
// - 'on' : switch mode on -- add class
|
// - 'on' : switch mode on -- add class
|
||||||
// - 'off' : switch mode off -- remove class
|
// - 'off' : switch mode off -- remove class
|
||||||
|
// - '!' : reload current state, same as toggler(toggler('?'))
|
||||||
// - '?' : return current state ('on'|'off')
|
// - '?' : return current state ('on'|'off')
|
||||||
//
|
//
|
||||||
// In forms 2 and 3, if class_list is a list of strings, the <action> can be:
|
// In forms 2 and 3, if class_list is a list of strings, the <action> can be:
|
||||||
// - <index> : explicitly set the state to index in class_list
|
// - <index> : explicitly set the state to index in class_list
|
||||||
// - <class-name> : explicitly set a class from the list
|
// - <class-name> : explicitly set a class from the list
|
||||||
|
// - '!' : reload current state, same as toggler(toggler('?'))
|
||||||
// - '?' : return current state ('on'|'off')
|
// - '?' : return current state ('on'|'off')
|
||||||
//
|
//
|
||||||
|
//
|
||||||
// In the third form the <target> is a jquery-compatible object.
|
// In the third form the <target> is a jquery-compatible object.
|
||||||
//
|
//
|
||||||
// In all forms this will return the current state string or null if the
|
// In all forms this will return the current state string or null if the
|
||||||
// action argument given is invalid.
|
// action argument given is invalid.
|
||||||
//
|
//
|
||||||
|
// NOTE: action '?' is handled internally and not passed to the callbacks.
|
||||||
// NOTE: there is a special action 'next', passing it will have the same
|
// NOTE: there is a special action 'next', passing it will have the same
|
||||||
// effect as not passing any action.
|
// effect as not passing any action -- we will change to the next
|
||||||
|
// state.
|
||||||
// NOTE: if it is needed to apply this to an explicit target but with
|
// NOTE: if it is needed to apply this to an explicit target but with
|
||||||
// no explicit action, just pass 'next' as the second argument.
|
// no explicit action, just pass 'next' as the second argument.
|
||||||
// NOTE: a special class name 'none' means no class is set, if it is present
|
// NOTE: a special class name 'none' means no class is set, if it is present
|
||||||
@ -58,14 +73,27 @@
|
|||||||
// a way around this is to pass an empty function as callback_b
|
// a way around this is to pass an empty function as callback_b
|
||||||
// NOTE: leading dots in class names in class_list are optional.
|
// NOTE: leading dots in class names in class_list are optional.
|
||||||
// this is due to several times I've repeated the same mistake of
|
// this is due to several times I've repeated the same mistake of
|
||||||
// forgetting to write the classes without leading dots, this now
|
// forgetting to write the classes without leading dots, the class
|
||||||
// will normalize the class list...
|
// list is not normalized...
|
||||||
|
// NOTE: the toggler can be passed a non-jquery object, but then only an
|
||||||
|
// explicit state is supported as the second argument, the reason
|
||||||
|
// being that we can not determain the current state without a propper
|
||||||
|
// .hasClass(..) test...
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// This also takes one or two callbacks. If only one is given then it is
|
// This also takes one or two callbacks. If only one is given then it is
|
||||||
// called after (post) the change is made. If two are given then the first
|
// called after (post) the change is made. If two are given then the first
|
||||||
// is called before the change and the second after the change.
|
// is called before the change and the second after the change.
|
||||||
// The callbacks are passed the current action.
|
//
|
||||||
|
// The callbacks are passed two arguments:
|
||||||
|
// - <action> : the state we are going in
|
||||||
|
// - <target> : the target element or the element passed to the
|
||||||
|
// toggler
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// The callback function will have 'this' set to the same value as the
|
||||||
|
// toggler itself, e.g. if the toggler is called as a method, the
|
||||||
|
// callback's 'this' will reference it's parent object.
|
||||||
//
|
//
|
||||||
// NOTE: the pre-callback will get the "intent" action, i.e. the state the
|
// NOTE: the pre-callback will get the "intent" action, i.e. the state the
|
||||||
// we are changing into but the changes are not yet made.
|
// we are changing into but the changes are not yet made.
|
||||||
@ -105,6 +133,7 @@ function createCSSClassToggler(elem, class_list, callback_a, callback_b){
|
|||||||
var e = a
|
var e = a
|
||||||
var action = b == 'next' ? null : b
|
var action = b == 'next' ? null : b
|
||||||
}
|
}
|
||||||
|
var args = args2array(arguments).slice(2)
|
||||||
e = $(e)
|
e = $(e)
|
||||||
// option number...
|
// option number...
|
||||||
if(typeof(action) == typeof(1)){
|
if(typeof(action) == typeof(1)){
|
||||||
@ -119,7 +148,7 @@ function createCSSClassToggler(elem, class_list, callback_a, callback_b){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// we need to get the current state...
|
// we need to get the current state...
|
||||||
if(action == null || action == '?'){
|
if(action == null || action == '?' || action == '!'){
|
||||||
// get current state...
|
// get current state...
|
||||||
var cur = 'none'
|
var cur = 'none'
|
||||||
for(var i=0; i < class_list.length; i++){
|
for(var i=0; i < class_list.length; i++){
|
||||||
@ -133,6 +162,11 @@ function createCSSClassToggler(elem, class_list, callback_a, callback_b){
|
|||||||
return bool_action ? (cur == 'none' ? 'off' : 'on') : cur
|
return bool_action ? (cur == 'none' ? 'off' : 'on') : cur
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// force reload of current state...
|
||||||
|
if(action == '!'){
|
||||||
|
action = bool_action ? (cur == 'none' ? 'off' : 'on') : cur
|
||||||
|
}
|
||||||
|
|
||||||
// invalid action...
|
// invalid action...
|
||||||
} else if((bool_action && ['on', 'off'].indexOf(action) == -1)
|
} else if((bool_action && ['on', 'off'].indexOf(action) == -1)
|
||||||
|| (!bool_action && class_list.indexOf(action) == -1)){
|
|| (!bool_action && class_list.indexOf(action) == -1)){
|
||||||
@ -154,10 +188,14 @@ function createCSSClassToggler(elem, class_list, callback_a, callback_b){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: the callbacks are passed the same this as the calling
|
||||||
|
// function, this will enable them to act as metods correctly
|
||||||
// pre callback...
|
// pre callback...
|
||||||
if(callback_pre != null){
|
if(callback_pre != null){
|
||||||
if(callback_pre(action) === false){
|
if(callback_pre.apply(this, [action, e].concat(args)) === false){
|
||||||
return
|
// XXX should we return action here???
|
||||||
|
//return
|
||||||
|
return func('?')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// update the element...
|
// update the element...
|
||||||
@ -167,7 +205,7 @@ function createCSSClassToggler(elem, class_list, callback_a, callback_b){
|
|||||||
}
|
}
|
||||||
// post callback...
|
// post callback...
|
||||||
if(callback_post != null){
|
if(callback_post != null){
|
||||||
callback_post(action)
|
callback_post.apply(this, [action, e].concat(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
return action
|
return action
|
||||||
@ -284,6 +322,7 @@ var getElementScale = makeCSSVendorAttrGetter(
|
|||||||
return parseFloat((/(scale|matrix)\(([^),]*)\)/).exec(data)[2])
|
return parseFloat((/(scale|matrix)\(([^),]*)\)/).exec(data)[2])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
var getElementShift = makeCSSVendorAttrGetter(
|
var getElementShift = makeCSSVendorAttrGetter(
|
||||||
'transform',
|
'transform',
|
||||||
{left: 0, top: 0},
|
{left: 0, top: 0},
|
||||||
@ -296,21 +335,17 @@ var getElementShift = makeCSSVendorAttrGetter(
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
var DEFAULT_TRANSITION_DURATION = 200
|
|
||||||
|
|
||||||
var getElementTransitionDuration = makeCSSVendorAttrGetter(
|
var getElementTransitionDuration = makeCSSVendorAttrGetter(
|
||||||
'transitionDuration',
|
'transitionDuration',
|
||||||
DEFAULT_TRANSITION_DURATION,
|
DEFAULT_TRANSITION_DURATION,
|
||||||
parseInt)
|
parseInt)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var USE_3D_TRANSFORM = true
|
|
||||||
|
|
||||||
// NOTE: at this point this works only on the X axis...
|
// NOTE: at this point this works only on the X axis...
|
||||||
function setElementTransform(elem, offset, scale, duration){
|
function setElementTransform(elem, offset, scale, duration){
|
||||||
elem = $(elem)
|
elem = $(elem)
|
||||||
var t3d = USE_3D_TRANSFORM ? 'translateZ(0px)' : ''
|
//var t3d = USE_3D_TRANSFORM ? 'translateZ(0px)' : ''
|
||||||
|
var t3d = USE_3D_TRANSFORM ? 'translate3d(0,0,0)' : ''
|
||||||
|
|
||||||
if(offset == null){
|
if(offset == null){
|
||||||
offset = getElementShift(elem)
|
offset = getElementShift(elem)
|
||||||
@ -366,9 +401,6 @@ function setElementTransform(elem, offset, scale, duration){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// XXX this affects only the innertial part, not setCurrentPage...
|
|
||||||
var USE_TRANSITIONS_FOR_ANIMATION = false
|
|
||||||
|
|
||||||
// XXX make this a drop-in replacement for setElementTransform...
|
// XXX make this a drop-in replacement for setElementTransform...
|
||||||
// XXX cleanup, still flacky...
|
// XXX cleanup, still flacky...
|
||||||
function animateElementTo(elem, to, duration, easing, speed, use_transitions){
|
function animateElementTo(elem, to, duration, easing, speed, use_transitions){
|
||||||
@ -430,12 +462,12 @@ function animateElementTo(elem, to, duration, easing, speed, use_transitions){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do an intermediate step...
|
// do an intermediate step...
|
||||||
// XXX do propper easing...
|
// XXX do proper easing...
|
||||||
// XXX sometimes results in jumping around...
|
// XXX sometimes results in jumping around...
|
||||||
// ...result of jumping over the to position...
|
// ...result of jumping over the to position...
|
||||||
if(speed != null){
|
if(speed != null){
|
||||||
|
|
||||||
// XXX the folowing two blocks are the same...
|
// XXX the following two blocks are the same...
|
||||||
// XXX looks a bit too complex, revise...
|
// XXX looks a bit too complex, revise...
|
||||||
if(Math.abs(dist.top) >= 1){
|
if(Math.abs(dist.top) >= 1){
|
||||||
dy = ((t - start) * speed.y)
|
dy = ((t - start) * speed.y)
|
||||||
@ -466,7 +498,7 @@ function animateElementTo(elem, to, duration, easing, speed, use_transitions){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX this is a staright forward linear function...
|
// XXX this is a straight forward linear function...
|
||||||
} else {
|
} else {
|
||||||
var r = (t - start) / duration
|
var r = (t - start) / duration
|
||||||
cur.top = Math.round(from.top + (dist.top * r))
|
cur.top = Math.round(from.top + (dist.top * r))
|
||||||
@ -481,6 +513,7 @@ function animateElementTo(elem, to, duration, easing, speed, use_transitions){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function stopAnimation(elem){
|
function stopAnimation(elem){
|
||||||
if(elem.next_frame){
|
if(elem.next_frame){
|
||||||
cancelAnimationFrame(elem.next_frame)
|
cancelAnimationFrame(elem.next_frame)
|
||||||
@ -493,11 +526,26 @@ function setElementScale(elem, scale){
|
|||||||
return setElementTransform(elem, null, scale)
|
return setElementTransform(elem, null, scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function setElementOrigin(elem, x, y, z){
|
||||||
|
x = x == null ? '50%' : x
|
||||||
|
y = y == null ? '50%' : y
|
||||||
|
z = z == null ? '0' : z
|
||||||
|
var value = x +' '+ y +' '+ z
|
||||||
|
|
||||||
|
return $(elem).css({
|
||||||
|
'transform-origin': value,
|
||||||
|
'-ms-transform-origin': value,
|
||||||
|
'-webkit-transform-origin': value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function setTransitionEasing(elem, ease){
|
function setTransitionEasing(elem, ease){
|
||||||
if(typeof(ms) == typeof(0)){
|
if(typeof(ms) == typeof(0)){
|
||||||
ms = ms + 'ms'
|
ms = ms + 'ms'
|
||||||
}
|
}
|
||||||
return elem.css({
|
return $(elem).css({
|
||||||
'transition-timing-function': ease,
|
'transition-timing-function': ease,
|
||||||
'-moz-transition-timing-function': ease,
|
'-moz-transition-timing-function': ease,
|
||||||
'-o-transition-timing-function': ease,
|
'-o-transition-timing-function': ease,
|
||||||
@ -506,6 +554,7 @@ function setTransitionEasing(elem, ease){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function setTransitionDuration(elem, ms){
|
function setTransitionDuration(elem, ms){
|
||||||
if(typeof(ms) == typeof(0)){
|
if(typeof(ms) == typeof(0)){
|
||||||
ms = ms + 'ms'
|
ms = ms + 'ms'
|
||||||
@ -521,7 +570,6 @@ function setTransitionDuration(elem, ms){
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************ jQuery extensions **/
|
/************************************************ jQuery extensions **/
|
||||||
|
|
||||||
jQuery.fn.reverseChildren = function(){
|
jQuery.fn.reverseChildren = function(){
|
||||||
@ -540,13 +588,406 @@ jQuery.fn.sortChildren = function(func){
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************** Deferred utils ***/
|
||||||
|
|
||||||
|
// Deferred worker pool...
|
||||||
|
//
|
||||||
|
// makeDeferredPool([size][, paused]) -> pool
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// This will create and return a pooled queue of deferred workers.
|
||||||
|
//
|
||||||
|
// Public interface:
|
||||||
|
//
|
||||||
|
// .enqueue(obj, func, args) -> deferred
|
||||||
|
// Add a worker to queue.
|
||||||
|
// If the pool is not filled and not paused, this will run the
|
||||||
|
// worker right away.
|
||||||
|
// If the pool is full the worker is added to queue (FIFO) and
|
||||||
|
// ran in its turn.
|
||||||
|
//
|
||||||
|
// .pause() -> pool
|
||||||
|
// Pause the queue.
|
||||||
|
// NOTE: this also has a second form: .pause(func), see below.
|
||||||
|
//
|
||||||
|
// .resume() -> pool
|
||||||
|
// Restart the queue.
|
||||||
|
//
|
||||||
|
// .dropQueue() -> pool
|
||||||
|
// Drop the queued workers.
|
||||||
|
// NOTE: this will not stop the already running workers.
|
||||||
|
//
|
||||||
|
// .isRunning() -> bool
|
||||||
|
// Test if any workers are running in the pool.
|
||||||
|
// NOTE: this will return false ONLY when the pool is empty.
|
||||||
|
//
|
||||||
|
// .isPaused() -> bool
|
||||||
|
// Test if pool is in a paused state.
|
||||||
|
// NOTE: some workers may sill be finishing up so if you want
|
||||||
|
// to test whether any workers are still running use
|
||||||
|
// .isRunning()
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Event handler/callback registration:
|
||||||
|
//
|
||||||
|
// .on(evt, func) -> pool
|
||||||
|
// Register a handler (func) for an event (evt).
|
||||||
|
//
|
||||||
|
// .off(evt[, func]) -> pool
|
||||||
|
// Remove a handler (func) form and event (evt).
|
||||||
|
// NOTE: if func is omitted, remove all handlers from the given
|
||||||
|
// event...
|
||||||
|
//
|
||||||
|
// .progress(func) -> pool
|
||||||
|
// Register a progress handler.
|
||||||
|
// The handler is called after each worker is done and will get
|
||||||
|
// passed:
|
||||||
|
// - workers done count
|
||||||
|
// - workers total count
|
||||||
|
// Short hand for:
|
||||||
|
// .on('progress', func) -> pool
|
||||||
|
// NOTE: the total number of workers can change as new workers
|
||||||
|
// are added or the queue is cleared...
|
||||||
|
//
|
||||||
|
// .fail(func) -> pool
|
||||||
|
// Register a worker fail handler.
|
||||||
|
// The handler is called when a worker goes into the fail state.
|
||||||
|
// This will get passed:
|
||||||
|
// - workers done count
|
||||||
|
// - workers total count
|
||||||
|
// Short hand for:
|
||||||
|
// .on('fail', func) -> pool
|
||||||
|
// NOTE: this will not stop the execution of other handlers.
|
||||||
|
//
|
||||||
|
// .pause(func) -> pool
|
||||||
|
// Register a pause handler.
|
||||||
|
// This handler is called after the last worker finishes when
|
||||||
|
// the queue is paused.
|
||||||
|
// Short hand for:
|
||||||
|
// .on('progress', func) -> pool
|
||||||
|
//
|
||||||
|
// .resume(func) -> pool
|
||||||
|
// Short hand for:
|
||||||
|
// .on('resume', func) -> pool
|
||||||
|
//
|
||||||
|
// .depleted(func) -> pool
|
||||||
|
// Register a depleted pool handler.
|
||||||
|
// The handler will get called when the queue and pool are empty
|
||||||
|
// (depleted) and the last worker is done.
|
||||||
|
// Short hand for:
|
||||||
|
// .on('deplete', func) -> pool
|
||||||
|
//
|
||||||
|
// XXX should this be an object or a factory???
|
||||||
|
function makeDeferredPool(size, paused){
|
||||||
|
size = size == null ? POOL_SIZE : size
|
||||||
|
size = size < 0 ? 1
|
||||||
|
: size > 512 ? 512
|
||||||
|
: size
|
||||||
|
paused = paused == null ? false : paused
|
||||||
|
|
||||||
|
|
||||||
|
var Pool = {
|
||||||
|
pool: [],
|
||||||
|
queue: [],
|
||||||
|
size: size,
|
||||||
|
|
||||||
|
// XXX do we need to hide or expose them and use their API???
|
||||||
|
_event_handlers: {
|
||||||
|
deplete: $.Callbacks(),
|
||||||
|
progress: $.Callbacks(),
|
||||||
|
pause: $.Callbacks(),
|
||||||
|
resume: $.Callbacks(),
|
||||||
|
fail: $.Callbacks()
|
||||||
|
},
|
||||||
|
|
||||||
|
_paused: paused,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run a worker...
|
||||||
|
//
|
||||||
|
// This will:
|
||||||
|
// - create and add a worker to the pool, which will:
|
||||||
|
// - run an element from the queue
|
||||||
|
// - remove self from pool
|
||||||
|
// - if the pool is not full, create another worker (call
|
||||||
|
// ._run(..)) else exit
|
||||||
|
// - call ._fill() to replenish the pool
|
||||||
|
Pool._run = function(deferred, func, args){
|
||||||
|
var that = this
|
||||||
|
var pool = this.pool
|
||||||
|
var pool_size = this.size
|
||||||
|
var queue = this.queue
|
||||||
|
var run = this._run
|
||||||
|
|
||||||
|
// run an element from the queue...
|
||||||
|
var worker = func.apply(null, args)
|
||||||
|
.always(function(){
|
||||||
|
// prepare to remove self from pool...
|
||||||
|
var i = pool.indexOf(worker)
|
||||||
|
|
||||||
|
Pool._event_handlers.progress.fire(pool.length - pool.len(), pool.length + queue.length)
|
||||||
|
|
||||||
|
// remove self from queue...
|
||||||
|
delete pool[i]
|
||||||
|
|
||||||
|
// shrink the pool if it's overfilled...
|
||||||
|
// i.e. do not pop another worker and let the "thread" die.
|
||||||
|
if(pool.len() > pool_size){
|
||||||
|
// remove self...
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// pause the queue -- do not do anything else...
|
||||||
|
if(that._paused == true){
|
||||||
|
// if pool is empty fire the pause event...
|
||||||
|
if(pool.len() == 0){
|
||||||
|
Pool._event_handlers.pause.fire()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next queued worker...
|
||||||
|
var next = queue.splice(0, 1)[0]
|
||||||
|
|
||||||
|
// run the next worker if it exists...
|
||||||
|
if(next != null){
|
||||||
|
run.apply(that, next)
|
||||||
|
|
||||||
|
// empty queue AND empty pool mean we are done...
|
||||||
|
} else if(pool.len() == 0){
|
||||||
|
var l = pool.length
|
||||||
|
// NOTE: potential race condition -- something can be
|
||||||
|
// pushed to pool just before it's "compacted"...
|
||||||
|
pool.length = 0
|
||||||
|
|
||||||
|
that._event_handlers.deplete.fire(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep the pool full...
|
||||||
|
that._fill()
|
||||||
|
})
|
||||||
|
.fail(function(){
|
||||||
|
Pool._event_handlers.fail.fire(pool.length - pool.len(), pool.length + queue.length)
|
||||||
|
deferred.reject.apply(deferred, arguments)
|
||||||
|
})
|
||||||
|
.progress(function(){
|
||||||
|
deferred.notify.apply(deferred, arguments)
|
||||||
|
})
|
||||||
|
.done(function(){
|
||||||
|
deferred.resolve.apply(deferred, arguments)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.pool.push(worker)
|
||||||
|
|
||||||
|
return worker
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the pool...
|
||||||
|
//
|
||||||
|
Pool._fill = function(){
|
||||||
|
var that = this
|
||||||
|
var pool_size = this.size
|
||||||
|
var run = this._run
|
||||||
|
var l = this.pool.len()
|
||||||
|
|
||||||
|
if(this._paused != true
|
||||||
|
&& l < pool_size
|
||||||
|
&& this.queue.length > 0){
|
||||||
|
this.queue.splice(0, pool_size - l)
|
||||||
|
.forEach(function(e){
|
||||||
|
run.apply(that, e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Public methods...
|
||||||
|
|
||||||
|
// Add a worker to queue...
|
||||||
|
//
|
||||||
|
Pool.enqueue = function(func){
|
||||||
|
var deferred = $.Deferred()
|
||||||
|
|
||||||
|
// add worker to queue...
|
||||||
|
this.queue.push([deferred, func, args2array(arguments).slice(1)])
|
||||||
|
|
||||||
|
// start work if we have not already...
|
||||||
|
this._fill()
|
||||||
|
|
||||||
|
//return this
|
||||||
|
return deferred
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop the queued workers...
|
||||||
|
//
|
||||||
|
// NOTE: this will not stop the running workers...
|
||||||
|
// XXX should this return the pool or the dropped queue???
|
||||||
|
Pool.dropQueue = function(){
|
||||||
|
this.queue.splice(0, this.queue.length)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: this will not directly cause .isRunning() to return false
|
||||||
|
// as this will not directly spot all workers, it will just
|
||||||
|
// pause the queue and the workers that have already started
|
||||||
|
// will keep running until they are done, and only when the
|
||||||
|
// pool is empty will the .isRunning() return false.
|
||||||
|
//
|
||||||
|
// XXX test...
|
||||||
|
Pool.pause = function(func){
|
||||||
|
if(func == null){
|
||||||
|
this._paused = true
|
||||||
|
} else {
|
||||||
|
this.on('pause', func)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX test...
|
||||||
|
Pool.resume = function(func){
|
||||||
|
if(func == null){
|
||||||
|
this._paused = false
|
||||||
|
this._event_handlers['resume'].forEach(function(f){ f() })
|
||||||
|
this._fill()
|
||||||
|
} else {
|
||||||
|
this.on('resume', func)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
Pool.isPaused = function(){
|
||||||
|
return this._paused
|
||||||
|
}
|
||||||
|
Pool.isRunning = function(){
|
||||||
|
return this.pool.len() > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Generic event handlers...
|
||||||
|
Pool.on = function(evt, handler){
|
||||||
|
this._event_handlers[evt].add(handler)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
// NOTE: if this is not given a handler, it will clear all handlers
|
||||||
|
// from the given event...
|
||||||
|
Pool.off = function(evt, handler){
|
||||||
|
if(handler != null){
|
||||||
|
this._event_handlers[evt].remove(handler)
|
||||||
|
} else {
|
||||||
|
this._event_handlers[evt].empty()
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a queue depleted handler...
|
||||||
|
//
|
||||||
|
// This occurs when a populated queue is depleted and the last worker
|
||||||
|
// is done.
|
||||||
|
//
|
||||||
|
// NOTE: this is similar to jQuery.Deferred().done(..) but differs in
|
||||||
|
// that the pool can fill up and get depleted more than once,
|
||||||
|
// thus, the handlers may get called more than once per pool
|
||||||
|
// life...
|
||||||
|
// NOTE: it is recommended to fill the queue faster than the workers
|
||||||
|
// finish, as this may get called after last worker is done and
|
||||||
|
// the next is queued...
|
||||||
|
Pool.depleted = function(func){
|
||||||
|
return this.on('deplete', func)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register queue progress handler...
|
||||||
|
//
|
||||||
|
// This occurs after each worker is done.
|
||||||
|
//
|
||||||
|
// handler will be passed:
|
||||||
|
// - the pool object
|
||||||
|
// - workers done
|
||||||
|
// - total workers (done + queued)
|
||||||
|
Pool.progress = function(func){
|
||||||
|
return this.on('progress', func)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register worker fail handler...
|
||||||
|
//
|
||||||
|
Pool.fail = function(func){
|
||||||
|
return this.on('fail', func)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************** JS utilities ***/
|
/**************************************************** JS utilities ***/
|
||||||
|
|
||||||
|
|
||||||
|
// Get screen dpi...
|
||||||
|
//
|
||||||
|
// This will calculate the value and save it to screen.dpi
|
||||||
|
//
|
||||||
|
// if force is true this will re-calculate the value.
|
||||||
|
//
|
||||||
|
// NOTE: this needs the body loaded to work...
|
||||||
|
// NOTE: this may depend on page zoom...
|
||||||
|
// NOTE: yes, this is a hack, but since we have no other reliable way to
|
||||||
|
// do this...
|
||||||
|
function getDPI(force){
|
||||||
|
if(screen.dpi == null || force){
|
||||||
|
var e = $('<div id="inch">')
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
width: '1in',
|
||||||
|
left: '-100%',
|
||||||
|
top: '-100%'
|
||||||
|
})
|
||||||
|
.appendTo($('body'))
|
||||||
|
var res = e.width()
|
||||||
|
e.remove()
|
||||||
|
screen.dpi = res
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
return screen.dpi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// XXX is this correct???
|
||||||
|
$(getDPI)
|
||||||
|
|
||||||
|
|
||||||
|
// return 1, -1, or 0 depending on sign of x
|
||||||
|
function sign(x){
|
||||||
|
return (x > 0) - (x < 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String.prototype.capitalize = function(){
|
String.prototype.capitalize = function(){
|
||||||
return this[0].toUpperCase() + this.slice(1)
|
return this[0].toUpperCase() + this.slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// XXX not sure if this has to be a utility or a method...
|
||||||
|
Object.get = function(obj, name, dfl){
|
||||||
|
var val = obj[name]
|
||||||
|
if(val === undefined && dfl != null){
|
||||||
|
return dfl
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// like .length but for sparse arrays will return the element count...
|
||||||
|
Array.prototype.len = function(){
|
||||||
|
return this.filter(function(){ return true }).length
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// convert JS arguments to Array...
|
||||||
|
function args2array(args){
|
||||||
|
return Array.apply(null, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var getAnimationFrame = (window.requestAnimationFrame
|
var getAnimationFrame = (window.requestAnimationFrame
|
||||||
|| window.webkitRequestAnimationFrame
|
|| window.webkitRequestAnimationFrame
|
||||||
|| window.mozRequestAnimationFrame
|
|| window.mozRequestAnimationFrame
|
||||||
@ -556,6 +997,7 @@ var getAnimationFrame = (window.requestAnimationFrame
|
|||||||
setTimeout(callback, 1000/60)
|
setTimeout(callback, 1000/60)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
var cancelAnimationFrame = (window.cancelRequestAnimationFrame
|
var cancelAnimationFrame = (window.cancelRequestAnimationFrame
|
||||||
|| window.webkitCancelAnimationFrame
|
|| window.webkitCancelAnimationFrame
|
||||||
|| window.webkitCancelRequestAnimationFrame
|
|| window.webkitCancelRequestAnimationFrame
|
||||||
@ -565,6 +1007,78 @@ var cancelAnimationFrame = (window.cancelRequestAnimationFrame
|
|||||||
|| clearTimeout)
|
|| clearTimeout)
|
||||||
|
|
||||||
|
|
||||||
|
Date.prototype.toShortDate = function(){
|
||||||
|
var y = this.getFullYear()
|
||||||
|
var M = this.getMonth()+1
|
||||||
|
M = M < 10 ? '0'+M : M
|
||||||
|
var D = this.getDate()
|
||||||
|
D = D < 10 ? '0'+D : D
|
||||||
|
var H = this.getHours()
|
||||||
|
H = H < 10 ? '0'+H : H
|
||||||
|
var m = this.getMinutes()
|
||||||
|
m = m < 10 ? '0'+m : m
|
||||||
|
var s = this.getSeconds()
|
||||||
|
s = s < 10 ? '0'+s : s
|
||||||
|
|
||||||
|
return ''+y+'-'+M+'-'+D+' '+H+':'+m+':'+s
|
||||||
|
}
|
||||||
|
Date.prototype.getTimeStamp = function(no_seconds){
|
||||||
|
var y = this.getFullYear()
|
||||||
|
var M = this.getMonth()+1
|
||||||
|
M = M < 10 ? '0'+M : M
|
||||||
|
var D = this.getDate()
|
||||||
|
D = D < 10 ? '0'+D : D
|
||||||
|
var H = this.getHours()
|
||||||
|
H = H < 10 ? '0'+H : H
|
||||||
|
var m = this.getMinutes()
|
||||||
|
m = m < 10 ? '0'+m : m
|
||||||
|
var s = this.getSeconds()
|
||||||
|
s = s < 10 ? '0'+s : s
|
||||||
|
|
||||||
|
return ''+y+M+D+H+m+s
|
||||||
|
}
|
||||||
|
Date.prototype.setTimeStamp = function(ts){
|
||||||
|
ts = ts.replace(/[^0-9]*/g, '')
|
||||||
|
this.setFullYear(ts.slice(0, 4))
|
||||||
|
this.setMonth(ts.slice(4, 6)*1-1)
|
||||||
|
this.setDate(ts.slice(6, 8))
|
||||||
|
this.setHours(ts.slice(8, 10))
|
||||||
|
this.setMinutes(ts.slice(10, 12))
|
||||||
|
this.setSeconds(ts.slice(12, 14))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
Date.timeStamp = function(){
|
||||||
|
return (new Date()).getTimeStamp()
|
||||||
|
}
|
||||||
|
Date.fromTimeStamp = function(ts){
|
||||||
|
return (new Date()).setTimeStamp(ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function logCalls(func, logger){
|
||||||
|
var that = this
|
||||||
|
var _func = function(){
|
||||||
|
logger(func, arguments)
|
||||||
|
return func.apply(that, arguments)
|
||||||
|
}
|
||||||
|
_func.name = func.name
|
||||||
|
return _func
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function assyncCall(func){
|
||||||
|
var that = this
|
||||||
|
var _func = function(){
|
||||||
|
var res = $.Deferred()
|
||||||
|
setTimeout(function(){
|
||||||
|
res.resolve(func.apply(that, arguments))
|
||||||
|
}, 0)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
_func.name = func.name
|
||||||
|
return _func
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user