Comparing version 3.0.5 to 3.0.6
1191
lib/browser.js
@@ -1,375 +0,377 @@ | ||
// #browser animation logic | ||
/* | ||
MooFx | ||
*/"use strict" | ||
// {requires} | ||
// requires | ||
var bezier = require("cubic-bezier"), | ||
color = require("./color"), | ||
frame = require("./frame") | ||
var color = require("./color"), | ||
frame = require("./frame") | ||
// {util} | ||
var cancelFrame = frame.cancel, | ||
requestFrame = frame.request | ||
var inherits = function(parent, child){ | ||
var C = function(){ | ||
this.constructor = parent | ||
} | ||
C.prototype = parent.prototype | ||
child.prototype = new C | ||
return child | ||
} | ||
var cancelFrame = frame.cancel, | ||
requestFrame = frame.request | ||
var bezier = require("cubic-bezier") | ||
var string = String, number = parseFloat | ||
var prime = require("prime/prime"), | ||
array = require("prime/es5/array"), | ||
string = require("prime/types/string") | ||
var camelize = function(self){ | ||
return self.replace(/-\D/g, function(match){ | ||
return match.charAt(1).toUpperCase() | ||
}) | ||
} | ||
var camelize = string.camelize, | ||
hyphenate = string.hyphenate, | ||
clean = string.clean, | ||
capitalize = string.capitalize | ||
var hyphenate = function(self){ | ||
return self.replace(/[A-Z]/g, function(match){ | ||
return "-" + match.charAt(0).toLowerCase() | ||
}) | ||
} | ||
var map = array.map, | ||
each = array.forEach, | ||
indexOf = array.indexOf | ||
var clean = function(self){ | ||
return string(self).replace(/\s+/g, " ").replace(/^\s+|\s+$/g, "") | ||
} | ||
var nodes = require("nodes") | ||
var map = Array.map || Array.prototype.map ? function(array, fn, context){ | ||
return Array.prototype.map.call(array, fn, context) | ||
} : function(array, fn, context){ | ||
var result = [] | ||
for (var i = 0, l = array.length; i < l; i++) result.push(fn.call(context, array[i], i, array)) | ||
return result | ||
} | ||
// util | ||
var each = Array.prototype.forEach ? function(array, fn, context){ | ||
Array.prototype.forEach.call(array, fn, context) | ||
return array | ||
} : function(array, fn, context){ | ||
for (var i = 0, l = array.length; i < l; i++) fn.call(context, array[i], i, array) | ||
return array | ||
var round = function(number){ | ||
return +(+number).toPrecision(3) | ||
} | ||
var mirror4 = function(values){ | ||
var length = values.length | ||
if (length === 1) values.push(values[0], values[0], values[0]) | ||
else if (length === 2) values.push(values[0], values[1]) | ||
else if (length === 3) values.push(values[1]) | ||
return values | ||
} | ||
// compute > node > property | ||
var computedStyle = global.getComputedStyle ? function(node){ | ||
var cts = getComputedStyle(node) | ||
return function(property){ | ||
return cts ? cts.getPropertyValue(hyphenate(property)) : "" | ||
} | ||
var compute = global.getComputedStyle ? function(node){ | ||
var cts = getComputedStyle(node) | ||
return function(property){ | ||
return cts ? cts.getPropertyValue(hyphenate(property)) : "" | ||
} | ||
} : function(node){ | ||
var cts = node.currentStyle | ||
return function(property){ | ||
return cts ? cts[camelize(property)] : "" | ||
} | ||
var cts = node.currentStyle | ||
return function(property){ | ||
return cts ? cts[camelize(property)] : "" | ||
} | ||
} | ||
// {Parser} | ||
// pixel ratio retriever | ||
var Parser = function(){} | ||
var test = document.createElement("div") | ||
Parser.prototype.extract = function(){ | ||
return [this] | ||
var cssText = "border:none;margin:none;padding:none;visibility:hidden;position:absolute;height:0;"; | ||
var pixelRatio = function(element, u){ | ||
var parent = element.parentNode, ratio = 1 | ||
if (parent){ | ||
test.style.cssText = cssText + ("width:100" + u + ";") | ||
parent.appendChild(test) | ||
ratio = test.offsetWidth / 100 | ||
parent.removeChild(test) | ||
} | ||
return ratio | ||
} | ||
Parser.prototype.toString = function(){ | ||
return string(this.value) | ||
// mirror 4 values | ||
var mirror4 = function(values){ | ||
var length = values.length | ||
if (length === 1) values.push(values[0], values[0], values[0]) | ||
else if (length === 2) values.push(values[0], values[1]) | ||
else if (length === 3) values.push(values[1]) | ||
return values | ||
} | ||
// {StringParser} | ||
// regular expressions strings | ||
var StringParser = inherits(Parser, function(value){ | ||
if (value == null) value = "" | ||
this.value = string(value) | ||
}) | ||
var sLength = "([-.\\d]+)(%|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vm)", | ||
sLengthLax = "([-.\\d]+)([\\w%]+)?", | ||
sBorderStyle = "none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset|inherit", | ||
sCubicBezier = "cubic-bezier\\(([-.\\d]+),([-.\\d]+),([-.\\d]+),([-.\\d]+)\\)", | ||
sDuration = "([\\d.]+)(s|ms)?" | ||
var NumberParser = inherits(Parser, function(value){ | ||
if (value == null) value = "" | ||
var n = number(value) | ||
this.value = isFinite(n) ? n : value | ||
}) | ||
// regular expressions | ||
// {Parsers} | ||
var rgLength = RegExp(sLength, "g"), | ||
rLengthLax = RegExp(sLengthLax), | ||
rgLengthLax = RegExp(sLengthLax, "g"), | ||
rBorderStyle = RegExp(sBorderStyle), | ||
rCubicBezier = RegExp(sCubicBezier), | ||
rgCubicBezier = RegExp(sCubicBezier, "g"), | ||
rDuration = RegExp(sDuration) | ||
var Parsers = function(){} | ||
// normalize > css | ||
Parsers.prototype.extract = function(){ | ||
return this.parsed | ||
var parseString = function(value){ | ||
return (value == null) ? "" : value + "" | ||
} | ||
Parsers.prototype.toString = function(normalize, node){ | ||
return clean(map(this.parsed, function(parsed){ | ||
return parsed.toString(normalize, node) | ||
}, this).join(" ")) | ||
var parseOpacity = function(value, normalize){ | ||
if (value == null || value === "") return normalize ? "1" : "" | ||
var number = +value | ||
return isFinite(number) ? number + "" : "1" | ||
} | ||
// {LengthParser} | ||
try { test.style.color = "rgba(0,0,0,0.5)" } catch(e){} | ||
var rgba = /^rgba/.test(test.style.color) | ||
var LengthParser = inherits(Parser, function(value){ | ||
var match | ||
if (value == null) value = "" | ||
if (value === "auto"){ | ||
this.value = "auto" | ||
} else if (match = clean(string(value)).match(/^([-\d.]+)(%|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vm)?$/)){ | ||
this.value = number(match[1]) | ||
this.unit = this.value === 0 || !match[2] ? "px" : match[2] | ||
} else { | ||
this.value = "" | ||
} | ||
}) | ||
LengthParser.prototype.toString = function(normalize, node){ | ||
if (this.value === "auto") return this.value | ||
if (this.value === "") return normalize ? "0px" : "" | ||
if (node && this.unit !== "px") return "" + pixelRatio(node, this.unit) * this.value + "px" | ||
return this.value + this.unit | ||
var parseColor = function(value, normalize){ | ||
if (!value) return normalize ? "rgba(0,0,0,1)" : "" | ||
if (value === "transparent") return normalize ? "rgba(0,0,0,0)" : value | ||
var c = color(value, true) | ||
if (!c) return normalize ? "rgba(0,0,0,1)" : "" | ||
if (c[3] === 0 && !rgba) return "transparent" | ||
return (!normalize && (!rgba || c[3] === 1)) ? "rgb(" + c.slice(0, 3) + ")" : "rgba(" + c + ")" | ||
} | ||
// {ColorParser} | ||
var parseLength = function(value, normalize, node){ | ||
if (value == null || value === "") return normalize ? "0px" : "" | ||
var match = string.match(value, rLengthLax) | ||
if (!match) return value // auto | ||
var value = +match[1], | ||
unit = match[2] || 'px' | ||
var ColorParser = inherits(Parser, function(value){ | ||
if (value === "transparent") value = "#00000000" | ||
this.value = value ? color(value, true) : "" | ||
}) | ||
if (value === 0) return value + unit | ||
return (node && unit !== "px") ? round(pixelRatio(node, unit) * value) + "px" : value + unit | ||
} | ||
ColorParser.prototype.toString = function(normalize){ | ||
if (!this.value) return normalize ? "rgba(0,0,0,1)" : "" | ||
if (!normalize && (this.value === "transparent" || this.value[3] === 0)) return "transparent" | ||
if (normalize || this.value[3] !== 1) return "rgba(" + this.value + ")" | ||
return "rgb(" + this.value[0] + "," + this.value[1] + "," + this.value[2] + ")" | ||
var parseBorderStyle = function(value, normalize){ | ||
if (value == null || value === "") return normalize ? "none" : "" | ||
var match = value.match(rBorderStyle) | ||
return match ? value : normalize ? "none" : "" | ||
} | ||
// {LengthsParser} | ||
var parseBorder = function(value, normalize, node){ | ||
var normalized = "0px none rgba(0,0,0,1)" | ||
if (value == null || value === "") return normalize ? normalized : "" | ||
if (value === 0 || value === "none") return normalize ? normalized : value | ||
var LengthsParser = inherits(Parsers, function(value){ | ||
if (value == null) value = "" | ||
this.parsed = map(mirror4(clean(value).split(" ")), function(v){ | ||
return new LengthParser(v) | ||
}) | ||
}) | ||
var c | ||
value = value.replace(color.x, function(match){ | ||
c = match | ||
return "" | ||
}) | ||
// {BorderStyleParser} | ||
var s = value.match(rBorderStyle), | ||
l = value.match(rgLengthLax) | ||
var BorderStyleParser = inherits(Parser, function(value){ | ||
if (value == null) value = "" | ||
var match = (value = clean(value)).match(/none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset|inherit/) | ||
this.value = match ? value : "" | ||
}) | ||
return clean([parseLength(l ? l[0] : "", normalize, node), parseBorderStyle(s ? s[0] : "", normalize), parseColor(c, normalize)].join(" ")) | ||
} | ||
BorderStyleParser.prototype.toString = function(normalize){ | ||
return (normalize && !this.value) ? "none" : this.value | ||
var parseShort4 = function(value, normalize, node){ | ||
if (value == null || value === "") return normalize ? "0px 0px 0px 0px" : "" | ||
return clean(mirror4(map(clean(value).split(" "), function(v){ | ||
return parseLength(v, normalize, node) | ||
})).join(" ")) | ||
} | ||
// {BorderParser} | ||
var parseShadow = function(value, normalize, node, len){ | ||
var ncolor = "rgba(0,0,0,0)", | ||
normalized = (len === 3) ? ncolor + " 0px 0px 0px" : ncolor + " 0px 0px 0px 0px" | ||
var BorderParser = inherits(Parsers, function(value){ | ||
if (value == null) value = "" | ||
else if (value === "none") value = "0 none #000" | ||
var match = (value = clean(value).match(/((?:[\d.]+)(?:[\w%]+)?)\s(\w+)\s(rgb(?:a)?\([\d,\s]+\)|hsl(?:a)?\([\d,\s]+\)|#[a-f0-9]+|\w+)/) || []) | ||
var matchedWidth = match[1], matchedStyle = match[2], matchedColor = match[3] | ||
this.parsed = [ | ||
new LengthParser(matchedWidth != null ? matchedWidth : ""), | ||
new BorderStyleParser(matchedStyle != null ? matchedStyle : ""), | ||
new ColorParser(matchedColor != null ? matchedColor : "") | ||
] | ||
}) | ||
if (value == null || value === "") return normalize ? normalized : "" | ||
if (value === "none") return normalize ? normalized : value | ||
// {BorderColorParser} | ||
var colors = [], value = clean(value).replace(color.x, function(match){ | ||
colors.push(match) | ||
return "" | ||
}) | ||
var BorderColorParser = inherits(Parsers, function(colors){ | ||
if (colors == null) colors = "" | ||
colors = mirror4(colors.match(/rgb(a)?\([\d,\s]+\)|hsl(a)?\([\d,\s]+\)|#[a-f0-9]+|\w+/g) || [""]) | ||
this.parsed = map(colors, function(c){ | ||
return new ColorParser(c) | ||
}) | ||
}) | ||
return map(value.split(","), function(shadow, i){ | ||
// {ZIndexParser} | ||
var c = parseColor(colors[i], normalize), | ||
inset = /inset/.test(shadow), | ||
lengths = shadow.match(rgLengthLax) || ["0px"] | ||
var ZIndexParser = inherits(Parser, function(value){ | ||
this.value = value === "auto" ? value : number(value) | ||
}) | ||
lengths = map(lengths, function(m){ | ||
return parseLength(m, normalize, node) | ||
}) | ||
// parsers, getters, setters | ||
while (lengths.length < len) lengths.push("0px") | ||
var parsers = {}, getters = {}, setters = {} | ||
var ret = inset ? ["inset", c] : [c] | ||
var translations = {} | ||
return ret.concat(lengths).join(" ") | ||
var html = document.documentElement | ||
// {get && set} | ||
var get = function(key){ | ||
return getters[key] || (getters[key] = function(){ | ||
var parser = parsers[key] || StringParser | ||
return function(){ | ||
return (new parser(computedStyle(this)(key))).toString(true, this) | ||
} | ||
}()) | ||
}).join(", ") | ||
} | ||
var set = function(key){ | ||
return setters[key] || (setters[key] = function(){ | ||
var parser = parsers[key] || StringParser | ||
return function(value){ | ||
return this.style[key] = (new parser(value)).toString() | ||
} | ||
}()) | ||
var parse = function(value, normalize, node){ | ||
if (value == null || value === "") return "" //cant normalize "" || null | ||
return value.replace(color.x, function(match){ | ||
return parseColor(match, normalize) | ||
}).replace(rgLength, function(match){ | ||
return parseLength(match, normalize, node) | ||
}) | ||
} | ||
// {pixel ratio retriever} | ||
// get && set | ||
var test = document.createElement("div") | ||
var getters = {}, setters = {}, parsers = {}, aliases = {} | ||
var cssText = "border:none;margin:none;padding:none;visibility:hidden;position:absolute;height:0;"; | ||
var getter = function(key){ | ||
return getters[key] || (getters[key] = (function(){ | ||
var alias = aliases[key] || key, | ||
parser = parsers[key] || parse | ||
var pixelRatio = function(element, u){ | ||
var parent = element.parentNode, ratio = 1 | ||
if (parent){ | ||
test.style.cssText = cssText + ("width:100" + u + ";") | ||
parent.appendChild(test) | ||
ratio = test.offsetWidth / 100 | ||
parent.removeChild(test) | ||
} | ||
return ratio | ||
return function(){ | ||
return parser(compute(this)(alias), true, this) | ||
} | ||
}())) | ||
} | ||
// {parsers, getters, setters} | ||
var setter = function(key){ | ||
return setters[key] || (setters[key] = (function(){ | ||
var alias = aliases[key] || key, | ||
parser = parsers[key] || parse | ||
return function(value){ | ||
this.style[alias] = parser(value) | ||
} | ||
}())) | ||
} | ||
// parsers | ||
var trbl = ["Top", "Right", "Bottom", "Left"], tlbl = ["TopLeft", "TopRight", "BottomRight", "BottomLeft"] | ||
parsers.color = parsers.backgroundColor = ColorParser | ||
each(trbl, function(d){ | ||
var bd = "border" + d | ||
each([ "margin" + d, "padding" + d, bd + "Width", d.toLowerCase()], function(n){ | ||
parsers[n] = parseLength | ||
}) | ||
parsers[bd + "Color"] = parseColor | ||
parsers[bd + "Style"] = parseBorderStyle | ||
parsers.width = parsers.height = parsers.fontSize = parsers.backgroundSize = LengthParser | ||
each (trbl, function(d){ | ||
var bd = "border" + d | ||
each([ "margin" + d, "padding" + d, bd + "Width", d.toLowerCase()], function(n){ | ||
parsers[n] = LengthParser | ||
}) | ||
parsers[bd + "Color"] = ColorParser | ||
parsers[bd + "Style"] = BorderStyleParser | ||
parsers[bd] = BorderParser | ||
getters[bd] = function(){ | ||
return [get(bd + "Width").call(this), get(bd + "Style").call(this), get(bd + "Color").call(this)].join(" ") | ||
} | ||
// borderDIR | ||
parsers[bd] = parseBorder | ||
getters[bd] = function(){ | ||
return [ | ||
getter(bd + "Width").call(this), | ||
getter(bd + "Style").call(this), | ||
getter(bd + "Color").call(this) | ||
].join(" ") | ||
} | ||
}) | ||
each(tlbl, function(d){ | ||
parsers["border" + d + "Radius"] = LengthParser | ||
parsers["border" + d + "Radius"] = parseLength | ||
}) | ||
parsers.zIndex = ZIndexParser | ||
parsers.color = parsers.backgroundColor = parseColor | ||
parsers.width = parsers.height = parsers.fontSize = parsers.backgroundSize = parseLength | ||
// margin + padding | ||
each(["margin", "padding"], function(name){ | ||
parsers[name] = LengthsParser | ||
return getters[name] = function(){ | ||
return map(trbl, function(d){ | ||
return get(name + d).call(this) | ||
}, this).join(" ") | ||
} | ||
parsers[name] = parseShort4 | ||
getters[name] = function(){ | ||
return map(trbl, function(d){ | ||
return getter(name + d).call(this) | ||
}, this).join(" ") | ||
} | ||
}) | ||
parsers.borderRadius = LengthsParser | ||
// borders | ||
getters.borderRadius = function(){ | ||
return map(trbl, function(d){ | ||
return get("border" + d + "Radius").call(this) | ||
}).join(" ") | ||
// borderDIRWidth, borderDIRStyle, borderDIRColor | ||
parsers.borderWidth = parseShort4 | ||
parsers.borderStyle = function(value, normalize, node){ | ||
if (value == null || value === "") return normalize ? mirror4(["none"]).join(" ") : "" | ||
value = clean(value).split(" ") | ||
return clean(mirror4(map(value, function(v){ | ||
parseBorderStyle(v, normalize) | ||
})).join(" ")) | ||
} | ||
parsers.borderWidth = LengthsParser | ||
parsers.borderColor = BorderColorParser | ||
parsers.borderColor = function(value, normalize){ | ||
if (!value || !(value = string.match(value, color.x))) return normalize ? mirror4(["rgba(0,0,0,1)"]).join(" ") : "" | ||
return clean(mirror4(map(value, function(v){ | ||
return parseColor(v, normalize) | ||
})).join(" ")) | ||
} | ||
each(["Width", "Style", "Color"], function(t){ | ||
getters["border" + t] = function(){ | ||
return map(trbl, function(d){ | ||
return get("border" + d + t).call(this) | ||
}, this).join(" ") | ||
} | ||
each(["Width", "Style", "Color"], function(name){ | ||
getters["border" + name] = function(){ | ||
return map(trbl, function(d){ | ||
return getter("border" + d + name).call(this) | ||
}, this).join(" ") | ||
} | ||
}) | ||
parsers.border = BorderParser | ||
// borderRadius | ||
getters.border = function(){ | ||
var pvalue | ||
for (var i = 0; i < trbl.length; i++){ | ||
var value = get("border" + trbl[i]).call(this) | ||
if (pvalue && value !== pvalue) return null | ||
pvalue = value | ||
} | ||
return value | ||
parsers.borderRadius = parseShort4 | ||
getters.borderRadius = function(){ | ||
return map(tlbl, function(d){ | ||
return getter("border" + d + "Radius").call(this) | ||
}, this).join(" ") | ||
} | ||
var filterName = html.style.MsFilter != null ? "MsFilter" : html.style.filter != null ? "filter" : null | ||
// border | ||
parsers.opacity = NumberParser | ||
parsers.border = parseBorder | ||
if (filterName && html.style.opacity == null){ | ||
matchOp = /alpha\(opacity=([\d.]+)\)/i | ||
setters.opacity = function(value){ | ||
value = (value = number(value) === 1) ? "" : "alpha(opacity=" + value * 100 + ")" | ||
var filter = computedStyle(this)(filterName) | ||
return this.style[filterName] = matchOp.test(filter) ? filter.replace(matchOp, value) : filter + value | ||
} | ||
getters.opacity = function(){ | ||
var match | ||
return string(!(match = computedStyle(this)(filterName).match(matchOp)) ? 1 : match[1] / 100) | ||
} | ||
getters.border = function(){ | ||
var pvalue | ||
for (var i = 0; i < trbl.length; i++){ | ||
var value = getter("border" + trbl[i]).call(this) | ||
if (pvalue && value !== pvalue) return null | ||
pvalue = value | ||
} | ||
return pvalue | ||
} | ||
var transitionName | ||
// zIndex | ||
each(["WebkitTransition", "MozTransition", "transition"], function(transition){ | ||
if (html.style[transition] != null) transitionName = transition | ||
}) | ||
parsers.zIndex = parseString | ||
var transitionEndName = transitionName === "MozTransition" ? "transitionend" : transitionName === "WebkitTransition" ? "webkitTransitionEnd" : "transitionEnd" | ||
// opacity | ||
var transformName | ||
var filterName = test.style.MsFilter != null ? "MsFilter" : test.style.filter != null ? "filter" : null | ||
each(["MozTransform", "WebkitTransform", "OTransform", "msTransform", "transform"], function(transform){ | ||
if (html.style[transform] != null) transformName = transform | ||
}) | ||
parsers.opacity = parseOpacity | ||
// transform animations only available on browsers with css3 transitions | ||
if (filterName && test.style.opacity == null){ | ||
parsers.transform = transitionName ? StringParser : inherits(Parser, function(){ | ||
return "none" | ||
}) | ||
var matchOp = /alpha\(opacity=([\d.]+)\)/i | ||
if (transformName){ | ||
translations.transform = transformName | ||
setters.transform = function(value){ | ||
return this.style[transformName] = value | ||
} | ||
getters.transform = function(){ | ||
return computedStyle(this)(transformName) | ||
} | ||
} else { | ||
setters.transform = function(){} | ||
getters.transform = function(){ | ||
return "none" | ||
} | ||
setters.opacity = function(value){ | ||
value = ((value = +value) === 1) ? "" : "alpha(opacity=" + value * 100 + ")" | ||
var filter = compute(this)(filterName) | ||
return this.style[filterName] = matchOp.test(filter) ? filter.replace(matchOp, value) : filter + value | ||
} | ||
getters.opacity = function(){ | ||
var match = compute(this)(filterName).match(matchOp) | ||
return (!match ? 1 : match[1] / 100) + "" | ||
} | ||
} | ||
var parseBoxShadow = parsers.boxShadow = function(value, normalize, node){ | ||
return parseShadow(value, normalize, node, 4) | ||
} | ||
var parseTextShadow = parsers.textShadow = function(value, normalize, node){ | ||
return parseShadow(value, normalize, node, 3) | ||
} | ||
// Aliases | ||
each(['Webkit', "Moz", "O", "ms", null], function(prefix){ | ||
each(["transition", "transform", "transformOrigin", "transformStyle", "perspective", "perspectiveOrigin", "backfaceVisibility"], function(style){ | ||
var cc = prefix ? prefix + capitalize(style) : style | ||
if (test.style[cc] != null) aliases[style] = cc | ||
}) | ||
}) | ||
var transitionName = aliases.transition | ||
// equations collection | ||
var equations = { | ||
"default": "cubic-bezier(0.25, 0.1, 0.25, 1.0)", | ||
"linear": "cubic-bezier(0, 0, 1, 1)", | ||
"ease-in": "cubic-bezier(0.42, 0, 1.0, 1.0)", | ||
"ease-out": "cubic-bezier(0, 0, 0.58, 1.0)", | ||
"ease-in-out": "cubic-bezier(0.42, 0, 0.58, 1.0)" | ||
"default" : "cubic-bezier(0.25, 0.1, 0.25, 1.0)", | ||
"linear" : "cubic-bezier(0, 0, 1, 1)", | ||
"ease-in" : "cubic-bezier(0.42, 0, 1.0, 1.0)", | ||
"ease-out" : "cubic-bezier(0, 0, 0.58, 1.0)", | ||
"ease-in-out" : "cubic-bezier(0.42, 0, 0.58, 1.0)" | ||
} | ||
@@ -379,342 +381,431 @@ | ||
// {BrowserAnimation} | ||
// BrowserAnimation | ||
var BrowserAnimation = function(node, property){ | ||
this.node = node | ||
this.property = property | ||
this.setter = set(property) | ||
this.getter = get(property) | ||
} | ||
var BrowserAnimation = prime({ | ||
BrowserAnimation.prototype.setOptions = function(options){ | ||
if (options == null) options = {} | ||
var duration = options.duration | ||
if (typeof duration === 'number') duration = duration + "ms" | ||
if (!(this.duration = this.parseDuration(duration || "500ms"))) throw new Error(this.duration + " is not a valid duration") | ||
if (!(this.equation = this.parseEquation(options.equation || "default"))) throw new Error(this.equation + " is not a valid equation") | ||
this.callback = options.callback || function(){} | ||
return this | ||
} | ||
constructor: function(node, property){ | ||
var _getter = getter(property), | ||
_setter = setter(property) | ||
BrowserAnimation.prototype.parseDuration = function(duration){ | ||
if (duration = string(duration).match(/([\d.]+)(s|ms)/)){ | ||
var time = number(duration[1]), unit = duration[2] | ||
if (unit === "s") return time * 1e3 | ||
if (unit === "ms") return time | ||
} | ||
return null | ||
} | ||
this.get = function(){ | ||
return _getter.call(node) | ||
} | ||
BrowserAnimation.prototype.parseEquation = function(equation){ | ||
equation = equations[equation] || equation | ||
var match = equation.replace(/\s+/g, "").match(/^cubic-bezier\(([\d.]+),([\d.]+),([\d.]+),([\d.]+)\)$/) | ||
return match ? map(match.slice(1), number) : null | ||
} | ||
this.set = function(value){ | ||
return _setter.call(node, value) | ||
} | ||
// {JSAnimation} | ||
this.node = node | ||
this.property = property | ||
this.parse = parsers[property] || parse | ||
var JSAnimation = inherits(BrowserAnimation, function(node, property){ | ||
BrowserAnimation.prototype.constructor.call(this, node, property) | ||
var self = this | ||
this.bstep = function(t){ | ||
return self.step(t) | ||
} | ||
var self = this | ||
this.bExit = function(time){ | ||
self.exit(time) | ||
} | ||
}, | ||
setOptions: function(options){ | ||
if (options == null) options = {} | ||
var duration = options.duration | ||
if (!(this.duration = this.parseDuration(duration || "500ms"))) throw new Error(this.duration + " is not a valid duration") | ||
if (!(this.equation = this.parseEquation(options.equation || "default"))) throw new Error(this.equation + " is not a valid equation") | ||
this.callback = options.callback || function(){} | ||
return this | ||
}, | ||
exit: function(time){ | ||
if (this.exitValue != null) this.set(this.exitValue) | ||
this.cancelExit = null | ||
this.callback(time) | ||
return null | ||
}, | ||
prepare: function(to){ | ||
this.exitValue = null | ||
// if we start() twice, once with incorrect values and once with correct values, we need to cancel the callback | ||
if (this.duration === 0){ | ||
this.exitValue = to | ||
this.cancelExit = requestFrame(this.bExit) | ||
} else { | ||
var node = this.node, | ||
p = this.parse, | ||
fromParsed = this.get(), // already "normalized" by get, always pixels lengths | ||
toParsed = p(to, true) // normalize colors, but keep lengths in their passed unit | ||
//automatic unit conversion for these specific parsers | ||
if (p === parseLength || p === parseBorder || p === parseShort4){ | ||
var toUnits = toParsed.match(rgLength), /*this should always match something*/ | ||
i = 0 | ||
if (toUnits) fromParsed = fromParsed.replace(rgLength, function(fromMatch){ | ||
var toMatch = toUnits[i++], | ||
fromValue = fromMatch.match(rLengthLax)[1], | ||
toUnit = toMatch.match(rLengthLax)[2] | ||
return (toUnit !== "px") ? round(fromValue / pixelRatio(node, toUnit)) + toUnit : fromMatch | ||
}) | ||
if (i > 0) this.set(fromParsed) | ||
} | ||
if (fromParsed === toParsed){ | ||
this.cancelExit = requestFrame(this.bExit) | ||
} else { | ||
return [fromParsed, toParsed] | ||
} | ||
} | ||
}, | ||
parseDuration: function(duration){ | ||
if (duration = string.match(duration, rDuration)){ | ||
var time = +duration[1], | ||
unit = duration[2] || "ms" | ||
if (unit === "s") return time * 1e3 | ||
if (unit === "ms") return time | ||
} | ||
return null | ||
}, | ||
parseEquation: function(equation){ | ||
equation = equations[equation] || equation | ||
var match = equation.replace(/\s+/g, "").match(rCubicBezier) | ||
return match ? map(match.slice(1), function(v){ | ||
return +v | ||
}) : null | ||
} | ||
}) | ||
var numbers = function(string){ | ||
var ns = [], replaced = string.replace(/[-\d.]+/g, function(n){ | ||
ns.push(number(n)) | ||
return "@" | ||
}) | ||
return [ns, replaced] | ||
var divide = function(string){ | ||
var numbers = [] | ||
string = string.replace(/[-.\d]+/g, function(number){ | ||
numbers.push(+number) | ||
return "@" | ||
}) | ||
return [numbers, string] | ||
} | ||
var compute = function(from, to, delta){ | ||
return (to - from) * delta + from | ||
var calc = function(from, to, delta){ | ||
return (to - from) * delta + from | ||
} | ||
JSAnimation.prototype.start = function(from, to){ | ||
if (from != to && this.duration !== 0){ | ||
this.time = 0 | ||
from = numbers(from) | ||
to = numbers(to) | ||
if (from[0].length !== to[0].length) throw new Error("length mismatch") | ||
this.from = from[0] | ||
this.to = to[0] | ||
this.template = to[1] | ||
requestFrame(this.bstep) | ||
} else { | ||
if (this.duration == 0) this.setter.call(this.node, to) | ||
requestFrame(this.callback) | ||
} | ||
return this | ||
} | ||
var JSAnimation = prime({ | ||
JSAnimation.prototype.stop = function(){ | ||
cancelFrame(this.bstep) | ||
return this | ||
} | ||
inherits: BrowserAnimation, | ||
JSAnimation.prototype.step = function(now){ | ||
this.time || (this.time = now) | ||
var factor = (now - this.time) / this.duration | ||
if (factor > 1) factor = 1 | ||
var delta = this.equation(factor) | ||
var tpl = this.template | ||
var from = this.from, to = this.to | ||
for (var i = 0, l = from.length; i < l; i++){ | ||
var f = from[i], t = to[i] | ||
tpl = tpl.replace("@", t !== f ? compute(f, t, delta) : t) | ||
} | ||
this.setter.call(this.node, tpl) | ||
if (factor !== 1) requestFrame(this.bstep) | ||
else this.callback(t) | ||
} | ||
constructor: function(node, property){ | ||
JSAnimation.parent.constructor.call(this, node, property) | ||
var self = this | ||
this.bStep = function(t){ | ||
return self.step(t) | ||
} | ||
}, | ||
JSAnimation.prototype.parseEquation = function(equation){ | ||
var equation = BrowserAnimation.prototype.parseEquation.call(this, equation) | ||
if (equation == [0, 0, 1, 1]) return function(x){ | ||
return x | ||
} | ||
return bezier(equation[0], equation[1], equation[2], equation[3], 1e3 / 60 / this.duration / 4) | ||
} | ||
start: function(to){ | ||
// {CSSAnimation} | ||
this.stop() | ||
var CSSAnimation = inherits(BrowserAnimation, function(node, property){ | ||
BrowserAnimation.prototype.constructor.call(this, node, property) | ||
var self = this | ||
this.hproperty = hyphenate(translations[this.property] || this.property) | ||
this.bdefer = function(t){ | ||
return self.defer(t) | ||
} | ||
this.bcomplete = function(e){ | ||
return self.complete(e) | ||
} | ||
var prepared = this.prepare(to), | ||
p = this.parse | ||
if (prepared){ | ||
this.time = 0 | ||
var from_ = divide(prepared[0]), | ||
to_ = divide(prepared[1]) | ||
// complex interpolations JSAnimation can't handle | ||
// even CSS3 animation gracefully fail with some of those edge cases | ||
// other "simple" properties, such as `border` can have different templates | ||
// because of string properties like "solid" and "dashed" | ||
if ((from_[0].length !== to_[0].length) || ((p === parseBoxShadow || p === parseTextShadow || p === parse) && (from_[1] !== to_[1]))){ | ||
this.exit(to) | ||
} else { | ||
this.from = from_[0] | ||
this.to = to_[0] | ||
this.template = to_[1] | ||
this.cancelStep = requestFrame(this.bStep) | ||
} | ||
} | ||
return this | ||
}, | ||
stop: function(){ | ||
if (this.cancelExit) this.cancelExit = this.cancelExit() | ||
else if (this.cancelStep) this.cancelStep = this.cancelStep() | ||
return this | ||
}, | ||
step: function(now){ | ||
this.time || (this.time = now) | ||
var factor = (now - this.time) / this.duration | ||
if (factor > 1) factor = 1 | ||
var delta = this.equation(factor), | ||
tpl = this.template, | ||
from = this.from, | ||
to = this.to | ||
for (var i = 0, l = from.length; i < l; i++){ | ||
var f = from[i], | ||
t = to[i] | ||
tpl = tpl.replace("@", t !== f ? calc(f, t, delta) : t) | ||
} | ||
this.set(tpl) | ||
if (factor !== 1) this.cancelStep = requestFrame(this.bStep) | ||
else { | ||
this.cancelStep = null | ||
this.callback(now) | ||
} | ||
}, | ||
parseEquation: function(equation){ | ||
var equation = JSAnimation.parent.parseEquation.call(this, equation) | ||
if (equation == [0, 0, 1, 1]) return function(x){ | ||
return x | ||
} | ||
return bezier(equation[0], equation[1], equation[2], equation[3], 1e3 / 60 / this.duration / 4) | ||
} | ||
}) | ||
CSSAnimation.prototype.start = function(from, to){ | ||
if (from != to && this.duration != 0){ | ||
this.to = to | ||
requestFrame(this.bdefer) | ||
} else { | ||
if (this.duration == 0) this.setter.call(this.node, to) | ||
requestFrame(this.callback) | ||
} | ||
// CSSAnimation | ||
return this | ||
var remove3 = function(value, a, b, c){ | ||
var index = indexOf(a, value) | ||
if (index !== -1){ | ||
a.splice(index, 1) | ||
b.splice(index, 1) | ||
c.splice(index, 1) | ||
} | ||
} | ||
CSSAnimation.prototype.stop = function(hard){ | ||
if (this.running){ | ||
this.running = false | ||
if (hard) this.setter.call(this.node, this.getter.call(this.node)) | ||
this.clean() | ||
} else { | ||
cancelFrame(this.bdefer) | ||
} | ||
return this | ||
} | ||
var CSSAnimation = prime({ | ||
CSSAnimation.prototype.defer = function(){ | ||
this.running = true | ||
this.modCSS(true) | ||
this.node.addEventListener(transitionEndName, this.bcomplete, false) | ||
this.setter.call(this.node, this.to) | ||
return null | ||
} | ||
inherits: BrowserAnimation, | ||
CSSAnimation.prototype.clean = function(){ | ||
this.modCSS() | ||
this.node.removeEventListener(transitionEndName, this.bcomplete) | ||
return null | ||
} | ||
constructor: function(node, property){ | ||
CSSAnimation.parent.constructor.call(this, node, property) | ||
CSSAnimation.prototype.complete = function(e){ | ||
if (e && e.propertyName === this.hproperty){ | ||
this.running = false | ||
this.clean() | ||
requestFrame(this.callback) | ||
} | ||
return null | ||
} | ||
this.hproperty = hyphenate(aliases[property] || property) | ||
var removeProp = function(prop, a, b, c){ | ||
var indexOf | ||
for (var i = 0, l = a.length; i < l; i++){ | ||
if (a[i] !== prop) continue | ||
indexOf = i | ||
break | ||
} | ||
if (indexOf != null){ | ||
a.splice(indexOf, 1) | ||
b.splice(indexOf, 1) | ||
c.splice(indexOf, 1) | ||
} | ||
} | ||
var self = this | ||
CSSAnimation.prototype.modCSS = function(inclusive){ | ||
var rules = computedStyle(this.node), | ||
p = rules(transitionName + "Property").replace(/\s+/g, "").split(","), | ||
d = rules(transitionName + "Duration").replace(/\s+/g, "").split(","), | ||
e = rules(transitionName + "TimingFunction").replace(/\s+/g, "").match(/cubic-bezier\(([\d.,]+)\)/g) | ||
this.bSetTransitionCSS = function(time){ | ||
self.setTransitionCSS(time) | ||
} | ||
removeProp("all", p, d, e) | ||
removeProp(this.hproperty, p, d, e) | ||
if (inclusive){ | ||
p.push(this.hproperty) | ||
d.push(this.duration) | ||
e.push(this.equation) | ||
} | ||
this.bSetStyleCSS = function(time){ | ||
self.setStyleCSS(time) | ||
} | ||
this.node.style[transitionName + "Property"] = p | ||
this.node.style[transitionName + "Duration"] = d | ||
this.node.style[transitionName + "TimingFunction"] = e | ||
} | ||
this.bComplete = function(){ | ||
self.complete() | ||
} | ||
}, | ||
CSSAnimation.prototype.parseDuration = function(duration){ | ||
return BrowserAnimation.prototype.parseDuration.call(this, duration) + "ms" | ||
} | ||
start: function(to){ | ||
CSSAnimation.prototype.parseEquation = function(equation){ | ||
return "cubic-bezier(" + BrowserAnimation.prototype.parseEquation.call(this, equation) + ")" | ||
} | ||
this.stop() | ||
// animations collector | ||
var prepared = this.prepare(to) | ||
var animations = { | ||
if (prepared){ | ||
this.to = prepared[1] | ||
// setting transition styles immediately will make good browsers behave weirdly | ||
// because DOM changes are always deferred, so we requestFrame | ||
this.cancelSetTransitionCSS = requestFrame(this.bSetTransitionCSS) | ||
} | ||
uid: 0, | ||
return this | ||
}, | ||
animations: {}, | ||
setTransitionCSS: function(){ | ||
this.cancelSetTransitionCSS = null | ||
this.resetCSS(true) | ||
// firefox flickers if we set css for transition as well as styles at the same time | ||
// so, other than deferring transition styles we defer actual styles as well on a requestFrame | ||
this.cancelSetStyleCSS = requestFrame(this.bSetStyleCSS) | ||
}, | ||
retrieve: function(node, property){ | ||
var animation, _base, _uid | ||
var uid = (_uid = node["µid"]) != null ? _uid : node["µid"] = (this.uid++).toString(36) | ||
animation = (_base = this.animations)[uid] || (_base[uid] = {}) | ||
return animation[property] || (animation[property] = transitionName ? new CSSAnimation(node, property) : new JSAnimation(node, property)) | ||
}, | ||
setStyleCSS: function(time){ | ||
this.cancelSetStyleCSS = null | ||
var duration = this.duration | ||
// we use setTimeout instead of transitionEnd because some browsers (looking at you foxy) | ||
// incorrectly set event.propertyName, so we cannot check which animation we are canceling | ||
this.cancelComplete = setTimeout(this.bComplete, duration) | ||
this.endTime = time + duration | ||
this.set(this.to) | ||
}, | ||
starts: function(nodes, styles, options){ | ||
if (options == null) options = {} | ||
complete: function(){ | ||
this.cancelComplete = null | ||
this.resetCSS() | ||
this.callback(this.endTime) | ||
return null | ||
}, | ||
var type = typeof options | ||
stop: function(hard){ | ||
if (this.cancelExit) this.cancelExit = this.cancelExit() | ||
options = type === "function" ? { | ||
callback: options | ||
} : (type === "string" || type === "number") ? { | ||
duration: options | ||
} : options | ||
else if (this.cancelSetTransitionCSS){ | ||
// if cancelSetTransitionCSS is set, means nothing is set yet | ||
this.cancelSetTransitionCSS = this.cancelSetTransitionCSS() //so we cancel and we're good | ||
} else if (this.cancelSetStyleCSS){ | ||
// if cancelSetStyleCSS is set, means transition css has been set, but no actual styles. | ||
this.cancelSetStyleCSS = this.cancelSetStyleCSS() | ||
// if its a hard stop (and not another start on top of the current animation) | ||
// we need to reset the transition CSS | ||
if (hard) this.resetCSS() | ||
} else if (this.cancelComplete){ | ||
// if cancelComplete is set, means style and transition css have been set, not yet completed. | ||
this.cancelComplete = clearTimeout(this.cancelComplete) | ||
// if its a hard stop (and not another start on top of the current animation) | ||
// we need to reset the transition CSS set the current animation styles | ||
if (hard){ | ||
this.resetCSS() | ||
this.set(this.get()) | ||
} | ||
} | ||
return this | ||
}, | ||
var callback = options.callback || function(){} | ||
resetCSS: function(inclusive){ | ||
var rules = compute(this.node), | ||
properties = rules(transitionName + "Property").replace(/\s+/g, "").split(","), | ||
durations = rules(transitionName + "Duration").replace(/\s+/g, "").split(","), | ||
equations = rules(transitionName + "TimingFunction").replace(/\s+/g, "").match(rgCubicBezier) | ||
var completed = 0, length = 0 | ||
remove3("all", properties, durations, equations) | ||
remove3(this.hproperty, properties, durations, equations) | ||
options.callback = function(t){ | ||
if (++completed === length) callback(t) | ||
} | ||
if (inclusive){ | ||
properties.push(this.hproperty) | ||
durations.push(this.duration + "ms") | ||
equations.push("cubic-bezier(" + this.equation + ")") | ||
} | ||
for (var property in styles){ | ||
var value = styles[property], parser = parsers[property = camelize(property)] | ||
if (!parser) throw new Error("no parser for " + property) | ||
var setter = set(property) | ||
var getter = get(property) | ||
for (var i = 0, l = nodes.length; i < l; i++){ | ||
length++ | ||
var node = nodes[i], | ||
instance = this.retrieve(node, property), | ||
parsedFrom = new parser(getter.call(node)), | ||
parsedTo = new parser(value), | ||
fromParsers = parsedFrom.extract(), | ||
toParsers = parsedTo.extract(), | ||
enforce = false | ||
var nodeStyle = this.node.style | ||
for (var j = 0, k = fromParsers.length; j < k; j++){ | ||
var fp = fromParsers[j], tp = toParsers[j] | ||
nodeStyle[transitionName + "Property"] = properties | ||
nodeStyle[transitionName + "Duration"] = durations | ||
nodeStyle[transitionName + "TimingFunction"] = equations | ||
} | ||
if ("auto" === tp.value || "auto" === fp.value) throw new Error("cannot animate " + property + " from or to `auto`") | ||
}) | ||
if (tp.unit && fp.unit){ | ||
enforce = true | ||
if (tp.unit !== "px"){ | ||
fp.value = fp.value / pixelRatio(node, tp.unit) | ||
fp.unit = tp.unit | ||
} | ||
} | ||
} | ||
var fs = parsedFrom.toString(true), ts = parsedTo.toString(true) | ||
// nodes methods | ||
if (enforce) setter.call(node, fs) | ||
instance.setOptions(options).start(fs, ts) | ||
} | ||
} | ||
}, | ||
var BaseAnimation = transitionName ? CSSAnimation : JSAnimation | ||
// var BaseAnimation = JSAnimation | ||
start: function(nodes, property, value, options){ | ||
var styles = {} | ||
styles[property] = value | ||
return this.starts(nodes, styles, options) | ||
}, | ||
var UID = 0 | ||
sets: function(nodes, styles){ | ||
for (var property in styles){ | ||
var value = styles[property], setter = set(property = camelize(property)) | ||
for (var i = 0, l = nodes.length; i < l; i++){ | ||
var node = nodes[i], aid, apid | ||
if ((aid = this.animations[node["µid"]]) != null){ | ||
if ((apid = aid[property]) != null) apid.stop(true) | ||
} | ||
setter.call(node, value) | ||
} | ||
} | ||
return this | ||
}, | ||
var animations = {} | ||
set: function(nodes, property, value){ | ||
var styles = {} | ||
styles[property] = value | ||
return this.sets(nodes, styles) | ||
} | ||
var moofx = nodes.implement({ | ||
} | ||
// {properties}, options or | ||
// property, value options | ||
animate: function(A, B, C){ | ||
var mu = function(nod){ | ||
this.valueOf = function(){ | ||
return nod | ||
} | ||
return this | ||
} | ||
var styles = A, options = B | ||
// moofx! | ||
if (typeof A === "string"){ | ||
styles = {} | ||
styles[A] = B | ||
options = C | ||
} | ||
moofx = function(nod){ | ||
if (!nod) return null | ||
return new mu(nod.length != null ? nod : nod.nodeType === 1 ? [nod] : []) | ||
} | ||
if (options == null) options = {} | ||
moofx.prototype = mu.prototype | ||
var type = typeof options | ||
moofx.prototype.animate = function(A, B, C){ | ||
if (typeof A !== "string") animations.starts(this.valueOf(), A, B) | ||
else animations.start(this.valueOf(), A, B, C) | ||
return this | ||
} | ||
options = type === "function" ? { | ||
callback: options | ||
} : (type === "string" || type === "number") ? { | ||
duration: options | ||
} : options | ||
moofx.prototype.style = function(A, B){ | ||
if (typeof A !== "string") animations.sets(this.valueOf(), A) | ||
else animations.set(this.valueOf(), A, B) | ||
return this | ||
} | ||
var callback = options.callback || function(){}, | ||
completed = 0, | ||
length = 0 | ||
moofx.prototype.compute = function(A){ | ||
return get(camelize(A)).call(this.valueOf()[0]) | ||
} | ||
options.callback = function(t){ | ||
if (++completed === length) callback(t) | ||
} | ||
// this is for testing | ||
for (var property in styles){ | ||
var value = styles[property], | ||
property = camelize(property) | ||
this.handle(function(node){ | ||
length++ | ||
var _xid = node._xid || (node._xid = (UID++).toString(36)), | ||
anims = animations[_xid] || (animations[_xid] = {}), | ||
anim = anims[property] || (anims[property] = new BaseAnimation(node, property)) | ||
anim.setOptions(options).start(value) | ||
}) | ||
} | ||
}, | ||
// {properties} or | ||
// property, value | ||
style: function(A, B){ | ||
var styles = A | ||
if (typeof A === "string"){ | ||
styles = {} | ||
styles[A] = B | ||
} | ||
for (var property in styles){ | ||
var value = styles[property], | ||
set = setter(property = camelize(property)) | ||
this.handle(function(node){ | ||
var anims = animations[node._xid], anim | ||
if (anims && (anim = anims[property])) anim.stop(true) | ||
set.call(node, value) | ||
}) | ||
} | ||
return this | ||
}, | ||
compute: function(property){ | ||
return getter(camelize(property)).call(this.node()) | ||
} | ||
}) | ||
moofx.parse = function(property, value, normalize, node){ | ||
if (!parsers[property = camelize(property)]) return null | ||
return new parsers[property](value).toString(normalize, node) | ||
if (!parsers[property = camelize(property)]) return null | ||
return parsers[property](value, normalize, node) | ||
} | ||
module.exports = moofx |
181
lib/color.js
@@ -1,47 +0,52 @@ | ||
// color conversion from any to rgb | ||
/* | ||
color | ||
*/"use strict" | ||
var colors = { | ||
maroon: "#800000", | ||
red: "#ff0000", | ||
orange: "#ffA500", | ||
yellow: "#ffff00", | ||
olive: "#808000", | ||
purple: "#800080", | ||
fuchsia: "#ff00ff", | ||
white: "#ffffff", | ||
lime: "#00ff00", | ||
green: "#008000", | ||
navy: "#000080", | ||
blue: "#0000ff", | ||
aqua: "#00ffff", | ||
teal: "#008080", | ||
black: "#000000", | ||
silver: "#c0c0c0", | ||
gray: "#808080" | ||
maroon : "#800000", | ||
red : "#ff0000", | ||
orange : "#ffA500", | ||
yellow : "#ffff00", | ||
olive : "#808000", | ||
purple : "#800080", | ||
fuchsia : "#ff00ff", | ||
white : "#ffffff", | ||
lime : "#00ff00", | ||
green : "#008000", | ||
navy : "#000080", | ||
blue : "#0000ff", | ||
aqua : "#00ffff", | ||
teal : "#008080", | ||
black : "#000000", | ||
silver : "#c0c0c0", | ||
gray : "#808080", | ||
transparent : "#0000" | ||
} | ||
var RGBtoRGB = function(r, g, b, a){ | ||
if (a == null) a = 1 | ||
r = parseInt(r, 10) | ||
g = parseInt(g, 10) | ||
b = parseInt(b, 10) | ||
a = parseFloat(a) | ||
if (!(r <= 255 && r >= 0 && g <= 255 && g >= 0 && b <= 255 && b >= 0 && a <= 1 && a >= 0)) return null | ||
if (a == null) a = 1 | ||
r = parseInt(r, 10) | ||
g = parseInt(g, 10) | ||
b = parseInt(b, 10) | ||
a = parseFloat(a) | ||
if (!(r <= 255 && r >= 0 && g <= 255 && g >= 0 && b <= 255 && b >= 0 && a <= 1 && a >= 0)) return null | ||
return [Math.round(r), Math.round(g), Math.round(b), a] | ||
return [Math.round(r), Math.round(g), Math.round(b), a] | ||
} | ||
var HEXtoRGB = function(hex){ | ||
if (hex.length === 3) hex += "f" | ||
if (hex.length === 4){ | ||
var h0 = hex.charAt(0), | ||
h1 = hex.charAt(1), | ||
h2 = hex.charAt(2), | ||
h3 = hex.charAt(3) | ||
hex = h0 + h0 + h1 + h1 + h2 + h2 + h3 + h3 | ||
} | ||
if (hex.length === 6) hex += "ff" | ||
var rgb = [] | ||
for (var i = 0, l = hex.length; i <= l; i += 2) rgb.push(parseInt(hex.substr(i, 2), 16) / (i === 6 ? 255 : 1)) | ||
return rgb | ||
if (hex.length === 3) hex += "f" | ||
if (hex.length === 4){ | ||
var h0 = hex.charAt(0), | ||
h1 = hex.charAt(1), | ||
h2 = hex.charAt(2), | ||
h3 = hex.charAt(3) | ||
hex = h0 + h0 + h1 + h1 + h2 + h2 + h3 + h3 | ||
} | ||
if (hex.length === 6) hex += "ff" | ||
var rgb = [] | ||
for (var i = 0, l = hex.length; i < l; i += 2) rgb.push(parseInt(hex.substr(i, 2), 16) / (i === 6 ? 255 : 1)) | ||
return rgb | ||
} | ||
@@ -54,47 +59,69 @@ | ||
var HUEtoRGB = function(p, q, t){ | ||
if (t < 0) t += 1 | ||
if (t > 1) t -= 1 | ||
if (t < 1 / 6) return p + (q - p) * 6 * t | ||
if (t < 1 / 2) return q | ||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6 | ||
return p | ||
if (t < 0) t += 1 | ||
if (t > 1) t -= 1 | ||
if (t < 1 / 6) return p + (q - p) * 6 * t | ||
if (t < 1 / 2) return q | ||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6 | ||
return p | ||
} | ||
var HSLtoRGB = function(h, s, l, a){ | ||
var r, b, g | ||
if (a == null) a = 1 | ||
h /= 360 | ||
s /= 100 | ||
l /= 100 | ||
a /= 1 | ||
if (h > 1 || h < 0 || s > 1 || s < 0 || l > 1 || l < 0 || a > 1 || a < 0) return null | ||
if (s === 0){ | ||
r = b = g = l | ||
} else { | ||
var q = l < .5 ? l * (1 + s) : l + s - l * s | ||
var p = 2 * l - q | ||
r = HUEtoRGB(p, q, h + 1 / 3) | ||
g = HUEtoRGB(p, q, h) | ||
b = HUEtoRGB(p, q, h - 1 / 3) | ||
} | ||
return [r * 255, g * 255, b * 255, a] | ||
var r, b, g | ||
if (a == null) a = 1 | ||
h /= 360 | ||
s /= 100 | ||
l /= 100 | ||
a /= 1 | ||
if (h > 1 || h < 0 || s > 1 || s < 0 || l > 1 || l < 0 || a > 1 || a < 0) return null | ||
if (s === 0){ | ||
r = b = g = l | ||
} else { | ||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s | ||
var p = 2 * l - q | ||
r = HUEtoRGB(p, q, h + 1 / 3) | ||
g = HUEtoRGB(p, q, h) | ||
b = HUEtoRGB(p, q, h - 1 / 3) | ||
} | ||
return [r * 255, g * 255, b * 255, a] | ||
} | ||
module.exports = function(input, array){ | ||
var match | ||
if (typeof input !== "string") return null | ||
input = colors[input = input.replace(/\s+/g, "")] || input | ||
if (input.match(/^#[a-f0-9]{3,8}/)){ | ||
input = HEXtoRGB(input.replace("#", "")) | ||
} else if (match = input.match(/([\d.])+/g)){ | ||
if (input.match(/^rgb/)) input = match | ||
else if (input.match(/^hsl/)) input = HSLtoRGB.apply(null, match) | ||
else return null | ||
} else { | ||
return null | ||
} | ||
if (!(input && (input = RGBtoRGB.apply(null, input)))) return null | ||
if (array) return input | ||
if (input[3] === 1) input.splice(3, 1) | ||
return "rgb" + (input.length > 3 ? "a" : "") + "(" + input + ")" | ||
var keys = [] | ||
for (var c in colors) keys.push(c) | ||
var shex = "(?:#([a-f0-9]{3,8}))", | ||
sval = "\\s*([.\\d%]+)\\s*", | ||
sop = "(?:,\\s*([.\\d]+)\\s*)?", | ||
slist = "\\(" + [sval, sval, sval] + sop + "\\)", | ||
srgb = "(?:rgb)a?", | ||
shsl = "(?:hsl)a?", | ||
skeys = "(" + keys.join("|") + ")" | ||
var xhex = RegExp(shex), | ||
xrgb = RegExp(srgb + slist), | ||
xhsl = RegExp(shsl + slist) | ||
var color = function(input, array){ | ||
if (input == null) return null | ||
input = (input + "").replace(/\s+/, "") | ||
var match = colors[input] | ||
if (match){ | ||
return color(match, array) | ||
} else if (match = input.match(xhex)){ | ||
input = HEXtoRGB(match[1]) | ||
} else if (match = input.match(xrgb)){ | ||
input = match.slice(1) | ||
} else if (match = input.match(xhsl)){ | ||
input = HSLtoRGB.apply(null, match.slice(1)) | ||
} else return null | ||
if (!(input && (input = RGBtoRGB.apply(null, input)))) return null | ||
if (array) return input | ||
if (input[3] === 1) input.splice(3, 1) | ||
return "rgb" + (input.length === 4 ? "a" : "") + "(" + input + ")" | ||
} | ||
color.x = RegExp([skeys, shex, srgb + slist, shsl + slist].join("|"), "g") | ||
module.exports = color |
@@ -1,32 +0,44 @@ | ||
// requestFrame impementation, supports frame canceling, and the time argument, 100% cross platform. | ||
/* | ||
requestFrame / cancelFrame | ||
*/"use strict" | ||
var requestFrame = global.requestAnimationFrame || | ||
global.webkitRequestAnimationFrame || | ||
global.mozRequestAnimationFrame || | ||
global.oRequestAnimationFrame || | ||
global.msRequestAnimationFrame || | ||
function(callback){ | ||
return setTimeout(callback, 1e3 / 60) | ||
} | ||
var callbacks = [], running = false | ||
var iterator = function(time){ | ||
if (time == null) time = +(new Date) | ||
running = false | ||
var i = callbacks.length | ||
while (i) callbacks.splice(--i, 1)[0](time) | ||
if (time == null) time = +(new Date) | ||
running = false | ||
for (var i = callbacks.length; i--;){ | ||
var callback = callbacks.shift() | ||
if (callback) callback(time) | ||
} | ||
} | ||
var requestFrame = global.requestAnimationFrame || global.webkitRequestAnimationFrame || global.mozRequestAnimationFrame || global.oRequestAnimationFrame || global.msRequestAnimationFrame || function(callback){ | ||
return setTimeout(callback, 1e3 / 60) | ||
var cancel = function(match){ | ||
for (var i = callbacks.length; i--;) if (callbacks[i] === match){ | ||
callbacks.splice(i, 1) | ||
break | ||
} | ||
} | ||
exports.request = function(callback){ | ||
callbacks.push(callback) | ||
if (!running){ | ||
running = true | ||
requestFrame(iterator) | ||
} | ||
return this | ||
var request = function(callback){ | ||
callbacks.push(callback) | ||
if (!running){ | ||
running = true | ||
requestFrame(iterator) | ||
} | ||
return function(){ | ||
cancel(callback) | ||
} | ||
} | ||
exports.cancel = function(match){ | ||
for (var i = 0, l = callbacks.length; i < l; i++){ | ||
var callback = callbacks[i] | ||
if (callback === match) callbacks.splice(i, 1) | ||
} | ||
return this | ||
} | ||
exports.request = request | ||
exports.cancel = cancel |
@@ -1,12 +0,23 @@ | ||
// main | ||
/* .- 3 | ||
.-.-..-..-.-|-._. | ||
' ' '`-'`-' ' ' ' | ||
*/"use strict" | ||
// color and timer | ||
var color = require("./color"), frame = require("./frame") | ||
// if we're in a browser we need ./browser, otherwise no | ||
var moofx = (typeof document !== "undefined") ? require("./browser") : {} | ||
// attach properties | ||
moofx.requestFrame = function(callback){ | ||
frame.request(callback) | ||
return this | ||
} | ||
moofx.requestFrame = frame.request | ||
moofx.cancelFrame = frame.cancel | ||
moofx.cancelFrame = function(callback){ | ||
frame.cancel(callback) | ||
return this | ||
} | ||
moofx.color = color | ||
@@ -13,0 +24,0 @@ |
@@ -21,2 +21,2 @@ The MIT License | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
THE SOFTWARE. |
{ | ||
"name": "moofx", | ||
"description": "A CSS3-enabled javascript animation library on caffeine", | ||
"version": "3.0.5", | ||
"description": "A CSS3-enabled javascript animation library for node and the browser", | ||
"version": "3.0.6", | ||
"license": "MIT (http://mootools.net/license.txt)", | ||
@@ -22,3 +22,5 @@ "main": "./lib/main.js", | ||
"dependencies": { | ||
"cubic-bezier": "0.1.2" | ||
"cubic-bezier": "0.1.2", | ||
"prime": "0.0.3-alpha", | ||
"nodes": "0.0.1-alpha" | ||
}, | ||
@@ -25,0 +27,0 @@ "sources": [ |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
30549
775
3
1
+ Addednodes@0.0.1-alpha
+ Addedprime@0.0.3-alpha
+ Addednodes@0.0.1-alpha(transitive)
+ Addedprime@0.0.3-alpha(transitive)