You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
7.0 KiB
263 lines
7.0 KiB
// ========================================== |
|
// Copyright 2013 Twitter, Inc |
|
// Licensed under The MIT License |
|
// http://opensource.org/licenses/MIT |
|
// ========================================== |
|
|
|
define( |
|
|
|
[], |
|
|
|
function() { |
|
'use strict'; |
|
|
|
var arry = []; |
|
var DEFAULT_INTERVAL = 100; |
|
|
|
var utils = { |
|
|
|
isDomObj: function(obj) { |
|
return !!(obj.nodeType || (obj === window)); |
|
}, |
|
|
|
toArray: function(obj, from) { |
|
return arry.slice.call(obj, from); |
|
}, |
|
|
|
// returns new object representing multiple objects merged together |
|
// optional final argument is boolean which specifies if merge is recursive |
|
// original objects are unmodified |
|
// |
|
// usage: |
|
// var base = {a:2, b:6}; |
|
// var extra = {b:3, c:4}; |
|
// merge(base, extra); //{a:2, b:3, c:4} |
|
// base; //{a:2, b:6} |
|
// |
|
// var base = {a:2, b:6}; |
|
// var extra = {b:3, c:4}; |
|
// var extraExtra = {a:4, d:9}; |
|
// merge(base, extra, extraExtra); //{a:4, b:3, c:4. d: 9} |
|
// base; //{a:2, b:6} |
|
// |
|
// var base = {a:2, b:{bb:4, cc:5}}; |
|
// var extra = {a:4, b:{cc:7, dd:1}}; |
|
// merge(base, extra, true); //{a:4, b:{bb:4, cc:7, dd:1}} |
|
// base; //{a:2, b:6} |
|
|
|
merge: function(/*obj1, obj2,....deepCopy*/) { |
|
// unpacking arguments by hand benchmarked faster |
|
var l = arguments.length, |
|
i = 0, |
|
args = new Array(l + 1); |
|
for (; i < l; i++) args[i + 1] = arguments[i]; |
|
|
|
if (l === 0) { |
|
return {}; |
|
} |
|
|
|
//start with empty object so a copy is created |
|
args[0] = {}; |
|
|
|
if (args[args.length - 1] === true) { |
|
//jquery extend requires deep copy as first arg |
|
args.pop(); |
|
args.unshift(true); |
|
} |
|
|
|
return $.extend.apply(undefined, args); |
|
}, |
|
|
|
// updates base in place by copying properties of extra to it |
|
// optionally clobber protected |
|
// usage: |
|
// var base = {a:2, b:6}; |
|
// var extra = {c:4}; |
|
// push(base, extra); //{a:2, b:6, c:4} |
|
// base; //{a:2, b:6, c:4} |
|
// |
|
// var base = {a:2, b:6}; |
|
// var extra = {b: 4 c:4}; |
|
// push(base, extra, true); //Error ("utils.push attempted to overwrite 'b' while running in protected mode") |
|
// base; //{a:2, b:6} |
|
// |
|
// objects with the same key will merge recursively when protect is false |
|
// eg: |
|
// var base = {a:16, b:{bb:4, cc:10}}; |
|
// var extra = {b:{cc:25, dd:19}, c:5}; |
|
// push(base, extra); //{a:16, {bb:4, cc:25, dd:19}, c:5} |
|
// |
|
push: function(base, extra, protect) { |
|
if (base) { |
|
Object.keys(extra || {}).forEach(function(key) { |
|
if (base[key] && protect) { |
|
throw new Error('utils.push attempted to overwrite "' + key + '" while running in protected mode'); |
|
} |
|
|
|
if (typeof base[key] == 'object' && typeof extra[key] == 'object') { |
|
// recurse |
|
this.push(base[key], extra[key]); |
|
} else { |
|
// no protect, so extra wins |
|
base[key] = extra[key]; |
|
} |
|
}, this); |
|
} |
|
|
|
return base; |
|
}, |
|
|
|
isEnumerable: function(obj, property) { |
|
return Object.keys(obj).indexOf(property) > -1; |
|
}, |
|
|
|
// build a function from other function(s) |
|
// utils.compose(a,b,c) -> a(b(c())); |
|
// implementation lifted from underscore.js (c) 2009-2012 Jeremy Ashkenas |
|
compose: function() { |
|
var funcs = arguments; |
|
|
|
return function() { |
|
var args = arguments; |
|
|
|
for (var i = funcs.length-1; i >= 0; i--) { |
|
args = [funcs[i].apply(this, args)]; |
|
} |
|
|
|
return args[0]; |
|
}; |
|
}, |
|
|
|
// Can only unique arrays of homogeneous primitives, e.g. an array of only strings, an array of only booleans, or an array of only numerics |
|
uniqueArray: function(array) { |
|
var u = {}, a = []; |
|
|
|
for (var i = 0, l = array.length; i < l; ++i) { |
|
if (u.hasOwnProperty(array[i])) { |
|
continue; |
|
} |
|
|
|
a.push(array[i]); |
|
u[array[i]] = 1; |
|
} |
|
|
|
return a; |
|
}, |
|
|
|
debounce: function(func, wait, immediate) { |
|
if (typeof wait != 'number') { |
|
wait = DEFAULT_INTERVAL; |
|
} |
|
|
|
var timeout, result; |
|
|
|
return function() { |
|
var context = this, args = arguments; |
|
var later = function() { |
|
timeout = null; |
|
if (!immediate) { |
|
result = func.apply(context, args); |
|
} |
|
}; |
|
var callNow = immediate && !timeout; |
|
|
|
clearTimeout(timeout); |
|
timeout = setTimeout(later, wait); |
|
|
|
if (callNow) { |
|
result = func.apply(context, args); |
|
} |
|
|
|
return result; |
|
}; |
|
}, |
|
|
|
throttle: function(func, wait) { |
|
if (typeof wait != 'number') { |
|
wait = DEFAULT_INTERVAL; |
|
} |
|
|
|
var context, args, timeout, throttling, more, result; |
|
var whenDone = this.debounce(function(){ |
|
more = throttling = false; |
|
}, wait); |
|
|
|
return function() { |
|
context = this; args = arguments; |
|
var later = function() { |
|
timeout = null; |
|
if (more) { |
|
result = func.apply(context, args); |
|
} |
|
whenDone(); |
|
}; |
|
|
|
if (!timeout) { |
|
timeout = setTimeout(later, wait); |
|
} |
|
|
|
if (throttling) { |
|
more = true; |
|
} else { |
|
throttling = true; |
|
result = func.apply(context, args); |
|
} |
|
|
|
whenDone(); |
|
return result; |
|
}; |
|
}, |
|
|
|
countThen: function(num, base) { |
|
return function() { |
|
if (!--num) { return base.apply(this, arguments); } |
|
}; |
|
}, |
|
|
|
delegate: function(rules) { |
|
return function(e, data) { |
|
var target = $(e.target), parent; |
|
|
|
Object.keys(rules).forEach(function(selector) { |
|
if (!e.isPropagationStopped() && (parent = target.closest(selector)).length) { |
|
data = data || {}; |
|
data.el = parent[0]; |
|
return rules[selector].apply(this, [e, data]); |
|
} |
|
}, this); |
|
}; |
|
}, |
|
|
|
// ensures that a function will only be called once. |
|
// usage: |
|
// will only create the application once |
|
// var initialize = utils.once(createApplication) |
|
// initialize(); |
|
// initialize(); |
|
// |
|
// will only delete a record once |
|
// var myHanlder = function () { |
|
// $.ajax({type: 'DELETE', url: 'someurl.com', data: {id: 1}}); |
|
// }; |
|
// this.on('click', utils.once(myHandler)); |
|
// |
|
once: function(func) { |
|
var ran, result; |
|
|
|
return function() { |
|
if (ran) { |
|
return result; |
|
} |
|
|
|
ran = true; |
|
result = func.apply(this, arguments); |
|
|
|
return result; |
|
}; |
|
} |
|
|
|
}; |
|
|
|
return utils; |
|
} |
|
);
|
|
|