icingaweb2/library/IcingaVendor/dompdf/www/cssSandpaper/js/cssSandpaper.js

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')