codecombat/app/lib/utils.coffee

133 lines
4.4 KiB
CoffeeScript
Raw Normal View History

2014-01-03 13:32:13 -05:00
module.exports.clone = (obj) ->
2014-06-30 22:16:26 -04:00
return obj if obj is null or typeof (obj) isnt 'object'
2014-01-03 13:32:13 -05: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
console.error "Could not find method #{func_thing} in object", object
2014-01-03 13:32:13 -05:00
return => null # always return a func, or Mediator will go boom
func_thing = func
2014-03-13 11:39:53 -04:00
return func_thing
2014-01-10 19:48:28 -05: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-06-30 22:16:26 -04:00
cutHex = (h) -> (if (h.charAt(0) is '#') then h.substring(1, 7) else h)
2014-03-13 11:39:53 -04:00
2014-01-10 19:48:28 -05:00
module.exports.hslToHex = (hsl) ->
'#' + (toHex(n) for n in hslToRgb(hsl...)).join('')
2014-03-13 11:39:53 -04:00
2014-01-10 19:48:28 -05:00
toHex = (n) ->
h = Math.floor(n).toString(16)
h = '0'+h if h.length is 1
2014-03-12 15:30:43 -04:00
h
2014-08-23 18:51:59 -04:00
module.exports.i18n = (say, target, language=me.get('preferredLanguage', true), fallback='en') ->
2014-03-12 15:30:43 -04: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-12 19:47:08 -04:00
for localeName, locale of say.i18n
continue if localeName is '-'
2014-03-12 19:47:08 -04:00
if target of locale
result = locale[target]
2014-03-12 15:30:43 -04:00
else continue
2014-07-04 10:23:47 -04: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 15:30:43 -04:00
return generalResult if generalResult?
return fallforwardResult if fallforwardResult?
2014-03-12 19:47:08 -04:00
return fallbackResult if fallbackResult?
return say[target] if target of say
2014-03-13 11:39:53 -04:00
null
2014-05-18 15:14:22 -04:00
module.exports.getByPath = (target, path) ->
throw new Error 'Expected an object to match a query against, instead got null' unless target
2014-05-18 15:14:22 -04:00
pieces = path.split('.')
obj = target
for piece in pieces
return undefined unless piece of obj
obj = obj[piece]
obj
2014-07-09 14:23:05 -04:00
module.exports.isID = (id) -> _.isString(id) and id.length is 24 and id.match(/[a-f0-9]/gi)?.length is 24
module.exports.round = _.curry (digits, n) ->
n = +n.toFixed(digits)
positify = (func) -> (params) -> (x) -> if x > 0 then func(params)(x) else 0
2014-06-12 13:39:45 -04:00
# f(x) = ax + b
createLinearFunc = (params) ->
(x) -> (params.a or 1) * x + (params.b or 0)
2014-06-12 13:39:45 -04: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 15:42:27 -04: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) ->
if (waitSoFar += wait) <= totalWait and not success
2014-06-17 15:42:27 -04:00
_.delay (-> func done), wait) false
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
# 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