1,515 → 1,823 |
/** |
* <title>PointedEars' CSS Library</title> |
* @version 0.1.2005052800 |
* @partof PointedEars' JavaScript Extensions (JSX) |
* @requires collection.js |
* |
* @section Copyright & Disclaimer |
* |
* @author (C) 2005 Thomas Lahn <css.js@PointedEars.de> |
* |
* This program is free software; you can redistribute it and/or |
* modify it under the terms of the GNU General Public License |
* as published by the Free Software Foundation; either version 2 |
* of the License, or (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License (GPL) for more details. |
* |
* You should have received a copy of the GNU GPL along with this |
* program (COPYING file); if not, go to [1] or write to the Free |
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
* MA 02111-1307, USA. |
* |
* [1] <http://www.gnu.org/licenses/licenses.html#GPL> |
*/ |
/* |
* The original source file |
* _css.js/0.1/2005-03-10-01/css.js |
* contains a complete documentation written in JSdoc, see |
* <http://pointedears.de/scripts/JSdoc/> for details. |
* |
* Since JSdoc is not yet ready for production purposes to |
* generate a HTML documentation from these comments and |
* including them in the production version means about 50% |
* of code overhead, most of the JSdoc comments have been |
* stripped from this file. |
*/ |
|
var CSSversion = "0.1.2005052800"; |
if (typeof CSS != "undefined") |
{ |
var CSS = {version: CSSversion}; |
} |
else |
{ |
CSS.version = CSSversion; |
} |
|
/** |
* A <code>CSSSelectorList</code> object encapsulates |
* all CSS selectors linked to from a document in a |
* @{Collection}. |
* |
* @optional Object |
* Object reference to override the default |
* <code>document</code> object reference. |
*/ |
function CSSSelectorList(oDocument) |
{ |
Collection.call(this); |
|
this.document = oDocument || document; |
|
/** |
* Populates the collection with the selectors |
* of the document. |
* |
* @optional Object |
* Object reference to override the default |
* <code>document</code> object reference. |
*/ |
CSSSelectorList.prototype.get = function cssSelectorList_get(oDocument) |
{ |
if (oDocument) |
{ |
this.document = oDocument; |
} |
|
this.clear(); |
|
var d, oSheets; |
if ((d = this.document) && (oSheets = d.styleSheets)) |
{ |
for (var i = 0, oRules; i < oSheets.length; i++) |
{ |
if ((oRules = oSheets[i].cssRules || oSheets[i].rules)) |
{ |
for (var j = 0; j < oRules.length; j++) |
{ |
this.add(oRules[j], oRules[j].selectorText); |
} |
} |
} |
return true; |
} |
|
return false; |
}; |
|
this.get(); |
} |
CSSSelectorList.prototype = new Collection(); |
|
/** |
* Returns a reference to the selector |
* containing a simple selector. |
* |
* @argument string |
* Simple selector. |
*/ |
CSSSelectorList.prototype.findSimpleSelector = |
function cssSelectorList_findSimpleSelector(sSelector) |
{ |
var s = |
"{simple_selector}({combinator}{simple_selector}*)*" |
.replace( |
/\{simple_selector\}/g, |
'(element_name(#|class|attrib|pseudo)*' |
+ '|(#|class|attrib|pseudo)+)') |
/* |
.replace(/element_name/g, "(IDENT|\\*)") |
.replace(/class/g, "\\.IDENT") |
.replace(/attrib/g, "\\[\\s*IDENT\\s*([~\\|]=" |
+ "\\s*(IDENT|STRING)\\s*)?\\]") |
.replace(/pseudo/g, ":(IDENT|FUNCTION\\s*IDENT?\\s*\\))") |
.replace(/FUNCTION/g, "IDENT\\(\\s*expr\\)\\s*") |
.replace(/\{expr\}/g, 'Term(OperatorTerm)*') |
.replace(/\{Operator\}/g, "(/\\s*|,\\s*|/\\*([^*]|\\*[\\/])*\\/)") |
.replace(/\{Term\}/g, ["([+-]?", |
"(NUMBER%?\\s*|LENGTH\\s*", |
"|ANGLE\\s*|TIME\\s*", |
"|FREQ\\s*|IDENT\\(\\s*expr\\)\\s*)", |
"|STRING\\s*|IDENT\\s*|URI\\s*|hexcolor)"] |
.join('')) |
.replace(/ANGLE/g, 'NUMBER(deg|g?rad)') |
.replace(/TIME/g, 'NUMBERm?s') |
.replace(/FREQ/g, 'NUMBERk?Hz') |
.replace(/LENGTH/g, 'NUMBER([cm]m|e[mx]|in|p[ctx])') |
.replace(/NUMBER/g, '([0-9]+|[0-9]*\\.[0-9]+)') |
.replace(/URI/g, "url\\(\\s*(STRING|URL)\\s*\\)") |
.replace(/STRING/g, '({string1}|{string2})') |
.replace(/URL/g, '([!#$%&*-~]|{nonascii}|{escape})*') |
.replace(/hexcolor/g, '#([0-9a-fA-F]{3}){1,2}') |
.replace(/IDENT/g, "{nmstart}{nmchar}*\\s*") |
.replace(/\{nmstart\}/g, '([_a-z{nonascii}]|{escape})') |
.replace(/\{nmchar\}/g, '([_a-zA-Z0-9{nonascii}-]|{escape})') |
.replace(/\{string1\}/g, "\"([\t !#$%&(-~]|\\{nl}|'|[{nonascii}]|{escape})*\"") |
.replace(/\{string2\}/g, "'([\t !#$%&(-~]|\\{nl}|\"|[{nonascii}]|{escape})*'") |
.replace(/\{nl\}/g, "(\\n|\\r\\n|\\r|\\f)") |
.replace(/\{nonascii\}/g, "\\x80-\\xFF") |
.replace(/\{escape\}/g, "({unicode}|\\\\[ -~\\x80-\\xFF])") |
.replace(/\{unicode\}/g, "\\\\[0-9a-f]{1,6}(\\r\\n|[ \\t\\r\\n\\f])?") |
.replace(/\{combinator\}/g, "(\\+\\s*|\\>\\s*|\\s+)"); |
*/ |
alert(s); |
|
var rxSimpleSelector = new RegExp(s); |
|
var i = this.iterator(); |
while ((s = i.next())) |
{ |
if ((new RegExp(sSelector)).test(s.selectorText)) |
{ |
return s; |
} |
} |
|
return null; |
} |
|
/** |
* Shows or hides elements with a certain class name. |
* |
* @arguments string |
* Class name of the elements to be hidden/shown. |
* @optional boolean bShow |
* If <code>false</code>, elements will be |
* hidden, otherwise shown. |
* @requires dhtml.js |
*/ |
function showByClassName(sClassName, bShow) |
{ |
var selectorList, selector; |
if (typeof CSSSelectorList != "undefined" |
&& (selectorList = new CSSSelectorList()) |
&& (selector = |
selectorList.findSimpleSelector("\\." + sClassName))) |
{ |
selector.display = bShow ? "" : "none"; |
return (selector.display == bShow ? "" : "none"); |
} |
else |
{ |
if (typeof dhtml != "undefined" |
&& isMethod("dhtml.getElemByClassName")) |
{ |
var es = dhtml.getElemByClassName(sClassName); |
|
for (var i = es.length; i--; 0) |
{ |
var o = es[i]; |
if (typeof o.display != "undefined") |
{ |
o.display = bShow ? "" : "none"; |
} |
} |
return true; |
} |
else |
{ |
alert("Sorry, you must include dhtml.js."); |
return false; |
} |
} |
} |
|
/** |
* The <code>Color</code> prototype encapsulates |
* color data given in RGB format. |
* |
* @argument number|string iRed |
* Red value or RGB color. Supported formats for RGB color are: |
* <code>rgb(<var>r</var>, <var>g</var>, <var>b</var>)</code>, |
* <code>#rgb</code> and <code>#rrggbb</code>. |
* @optional number iGreen |
* Green value. |
* @optional number iBlue |
* Blue value. |
* @property number red |
* Red value. |
* @property number green |
* Green value. |
* @property number blue |
* Blue value. |
*/ |
function Color(iRed, iGreen, iBlue) |
{ |
/** |
* Fixes RGB values, i.e. brings them into |
* range if they are out of range. |
* Note: Brightness/contrast are disregarded. |
*/ |
Color.prototype.fix = function color_fix() |
{ |
if (this.red < 0) this.red = 0; |
if (this.red > 255) this.red = 255; |
if (this.green < 0) this.green = 0; |
if (this.green > 255) this.green = 255; |
if (this.blue < 0) this.blue = 0; |
if (this.blue > 255) this.blue = 255; |
} |
|
/** |
* Sets the color values from a RGB value. |
* |
* @argument string |
* RGB value as supported by @{#Color()}. |
*/ |
Color.prototype.setRGB = function color_setRGB(v) |
{ |
var m; |
|
if ((m = new RegExp( |
'((rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\))' |
+ '|(#([0-9a-f]{3})([0-9a-f]{3})?))', |
'i').exec(v))) |
{ |
// rgb(...) |
if (m[2]) |
{ |
this.red = m[3]; |
this.green = m[4]; |
this.blue = m[5]; |
} |
// #xxxxxx |
else if (m[6]) |
{ |
if (m[8]) |
{ |
if ((m = |
/([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i.exec(m[7] + m[8]))) |
{ |
this.red = parseInt(m[1], 16); |
this.green = parseInt(m[2], 16); |
this.blue = parseInt(m[3], 16); |
} |
} |
// #xxx |
else |
{ |
var c; |
this.red = parseInt((c = m[7].charAt(0)) + c, 16); |
this.green = parseInt((c = m[7].charAt(1)) + c, 16); |
this.blue = parseInt((c = m[7].charAt(2)) + c, 16); |
} |
} |
} |
|
this.fix(); |
|
return this; |
} |
|
/** |
* Sets the color values from Red, Green and Blue values or a |
* RGB value. |
* |
* @argument number|string iRed |
* Red value or RGB color. Supported formats |
* for RGB color are the same as for @{#Color()}. |
* @optional number iGreen |
* Green value. |
* @optional number iBlue |
* Blue value. |
*/ |
Color.prototype.set = function color_set(iRed, iGreen, iBlue) |
{ |
if (typeof iRed != 'undefined') |
{ |
// rgb(...) or /#xxx(xxx)?/ |
if (typeof iRed == 'string') |
{ |
this.setRGB(iRed); |
} |
else |
{ |
this.red = iRed; |
if (typeof iGreen != 'undefined') this.green = iGreen; |
if (typeof iBlue != 'undefined') this.blue = iBlue; |
} |
} |
|
this.fix(); |
|
return this; |
} |
|
this.set(iRed, iGreen, iBlue); |
} |
|
/** |
* Returns the monochrome version of a color as an object. |
*/ |
Color.prototype.getMono = function color_getMono() |
{ |
var avg = Math.floor(((+this.red) + (+this.green) + (+this.blue)) / 3); |
return new Color(avg, avg, avg); |
} |
|
/** |
* Sets the color values from Red, Green and Blue values or |
* an RGB value and returns a monochrome version of the color |
* as an object. |
* |
* @argument number|string iRed |
* Red value or RGB color. Supported formats |
* for RGB color are the same as for @{#Color()}. |
* @optional number iGreen |
* Green value. |
* @optional number iBlue |
* Blue value. |
*/ |
Color.prototype.setMono = function color_setMono(iRed, iGreen, iBlue) |
{ |
this.set(iRed, iGreen, iBlue); |
|
var c = this.getMono(); |
this.red = c.red; |
this.green = c.green; |
this.blue = c.blue; |
|
return this; |
} |
|
Color.prototype.getWebSafe = function color_getWebSafe() |
{ |
function getNearestSafeValue(v) |
{ |
if (v >= 0xFF) |
{ |
return 0xFF; |
} |
|
if (v <= 0) |
{ |
return 0; |
} |
|
for (var a = [0, 0x33, 0x66, 0x99, 0xCC, 0xFF], i = a.length-1; |
i--;) |
{ |
if (v >= a[i]) |
{ |
if (v == a[i]) |
{ |
return v; |
} |
else |
{ |
if (v - a[i] < a[i+1] - v) |
{ |
return a[i]; |
} |
else |
{ |
return a[i+1]; |
} |
} |
} |
} |
return -1; |
} |
|
return new Color( |
getNearestSafeValue(this.red), |
getNearestSafeValue(this.green), |
getNearestSafeValue(this.blue)); |
} |
|
Color.prototype.setWebSafe = function color_setMono(iRed, iGreen, iBlue) |
{ |
this.set(iRed, iGreen, iBlue); |
|
var c = this.getWebSafe(); |
this.red = c.red; |
this.green = c.green; |
this.blue = c.blue; |
|
return this; |
} |
|
/** |
* Returns the color as a string |
* <code>rgb(<var>r</var>,<var>g</var>,<var>b</var>)</code> |
* representation supported by CSS. |
*/ |
Color.prototype.getRGB = function color_getMono() |
{ |
return ['rgb(', this.red, ',', this.green, ',', this.blue, ')'].join(''); |
} |
|
Color.prototype.toHex = function toHex() |
{ |
var |
r = leadingZero(this.red.toString(16), 2), |
g = leadingZero(this.green.toString(16), 2), |
b = leadingZero(this.blue.toString(16), 2), |
rx = /([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3/i, |
m; |
|
if ((m = rx.exec([r, g, b].join('')))) |
{ |
r = m[1]; |
g = m[2]; |
b = m[3]; |
} |
|
return ['#', r, g, b].join(''); |
} |
|
/** |
* Returns the color as a string |
* <code>{red: <var>r</var>, green: <var>g</var>, blue: <var>b</var>}</code> |
* representation. |
*/ |
Color.prototype.toString = function color_toString() |
{ |
return [ |
'{red: ', this.red, ', green: ', this.green, ', blue: ', this.blue, '}' |
].join(''); |
} |
|
/** |
* Changes the current document into a monochrome version of itself. |
* |
* @requires dhtml.js |
*/ |
function makeMono() |
{ |
var |
sl = new CSSSelectorList(), |
oIt = sl.iterator(), |
s, |
c = new Color(), |
a = ['backgroundColor', 'borderColor', 'borderTopColor', |
'borderRightColor', 'borderBottomColor', 'borderLeftColor', |
'outlineColor', 'color'], |
j, |
p; |
|
while ((s = oIt.next())) |
{ |
for (j = a.length; j--;) |
{ |
if ((p = s[a[j]])) |
{ |
s[a[j]] = c.setMono(p).getRGB(); |
} |
} |
} |
|
for (var es = dhtml.getElemByTagName('*'), i = es && es.length; i--;) |
{ |
var e = es[i]; |
for (j = a.length; j--;) |
{ |
if ((p = e.style[a[j]])) |
{ |
e.style[a[j]] = c.setMono(p).getRGB(); |
} |
} |
} |
} |
/** |
* <title>PointedEars' CSS Library</title> |
* @version 0.1.2009041509 |
* @partof PointedEars' JavaScript Extensions (JSX) |
* @requires collection.js |
* |
* @section Copyright & Disclaimer |
* |
* @author (C) 2005, 2009 Thomas Lahn <css.js@PointedEars.de> |
* |
* This program is free software; you can redistribute it and/or |
* modify it under the terms of the GNU General Public License |
* as published by the Free Software Foundation; either version 2 |
* of the License, or (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License (GPL) for more details. |
* |
* You should have received a copy of the GNU GPL along with this |
* program (COPYING file); if not, go to [1] or write to the Free |
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
* MA 02111-1307, USA. |
* |
* [1] <http://www.gnu.org/licenses/licenses.html#GPL> |
*/ |
|
var CSSversion = "0.1.1.2007031314"; |
if (typeof css == "undefined") |
{ |
var css = {version: CSSversion}; |
} |
else |
{ |
css.version = CSSversion; |
} |
|
/** |
* A <code>CSSSelectorList</code> object encapsulates |
* all CSS selectors linked to from a document in a |
* {@link Collection}. |
* |
* @param oDocument : optional Object |
* Object reference to override the default |
* <code>document</code> object reference. |
* @return undefined |
*/ |
function CSSSelectorList(oDocument) |
{ |
this._super(); |
this.document = oDocument || document; |
this.get(); |
} |
CSSSelectorList.extend(Collection); |
|
/** |
* Populates the collection with the selectors |
* of the document. |
* |
* @param oDocument : optional Object |
* Object reference to override the default |
* <code>document</code> object reference. |
* @return undefined |
*/ |
CSSSelectorList.prototype.get = function(oDocument) { |
if (oDocument) |
{ |
this.document = oDocument; |
} |
|
this.clear(); |
|
var d, oSheets; |
if ((d = this.document) && (oSheets = d.styleSheets)) |
{ |
for (var i = 0, oRules; i < oSheets.length; i++) |
{ |
if ((oRules = oSheets[i].cssRules || oSheets[i].rules)) |
{ |
for (var j = 0; j < oRules.length; j++) |
{ |
this.add(oRules[j], oRules[j].selectorText); |
} |
} |
} |
return true; |
} |
|
return false; |
}; |
|
/** |
* Returns a reference to the selector |
* containing a simple selector. |
* |
* @param sSelector : String |
* Simple selector |
* @return CSSStyleRule | Null |
*/ |
CSSSelectorList.prototype.findSimpleSelector = function(sSelector) { |
var s = |
"{simple_selector}({combinator}{simple_selector}*)*" |
.replace( |
/\{simple_selector\}/g, |
'(element_name(#|class|attrib|pseudo)*' |
+ '|(#|class|attrib|pseudo)+)'); |
|
// .replace(/element_name/g, "(IDENT|\\*)") |
// .replace(/class/g, "\\.IDENT") |
// .replace(/attrib/g, "\\[\\s*IDENT\\s*([~\\|]=" |
// + "\\s*(IDENT|STRING)\\s*)?\\]") |
// .replace(/pseudo/g, ":(IDENT|FUNCTION\\s*IDENT?\\s*\\))") |
// .replace(/FUNCTION/g, "IDENT\\(\\s*expr\\)\\s*") |
// .replace(/\{expr\}/g, 'Term(OperatorTerm)*') |
// .replace(/\{Operator\}/g, "(/\\s*|,\\s*|/\\*([^*]|\\*[\\/])*\\/)") |
// .replace(/\{Term\}/g, ["([+-]?", |
// "(NUMBER%?\\s*|LENGTH\\s*", |
// "|ANGLE\\s*|TIME\\s*", |
// "|FREQ\\s*|IDENT\\(\\s*expr\\)\\s*)", |
// "|STRING\\s*|IDENT\\s*|URI\\s*|hexcolor)"] |
// .join('')) |
// .replace(/ANGLE/g, 'NUMBER(deg|g?rad)') |
// .replace(/TIME/g, 'NUMBERm?s') |
// .replace(/FREQ/g, 'NUMBERk?Hz') |
// .replace(/LENGTH/g, 'NUMBER([cm]m|e[mx]|in|p[ctx])') |
// .replace(/NUMBER/g, '([0-9]+|[0-9]*\\.[0-9]+)') |
// .replace(/URI/g, "url\\(\\s*(STRING|URL)\\s*\\)") |
// .replace(/STRING/g, '({string1}|{string2})') |
// .replace(/URL/g, '([!#$%&*-~]|{nonascii}|{escape})*') |
// .replace(/hexcolor/g, '#([0-9a-fA-F]{3}){1,2}') |
// .replace(/IDENT/g, "{nmstart}{nmchar}*\\s*") |
// .replace(/\{nmstart\}/g, '([_a-z{nonascii}]|{escape})') |
// .replace(/\{nmchar\}/g, '([_a-zA-Z0-9{nonascii}-]|{escape})') |
// .replace(/\{string1\}/g, "\"([\t !#$%&(-~]|\\{nl}|'|[{nonascii}]|{escape})*\"") |
// .replace(/\{string2\}/g, "'([\t !#$%&(-~]|\\{nl}|\"|[{nonascii}]|{escape})*'") |
// .replace(/\{nl\}/g, "(\\n|\\r\\n|\\r|\\f)") |
// .replace(/\{nonascii\}/g, "\\x80-\\xFF") |
// .replace(/\{escape\}/g, "({unicode}|\\\\[ -~\\x80-\\xFF])") |
// .replace(/\{unicode\}/g, "\\\\[0-9a-f]{1,6}(\\r\\n|[ \\t\\r\\n\\f])?") |
// .replace(/\{combinator\}/g, "(\\+\\s*|\\>\\s*|\\s+)"); |
|
// try |
// { |
// x = y; |
// } |
// catch (e) |
// { |
// alert("TODO in \n" + e.stack + "\n" + s); |
// } |
|
// var rxSimpleSelector = new RegExp(s); |
|
var i = this.iterator(); |
while ((s = i.next())) |
{ |
if ((new RegExp(sSelector)).test(s.selectorText)) |
{ |
return s; |
} |
} |
|
return null; |
}; |
|
/** |
* Shows or hides elements with a certain class name. |
* |
* @param sClassName : string |
* Class name of the elements to be hidden/shown. |
* @param bShow : optional boolean |
* If <code>false</code>, elements will be |
* hidden, otherwise shown. |
* @requires dhtml.js |
* @return boolean |
* <code>true</code> if successful, <code>false</code> otherwise. |
*/ |
function showByClassName(sClassName, bShow) |
{ |
var selectorList, selector; |
if (typeof CSSSelectorList != "undefined" |
&& (selectorList = new CSSSelectorList()) |
&& (selector = |
selectorList.findSimpleSelector("\\." + sClassName))) |
{ |
selector.display = bShow ? "" : "none"; |
return (selector.display == bShow ? "" : "none"); |
} |
else |
{ |
if (typeof dhtml != "undefined" |
&& dhtml.isMethodType(typeof dhtml.getElemByClassName)) |
{ |
var es = dhtml.getElemByClassName(sClassName); |
|
for (var i = es.length; i--; 0) |
{ |
var o = es[i]; |
if (typeof o.display != "undefined") |
{ |
o.display = bShow ? "" : "none"; |
} |
} |
return true; |
} |
else |
{ |
window.alert("Sorry, JSX:css.js:showByClassName() requires JSX:dhtml.js"); |
return false; |
} |
} |
} |
|
/** |
* The <code>Color</code> prototype encapsulates |
* color data given in RGB format. |
* |
* @param iRed : number|string |
* Red value or RGB color. Supported formats for RGB color are: |
* <code>rgb(<var>r</var>, <var>g</var>, <var>b</var>)</code>, |
* <code>#rgb</code> and <code>#rrggbb</code>. |
* @param iGreen : optional number |
* Green value. |
* @param iBlue : optional number |
* Blue value. |
* @property red : number |
* Red value. |
* @property green : number |
* Green value. |
* @property blue : number |
* Blue value. |
* @return undefined |
*/ |
function Color(iRed, iGreen, iBlue) |
{ |
this.set(iRed, iGreen, iBlue); |
} |
|
/** |
* Sets the color values from Red, Green and Blue values or a |
* RGB value. |
* |
* @param iRed : number|string |
* Red value or RGB color. Supported formats |
* for RGB color are the same as for @{#Color()}. |
* @param iGreen : optional number |
* Green value. |
* @param iBlue : optional number |
* Blue value. |
* @return Color |
*/ |
Color.prototype.set = function(iRed, iGreen, iBlue) { |
if (typeof iRed != 'undefined') |
{ |
/* rgb(...) or /#xxx(xxx)?/ */ |
if (typeof iRed == 'string') |
{ |
this.setRGB(iRed); |
} |
else |
{ |
this.red = iRed; |
if (typeof iGreen != 'undefined') this.green = iGreen; |
if (typeof iBlue != 'undefined') this.blue = iBlue; |
} |
} |
|
this.fix(); |
|
return this; |
}; |
|
/** |
* Returns the difference between two colors. |
* |
* @param color2 : Color |
* @param color1 : optional Color |
* @return |
* The difference between the current color (A) |
* and another color (B) as a tuple (object) consisting |
* of the differences between each RGB color component |
* of each color. That is, if A := (r1, g1, b1) and |
* B := (r2, g2, b2) then <code>A.diff(B)</code> returns |
* B - A := (r2 - r1, g2 - g1, b2 - b1). |
* |
* If this method is passed a second Color object as |
* argument, color A will be that object instead of |
* the calling object. |
* |
* Note that since each component value of the result |
* may be negative, the result is normalized through |
* {@link Color.prototype#fix} if its properties are |
* used for creating a Color object.() |
* @type {red, green, blue} |
*/ |
Color.prototype.diff = function(color2, color1) { |
if (color1.constructor != Color) |
{ |
if (this.constructor == Color) |
{ |
color1 = this; |
} |
else |
{ |
jsx.throwException( |
"TypeError", |
"Color.prototype.diff(color2, color1):" |
+ " Caller must be a Color object if color1 does not refer to one"); |
} |
} |
|
return { |
red: color2.red - color1.red, |
green: color2.green - color1.green, |
blue: color2.blue - color1.blue |
}; |
}; |
|
/** |
* Fixes RGB values, i.e. brings them into range |
* if they are out of range, and returns the new value. |
* Note: Brightness/contrast are disregarded. |
* |
* @return Color |
*/ |
Color.prototype.fix = function() { |
if (this.red < 0) this.red = 0; |
if (this.red > 255) this.red = 255; |
if (this.green < 0) this.green = 0; |
if (this.green > 255) this.green = 255; |
if (this.blue < 0) this.blue = 0; |
if (this.blue > 255) this.blue = 255; |
|
return this; |
}; |
|
/** |
* Increase/decrease one or more RGB components of a color. |
* |
* @param iRed |
* @param iGreen |
* @param iBlue |
* @return Color |
*/ |
Color.prototype.inc = function(iRed, iGreen, iBlue) { |
switch (iRed.constructor) |
{ |
case String: |
iRed = new Color(iRed); |
|
case Object: |
case Color: |
if (typeof iRed.green != "undefined") iGreen = iRed.green; |
if (typeof iRed.blue != "undefined") iBlue = iRed.blue; |
iRed = iRed.red; |
break; |
|
case Array: |
if (typeof iRed[1] != "undefined") iGreen = iRed[1]; |
if (typeof iRed[2] != "undefined") iBlue = iRed[2]; |
iRed = iRed[0]; |
break; |
} |
|
this.red += (parseInt(iRed, 10) || 0); |
this.green += (parseInt(iGreen, 10) || 0); |
this.blue += (parseInt(iBlue, 10) || 0); |
|
return this.fix(); |
}; |
|
/** |
* Sets the color values from a RGB value. |
* |
* @param v : string |
* RGB value as supported by @{#Color()}. |
* @return Color |
*/ |
Color.prototype.setRGB = function(v) { |
var m; |
|
if ((m = |
new RegExp( |
'((rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\))' |
+ '|(#([0-9a-f]{3})([0-9a-f]{3})?))', |
'i').exec(v))) |
{ |
/* rgb(...) */ |
if (m[2]) |
{ |
this.red = m[3]; |
this.green = m[4]; |
this.blue = m[5]; |
} |
/* #xxxxxx */ |
else if (m[6]) |
{ |
if (m[8]) |
{ |
if ((m = |
/([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i.exec(m[7] + m[8]))) |
{ |
this.red = parseInt(m[1], 16); |
this.green = parseInt(m[2], 16); |
this.blue = parseInt(m[3], 16); |
} |
} |
/* #xxx */ |
else |
{ |
var c; |
this.red = parseInt((c = m[7].charAt(0)) + c, 16); |
this.green = parseInt((c = m[7].charAt(1)) + c, 16); |
this.blue = parseInt((c = m[7].charAt(2)) + c, 16); |
} |
} |
} |
|
this.fix(); |
|
return this; |
}; |
|
/** |
* Returns the monochrome version of a color as an object. |
* |
* @return Color |
*/ |
Color.prototype.getMono = function() { |
var v = this.getHSV().value; |
return new Color(v, v, v); |
}; |
|
/** |
* Sets the color values from Red, Green and Blue values or |
* an RGB value and returns a monochrome version of the color |
* as an object. |
* |
* @param iRed : number|string |
* Red value or RGB color. Supported formats |
* for RGB color are the same as for @{#Color()}. |
* @param iGreen : optional number |
* Green value. |
* @param iBlue : optional number |
* Blue value. |
* @return Color |
*/ |
Color.prototype.setMono = function(iRed, iGreen, iBlue) { |
this.set(iRed, iGreen, iBlue); |
|
var c = this.getMono(); |
this.red = c.red; |
this.green = c.green; |
this.blue = c.blue; |
|
return this; |
}; |
|
/** |
* Returns the next similar color to the represented color on the |
* 214-color Web-safe palette, i.e. a color where each sRGB component |
* is one of the hexadecimal values 0x00 (0), 0x33 (51), 0x66 (102), |
* 0x99 (153), 0xCC (204), and 0xFF (255). |
* |
* @return Color |
*/ |
Color.prototype.getWebSafe = function() { |
function getNearestSafeValue(v) |
{ |
if (v >= 0xFF) |
{ |
return 0xFF; |
} |
|
if (v <= 0) |
{ |
return 0; |
} |
|
for (var a = [0, 0x33, 0x66, 0x99, 0xCC, 0xFF], i = a.length-1; |
i--;) |
{ |
if (v >= a[i]) |
{ |
if (v == a[i]) |
{ |
return v; |
} |
|
if (v - a[i] < a[i+1] - v) |
{ |
return a[i]; |
} |
|
return a[i+1]; |
} |
} |
return -1; |
} |
|
return new Color( |
getNearestSafeValue(this.red), |
getNearestSafeValue(this.green), |
getNearestSafeValue(this.blue)); |
}; |
|
Color.prototype.setWebSafe = function(iRed, iGreen, iBlue) { |
this.set(iRed, iGreen, iBlue); |
|
var c = this.getWebSafe(); |
this.red = c.red; |
this.green = c.green; |
this.blue = c.blue; |
|
return this; |
}; |
|
/** |
* Returns the color in the sRGB color space as an object |
* identifying the coordinates of that color in the |
* HSV/HSB (Hue, Saturation, Value/Brightness) color space. |
* |
* @return Object |
*/ |
Color.prototype.getHSV = function() { |
/* We need the maximum value out of three */ |
if (Math.max(1, 2, 3) != 3) |
{ |
Math.max = function() { |
var result = arguments[0]; |
|
for (var i = arguments.length; i--;) |
{ |
if (result < arguments[i]) result = arguments[i]; |
} |
|
return result; |
}; |
} |
|
/* We need the minimum value out of three */ |
if (Math.min(3, 2, 1) != 1) |
{ |
Math.min = function() { |
var result = arguments[0]; |
|
for (var i = arguments.length; i--;) |
{ |
if (result > arguments[i]) result = arguments[i]; |
} |
|
return result; |
}; |
} |
|
/* Cf. http://en.wikipedia.org/wiki/HSV_color_space#Transformation_between_HSV_and_RGB */ |
var |
r = this.red / 255, |
g = this.green / 255, |
b = this.blue / 255, |
max = Math.max(r, g, b), |
min = Math.min(r, g, b), |
h = 0, /* hue */ |
s = 0, /* saturation */ |
v, /* value */ |
d = max - min; |
|
if (max != min) |
{ |
|
if (r == max) |
{ |
h = (g - b)/d * 60; |
} |
else if (g == max) |
{ |
h = (2 + (b - r)/d) * 60; |
} |
else if (b == max) |
{ |
h = (4 + (r - g)/d) * 60; |
} |
} |
|
if (h < 0) h = h + 360; |
|
if (max == 0) |
{ |
s = 0; |
} |
else |
{ |
s = 100 * (d / max); |
} |
|
v = 100 * max; |
|
return {hue: h, saturation: s, value: v}; |
}; |
|
/** |
* Returns a <code>Color</code> object, identifying a color in the |
* sRGB color space, defined by given coordinates for that color |
* in the HSV/HSB (Hue, Saturation, Value/Brightness) color space. |
* If any of the coordinates is not provided, it is assumed to be |
* 0 (zero). |
* |
* @param h : number |
* Hue, from 0 to 360 (degrees). |
* @param s : number |
* Saturation, from 0.0 to 1.0 (0 to 100%). |
* @param v : number |
* Brightness value, from 0.0 to 1.0 (0 to 100%). |
* @return Color |
*/ |
Color.prototype.HSVtoRGB = function(h, s, v) { |
/* Cf. http://en.wikipedia.org/wiki/HSV_color_space#Transformation_between_HSV_and_RGB */ |
if (s == 0.0) |
{ |
return new Color(v * 255, v * 255, v * 255); |
} |
|
var |
h_i = Math.floor(h / 60) % 6, |
f = (h / 60) - h_i, |
p = v * (1 - s), |
q = v * (1 - f * s), |
t = v * (1 - (1 - f) * s), |
r, g, b; |
|
switch (h_i) |
{ |
case 0: |
r = v; g = t; b = p; |
break; |
|
case 1: |
r = q; g = v; b = p; |
break; |
|
case 2: |
r = p; g = v; b = t; |
break; |
|
case 3: |
r = p; g = q; b = v; |
break; |
|
case 4: |
r = t; g = p; b = v; |
break; |
|
case 5: |
r = v; g = p; b = q; |
break; |
} |
|
return new Color(r * 255, g * 255, b * 255); |
}; |
|
Color.prototype.toHex = function() { |
var |
r = leadingZero(this.red.toString(16), 2), |
g = leadingZero(this.green.toString(16), 2), |
b = leadingZero(this.blue.toString(16), 2), |
rx = /([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3/i, |
m; |
|
if ((m = rx.exec([r, g, b].join('')))) |
{ |
r = m[1]; |
g = m[2]; |
b = m[3]; |
} |
|
return ['#', r, g, b].join(''); |
}; |
|
/** |
* Returns the color as a string |
* <code>rgb(<var>r</var>,<var>g</var>,<var>b</var>)</code> |
* representation supported by CSS. |
* |
* @return string |
*/ |
Color.prototype.toRGBString = |
Color.prototype.toString = function() { |
return ['rgb(', this.red, ',', this.green, ',', this.blue, ')'].join(''); |
}; |
|
/** |
* Returns the color as a string |
* <code>{red: <var>r</var>, green: <var>g</var>, blue: <var>b</var>}</code> |
* representation as supported by e.g. JSON. |
* |
* @return string |
*/ |
Color.prototype.toObjectString = function color_toObjectString() { |
return [ |
'{red: ', this.red, ', green: ', this.green, ', blue: ', this.blue, '}' |
].join(''); |
}; |
|
/** |
* Changes the current document into a monochrome version of itself. |
* |
* @requires dhtml.js |
*/ |
function makeMono() |
{ |
var |
sl = new CSSSelectorList(), |
oIt = sl.iterator(), |
s, |
c = new Color(), |
a = ['backgroundColor', 'borderColor', 'borderTopColor', |
'borderRightColor', 'borderBottomColor', 'borderLeftColor', |
'outlineColor', 'color'], |
j, |
p; |
|
while ((s = oIt.next())) |
{ |
for (j = a.length; j--;) |
{ |
if ((p = s[a[j]])) |
{ |
s[a[j]] = c.setMono(p).toString(); |
} |
} |
} |
|
for (var es = dhtml.getElemByTagName('*'), i = es && es.length; i--;) |
{ |
var e = es[i]; |
for (j = a.length; j--;) |
{ |
if ((p = e.style[a[j]])) |
{ |
e.style[a[j]] = c.setMono(p).toString(); |
} |
} |
} |
} |
|
/** |
* Returns the computed style of an element or |
* the computed value of a style property of an element. |
* |
* @param o : HTMLElement |
* @param p : string |
* @return |
* The return value depends on both the passed arguments |
* and the capabilities of the user agent: |
* |
* If the UA supports either ViewCSS::getComputedStyle() |
* from W3C DOM Level 2 CSS or MSHTML's currentStyle |
* property, then |
* a) if p was passed, the value of the style property |
* with name p is returned; it is a string if the |
* property is supported; |
* b) if p was not passed, the corresponding style object |
* is returned |
* |
* If the UA supports neither of the above, `undefined' is |
* returned. |
* @type string|CSSStyleDeclaration|currentStyle |
*/ |
function _getComputedStyle(o, p) |
{ |
var s; |
|
if (jsx.object.isMethod(document, "defaultView", "getComputedStyle") |
&& (s = document.defaultView.getComputedStyle(o, null))) |
{ |
if (p && isMethod(s, "getPropertyValue")) |
{ |
return s.getPropertyValue(p); |
} |
|
return s; |
} |
else if (typeof (s = o.currentStyle) != "undefined") |
{ |
if (p) |
{ |
return s[p]; |
} |
|
return s; |
} |
|
return s; |
} |
var currentStyle = _getComputedStyle; |
css.getComputedStyle = currentStyle; |
|
function isHidden(o) |
{ |
while (o) |
{ |
if (typeof o.style == "undefined" |
|| typeof o.style.visibility != "undefined" |
&& /hidden/i.test(o.style.visibility) |
|| /hidden/i.test(_getComputedStyle(o, "visibility"))) |
{ |
return true; |
} |
|
o = o.parentNode; |
} |
|
return false; |
} |
|
function focusElement(s) |
{ |
var o = document.getElementById(s); |
if (o && isMethod(o, "focus") && !isHidden(o)) |
{ |
o.focus(); |
} |
} |