/**************************************************************** * * * CurvyCorners * * ------------ * * * * This script generates rounded corners for your boxes. * * * * Version 2.1 * * Copyright (c) 2010 Cameron Cooke * * Contributors: Tim Hutchison, CPK Smithies, Terry Riegel, * * Simó Albert. * * * * Website: http://www.curvycorners.net * * SVN: http://curvycorners.googlecode.com/ * * Email: cameron@curvycorners.net * * Discuss: http://groups.google.com/group/curvycorners * * * * Please consult the SVN for a list of changes since the last * * revision. * * * * This library is free software; you can redistribute * * it and/or modify it under the terms of the GNU * * Lesser General Public License as published by the * * Free Software Foundation; either version 2.1 of the * * License, or (at your option) any later version. * * * * This library 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 Lesser General Public * * License for more details. * * * * You should have received a copy of the GNU Lesser * * General Public License along with this library; * * Inc., 59 Temple Place, Suite 330, Boston, * * MA 02111-1307 USA * * * ****************************************************************/ /* Version 2.x now autoMagically applies borders via CSS rules. Opera and Chrome support rounded corners via border-radius Safari and Mozilla support rounded borders via -webkit-border-radius, -moz-border-radius We let these browsers render their borders natively. Firefox for Windows renders non-antialiased borders so they look a bit ugly. Google's Chrome will render its "ugly" borders as well. So if we let FireFox, Safari, Opera and Chrome render their borders natively, then we only have to support IE for rounded borders. Fortunately IE reads CSS properties that it doesn't understand (Opera, Firefox and Safari discard them); so for IE we find and apply -moz-border-radius and friends. So to make curvycorners work with any major browser simply add the following CSS declarations and it should be good to go... .round { border-radius: 3ex; -webkit-border-radius: 3ex; -moz-border-radius: 3ex; } */ function browserdetect() { var agent = navigator.userAgent.toLowerCase(); this.isIE = agent.indexOf("msie") > -1; if (this.isIE) { this.ieVer = /msie\s(\d\.\d)/.exec(agent)[1]; this.quirksMode = !document.compatMode || document.compatMode.indexOf("BackCompat") > -1; this.get_style = function(obj, prop) { if (!(prop in obj.currentStyle)) return ""; var matches = /^([\d.]+)(\w*)/.exec(obj.currentStyle[prop]); if (!matches) return obj.currentStyle[prop]; if (matches[1] == 0) return '0'; // now convert to pixels if necessary if (matches[2] && matches[2] !== 'px') { var style = obj.style.left; var rtStyle = obj.runtimeStyle.left; obj.runtimeStyle.left = obj.currentStyle.left; obj.style.left = matches[1] + matches[2]; matches[0] = obj.style.pixelLeft; obj.style.left = style; obj.runtimeStyle.left = rtStyle; } return matches[0]; }; this.supportsCorners = false; } else { this.ieVer = this.quirksMode = 0; this.get_style = function(obj, prop) { prop = prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); return document.defaultView.getComputedStyle(obj, '').getPropertyValue(prop); }; this.isIE11 = agent.indexOf('trident/') != -1; this.isSafari = agent.indexOf('safari') != -1; this.isWebKit = agent.indexOf('webkit') != -1; this.isOp = 'opera' in window; if (this.isOp) this.supportsCorners = (this.isOp = window.opera.version()) >= 10.5; else { if (!this.isWebkit) { // firefox check if (!(this.isMoz = agent.indexOf('firefox') !== -1)) { for (var i = document.childNodes.length; --i >= 0; ) if ('style' in document.childNodes[i]) { this.isMoz = 'MozBorderRadius' in document.childNodes[i].style; break; } } } this.supportsCorners = this.isWebKit || this.isMoz; } } } var curvyBrowser = new browserdetect; /* Force caching of bg images in IE6 */ if (curvyBrowser.isIE) { try { document.execCommand("BackgroundImageCache", false, true); } catch(e) {} } // object that parses border-radius properties for a box function curvyCnrSpec(selText) { this.selectorText = selText; this.tlR = this.trR = this.blR = this.brR = 0; this.tlu = this.tru = this.blu = this.bru = ""; this.antiAlias = true; // default true } curvyCnrSpec.prototype.setcorner = function(tb, lr, radius, unit) { if (!tb) { // no corner specified this.tlR = this.trR = this.blR = this.brR = parseInt(radius); this.tlu = this.tru = this.blu = this.bru = unit; } else { // corner specified var propname = tb.charAt(0) + lr.charAt(0); this[propname + 'R'] = parseInt(radius); this[propname + 'u'] = unit; } }; /* get(propstring) where propstring is: - 'tR' or 'bR' : returns top or bottom radius. - 'tlR', 'trR', 'blR' or 'brR' : returns top/bottom left/right radius. - 'tlu', 'tru', 'blr' or 'bru' : returns t/b l/r unit (px, em...) - 'tRu' or 'bRu' : returns top/bottom radius+unit - 'tlRu', 'trRu', 'blRu', 'brRu' : returns t/b l/r radius+unit */ curvyCnrSpec.prototype.get = function(prop) { if (/^(t|b)(l|r)(R|u)$/.test(prop)) return this[prop]; if (/^(t|b)(l|r)Ru$/.test(prop)) { var pname = prop.charAt(0) + prop.charAt(1); return this[pname + 'R'] + this[pname + 'u']; } if (/^(t|b)Ru?$/.test(prop)) { var tb = prop.charAt(0); tb += this[tb + 'lR'] > this[tb + 'rR'] ? 'l' : 'r'; var retval = this[tb + 'R']; if (prop.length === 3 && prop.charAt(2) === 'u') retval += this[tb = 'u']; return retval; } throw new Error('Don\'t recognize property ' + prop); }; curvyCnrSpec.prototype.radiusdiff = function(tb) { if (tb !== 't' && tb !== 'b') throw new Error("Param must be 't' or 'b'"); return Math.abs(this[tb + 'lR'] - this[tb + 'rR']); }; curvyCnrSpec.prototype.setfrom = function(obj) { this.tlu = this.tru = this.blu = this.bru = 'px'; // default to px if ('tl' in obj) this.tlR = obj.tl.radius; if ('tr' in obj) this.trR = obj.tr.radius; if ('bl' in obj) this.blR = obj.bl.radius; if ('br' in obj) this.brR = obj.br.radius; if ('antiAlias' in obj) this.antiAlias = obj.antiAlias; }; curvyCnrSpec.prototype.cloneOn = function(box) { // not needed by IE var props = ['tl', 'tr', 'bl', 'br']; var converted = 0; var i, propu; for (i in props) if (!isNaN(i)) { propu = this[props[i] + 'u']; if (propu !== '' && propu !== 'px') { converted = new curvyCnrSpec; break; } } if (!converted) converted = this; // no need to clone else { var propi, propR, save = curvyBrowser.get_style(box, 'left'); for (i in props) if (!isNaN(i)) { propi = props[i]; propu = this[propi + 'u']; propR = this[propi + 'R']; if (propu !== 'px') { var save2 = box.style.left; box.style.left = propR + propu; propR = box.style.pixelLeft; box.style.left = save2; } converted[propi + 'R'] = propR; converted[propi + 'u'] = 'px'; } box.style.left = save; } return converted; }; curvyCnrSpec.prototype.radiusSum = function(tb) { if (tb !== 't' && tb !== 'b') throw new Error("Param must be 't' or 'b'"); return this[tb + 'lR'] + this[tb + 'rR']; }; curvyCnrSpec.prototype.radiusCount = function(tb) { var count = 0; if (this[tb + 'lR']) ++count; if (this[tb + 'rR']) ++count; return count; }; curvyCnrSpec.prototype.cornerNames = function() { var ret = []; if (this.tlR) ret.push('tl'); if (this.trR) ret.push('tr'); if (this.blR) ret.push('bl'); if (this.brR) ret.push('br'); return ret; }; /* Object that parses Opera CSS */ function operasheet(sheetnumber) { var txt = document.styleSheets.item(sheetnumber).ownerNode.text; txt = txt.replace(/\/\*(\n|\r|.)*?\*\//g, ''); // strip comments // this pattern extracts all border-radius-containing rulesets // matches will be: // [0] = the whole lot // [1] = the selector text // [2] = all the rule text between braces // [3] = top/bottom and left/right parts if present (only if webkit/CSS3) // [4] = top|bottom // [5] = left|right // .. but 3..5 are useless as they're only the first match. var pat = new RegExp("^\\s*([\\w.#][-\\w.#, ]+)[\\n\\s]*\\{([^}]+border-((top|bottom)-(left|right)-)?radius[^}]*)\\}", "mg"); var matches; this.rules = []; while ((matches = pat.exec(txt)) !== null) { var pat2 = new RegExp("(..)border-((top|bottom)-(left|right)-)?radius:\\s*([\\d.]+)(in|em|px|ex|pt)", "g"); var submatches, cornerspec = new curvyCnrSpec(matches[1]); while ((submatches = pat2.exec(matches[2])) !== null) if (submatches[1] !== "z-") cornerspec.setcorner(submatches[3], submatches[4], submatches[5], submatches[6]); this.rules.push(cornerspec); } } // static class function to determine if the sheet is worth parsing operasheet.contains_border_radius = function(sheetnumber) { return /border-((top|bottom)-(left|right)-)?radius/.test(document.styleSheets.item(sheetnumber).ownerNode.text); }; /* Usage: curvyCorners(settingsObj, "selectorStr"); curvyCorners(settingsObj, domObj1[, domObj2[, domObj3[, . . . [, domObjN]]]]); selectorStr::= "[, ]..." complexSelector::= [