module.exports.clone = (obj) -> return obj if obj is null or typeof (obj) isnt 'object' 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 return => null # always return a func, or Mediator will go boom func_thing = func return func_thing 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 cutHex = (h) -> (if (h.charAt(0) is '#') then h.substring(1, 7) else h) module.exports.hslToHex = (hsl) -> '#' + (toHex(n) for n in hslToRgb(hsl...)).join('') toHex = (n) -> h = Math.floor(n).toString(16) h = '0'+h if h.length is 1 h module.exports.i18n = (say, target, language=me.get('preferredLanguage', true), fallback='en') -> 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 for localeName, locale of say.i18n continue if localeName is '-' if target of locale result = locale[target] else continue 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? return generalResult if generalResult? return fallforwardResult if fallforwardResult? return fallbackResult if fallbackResult? return say[target] if target of say null module.exports.getByPath = (target, path) -> throw new Error 'Expected an object to match a query against, instead got null' unless target pieces = path.split('.') obj = target for piece in pieces return undefined unless piece of obj obj = obj[piece] obj 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 # f(x) = ax + b createLinearFunc = (params) -> (x) -> (params.a or 1) * x + (params.b or 0) # 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 # f(x) = ax^b + c createPowFunc = (params) -> (x) -> (params.a or 1) * Math.pow(x, params.b or 1) + (params.c or 0) module.exports.functionCreators = linear: positify(createLinearFunc) quadratic: positify(createQuadraticFunc) logarithmic: positify(createLogFunc) pow: positify(createPowFunc) # 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 _.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 # Return UTC string "YYYYMMDD" for today + offset module.exports.getUTCDay = (offset=0) -> day = new Date() day.setDate(day.getUTCDate() + offset) partYear = day.getUTCFullYear() partMonth = (day.getUTCMonth() + 1) partMonth = "0" + partMonth if partMonth < 10 partDay = day.getUTCDate() partDay = "0" + partDay if partDay < 10 "#{partYear}#{partMonth}#{partDay}" # Fast, basic way to replace text in an element when you don't need much. # http://stackoverflow.com/a/4962398/540620 if document?.createElement 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 # 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?.createElement 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 #
for IE: http://goo.gl/vLY4x7 temp.innerHTML = "
" wrap.appendChild temp.children[1] return )(document) module.exports.getQueryVariable = getQueryVariable = (param, defaultValue) -> query = document.location.search.substring 1 pairs = (pair.split('=') for pair in query.split '&') for pair in pairs when pair[0] is param return {'true': true, 'false': false}[pair[1]] ? decodeURIComponent(pair[1]) defaultValue