2014-01-03 10:32:13 -08:00
module.exports.clone = (obj) ->
2014-07-01 10:16:26 +08:00
return obj if obj is null or typeof ( obj ) isnt ' object '
2014-01-03 10:32:13 -08:00
temp = obj . constructor ( )
for key of obj
temp [ key ] = module . exports . clone ( obj [ key ] )
temp
module.exports.combineAncestralObject = (obj, propertyName) ->
combined = { }
while obj ? [ propertyName ]
for key , value of obj [ propertyName ]
continue if combined [ key ]
combined [ key ] = value
if obj . __proto__
obj = obj . __proto__
else
# IE has no __proto__. TODO: does this even work? At most it doesn't crash.
obj = Object . getPrototypeOf ( obj )
combined
module.exports.normalizeFunc = (func_thing, object) ->
# func could be a string to a function in this class
# or a function in its own right
object ? = { }
if _ . isString ( func_thing )
func = object [ func_thing ]
if not func
2014-08-14 10:28:50 -07:00
console . error " Could not find method #{ func_thing } in object " , object
2014-01-03 10:32:13 -08:00
return => null # always return a func, or Mediator will go boom
func_thing = func
2014-03-13 08:39:53 -07:00
return func_thing
2014-01-10 16:48:28 -08:00
module.exports.hexToHSL = (hex) ->
rgbToHsl ( hexToR ( hex ) , hexToG ( hex ) , hexToB ( hex ) )
hexToR = (h) -> parseInt ( cutHex ( h ) ) . substring ( 0 , 2 ) , 16
hexToG = (h) -> parseInt ( cutHex ( h ) ) . substring ( 2 , 4 ) , 16
hexToB = (h) -> parseInt ( cutHex ( h ) ) . substring ( 4 , 6 ) , 16
2014-07-01 10:16:26 +08:00
cutHex = (h) -> ( if ( h . charAt ( 0 ) is ' # ' ) then h . substring ( 1 , 7 ) else h )
2014-03-13 08:39:53 -07:00
2014-01-10 16:48:28 -08:00
module.exports.hslToHex = (hsl) ->
' # ' + ( toHex ( n ) for n in hslToRgb ( hsl . . . ) ) . join ( ' ' )
2014-03-13 08:39:53 -07:00
2014-01-10 16:48:28 -08:00
toHex = (n) ->
h = Math . floor ( n ) . toString ( 16 )
h = ' 0 ' + h if h . length is 1
2014-03-12 20:30:43 +01:00
h
2014-08-23 15:51:59 -07:00
module.exports.i18n = ( say , target , language = me . get ( ' preferredLanguage ' , true ) , fallback = ' en ' ) ->
2014-03-12 20:30:43 +01:00
generalResult = null
fallbackResult = null
fallforwardResult = null # If a general language isn't available, the first specific one will do
matches = ( /\w+/gi ) . exec ( language )
generalName = matches [ 0 ] if matches
2014-03-13 00:47:08 +01:00
for localeName , locale of say . i18n
2014-07-13 10:05:58 -07:00
continue if localeName is ' - '
2014-03-13 00:47:08 +01:00
if target of locale
result = locale [ target ]
2014-03-12 20:30:43 +01:00
else continue
2014-07-04 22:23:47 +08:00
return result if localeName is language
generalResult = result if localeName is generalName
fallbackResult = result if localeName is fallback
fallforwardResult = result if localeName . indexOf ( language ) is 0 and not fallforwardResult ?
2014-03-12 20:30:43 +01:00
return generalResult if generalResult ?
return fallforwardResult if fallforwardResult ?
2014-03-13 00:47:08 +01:00
return fallbackResult if fallbackResult ?
2014-03-13 01:07:36 +01:00
return say [ target ] if target of say
2014-03-13 08:39:53 -07:00
null
2014-05-18 21:14:22 +02:00
module.exports.getByPath = (target, path) ->
2014-06-14 20:12:17 +02:00
throw new Error ' Expected an object to match a query against, instead got null ' unless target
2014-05-18 21:14:22 +02:00
pieces = path . split ( ' . ' )
obj = target
for piece in pieces
return undefined unless piece of obj
obj = obj [ piece ]
obj
2014-06-03 12:40:47 +02:00
2014-07-09 20:23:05 +02:00
module.exports.isID = (id) -> _ . isString ( id ) and id . length is 24 and id . match ( /[a-f0-9]/gi ) ? . length is 24
2014-06-03 12:40:47 +02:00
module.exports.round = _ . curry (digits, n) ->
n = + n . toFixed ( digits )
2014-06-14 20:12:17 +02:00
positify = (func) -> (params) -> (x) -> if x > 0 then func ( params ) ( x ) else 0
2014-06-12 19:39:45 +02:00
# f(x) = ax + b
createLinearFunc = (params) ->
2014-06-03 12:40:47 +02:00
(x) -> ( params . a or 1 ) * x + ( params . b or 0 )
2014-06-12 19:39:45 +02:00
# f(x) = ax² + bx + c
createQuadraticFunc = (params) ->
(x) -> ( params . a or 1 ) * x * x + ( params . b or 1 ) * x + ( params . c or 0 )
# f(x) = a log(b (x + c)) + d
createLogFunc = (params) ->
(x) -> if x > 0 then ( params . a or 1 ) * Math . log ( ( params . b or 1 ) * ( x + ( params . c or 0 ) ) ) + ( params . d or 0 ) else 0
module.exports.functionCreators =
linear: positify ( createLinearFunc )
quadratic: positify ( createQuadraticFunc )
logarithmic: positify ( createLogFunc )
2014-06-17 21:42:27 +02:00
# Call done with true to satisfy the 'until' goal and stop repeating func
module.exports.keepDoingUntil = (func, wait=100, totalWait=5000) ->
waitSoFar = 0
( done = (success) ->
2014-07-07 19:56:30 +02:00
if ( waitSoFar += wait ) <= totalWait and not success
2014-06-17 21:42:27 +02:00
_ . delay ( -> func done ) , wait ) false
2014-08-04 15:26:21 +02:00
module.exports.grayscale = (imageData) ->
d = imageData . data
for i in [ 0 . . d . length ] by 4
r = d [ i ]
g = d [ i + 1 ]
b = d [ i + 2 ]
v = 0.2126 * r + 0.7152 * g + 0.0722 * b
d [ i ] = d [ i + 1 ] = d [ i + 2 ] = v
imageData
2014-08-08 13:08:13 +02:00
# Deep compares l with r, with the exception that undefined values are considered equal to missing values
# Very practical for comparing Mongoose documents where undefined is not allowed, instead fields get deleted
module.exports.kindaEqual = compare = (l, r) ->
if _ . isObject ( l ) and _ . isObject ( r )
for key in _ . union Object . keys ( l ) , Object . keys ( r )
return false unless compare l [ key ] , r [ key ]
return true
else if l is r
return true
else
return false
2014-11-29 13:09:38 -08:00
# Fast, basic way to replace text in an element when you don't need much.
# http://stackoverflow.com/a/4962398/540620
if document ?
dummy = document . createElement ' div '
dummy.innerHTML = ' text '
TEXT = if dummy . textContent is ' text ' then ' textContent ' else ' innerText '
module.exports.replaceText = (elems, text) ->
elem [ TEXT ] = text for elem in elems
null
2014-12-28 13:25:20 -08:00
# Add a stylesheet rule
# http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript/26230472#26230472
# Don't use wantonly, or we'll have to implement a simple mechanism for clearing out old rules.
if document ?
module.exports.injectCSS = ( (doc) ->
# wrapper for all injected styles and temp el to create them
wrap = doc . createElement ( " div " )
temp = doc . createElement ( " div " )
# rules like "a {color: red}" etc.
return (cssRules) ->
# append wrapper to the body on the first call
unless wrap . id
wrap.id = " injected-css "
wrap.style.display = " none "
doc . body . appendChild wrap
# <br> for IE: http://goo.gl/vLY4x7
temp.innerHTML = " <br><style> " + cssRules + " </style> "
wrap . appendChild temp . children [ 1 ]
return
) ( document )