Matthias Jentsch 124b42c9f1 Remove tcpdf library and use dompdf instead
Remove tcpdf because of improper CSS support and use Dompdf instead, to be able
to generate pdfs that look similar to the html views

refs #4356
2014-02-12 12:11:01 +01:00

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