2396 lines
73 KiB
JavaScript
2396 lines
73 KiB
JavaScript
|
|
/*******************************************************************************
|
|
* This notice must be untouched at all times.
|
|
*
|
|
* CSS Sandpaper: smooths out differences between CSS implementations.
|
|
*
|
|
* This javascript library contains routines to implement the CSS transform,
|
|
* box-shadow and gradient in IE. It also provides a common syntax for other
|
|
* browsers that support vendor-specific methods.
|
|
*
|
|
* Written by: Zoltan Hawryluk. Version 1.0 beta 1 completed on March 8, 2010.
|
|
*
|
|
* Some routines are based on code from CSS Gradients via Canvas v1.2
|
|
* by Weston Ruter <http://weston.ruter.net/projects/css-gradients-via-canvas/>
|
|
*
|
|
* Requires sylvester.js by James Coglan http://sylvester.jcoglan.com/
|
|
*
|
|
* cssSandpaper.js v.1.0 beta 1 available at http://www.useragentman.com/
|
|
*
|
|
* released under the MIT License:
|
|
* http://www.opensource.org/licenses/mit-license.php
|
|
*
|
|
******************************************************************************/
|
|
if (!document.querySelectorAll) {
|
|
document.querySelectorAll = cssQuery;
|
|
}
|
|
|
|
var cssSandpaper = new function(){
|
|
var me = this;
|
|
|
|
var styleNodes, styleSheets = new Array();
|
|
|
|
var ruleSetRe = /[^\{]*{[^\}]*}/g;
|
|
var ruleSplitRe = /[\{\}]/g;
|
|
|
|
var reGradient = /gradient\([\s\S]*\)/g;
|
|
var reHSL = /hsl\([\s\S]*\)/g;
|
|
|
|
// This regexp from the article
|
|
// http://james.padolsey.com/javascript/javascript-comment-removal-revisted/
|
|
var reMultiLineComment = /\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g;
|
|
|
|
var reAtRule = /@[^\{\};]*;|@[^\{\};]*\{[^\}]*\}/g;
|
|
|
|
var reFunctionSpaces = /\(\s*/g
|
|
|
|
|
|
var ruleLists = new Array();
|
|
var styleNode;
|
|
|
|
var tempObj;
|
|
var body;
|
|
|
|
|
|
me.init = function(reinit){
|
|
|
|
if (EventHelpers.hasPageLoadHappened(arguments) && !reinit) {
|
|
return;
|
|
}
|
|
|
|
body = document.body;
|
|
|
|
tempObj = document.createElement('div');
|
|
|
|
getStyleSheets();
|
|
|
|
indexRules();
|
|
|
|
|
|
fixTransforms();
|
|
fixBoxShadow();
|
|
fixLinearGradients();
|
|
|
|
fixBackgrounds();
|
|
fixColors();
|
|
fixOpacity();
|
|
setClasses();
|
|
//fixBorderRadius();
|
|
|
|
}
|
|
|
|
me.setOpacity = function(obj, value){
|
|
var property = CSS3Helpers.findProperty(document.body, 'opacity');
|
|
|
|
if (property == "filter") {
|
|
// IE must have layout, see
|
|
// http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html
|
|
// for details.
|
|
obj.style.zoom = "100%";
|
|
|
|
var filter = CSS3Helpers.addFilter(obj, 'DXImageTransform.Microsoft.Alpha', StringHelpers.sprintf("opacity=%d", ((value) * 100)));
|
|
|
|
filter.opacity = value * 100;
|
|
|
|
|
|
} else if (obj.style[property] != null) {
|
|
obj.style[property] = value;
|
|
}
|
|
}
|
|
|
|
|
|
function fixOpacity(){
|
|
|
|
var transformRules = getRuleList('opacity').values;
|
|
|
|
for (var i in transformRules) {
|
|
var rule = transformRules[i];
|
|
var nodes = document.querySelectorAll(rule.selector);
|
|
|
|
for (var j = 0; j < nodes.length; j++) {
|
|
me.setOpacity(nodes[j], rule.value)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
me.setTransform = function(obj, transformString){
|
|
var property = CSS3Helpers.findProperty(obj, 'transform');
|
|
|
|
if (property == "filter") {
|
|
var matrix = CSS3Helpers.getTransformationMatrix(transformString);
|
|
CSS3Helpers.setMatrixFilter(obj, matrix)
|
|
} else if (obj.style[property] != null) {
|
|
obj.style[property] = transformString;
|
|
}
|
|
}
|
|
|
|
function fixTransforms(){
|
|
|
|
var transformRules = getRuleList('-sand-transform').values;
|
|
var property = CSS3Helpers.findProperty(document.body, 'transform');
|
|
|
|
|
|
for (var i in transformRules) {
|
|
var rule = transformRules[i];
|
|
var nodes = document.querySelectorAll(rule.selector);
|
|
|
|
for (var j = 0; j < nodes.length; j++) {
|
|
me.setTransform(nodes[j], rule.value)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
me.setBoxShadow = function(obj, value){
|
|
var property = CSS3Helpers.findProperty(obj, 'boxShadow');
|
|
|
|
var values = CSS3Helpers.getBoxShadowValues(value);
|
|
|
|
if (property == "filter") {
|
|
var filter = CSS3Helpers.addFilter(obj, 'DXImageTransform.Microsoft.DropShadow', StringHelpers.sprintf("color=%s,offX=%d,offY=%d", values.color, values.offsetX, values.offsetY));
|
|
filter.color = values.color;
|
|
filter.offX = values.offsetX;
|
|
filter.offY = values.offsetY;
|
|
|
|
} else if (obj.style[property] != null) {
|
|
obj.style[property] = value;
|
|
}
|
|
}
|
|
|
|
function fixBoxShadow(){
|
|
|
|
var transformRules = getRuleList('-sand-box-shadow').values;
|
|
|
|
//var matrices = new Array();
|
|
|
|
|
|
for (var i in transformRules) {
|
|
var rule = transformRules[i];
|
|
|
|
var nodes = document.querySelectorAll(rule.selector);
|
|
|
|
|
|
|
|
for (var j = 0; j < nodes.length; j++) {
|
|
me.setBoxShadow(nodes[j], rule.value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function setGradientFilter(node, values){
|
|
|
|
if (values.colorStops.length == 2 &&
|
|
values.colorStops[0].stop == 0.0 &&
|
|
values.colorStops[1].stop == 1.0) {
|
|
var startColor = new RGBColor(values.colorStops[0].color);
|
|
var endColor = new RGBColor(values.colorStops[1].color);
|
|
|
|
startColor = startColor.toHex();
|
|
endColor = endColor.toHex();
|
|
|
|
var filter = CSS3Helpers.addFilter(node, 'DXImageTransform.Microsoft.Gradient', StringHelpers.sprintf("GradientType = %s, StartColorStr = '%s', EndColorStr = '%s'", values.IEdir, startColor, endColor));
|
|
|
|
filter.GradientType = values.IEdir;
|
|
filter.StartColorStr = startColor;
|
|
filter.EndColorStr = endColor;
|
|
node.style.zoom = 1;
|
|
}
|
|
}
|
|
|
|
me.setGradient = function(node, value){
|
|
|
|
var support = CSS3Helpers.reportGradientSupport();
|
|
|
|
var values = CSS3Helpers.getGradient(value);
|
|
|
|
if (values == null) {
|
|
return;
|
|
}
|
|
|
|
if (node.filters) {
|
|
setGradientFilter(node, values);
|
|
} else if (support == implementation.MOZILLA) {
|
|
|
|
node.style.backgroundImage = StringHelpers.sprintf('-moz-gradient( %s, %s, from(%s), to(%s))', values.dirBegin, values.dirEnd, values.colorStops[0].color, values.colorStops[1].color);
|
|
} else if (support == implementation.WEBKIT) {
|
|
var tmp = StringHelpers.sprintf('-webkit-gradient(%s, %s, %s %s, %s %s)', values.type, values.dirBegin, values.r0 ? values.r0 + ", " : "", values.dirEnd, values.r1 ? values.r1 + ", " : "", listColorStops(values.colorStops));
|
|
node.style.backgroundImage = tmp;
|
|
} else if (support == implementation.CANVAS_WORKAROUND) {
|
|
try {
|
|
CSS3Helpers.applyCanvasGradient(node, values);
|
|
}
|
|
catch (ex) {
|
|
// do nothing (for now).
|
|
}
|
|
}
|
|
}
|
|
|
|
me.setRGBABackground = function(node, value){
|
|
|
|
var support = CSS3Helpers.reportColorSpaceSupport('RGBA', colorType.BACKGROUND);
|
|
|
|
switch (support) {
|
|
case implementation.NATIVE:
|
|
node.style.value = value;
|
|
break;
|
|
case implementation.FILTER_WORKAROUND:
|
|
setGradientFilter(node, {
|
|
IEdir: 0,
|
|
colorStops: [{
|
|
stop: 0.0,
|
|
color: value
|
|
}, {
|
|
stop: 1.0,
|
|
color: value
|
|
}]
|
|
});
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
me.setHSLABackground = function(node, value) {
|
|
var support = CSS3Helpers.reportColorSpaceSupport('HSLA', colorType.BACKGROUND);
|
|
|
|
switch (support) {
|
|
case implementation.NATIVE:
|
|
/* node.style.value = value;
|
|
break; */
|
|
case implementation.FILTER_WORKAROUND:
|
|
var rgbColor = new RGBColor(value);
|
|
|
|
if (rgbColor.a == 1) {
|
|
node.style.backgroundColor = rgbColor.toHex();
|
|
} else {
|
|
var rgba = rgbColor.toRGBA();
|
|
setGradientFilter(node, {
|
|
IEdir: 0,
|
|
colorStops: [{
|
|
stop: 0.0,
|
|
color: rgba
|
|
}, {
|
|
stop: 1.0,
|
|
color: rgba
|
|
}]
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert a hyphenated string to camelized text. For example, the string "font-type" will be converted
|
|
* to "fontType".
|
|
*
|
|
* @param {Object} s - the string that needs to be camelized.
|
|
* @return {String} - the camelized text.
|
|
*/
|
|
me.camelize = function (s) {
|
|
var r="";
|
|
|
|
for (var i=0; i<s.length; i++) {
|
|
if (s.substring(i, i+1) == '-') {
|
|
i++;
|
|
r+= s.substring(i, i+1).toUpperCase();
|
|
} else {
|
|
r+= s.substring(i, i+1);
|
|
}
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
me.setHSLColor = function (node, property, value) {
|
|
var support = CSS3Helpers.reportColorSpaceSupport('HSL', colorType.FOREGROUND);
|
|
|
|
switch (support) {
|
|
case implementation.NATIVE:
|
|
/* node.style.value = value;
|
|
break; */
|
|
case implementation.HEX_WORKAROUND:
|
|
|
|
var hslColor = value.match(reHSL)[0];
|
|
var hexColor = new RGBColor(hslColor).toHex()
|
|
var newPropertyValue = value.replace(reHSL, hexColor);
|
|
|
|
|
|
|
|
node.style[me.camelize(property)] = newPropertyValue;
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
function fixLinearGradients(){
|
|
|
|
var backgroundRules = getRuleList('background').values.concat(getRuleList('background-image').values);
|
|
|
|
for (var i in backgroundRules) {
|
|
var rule = backgroundRules[i];
|
|
var nodes = document.querySelectorAll(rule.selector);
|
|
for (var j = 0; j < nodes.length; j++) {
|
|
me.setGradient(nodes[j], rule.value)
|
|
}
|
|
}
|
|
}
|
|
|
|
function fixBackgrounds(){
|
|
|
|
var support = CSS3Helpers.reportColorSpaceSupport('RGBA', colorType.BACKGROUND);
|
|
if (support == implementation.NATIVE) {
|
|
return;
|
|
}
|
|
|
|
|
|
var backgroundRules = getRuleList('background').values.concat(getRuleList('background-color').values);
|
|
|
|
for (var i in backgroundRules) {
|
|
var rule = backgroundRules[i];
|
|
var nodes = document.querySelectorAll(rule.selector);
|
|
for (var j = 0; j < nodes.length; j++) {
|
|
if (rule.value.indexOf('rgba(') == 0) {
|
|
me.setRGBABackground(nodes[j], rule.value);
|
|
} else if (rule.value.indexOf('hsla(') == 0 || rule.value.indexOf('hsl(') == 0) {
|
|
|
|
me.setHSLABackground(nodes[j], rule.value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
me.getProperties = function (obj, objName)
|
|
{
|
|
var result = ""
|
|
|
|
if (!obj) {
|
|
return result;
|
|
}
|
|
|
|
for (var i in obj)
|
|
{
|
|
try {
|
|
result += objName + "." + i.toString() + " = " + obj[i] + ", ";
|
|
} catch (ex) {
|
|
// nothing
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
function fixColors() {
|
|
var support = CSS3Helpers.reportColorSpaceSupport('HSL', colorType.FOREGROUND);
|
|
if (support == implementation.NATIVE) {
|
|
return;
|
|
}
|
|
|
|
var colorRules = getRuleList('color').values;
|
|
|
|
var properties = ['color', 'border',
|
|
'border-left', 'border-right', 'border-bottom', 'border-top',
|
|
'border-left-color', 'border-right-color', 'border-bottom-color', 'border-top-color'];
|
|
|
|
for (var i=0; i<properties.length; i++) {
|
|
var rules = getRuleList(properties[i]).values;
|
|
colorRules = colorRules.concat(rules);
|
|
}
|
|
|
|
for (var i in colorRules) {
|
|
var rule = colorRules[i];
|
|
|
|
var nodes = document.querySelectorAll(rule.selector);
|
|
for (var j = 0; j < nodes.length; j++) {
|
|
var isBorder = (rule.name.indexOf('border') == 0);
|
|
var ruleMatch = rule.value.match(reHSL);
|
|
|
|
|
|
if (ruleMatch) {
|
|
|
|
var cssProperty;
|
|
if (isBorder && rule.name.indexOf('-color') < 0) {
|
|
cssProperty = rule.name;
|
|
} else {
|
|
cssProperty = rule.name;
|
|
}
|
|
|
|
me.setHSLColor(nodes[j], cssProperty, rule.value);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function listColorStops(colorStops){
|
|
var sb = new StringBuffer();
|
|
|
|
for (var i = 0; i < colorStops.length; i++) {
|
|
sb.append(StringHelpers.sprintf("color-stop(%s, %s)", colorStops[i].stop, colorStops[i].color));
|
|
if (i < colorStops.length - 1) {
|
|
sb.append(', ');
|
|
}
|
|
}
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
|
|
function getStyleSheet(node){
|
|
var sheetCssText;
|
|
switch (node.nodeName.toLowerCase()) {
|
|
case 'style':
|
|
sheetCssText = StringHelpers.uncommentHTML(node.innerHTML); //does not work with inline styles because IE doesn't allow you to get the text content of a STYLE element
|
|
break;
|
|
case 'link':
|
|
|
|
var xhr = XMLHelpers.getXMLHttpRequest(node.href, null, "GET", null, false);
|
|
sheetCssText = xhr.responseText;
|
|
|
|
break;
|
|
}
|
|
|
|
sheetCssText = sheetCssText.replace(reMultiLineComment, '').replace(reAtRule, '');
|
|
|
|
return sheetCssText;
|
|
}
|
|
|
|
function getStyleSheets(){
|
|
|
|
styleNodes = document.querySelectorAll('style, link[rel="stylesheet"]');
|
|
|
|
for (var i = 0; i < styleNodes.length; i++) {
|
|
if (!CSSHelpers.isMemberOfClass(styleNodes[i], 'cssSandpaper-noIndex')) {
|
|
styleSheets.push(getStyleSheet(styleNodes[i]))
|
|
}
|
|
}
|
|
}
|
|
|
|
function indexRules(){
|
|
|
|
for (var i = 0; i < styleSheets.length; i++) {
|
|
var sheet = styleSheets[i];
|
|
|
|
rules = sheet.match(ruleSetRe);
|
|
if (rules) {
|
|
for (var j = 0; j < rules.length; j++) {
|
|
var parsedRule = rules[j].split(ruleSplitRe);
|
|
var selector = parsedRule[0].trim();
|
|
var propertiesStr = parsedRule[1];
|
|
var properties = propertiesStr.split(';');
|
|
for (var k = 0; k < properties.length; k++) {
|
|
if (properties[k].trim() != '') {
|
|
var splitProperty = properties[k].split(':')
|
|
var name = splitProperty[0].trim().toLowerCase();
|
|
var value = splitProperty[1];
|
|
if (!ruleLists[name]) {
|
|
ruleLists[name] = new RuleList(name);
|
|
}
|
|
|
|
if (value && typeof(ruleLists[name]) == 'object') {
|
|
ruleLists[name].add(selector, value.trim());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
function getRuleList(name){
|
|
var list = ruleLists[name];
|
|
if (!list) {
|
|
list = new RuleList(name);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
function setClasses(){
|
|
|
|
|
|
var htmlNode = document.getElementsByTagName('html')[0];
|
|
var properties = ['transform', 'opacity'];
|
|
|
|
for (var i = 0; i < properties.length; i++) {
|
|
var prop = properties[i];
|
|
if (CSS3Helpers.supports(prop)) {
|
|
CSSHelpers.addClass(htmlNode, 'cssSandpaper-' + prop);
|
|
}
|
|
}
|
|
|
|
// Now .. remove the initially hidden classes
|
|
var hiddenNodes = CSSHelpers.getElementsByClassName(document, 'cssSandpaper-initiallyHidden');
|
|
|
|
for (var i=0; i<hiddenNodes.length; i++){
|
|
CSSHelpers.removeClass(hiddenNodes[i], 'cssSandpaper-initiallyHidden');
|
|
}
|
|
}
|
|
}
|
|
|
|
function RuleList(propertyName){
|
|
var me = this;
|
|
me.values = new Array();
|
|
me.propertyName = propertyName;
|
|
me.add = function(selector, value){
|
|
me.values.push(new CSSRule(selector, me.propertyName, value));
|
|
}
|
|
}
|
|
|
|
function CSSRule(selector, name, value){
|
|
var me = this;
|
|
me.selector = selector;
|
|
me.name = name;
|
|
me.value = value;
|
|
|
|
me.toString = function(){
|
|
return StringHelpers.sprintf("%s { %s: %s}", me.selector, me.name, me.value);
|
|
}
|
|
}
|
|
|
|
var MatrixGenerator = new function(){
|
|
var me = this;
|
|
var reUnit = /[a-z]+$/;
|
|
me.identity = $M([[1, 0, 0], [0, 1, 0], [0, 0, 1]]);
|
|
|
|
|
|
function degreesToRadians(degrees){
|
|
return (degrees - 360) * Math.PI / 180;
|
|
}
|
|
|
|
function getRadianScalar(angleStr){
|
|
|
|
var num = parseFloat(angleStr);
|
|
var unit = angleStr.match(reUnit);
|
|
|
|
|
|
if (angleStr.trim() == '0') {
|
|
num = 0;
|
|
unit = 'rad';
|
|
}
|
|
|
|
if (unit.length != 1 || num == 0) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
unit = unit[0];
|
|
|
|
|
|
var rad;
|
|
switch (unit) {
|
|
case "deg":
|
|
rad = degreesToRadians(num);
|
|
break;
|
|
case "rad":
|
|
rad = num;
|
|
break;
|
|
default:
|
|
throw "Not an angle: " + angleStr;
|
|
}
|
|
return rad;
|
|
}
|
|
|
|
me.prettyPrint = function(m){
|
|
return StringHelpers.sprintf('| %s %s %s | - | %s %s %s | - |%s %s %s|', m.e(1, 1), m.e(1, 2), m.e(1, 3), m.e(2, 1), m.e(2, 2), m.e(2, 3), m.e(3, 1), m.e(3, 2), m.e(3, 3))
|
|
}
|
|
|
|
me.rotate = function(angleStr){
|
|
var num = getRadianScalar(angleStr);
|
|
return Matrix.RotationZ(num);
|
|
}
|
|
|
|
me.scale = function(sx, sy){
|
|
sx = parseFloat(sx)
|
|
|
|
if (!sy) {
|
|
sy = sx;
|
|
} else {
|
|
sy = parseFloat(sy)
|
|
}
|
|
|
|
|
|
return $M([[sx, 0, 0], [0, sy, 0], [0, 0, 1]]);
|
|
}
|
|
|
|
me.scaleX = function(sx){
|
|
return me.scale(sx, 1);
|
|
}
|
|
|
|
me.scaleY = function(sy){
|
|
return me.scale(1, sy);
|
|
}
|
|
|
|
me.skew = function(ax, ay){
|
|
var xRad = getRadianScalar(ax);
|
|
var yRad;
|
|
|
|
if (ay != null) {
|
|
yRad = getRadianScalar(ay)
|
|
} else {
|
|
yRad = xRad
|
|
}
|
|
|
|
if (xRad != null && yRad != null) {
|
|
|
|
return $M([[1, Math.tan(xRad), 0], [Math.tan(yRad), 1, 0], [0, 0, 1]]);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
me.skewX = function(ax){
|
|
|
|
return me.skew(ax, "0");
|
|
}
|
|
|
|
me.skewY = function(ay){
|
|
return me.skew("0", ay);
|
|
}
|
|
|
|
me.translate = function(tx, ty){
|
|
|
|
var TX = parseInt(tx);
|
|
var TY = parseInt(ty)
|
|
|
|
//jslog.debug(StringHelpers.sprintf('translate %f %f', TX, TY));
|
|
|
|
return $M([[1, 0, TX], [0, 1, TY], [0, 0, 1]]);
|
|
}
|
|
|
|
me.translateX = function(tx){
|
|
return me.translate(tx, 0);
|
|
}
|
|
|
|
me.translateY = function(ty){
|
|
return me.translate(0, ty);
|
|
}
|
|
|
|
|
|
me.matrix = function(a, b, c, d, e, f){
|
|
|
|
// for now, e and f are ignored
|
|
return $M([[a, c, parseInt(e)], [b, d, parseInt(f)], [0, 0, 1]])
|
|
}
|
|
}
|
|
|
|
var CSS3Helpers = new function(){
|
|
var me = this;
|
|
|
|
|
|
var reTransformListSplitter = /[a-zA-Z]+\([^\)]*\)\s*/g;
|
|
|
|
var reLeftBracket = /\(/g;
|
|
var reRightBracket = /\)/g;
|
|
var reComma = /,/g;
|
|
|
|
var reSpaces = /\s+/g
|
|
|
|
var reFilterNameSplitter = /progid:([^\(]*)/g;
|
|
|
|
var reLinearGradient
|
|
|
|
var canvas;
|
|
|
|
var cache = new Array();
|
|
|
|
|
|
me.supports = function(cssProperty){
|
|
if (CSS3Helpers.findProperty(document.body, cssProperty) != null) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
me.getCanvas = function(){
|
|
|
|
if (canvas) {
|
|
return canvas;
|
|
} else {
|
|
canvas = document.createElement('canvas');
|
|
return canvas;
|
|
}
|
|
}
|
|
|
|
me.getTransformationMatrix = function(CSS3TransformProperty, doThrowIfError){
|
|
|
|
var transforms = CSS3TransformProperty.match(reTransformListSplitter);
|
|
|
|
/*
|
|
* Do a check here to see if there is anything in the transformation
|
|
* besides legit transforms
|
|
*/
|
|
if (doThrowIfError) {
|
|
var checkString = transforms.join(" ").replace(/\s*/g, ' ');
|
|
var normalizedCSSProp = CSS3TransformProperty.replace(/\s*/g, ' ');
|
|
|
|
if (checkString != normalizedCSSProp) {
|
|
throw ("An invalid transform was given.")
|
|
}
|
|
}
|
|
|
|
|
|
var resultantMatrix = MatrixGenerator.identity;
|
|
|
|
for (var j = 0; j < transforms.length; j++) {
|
|
|
|
var transform = transforms[j];
|
|
|
|
transform = transform.replace(reLeftBracket, '("').replace(reComma, '", "').replace(reRightBracket, '")');
|
|
|
|
|
|
try {
|
|
var matrix = eval('MatrixGenerator.' + transform);
|
|
|
|
|
|
//jslog.debug( transform + ': ' + MatrixGenerator.prettyPrint(matrix))
|
|
resultantMatrix = resultantMatrix.x(matrix);
|
|
}
|
|
catch (ex) {
|
|
|
|
if (doThrowIfError) {
|
|
var method = transform.split('(')[0];
|
|
|
|
var funcCall = transform.replace(/\"/g, '');
|
|
|
|
if (MatrixGenerator[method] == undefined) {
|
|
throw "Error: invalid tranform function: " + funcCall;
|
|
} else {
|
|
throw "Error: Invalid or missing parameters in function call: " + funcCall;
|
|
|
|
}
|
|
}
|
|
// do nothing;
|
|
}
|
|
}
|
|
|
|
return resultantMatrix;
|
|
|
|
}
|
|
|
|
me.getBoxShadowValues = function(propertyValue){
|
|
var r = new Object();
|
|
|
|
var values = propertyValue.split(reSpaces);
|
|
|
|
if (values[0] == 'inset') {
|
|
r.inset = true;
|
|
values = values.reverse().pop().reverse();
|
|
} else {
|
|
r.inset = false;
|
|
}
|
|
|
|
r.offsetX = parseInt(values[0]);
|
|
r.offsetY = parseInt(values[1]);
|
|
|
|
if (values.length > 3) {
|
|
r.blurRadius = values[2];
|
|
|
|
if (values.length > 4) {
|
|
r.spreadRadius = values[3]
|
|
}
|
|
}
|
|
|
|
r.color = values[values.length - 1];
|
|
|
|
return r;
|
|
}
|
|
|
|
me.getGradient = function(propertyValue){
|
|
var r = new Object();
|
|
r.colorStops = new Array();
|
|
|
|
|
|
var substring = me.getBracketedSubstring(propertyValue, '-sand-gradient');
|
|
if (substring == undefined) {
|
|
return null;
|
|
}
|
|
var parameters = substring.match(/[^\(,]+(\([^\)]*\))?[^,]*/g); //substring.split(reComma);
|
|
r.type = parameters[0].trim();
|
|
|
|
if (r.type == 'linear') {
|
|
r.dirBegin = parameters[1].trim();
|
|
r.dirEnd = parameters[2].trim();
|
|
var beginCoord = r.dirBegin.split(reSpaces);
|
|
var endCoord = r.dirEnd.split(reSpaces);
|
|
|
|
for (var i = 3; i < parameters.length; i++) {
|
|
r.colorStops.push(parseColorStop(parameters[i].trim(), i - 3));
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The following logic only applies to IE */
|
|
if (document.body.filters) {
|
|
if (r.x0 == r.x1) {
|
|
/* IE only supports "center top", "center bottom", "top left" and "top right" */
|
|
|
|
switch (beginCoord[1]) {
|
|
case 'top':
|
|
r.IEdir = 0;
|
|
break;
|
|
case 'bottom':
|
|
swapIndices(r.colorStops, 0, 1);
|
|
r.IEdir = 0;
|
|
/* r.from = parameters[4].trim();
|
|
r.to = parameters[3].trim(); */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (r.y0 == r.y1) {
|
|
switch (beginCoord[0]) {
|
|
case 'left':
|
|
r.IEdir = 1;
|
|
break;
|
|
case 'right':
|
|
r.IEdir = 1;
|
|
swapIndices(r.colorStops, 0, 1);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// don't even bother with IE
|
|
if (document.body.filters) {
|
|
return null;
|
|
}
|
|
|
|
|
|
r.dirBegin = parameters[1].trim();
|
|
r.r0 = parameters[2].trim();
|
|
|
|
r.dirEnd = parameters[3].trim();
|
|
r.r1 = parameters[4].trim();
|
|
|
|
var beginCoord = r.dirBegin.split(reSpaces);
|
|
var endCoord = r.dirEnd.split(reSpaces);
|
|
|
|
for (var i = 5; i < parameters.length; i++) {
|
|
r.colorStops.push(parseColorStop(parameters[i].trim(), i - 5));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
r.x0 = beginCoord[0];
|
|
r.y0 = beginCoord[1];
|
|
|
|
r.x1 = endCoord[0];
|
|
r.y1 = endCoord[1];
|
|
|
|
return r;
|
|
}
|
|
|
|
function swapIndices(array, index1, index2){
|
|
var tmp = array[index1];
|
|
array[index1] = array[index2];
|
|
array[index2] = tmp;
|
|
}
|
|
|
|
function parseColorStop(colorStop, index){
|
|
var r = new Object();
|
|
var substring = me.getBracketedSubstring(colorStop, 'color-stop');
|
|
var from = me.getBracketedSubstring(colorStop, 'from');
|
|
var to = me.getBracketedSubstring(colorStop, 'to');
|
|
|
|
|
|
if (substring) {
|
|
//color-stop
|
|
var parameters = substring.split(',')
|
|
r.stop = normalizePercentage(parameters[0].trim());
|
|
r.color = parameters[1].trim();
|
|
} else if (from) {
|
|
r.stop = 0.0;
|
|
r.color = from.trim();
|
|
} else if (to) {
|
|
r.stop = 1.0;
|
|
r.color = to.trim();
|
|
} else {
|
|
if (index <= 1) {
|
|
r.color = colorStop;
|
|
if (index == 0) {
|
|
r.stop = 0.0;
|
|
} else {
|
|
r.stop = 1.0;
|
|
}
|
|
} else {
|
|
throw (StringHelpers.sprintf('invalid argument "%s"', colorStop));
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
function normalizePercentage(s){
|
|
if (s.substring(s.length - 1, s.length) == '%') {
|
|
return parseFloat(s) / 100 + "";
|
|
} else {
|
|
return s;
|
|
}
|
|
|
|
}
|
|
|
|
me.reportGradientSupport = function(){
|
|
|
|
if (!cache["gradientSupport"]) {
|
|
var r;
|
|
var div = document.createElement('div');
|
|
div.style.cssText = "background-image:-webkit-gradient(linear, 0% 0%, 0% 100%, from(red), to(blue));";
|
|
|
|
if (div.style.backgroundImage) {
|
|
r = implementation.WEBKIT;
|
|
|
|
} else {
|
|
|
|
/* div.style.cssText = "background-image:-moz-linear-gradient(top, blue, white 80%, orange);";
|
|
|
|
if (div.style.backgroundImage) {
|
|
|
|
r = implementation.MOZILLA;
|
|
|
|
} else { */
|
|
var canvas = CSS3Helpers.getCanvas();
|
|
if (canvas.getContext && canvas.toDataURL) {
|
|
r = implementation.CANVAS_WORKAROUND;
|
|
|
|
} else {
|
|
r = implementation.NONE;
|
|
}
|
|
/* } */
|
|
}
|
|
|
|
cache["gradientSupport"] = r;
|
|
}
|
|
return cache["gradientSupport"];
|
|
}
|
|
|
|
me.reportColorSpaceSupport = function(colorSpace, type){
|
|
|
|
if (!cache[colorSpace + type]) {
|
|
var r;
|
|
var div = document.createElement('div');
|
|
|
|
switch (type) {
|
|
|
|
case colorType.BACKGROUND:
|
|
|
|
switch(colorSpace) {
|
|
case 'RGBA':
|
|
div.style.cssText = "background-color: rgba(255, 32, 34, 0.5)";
|
|
break;
|
|
case 'HSL':
|
|
div.style.cssText = "background-color: hsl(0,0%,100%)";
|
|
break;
|
|
case 'HSLA':
|
|
div.style.cssText = "background-color: hsla(0,0%,100%,.5)";
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
var body = document.body;
|
|
|
|
|
|
if (div.style.backgroundColor) {
|
|
r = implementation.NATIVE;
|
|
|
|
} else if (body.filters && body.filters != undefined) {
|
|
r = implementation.FILTER_WORKAROUND;
|
|
} else {
|
|
r = implementation.NONE;
|
|
}
|
|
break;
|
|
case colorType.FOREGROUND:
|
|
switch(colorSpace) {
|
|
case 'RGBA':
|
|
div.style.cssText = "color: rgba(255, 32, 34, 0.5)";
|
|
break;
|
|
case 'HSL':
|
|
div.style.cssText = "color: hsl(0,0%,100%)";
|
|
break;
|
|
case 'HSLA':
|
|
div.style.cssText = "color: hsla(0,0%,100%,.5)";
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (div.style.color) {
|
|
r = implementation.NATIVE;
|
|
} else if (colorSpace == 'HSL') {
|
|
|
|
r = implementation.HEX_WORKAROUND;
|
|
} else {
|
|
r = implementation.NONE;
|
|
}
|
|
break
|
|
}
|
|
|
|
|
|
cache[colorSpace] = r;
|
|
}
|
|
return cache[colorSpace];
|
|
}
|
|
|
|
|
|
|
|
me.getBracketedSubstring = function(s, header){
|
|
var gradientIndex = s.indexOf(header + '(')
|
|
|
|
if (gradientIndex != -1) {
|
|
var substring = s.substring(gradientIndex);
|
|
|
|
var openBrackets = 1;
|
|
for (var i = header.length + 1; i < 100 || i < substring.length; i++) {
|
|
var c = substring.substring(i, i + 1);
|
|
switch (c) {
|
|
case "(":
|
|
openBrackets++;
|
|
break;
|
|
case ")":
|
|
openBrackets--;
|
|
break;
|
|
}
|
|
|
|
if (openBrackets == 0) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return substring.substring(gradientIndex + header.length + 1, i);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
me.setMatrixFilter = function(obj, matrix){
|
|
|
|
|
|
if (!hasIETransformWorkaround(obj)) {
|
|
addIETransformWorkaround(obj)
|
|
}
|
|
|
|
var container = obj.parentNode;
|
|
//container.xTransform = degrees;
|
|
|
|
|
|
filter = obj.filters.item('DXImageTransform.Microsoft.Matrix');
|
|
//jslog.debug(MatrixGenerator.prettyPrint(matrix))
|
|
filter.M11 = matrix.e(1, 1);
|
|
filter.M12 = matrix.e(1, 2);
|
|
filter.M21 = matrix.e(2, 1);
|
|
filter.M22 = matrix.e(2, 2);
|
|
|
|
|
|
// Now, adjust the margins of the parent object
|
|
var offsets = me.getIEMatrixOffsets(obj, matrix, container.xOriginalWidth, container.xOriginalHeight);
|
|
container.style.marginLeft = offsets.x;
|
|
container.style.marginTop = offsets.y;
|
|
container.style.marginRight = 0;
|
|
container.style.marginBottom = 0;
|
|
}
|
|
|
|
me.getTransformedDimensions = function (obj, matrix) {
|
|
var r = {};
|
|
|
|
if (hasIETransformWorkaround(obj)) {
|
|
r.width = obj.offsetWidth;
|
|
r.height = obj.offsetHeight;
|
|
} else {
|
|
var pts = [
|
|
matrix.x($V([0, 0, 1])) ,
|
|
matrix.x($V([0, obj.offsetHeight, 1])),
|
|
matrix.x($V([obj.offsetWidth, 0, 1])),
|
|
matrix.x($V([obj.offsetWidth, obj.offsetHeight, 1]))
|
|
];
|
|
var maxX = 0, maxY =0, minX=0, minY=0;
|
|
|
|
for (var i = 0; i < pts.length; i++) {
|
|
var pt = pts[i];
|
|
var x = pt.e(1), y = pt.e(2);
|
|
var minX = Math.min(minX, x);
|
|
var maxX = Math.max(maxX, x);
|
|
var minY = Math.min(minY, y);
|
|
var maxY = Math.max(maxY, y);
|
|
}
|
|
|
|
|
|
r.width = maxX - minX;
|
|
r.height = maxY - minY;
|
|
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
me.getIEMatrixOffsets = function (obj, matrix, width, height) {
|
|
var r = {};
|
|
|
|
var originalWidth = parseFloat(width);
|
|
var originalHeight = parseFloat(height);
|
|
|
|
|
|
var offset;
|
|
if (CSSHelpers.getComputedStyle(obj, 'display') == 'inline') {
|
|
offset = 0;
|
|
} else {
|
|
offset = 13; // This works ... don't know why.
|
|
}
|
|
var transformedDimensions = me.getTransformedDimensions(obj, matrix);
|
|
|
|
r.x = (((originalWidth - transformedDimensions.width) / 2) - offset + matrix.e(1, 3)) + 'px';
|
|
r.y = (((originalHeight - transformedDimensions.height) / 2) - offset + matrix.e(2, 3)) + 'px';
|
|
|
|
return r;
|
|
}
|
|
|
|
function hasIETransformWorkaround(obj){
|
|
|
|
return CSSHelpers.isMemberOfClass(obj.parentNode, 'IETransformContainer');
|
|
}
|
|
|
|
function addIETransformWorkaround(obj){
|
|
if (!hasIETransformWorkaround(obj)) {
|
|
var parentNode = obj.parentNode;
|
|
var filter;
|
|
|
|
// This is the container to offset the strange rotation behavior
|
|
var container = document.createElement('div');
|
|
CSSHelpers.addClass(container, 'IETransformContainer');
|
|
|
|
|
|
container.style.width = obj.offsetWidth + 'px';
|
|
container.style.height = obj.offsetHeight + 'px';
|
|
|
|
container.xOriginalWidth = obj.offsetWidth;
|
|
container.xOriginalHeight = obj.offsetHeight;
|
|
container.style.position = 'absolute'
|
|
container.style.zIndex = obj.currentStyle.zIndex;
|
|
|
|
|
|
var horizPaddingFactor = 0; //parseInt(obj.currentStyle.paddingLeft);
|
|
var vertPaddingFactor = 0; //parseInt(obj.currentStyle.paddingTop);
|
|
if (obj.currentStyle.display == 'block') {
|
|
container.style.left = obj.offsetLeft + 13 - horizPaddingFactor + "px";
|
|
container.style.top = obj.offsetTop + 13 + -vertPaddingFactor + 'px';
|
|
} else {
|
|
container.style.left = obj.offsetLeft + "px";
|
|
container.style.top = obj.offsetTop + 'px';
|
|
|
|
}
|
|
//container.style.float = obj.currentStyle.float;
|
|
|
|
|
|
obj.style.top = "auto";
|
|
obj.style.left = "auto"
|
|
obj.style.bottom = "auto";
|
|
obj.style.right = "auto";
|
|
// This is what we need in order to insert to keep the document
|
|
// flow ok
|
|
var replacement = obj.cloneNode(true);
|
|
replacement.style.visibility = 'hidden';
|
|
|
|
obj.replaceNode(replacement);
|
|
|
|
// now, wrap container around the original node ...
|
|
|
|
obj.style.position = 'absolute';
|
|
container.appendChild(obj);
|
|
parentNode.insertBefore(container, replacement);
|
|
container.style.backgroundColor = 'transparent';
|
|
|
|
container.style.padding = '0';
|
|
|
|
filter = me.addFilter(obj, 'DXImageTransform.Microsoft.Matrix', "M11=1, M12=0, M21=0, M22=1, sizingMethod='auto expand'")
|
|
var bgImage = obj.currentStyle.backgroundImage.split("\"")[1];
|
|
/*
|
|
|
|
|
|
|
|
if (bgImage) {
|
|
|
|
|
|
|
|
var alphaFilter = me.addFilter(obj, "DXImageTransform.Microsoft.AlphaImageLoader", "src='" + bgImage + "', sizingMethod='scale'");
|
|
|
|
|
|
|
|
alert(bgImage)
|
|
|
|
|
|
|
|
alphaFilter.src = bgImage;
|
|
|
|
|
|
|
|
sizingMethod = 'scale';
|
|
|
|
|
|
|
|
obj.style.background = 'none';
|
|
|
|
|
|
|
|
obj.style.backgroundImage = 'none';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
me.addFilter = function(obj, filterName, filterValue){
|
|
// now ... insert the filter so we can exploit its wonders
|
|
|
|
var filter;
|
|
try {
|
|
filter = obj.filters.item(filterName);
|
|
}
|
|
catch (ex) {
|
|
// dang! We have to go through all of them and make sure filter
|
|
// is set right before we add the new one.
|
|
|
|
|
|
var filterList = new MSFilterList(obj)
|
|
|
|
filterList.fixFilterStyle();
|
|
|
|
var comma = ", ";
|
|
|
|
if (obj.filters.length == 0) {
|
|
comma = "";
|
|
}
|
|
|
|
obj.style.filter += StringHelpers.sprintf("%sprogid:%s(%s)", comma, filterName, filterValue);
|
|
|
|
filter = obj.filters.item(filterName);
|
|
|
|
}
|
|
|
|
return filter;
|
|
}
|
|
|
|
|
|
function degreesToRadians(degrees){
|
|
return (degrees - 360) * Math.PI / 180;
|
|
}
|
|
|
|
me.findProperty = function(obj, type){
|
|
capType = type.capitalize();
|
|
|
|
var r = cache[type]
|
|
if (!r) {
|
|
|
|
|
|
var style = obj.style;
|
|
|
|
|
|
var properties = [type, 'Moz' + capType, 'Webkit' + capType, 'O' + capType, 'filter'];
|
|
for (var i = 0; i < properties.length; i++) {
|
|
if (style[properties[i]] != null) {
|
|
r = properties[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (r == 'filter' && document.body.filters == undefined) {
|
|
r = null;
|
|
}
|
|
cache[type] = r;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* "A point is a pair of space-separated values. The syntax supports numbers,
|
|
* percentages or the keywords top, bottom, left and right for point values."
|
|
* This keywords and percentages into pixel equivalents
|
|
*/
|
|
me.parseCoordinate = function(value, max){
|
|
//Convert keywords
|
|
switch (value) {
|
|
case 'top':
|
|
case 'left':
|
|
return 0;
|
|
case 'bottom':
|
|
case 'right':
|
|
return max;
|
|
case 'center':
|
|
return max / 2;
|
|
}
|
|
|
|
//Convert percentage
|
|
if (value.indexOf('%') != -1)
|
|
value = parseFloat(value.substr(0, value.length - 1)) / 100 * max;
|
|
//Convert bare number (a pixel value)
|
|
else
|
|
value = parseFloat(value);
|
|
if (isNaN(value))
|
|
throw Error("Unable to parse coordinate: " + value);
|
|
return value;
|
|
}
|
|
|
|
me.applyCanvasGradient = function(el, gradient){
|
|
|
|
var canvas = me.getCanvas();
|
|
var computedStyle = document.defaultView.getComputedStyle(el, null);
|
|
|
|
canvas.width = parseInt(computedStyle.width) + parseInt(computedStyle.paddingLeft) + parseInt(computedStyle.paddingRight) + 1; // inserted by Zoltan
|
|
canvas.height = parseInt(computedStyle.height) + parseInt(computedStyle.paddingTop) + parseInt(computedStyle.paddingBottom) + 2; // 1 inserted by Zoltan
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
//Iterate over the gradients and build them up
|
|
|
|
var canvasGradient;
|
|
// Linear gradient
|
|
if (gradient.type == 'linear') {
|
|
|
|
|
|
canvasGradient = ctx.createLinearGradient(me.parseCoordinate(gradient.x0, canvas.width), me.parseCoordinate(gradient.y0, canvas.height), me.parseCoordinate(gradient.x1, canvas.width), me.parseCoordinate(gradient.y1, canvas.height));
|
|
} // Radial gradient
|
|
else /*if(gradient.type == 'radial')*/ {
|
|
canvasGradient = ctx.createRadialGradient(me.parseCoordinate(gradient.x0, canvas.width), me.parseCoordinate(gradient.y0, canvas.height), gradient.r0, me.parseCoordinate(gradient.x1, canvas.width), me.parseCoordinate(gradient.y1, canvas.height), gradient.r1);
|
|
}
|
|
|
|
//Add each of the color stops to the gradient
|
|
for (var i = 0; i < gradient.colorStops.length; i++) {
|
|
var cs = gradient.colorStops[i];
|
|
|
|
canvasGradient.addColorStop(cs.stop, cs.color);
|
|
};
|
|
|
|
//Paint the gradient
|
|
ctx.fillStyle = canvasGradient;
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
|
|
//Apply the gradient to the selectedElement
|
|
el.style.backgroundImage = "url('" + canvas.toDataURL() + "')";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function MSFilterList(node){
|
|
var me = this;
|
|
|
|
me.list = new Array();
|
|
me.node = node;
|
|
|
|
var reFilterListSplitter = /[\s\S]*\([\s\S]*\)/g;
|
|
|
|
var styleAttr = node.style;
|
|
|
|
function init(){
|
|
|
|
var filterCalls = styleAttr.filter.match(reFilterListSplitter);
|
|
|
|
if (filterCalls != null) {
|
|
|
|
for (var i = 0; i < filterCalls.length; i++) {
|
|
var call = filterCalls[i];
|
|
|
|
me.list.push(new MSFilter(node, call));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
me.toString = function(){
|
|
var sb = new StringBuffer();
|
|
|
|
for (var i = 0; i < me.list.length; i++) {
|
|
|
|
sb.append(me.list[i].toString());
|
|
if (i < me.list.length - 1) {
|
|
sb.append(',')
|
|
}
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
|
|
me.fixFilterStyle = function(){
|
|
|
|
try {
|
|
me.node.style.filter = me.toString();
|
|
}
|
|
catch (ex) {
|
|
// do nothing.
|
|
}
|
|
|
|
}
|
|
|
|
init();
|
|
}
|
|
|
|
function MSFilter(node, filterCall){
|
|
var me = this;
|
|
|
|
me.node = node;
|
|
me.filterCall = filterCall;
|
|
|
|
var reFilterNameSplitter = /progid:([^\(]*)/g;
|
|
var reParameterName = /([a-zA-Z0-9]+\s*)=/g;
|
|
|
|
|
|
function init(){
|
|
me.name = me.filterCall.match(reFilterNameSplitter)[0].replace('progid:', '');
|
|
|
|
//This may not be the best way to do this.
|
|
var parameterString = filterCall.split('(')[1].replace(')', '');
|
|
me.parameters = parameterString.match(reParameterName);
|
|
|
|
for (var i = 0; i < me.parameters.length; i++) {
|
|
me.parameters[i] = me.parameters[i].replace('=', '');
|
|
}
|
|
|
|
}
|
|
|
|
me.toString = function(){
|
|
|
|
var sb = new StringBuffer();
|
|
|
|
sb.append(StringHelpers.sprintf('progid:%s(', me.name));
|
|
|
|
for (var i = 0; i < me.parameters.length; i++) {
|
|
var param = me.parameters[i];
|
|
var filterObj = me.node.filters.item(me.name);
|
|
var paramValue = filterObj[param];
|
|
if (typeof(paramValue) == 'string') {
|
|
sb.append(StringHelpers.sprintf('%s="%s"', param, filterObj[param]));
|
|
} else {
|
|
sb.append(StringHelpers.sprintf('%s=%s', param, filterObj[param]));
|
|
}
|
|
|
|
if (i != me.parameters.length - 1) {
|
|
sb.append(', ')
|
|
}
|
|
}
|
|
sb.append(')');
|
|
|
|
return sb.toString();
|
|
}
|
|
|
|
|
|
|
|
init();
|
|
}
|
|
|
|
var implementation = new function(){
|
|
this.NONE = 0;
|
|
|
|
// Native Support.
|
|
this.NATIVE = 1;
|
|
|
|
// Vendor specific prefix implementations
|
|
this.MOZILLA = 2;
|
|
this.WEBKIT = 3;
|
|
this.IE = 4;
|
|
this.OPERA = 5;
|
|
|
|
// Non CSS3 Workarounds
|
|
this.CANVAS_WORKAROUND = 6;
|
|
this.FILTER_WORKAROUND = 7;
|
|
this.HEX_WORKAROUND = 8;
|
|
}
|
|
|
|
var colorType = new function () {
|
|
this.BACKGROUND = 0;
|
|
this.FOREGROUND = 1;
|
|
}
|
|
|
|
/*
|
|
* Extra helper routines
|
|
*/
|
|
if (!window.StringHelpers) {
|
|
StringHelpers = new function(){
|
|
var me = this;
|
|
|
|
// used by the String.prototype.trim()
|
|
me.initWhitespaceRe = /^\s\s*/;
|
|
me.endWhitespaceRe = /\s\s*$/;
|
|
me.whitespaceRe = /\s/;
|
|
|
|
/*******************************************************************************
|
|
* Function sprintf(format_string,arguments...) Javascript emulation of the C
|
|
* printf function (modifiers and argument types "p" and "n" are not supported
|
|
* due to language restrictions)
|
|
*
|
|
* Copyright 2003 K&L Productions. All rights reserved
|
|
* http://www.klproductions.com
|
|
*
|
|
* Terms of use: This function can be used free of charge IF this header is not
|
|
* modified and remains with the function code.
|
|
*
|
|
* Legal: Use this code at your own risk. K&L Productions assumes NO
|
|
* resposibility for anything.
|
|
******************************************************************************/
|
|
me.sprintf = function(fstring){
|
|
var pad = function(str, ch, len){
|
|
var ps = '';
|
|
for (var i = 0; i < Math.abs(len); i++)
|
|
ps += ch;
|
|
return len > 0 ? str + ps : ps + str;
|
|
}
|
|
var processFlags = function(flags, width, rs, arg){
|
|
var pn = function(flags, arg, rs){
|
|
if (arg >= 0) {
|
|
if (flags.indexOf(' ') >= 0)
|
|
rs = ' ' + rs;
|
|
else if (flags.indexOf('+') >= 0)
|
|
rs = '+' + rs;
|
|
} else
|
|
rs = '-' + rs;
|
|
return rs;
|
|
}
|
|
var iWidth = parseInt(width, 10);
|
|
if (width.charAt(0) == '0') {
|
|
var ec = 0;
|
|
if (flags.indexOf(' ') >= 0 || flags.indexOf('+') >= 0)
|
|
ec++;
|
|
if (rs.length < (iWidth - ec))
|
|
rs = pad(rs, '0', rs.length - (iWidth - ec));
|
|
return pn(flags, arg, rs);
|
|
}
|
|
rs = pn(flags, arg, rs);
|
|
if (rs.length < iWidth) {
|
|
if (flags.indexOf('-') < 0)
|
|
rs = pad(rs, ' ', rs.length - iWidth);
|
|
else
|
|
rs = pad(rs, ' ', iWidth - rs.length);
|
|
}
|
|
return rs;
|
|
}
|
|
var converters = new Array();
|
|
converters['c'] = function(flags, width, precision, arg){
|
|
if (typeof(arg) == 'number')
|
|
return String.fromCharCode(arg);
|
|
if (typeof(arg) == 'string')
|
|
return arg.charAt(0);
|
|
return '';
|
|
}
|
|
converters['d'] = function(flags, width, precision, arg){
|
|
return converters['i'](flags, width, precision, arg);
|
|
}
|
|
converters['u'] = function(flags, width, precision, arg){
|
|
return converters['i'](flags, width, precision, Math.abs(arg));
|
|
}
|
|
converters['i'] = function(flags, width, precision, arg){
|
|
var iPrecision = parseInt(precision);
|
|
var rs = ((Math.abs(arg)).toString().split('.'))[0];
|
|
if (rs.length < iPrecision)
|
|
rs = pad(rs, ' ', iPrecision - rs.length);
|
|
return processFlags(flags, width, rs, arg);
|
|
}
|
|
converters['E'] = function(flags, width, precision, arg){
|
|
return (converters['e'](flags, width, precision, arg)).toUpperCase();
|
|
}
|
|
converters['e'] = function(flags, width, precision, arg){
|
|
iPrecision = parseInt(precision);
|
|
if (isNaN(iPrecision))
|
|
iPrecision = 6;
|
|
rs = (Math.abs(arg)).toExponential(iPrecision);
|
|
if (rs.indexOf('.') < 0 && flags.indexOf('#') >= 0)
|
|
rs = rs.replace(/^(.*)(e.*)$/, '$1.$2');
|
|
return processFlags(flags, width, rs, arg);
|
|
}
|
|
converters['f'] = function(flags, width, precision, arg){
|
|
iPrecision = parseInt(precision);
|
|
if (isNaN(iPrecision))
|
|
iPrecision = 6;
|
|
rs = (Math.abs(arg)).toFixed(iPrecision);
|
|
if (rs.indexOf('.') < 0 && flags.indexOf('#') >= 0)
|
|
rs = rs + '.';
|
|
return processFlags(flags, width, rs, arg);
|
|
}
|
|
converters['G'] = function(flags, width, precision, arg){
|
|
return (converters['g'](flags, width, precision, arg)).toUpperCase();
|
|
}
|
|
converters['g'] = function(flags, width, precision, arg){
|
|
iPrecision = parseInt(precision);
|
|
absArg = Math.abs(arg);
|
|
rse = absArg.toExponential();
|
|
rsf = absArg.toFixed(6);
|
|
if (!isNaN(iPrecision)) {
|
|
rsep = absArg.toExponential(iPrecision);
|
|
rse = rsep.length < rse.length ? rsep : rse;
|
|
rsfp = absArg.toFixed(iPrecision);
|
|
rsf = rsfp.length < rsf.length ? rsfp : rsf;
|
|
}
|
|
if (rse.indexOf('.') < 0 && flags.indexOf('#') >= 0)
|
|
rse = rse.replace(/^(.*)(e.*)$/, '$1.$2');
|
|
if (rsf.indexOf('.') < 0 && flags.indexOf('#') >= 0)
|
|
rsf = rsf + '.';
|
|
rs = rse.length < rsf.length ? rse : rsf;
|
|
return processFlags(flags, width, rs, arg);
|
|
}
|
|
converters['o'] = function(flags, width, precision, arg){
|
|
var iPrecision = parseInt(precision);
|
|
var rs = Math.round(Math.abs(arg)).toString(8);
|
|
if (rs.length < iPrecision)
|
|
rs = pad(rs, ' ', iPrecision - rs.length);
|
|
if (flags.indexOf('#') >= 0)
|
|
rs = '0' + rs;
|
|
return processFlags(flags, width, rs, arg);
|
|
}
|
|
converters['X'] = function(flags, width, precision, arg){
|
|
return (converters['x'](flags, width, precision, arg)).toUpperCase();
|
|
}
|
|
converters['x'] = function(flags, width, precision, arg){
|
|
var iPrecision = parseInt(precision);
|
|
arg = Math.abs(arg);
|
|
var rs = Math.round(arg).toString(16);
|
|
if (rs.length < iPrecision)
|
|
rs = pad(rs, ' ', iPrecision - rs.length);
|
|
if (flags.indexOf('#') >= 0)
|
|
rs = '0x' + rs;
|
|
return processFlags(flags, width, rs, arg);
|
|
}
|
|
converters['s'] = function(flags, width, precision, arg){
|
|
var iPrecision = parseInt(precision);
|
|
var rs = arg;
|
|
if (rs.length > iPrecision)
|
|
rs = rs.substring(0, iPrecision);
|
|
return processFlags(flags, width, rs, 0);
|
|
}
|
|
farr = fstring.split('%');
|
|
retstr = farr[0];
|
|
fpRE = /^([-+ #]*)(\d*)\.?(\d*)([cdieEfFgGosuxX])(.*)$/;
|
|
for (var i = 1; i < farr.length; i++) {
|
|
fps = fpRE.exec(farr[i]);
|
|
if (!fps)
|
|
continue;
|
|
if (arguments[i] != null)
|
|
retstr += converters[fps[4]](fps[1], fps[2], fps[3], arguments[i]);
|
|
retstr += fps[5];
|
|
}
|
|
return retstr;
|
|
}
|
|
|
|
/**
|
|
* Take out the first comment inside a block of HTML
|
|
*
|
|
* @param {String} s - an HTML block
|
|
* @return {String} s - the HTML block uncommented.
|
|
*/
|
|
me.uncommentHTML = function(s){
|
|
if (s.indexOf('-->') != -1 && s.indexOf('<!--') != -1) {
|
|
return s.replace("<!--", "").replace("-->", "");
|
|
} else {
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!window.XMLHelpers) {
|
|
|
|
XMLHelpers = new function(){
|
|
|
|
var me = this;
|
|
|
|
/**
|
|
* Wrapper for XMLHttpRequest Object. Grabbing data (XML and/or text) from a URL.
|
|
* Grabbing data from a URL. Input is one parameter, url. It returns a request
|
|
* object. Based on code from
|
|
* http://www.xml.com/pub/a/2005/02/09/xml-http-request.html. IE caching problem
|
|
* fix from Wikipedia article http://en.wikipedia.org/wiki/XMLHttpRequest
|
|
*
|
|
* @param {String} url - the URL to retrieve
|
|
* @param {Function} processReqChange - the function/method to call at key events of the URL retrieval.
|
|
* @param {String} method - (optional) "GET" or "POST" (default "GET")
|
|
* @param {String} data - (optional) the CGI data to pass. Default null.
|
|
* @param {boolean} isAsync - (optional) is this call asyncronous. Default true.
|
|
*
|
|
* @return {Object} a XML request object.
|
|
*/
|
|
me.getXMLHttpRequest = function(url, processReqChange) //, method, data, isAsync)
|
|
{
|
|
var argv = me.getXMLHttpRequest.arguments;
|
|
var argc = me.getXMLHttpRequest.arguments.length;
|
|
var httpMethod = (argc > 2) ? argv[2] : 'GET';
|
|
var data = (argc > 3) ? argv[3] : "";
|
|
var isAsync = (argc > 4) ? argv[4] : true;
|
|
|
|
var req;
|
|
// branch for native XMLHttpRequest object
|
|
if (window.XMLHttpRequest) {
|
|
req = new XMLHttpRequest();
|
|
// branch for IE/Windows ActiveX version
|
|
} else if (window.ActiveXObject) {
|
|
try {
|
|
req = new ActiveXObject('Msxml2.XMLHTTP');
|
|
}
|
|
catch (ex) {
|
|
req = new ActiveXObject("Microsoft.XMLHTTP");
|
|
}
|
|
// the browser doesn't support XML HttpRequest. Return null;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
if (isAsync) {
|
|
req.onreadystatechange = processReqChange;
|
|
}
|
|
|
|
if (httpMethod == "GET" && data != "") {
|
|
url += "?" + data;
|
|
}
|
|
|
|
req.open(httpMethod, url, isAsync);
|
|
|
|
//Fixes IE Caching problem
|
|
req.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
|
|
req.send(data);
|
|
|
|
return req;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!window.CSSHelpers) {
|
|
CSSHelpers = new function(){
|
|
var me = this;
|
|
|
|
var blankRe = new RegExp('\\s');
|
|
|
|
/*
|
|
* getComputedStyle: code from http://blog.stchur.com/2006/06/21/css-computed-style/
|
|
*/
|
|
me.getComputedStyle = function(elem, style)
|
|
{
|
|
var computedStyle;
|
|
if (typeof elem.currentStyle != 'undefined')
|
|
{ computedStyle = elem.currentStyle; }
|
|
else
|
|
{ computedStyle = document.defaultView.getComputedStyle(elem, null); }
|
|
|
|
return computedStyle[style];
|
|
}
|
|
|
|
|
|
/**
|
|
* Determines if an HTML object is a member of a specific class.
|
|
* @param {Object} obj - an HTML object.
|
|
* @param {Object} className - the CSS class name.
|
|
*/
|
|
me.isMemberOfClass = function(obj, className){
|
|
|
|
if (blankRe.test(className))
|
|
return false;
|
|
|
|
var re = new RegExp(getClassReString(className), "g");
|
|
|
|
return (re.test(obj.className));
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* Make an HTML object be a member of a certain class.
|
|
*
|
|
* @param {Object} obj - an HTML object
|
|
* @param {String} className - a CSS class name.
|
|
*/
|
|
me.addClass = function(obj, className){
|
|
if (blankRe.test(className)) {
|
|
return;
|
|
}
|
|
|
|
// only add class if the object is not a member of it yet.
|
|
if (!me.isMemberOfClass(obj, className)) {
|
|
obj.className += " " + className;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Make an HTML object *not* be a member of a certain class.
|
|
*
|
|
* @param {Object} obj - an HTML object
|
|
* @param {Object} className - a CSS class name.
|
|
*/
|
|
me.removeClass = function(obj, className){
|
|
|
|
if (blankRe.test(className)) {
|
|
return;
|
|
}
|
|
|
|
|
|
var re = new RegExp(getClassReString(className), "g");
|
|
|
|
var oldClassName = obj.className;
|
|
|
|
|
|
if (obj.className) {
|
|
obj.className = oldClassName.replace(re, '');
|
|
}
|
|
|
|
|
|
}
|
|
|
|
function getClassReString(className) {
|
|
return '\\s'+className+'\\s|^' + className + '\\s|\\s' + className + '$|' + '^' + className +'$';
|
|
}
|
|
|
|
/**
|
|
* Given an HTML element, find all child nodes of a specific class.
|
|
*
|
|
* With ideas from Jonathan Snook
|
|
* (http://snook.ca/archives/javascript/your_favourite_1/)
|
|
* Since this was presented within a post on this site, it is for the
|
|
* public domain according to the site's copyright statement.
|
|
*
|
|
* @param {Object} obj - an HTML element. If you want to search a whole document, set
|
|
* this to the document object.
|
|
* @param {String} className - the class name of the objects to return
|
|
* @return {Array} - the list of objects of class cls.
|
|
*/
|
|
me.getElementsByClassName = function (obj, className)
|
|
{
|
|
if (obj.getElementsByClassName) {
|
|
return DOMHelpers.nodeListToArray(obj.getElementsByClassName(className))
|
|
}
|
|
else {
|
|
var a = [];
|
|
var re = new RegExp(getClassReString(className));
|
|
var els = DOMHelpers.getAllDescendants(obj);
|
|
for (var i = 0, j = els.length; i < j; i++) {
|
|
if (re.test(els[i].className)) {
|
|
a.push(els[i]);
|
|
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates a regular expression string that can be used to detect a class name
|
|
* in a tag's class attribute. It is used by a few methods, so I
|
|
* centralized it.
|
|
*
|
|
* @param {String} className - a name of a CSS class.
|
|
*/
|
|
function getClassReString(className){
|
|
return '\\s' + className + '\\s|^' + className + '\\s|\\s' + className + '$|' + '^' + className + '$';
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Adding trim method to String Object. Ideas from
|
|
* http://www.faqts.com/knowledge_base/view.phtml/aid/1678/fid/1 and
|
|
* http://blog.stevenlevithan.com/archives/faster-trim-javascript
|
|
*/
|
|
String.prototype.trim = function(){
|
|
var str = this;
|
|
|
|
// The first method is faster on long strings than the second and
|
|
// vice-versa.
|
|
if (this.length > 6000) {
|
|
str = this.replace(StringHelpers.initWhitespaceRe, '');
|
|
var i = str.length;
|
|
while (StringHelpers.whitespaceRe.test(str.charAt(--i)))
|
|
;
|
|
return str.slice(0, i + 1);
|
|
} else {
|
|
return this.replace(StringHelpers.initWhitespaceRe, '').replace(StringHelpers.endWhitespaceRe, '');
|
|
}
|
|
|
|
|
|
};
|
|
|
|
if (!window.DOMHelpers) {
|
|
|
|
DOMHelpers = new function () {
|
|
var me = this;
|
|
|
|
/**
|
|
* Returns all children of an element. Needed if it is necessary to do
|
|
* the equivalent of getElementsByTagName('*') for IE5 for Windows.
|
|
*
|
|
* @param {Object} e - an HTML object.
|
|
*/
|
|
me.getAllDescendants = function(obj) {
|
|
return obj.all ? obj.all : obj.getElementsByTagName('*');
|
|
}
|
|
|
|
/******
|
|
* Converts a DOM live node list to a static/dead array. Good when you don't
|
|
* want the thing you are iterating in a for loop changing as the DOM changes.
|
|
*
|
|
* @param {Object} nodeList - a node list (like one returned by document.getElementsByTagName)
|
|
* @return {Array} - an array of nodes.
|
|
*
|
|
*******/
|
|
me.nodeListToArray = function (nodeList)
|
|
{
|
|
var ary = [];
|
|
for(var i=0, len = nodeList.length; i < len; i++)
|
|
{
|
|
ary.push(nodeList[i]);
|
|
}
|
|
return ary;
|
|
}
|
|
}
|
|
}
|
|
|
|
//+ Jonas Raoni Soares Silva
|
|
//@ http://jsfromhell.com/string/capitalize [v1.0]
|
|
|
|
String.prototype.capitalize = function(){ //v1.0
|
|
return this.charAt(0).toUpperCase() + this.substr(1);
|
|
|
|
};
|
|
|
|
|
|
/*
|
|
* stringBuffer.js - ideas from
|
|
* http://www.multitask.com.au/people/dion/archives/000354.html
|
|
*/
|
|
function StringBuffer(){
|
|
var me = this;
|
|
|
|
var buffer = [];
|
|
|
|
|
|
me.append = function(string){
|
|
buffer.push(string);
|
|
return me;
|
|
}
|
|
|
|
me.appendBuffer = function(bufferToAppend){
|
|
buffer = buffer.concat(bufferToAppend);
|
|
}
|
|
|
|
me.toString = function(){
|
|
return buffer.join("");
|
|
}
|
|
|
|
me.getLength = function(){
|
|
return buffer.length;
|
|
}
|
|
|
|
me.flush = function(){
|
|
buffer.length = 0;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* A class to parse color values
|
|
* @author Stoyan Stefanov <sstoo@gmail.com> (with modifications)
|
|
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
|
|
* @license Use it if you like it
|
|
*/
|
|
function RGBColor(color_string){
|
|
|
|
var me = this;
|
|
|
|
|
|
|
|
me.ok = false;
|
|
|
|
// strip any leading #
|
|
if (color_string.charAt(0) == '#') { // remove # if any
|
|
color_string = color_string.substr(1, 6);
|
|
}
|
|
|
|
color_string = color_string.replace(/ /g, '');
|
|
color_string = color_string.toLowerCase();
|
|
|
|
// before getting into regexps, try simple matches
|
|
// and overwrite the input
|
|
var simple_colors = {
|
|
aliceblue: 'f0f8ff',
|
|
antiquewhite: 'faebd7',
|
|
aqua: '00ffff',
|
|
aquamarine: '7fffd4',
|
|
azure: 'f0ffff',
|
|
beige: 'f5f5dc',
|
|
bisque: 'ffe4c4',
|
|
black: '000000',
|
|
blanchedalmond: 'ffebcd',
|
|
blue: '0000ff',
|
|
blueviolet: '8a2be2',
|
|
brown: 'a52a2a',
|
|
burlywood: 'deb887',
|
|
cadetblue: '5f9ea0',
|
|
chartreuse: '7fff00',
|
|
chocolate: 'd2691e',
|
|
coral: 'ff7f50',
|
|
cornflowerblue: '6495ed',
|
|
cornsilk: 'fff8dc',
|
|
crimson: 'dc143c',
|
|
cyan: '00ffff',
|
|
darkblue: '00008b',
|
|
darkcyan: '008b8b',
|
|
darkgoldenrod: 'b8860b',
|
|
darkgray: 'a9a9a9',
|
|
darkgreen: '006400',
|
|
darkkhaki: 'bdb76b',
|
|
darkmagenta: '8b008b',
|
|
darkolivegreen: '556b2f',
|
|
darkorange: 'ff8c00',
|
|
darkorchid: '9932cc',
|
|
darkred: '8b0000',
|
|
darksalmon: 'e9967a',
|
|
darkseagreen: '8fbc8f',
|
|
darkslateblue: '483d8b',
|
|
darkslategray: '2f4f4f',
|
|
darkturquoise: '00ced1',
|
|
darkviolet: '9400d3',
|
|
deeppink: 'ff1493',
|
|
deepskyblue: '00bfff',
|
|
dimgray: '696969',
|
|
dodgerblue: '1e90ff',
|
|
feldspar: 'd19275',
|
|
firebrick: 'b22222',
|
|
floralwhite: 'fffaf0',
|
|
forestgreen: '228b22',
|
|
fuchsia: 'ff00ff',
|
|
gainsboro: 'dcdcdc',
|
|
ghostwhite: 'f8f8ff',
|
|
gold: 'ffd700',
|
|
goldenrod: 'daa520',
|
|
gray: '808080',
|
|
green: '008000',
|
|
greenyellow: 'adff2f',
|
|
honeydew: 'f0fff0',
|
|
hotpink: 'ff69b4',
|
|
indianred: 'cd5c5c',
|
|
indigo: '4b0082',
|
|
ivory: 'fffff0',
|
|
khaki: 'f0e68c',
|
|
lavender: 'e6e6fa',
|
|
lavenderblush: 'fff0f5',
|
|
lawngreen: '7cfc00',
|
|
lemonchiffon: 'fffacd',
|
|
lightblue: 'add8e6',
|
|
lightcoral: 'f08080',
|
|
lightcyan: 'e0ffff',
|
|
lightgoldenrodyellow: 'fafad2',
|
|
lightgrey: 'd3d3d3',
|
|
lightgreen: '90ee90',
|
|
lightpink: 'ffb6c1',
|
|
lightsalmon: 'ffa07a',
|
|
lightseagreen: '20b2aa',
|
|
lightskyblue: '87cefa',
|
|
lightslateblue: '8470ff',
|
|
lightslategray: '778899',
|
|
lightsteelblue: 'b0c4de',
|
|
lightyellow: 'ffffe0',
|
|
lime: '00ff00',
|
|
limegreen: '32cd32',
|
|
linen: 'faf0e6',
|
|
magenta: 'ff00ff',
|
|
maroon: '800000',
|
|
mediumaquamarine: '66cdaa',
|
|
mediumblue: '0000cd',
|
|
mediumorchid: 'ba55d3',
|
|
mediumpurple: '9370d8',
|
|
mediumseagreen: '3cb371',
|
|
mediumslateblue: '7b68ee',
|
|
mediumspringgreen: '00fa9a',
|
|
mediumturquoise: '48d1cc',
|
|
mediumvioletred: 'c71585',
|
|
midnightblue: '191970',
|
|
mintcream: 'f5fffa',
|
|
mistyrose: 'ffe4e1',
|
|
moccasin: 'ffe4b5',
|
|
navajowhite: 'ffdead',
|
|
navy: '000080',
|
|
oldlace: 'fdf5e6',
|
|
olive: '808000',
|
|
olivedrab: '6b8e23',
|
|
orange: 'ffa500',
|
|
orangered: 'ff4500',
|
|
orchid: 'da70d6',
|
|
palegoldenrod: 'eee8aa',
|
|
palegreen: '98fb98',
|
|
paleturquoise: 'afeeee',
|
|
palevioletred: 'd87093',
|
|
papayawhip: 'ffefd5',
|
|
peachpuff: 'ffdab9',
|
|
peru: 'cd853f',
|
|
pink: 'ffc0cb',
|
|
plum: 'dda0dd',
|
|
powderblue: 'b0e0e6',
|
|
purple: '800080',
|
|
red: 'ff0000',
|
|
rosybrown: 'bc8f8f',
|
|
royalblue: '4169e1',
|
|
saddlebrown: '8b4513',
|
|
salmon: 'fa8072',
|
|
sandybrown: 'f4a460',
|
|
seagreen: '2e8b57',
|
|
seashell: 'fff5ee',
|
|
sienna: 'a0522d',
|
|
silver: 'c0c0c0',
|
|
skyblue: '87ceeb',
|
|
slateblue: '6a5acd',
|
|
slategray: '708090',
|
|
snow: 'fffafa',
|
|
springgreen: '00ff7f',
|
|
steelblue: '4682b4',
|
|
tan: 'd2b48c',
|
|
teal: '008080',
|
|
metle: 'd8bfd8',
|
|
tomato: 'ff6347',
|
|
turquoise: '40e0d0',
|
|
violet: 'ee82ee',
|
|
violetred: 'd02090',
|
|
wheat: 'f5deb3',
|
|
white: 'ffffff',
|
|
whitesmoke: 'f5f5f5',
|
|
yellow: 'ffff00',
|
|
yellowgreen: '9acd32'
|
|
};
|
|
for (var key in simple_colors) {
|
|
if (color_string == key) {
|
|
color_string = simple_colors[key];
|
|
}
|
|
}
|
|
// emd of simple type-in colors
|
|
|
|
// array of color definition objects
|
|
var color_defs = [{
|
|
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
|
|
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
|
|
process: function(bits){
|
|
return [parseInt(bits[1]), parseInt(bits[2]), parseInt(bits[3])];
|
|
}
|
|
}, {
|
|
re: /^(\w{2})(\w{2})(\w{2})$/,
|
|
example: ['#00ff00', '336699'],
|
|
process: function(bits){
|
|
return [parseInt(bits[1], 16), parseInt(bits[2], 16), parseInt(bits[3], 16)];
|
|
}
|
|
}, {
|
|
re: /^(\w{1})(\w{1})(\w{1})$/,
|
|
example: ['#fb0', 'f0f'],
|
|
process: function(bits){
|
|
return [parseInt(bits[1] + bits[1], 16), parseInt(bits[2] + bits[2], 16), parseInt(bits[3] + bits[3], 16)];
|
|
}
|
|
}, {
|
|
re: /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(0{0,1}\.\d{1,}|0\.{0,}0*|1\.{0,}0*)\)$/,
|
|
example: ['rgba(123, 234, 45, 22)', 'rgba(255, 234,245, 34)'],
|
|
process: function(bits){
|
|
return [parseInt(bits[1]), parseInt(bits[2]), parseInt(bits[3]), parseFloat(bits[4])];
|
|
}
|
|
}, {
|
|
re: /^hsla\((\d{1,3}),\s*(\d{1,3}%),\s*(\d{1,3}%),\s*(0{0,1}\.\d{1,}|0\.{0,}0*|1\.{0,}0*)\)$/,
|
|
example: ['hsla(0,100%,50%,0.2)'],
|
|
process: function(bits){
|
|
var result = hsl2rgb(parseInt(bits[1]), parseInt(bits[2]), parseInt(bits[3]), parseFloat(bits[4]));
|
|
|
|
return [result.r, result.g, result.b, parseFloat(bits[4])];
|
|
|
|
}
|
|
}, {
|
|
re: /^hsl\((\d{1,3}),\s*(\d{1,3}%),\s*(\d{1,3}%)\)$/,
|
|
example: ['hsl(0,100%,50%)'],
|
|
process: function(bits){
|
|
var result = hsl2rgb(parseInt(bits[1]), parseInt(bits[2]), parseInt(bits[3]), 1);
|
|
|
|
return [result.r, result.g, result.b, 1];
|
|
|
|
}
|
|
}];
|
|
|
|
// search through the definitions to find a match
|
|
for (var i = 0; i < color_defs.length; i++) {
|
|
var re = color_defs[i].re;
|
|
var processor = color_defs[i].process;
|
|
var bits = re.exec(color_string);
|
|
if (bits) {
|
|
channels = processor(bits);
|
|
me.r = channels[0];
|
|
me.g = channels[1];
|
|
me.b = channels[2];
|
|
me.a = channels[3];
|
|
me.ok = true;
|
|
}
|
|
|
|
}
|
|
|
|
// validate/cleanup values
|
|
me.r = (me.r < 0 || isNaN(me.r)) ? 0 : ((me.r > 255) ? 255 : me.r);
|
|
me.g = (me.g < 0 || isNaN(me.g)) ? 0 : ((me.g > 255) ? 255 : me.g);
|
|
me.b = (me.b < 0 || isNaN(me.b)) ? 0 : ((me.b > 255) ? 255 : me.b);
|
|
|
|
|
|
|
|
me.a = (isNaN(me.a)) ? 1 : ((me.a > 255) ? 255 : (me.a < 0) ? 0 : me.a);
|
|
|
|
|
|
|
|
// some getters
|
|
me.toRGB = function(){
|
|
return 'rgb(' + me.r + ', ' + me.g + ', ' + me.b + ')';
|
|
}
|
|
|
|
// some getters
|
|
me.toRGBA = function(){
|
|
return 'rgba(' + me.r + ', ' + me.g + ', ' + me.b + ', ' + me.a + ')';
|
|
}
|
|
|
|
/**
|
|
* Converts an RGB color value to HSV. Conversion formula
|
|
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
|
|
* Assumes r, g, and b are contained in the set [0, 255] and
|
|
* returns h, s, and v in the set [0, 1].
|
|
*
|
|
* This routine by Michael Jackson (not *that* one),
|
|
* from http://www.mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
|
|
*
|
|
* @param Number r The red color value
|
|
* @param Number g The green color value
|
|
* @param Number b The blue color value
|
|
* @return Array The HSV representation
|
|
*/
|
|
me.toHSV = function(){
|
|
var r = me.r / 255, g = me.g / 255, b = me.b / 255;
|
|
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
var h, s, v = max;
|
|
|
|
var d = max - min;
|
|
s = max == 0 ? 0 : d / max;
|
|
|
|
if (max == min) {
|
|
h = 0; // achromatic
|
|
} else {
|
|
switch (max) {
|
|
case r:
|
|
h = (g - b) / d + (g < b ? 6 : 0);
|
|
break;
|
|
case g:
|
|
h = (b - r) / d + 2;
|
|
break;
|
|
case b:
|
|
h = (r - g) / d + 4;
|
|
break;
|
|
}
|
|
h /= 6;
|
|
}
|
|
|
|
return {
|
|
h: h,
|
|
s: s,
|
|
v: v
|
|
};
|
|
}
|
|
|
|
/*
|
|
* hsl2rgb from http://codingforums.com/showthread.php?t=11156
|
|
* code by Jason Karl Davis (http://www.jasonkarldavis.com)
|
|
*/
|
|
function hsl2rgb(h, s, l) {
|
|
var m1, m2, hue;
|
|
var r, g, b
|
|
s /=100;
|
|
l /= 100;
|
|
if (s == 0)
|
|
r = g = b = (l * 255);
|
|
else {
|
|
if (l <= 0.5)
|
|
m2 = l * (s + 1);
|
|
else
|
|
m2 = l + s - l * s;
|
|
m1 = l * 2 - m2;
|
|
hue = h / 360;
|
|
r = HueToRgb(m1, m2, hue + 1/3);
|
|
g = HueToRgb(m1, m2, hue);
|
|
b = HueToRgb(m1, m2, hue - 1/3);
|
|
}
|
|
return {r: Math.round(r), g: Math.round(g), b: Math.round(b)};
|
|
}
|
|
|
|
function HueToRgb(m1, m2, hue) {
|
|
var v;
|
|
if (hue < 0)
|
|
hue += 1;
|
|
else if (hue > 1)
|
|
hue -= 1;
|
|
|
|
if (6 * hue < 1)
|
|
v = m1 + (m2 - m1) * hue * 6;
|
|
else if (2 * hue < 1)
|
|
v = m2;
|
|
else if (3 * hue < 2)
|
|
v = m1 + (m2 - m1) * (2/3 - hue) * 6;
|
|
else
|
|
v = m1;
|
|
|
|
return 255 * v;
|
|
}
|
|
|
|
|
|
|
|
me.toHex = function(){
|
|
var r = me.r.toString(16);
|
|
var g = me.g.toString(16);
|
|
var b = me.b.toString(16);
|
|
|
|
var a = Math.floor((me.a * 255)).toString(16);
|
|
|
|
if (r.length == 1)
|
|
r = '0' + r;
|
|
if (g.length == 1)
|
|
g = '0' + g;
|
|
if (b.length == 1)
|
|
b = '0' + b;
|
|
|
|
|
|
if (a == 'ff') {
|
|
a = '';
|
|
} else if (a.length == 1) {
|
|
a = '0' + a;
|
|
}
|
|
return '#' + a + r + g + b;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
document.write('<style type="text/css">.cssSandpaper-initiallyHidden { visibility: hidden;} </style>');
|
|
|
|
|
|
|
|
EventHelpers.addPageLoadEvent('cssSandpaper.init')
|
|
|