1function browserdetect() { 2 var agent = navigator.userAgent.toLowerCase(); 3 this.isIE = agent.indexOf("msie") > -1; 4 if (this.isIE) { 5 this.ieVer = /msie\s(\d\.\d)/.exec(agent)[1]; 6 this.quirksMode = !document.compatMode || document.compatMode.indexOf("BackCompat") > -1; 7 this.get_style = function(obj, prop) { 8 if (!(prop in obj.currentStyle)) return ""; 9 var matches = /^([\d.]+)(\w*)/.exec(obj.currentStyle[prop]); 10 if (!matches) return obj.currentStyle[prop]; 11 if (matches[1] == 0) return '0'; 12 // now convert to pixels if necessary 13 if (matches[2] && matches[2] !== 'px') { 14 var style = obj.style.left; 15 var rtStyle = obj.runtimeStyle.left; 16 obj.runtimeStyle.left = obj.currentStyle.left; 17 obj.style.left = matches[1] + matches[2]; 18 matches[0] = obj.style.pixelLeft; 19 obj.style.left = style; 20 obj.runtimeStyle.left = rtStyle; 21 } 22 return matches[0]; 23 }; 24 } 25 else { 26 this.ieVer = this.quirksMode = 0; 27 this.isMoz = agent.indexOf('firefox') !== -1 || ('style' in document.childNodes[1] && 'MozBorderRadius' in document.childNodes[1].style); 28 this.isSafari = agent.indexOf('safari') != -1; 29 this.isOp = 'opera' in window; 30 this.isWebKit = agent.indexOf('webkit') != -1; 31 this.get_style = function(obj, prop) { 32 prop = prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); 33 return document.defaultView.getComputedStyle(obj, '').getPropertyValue(prop); 34 }; 35 } 36} 37var curvyBrowser = new browserdetect; 38 39/* Force caching of bg images in IE6 */ 40if (curvyBrowser.isIE) { 41 try { 42 document.execCommand("BackgroundImageCache", false, true); 43 } 44 catch(e) {}; 45} 46 47// object that parses border-radius properties for a box 48 49function curvyCnrSpec(selText) { 50 this.selectorText = selText; 51 this.tlR = this.trR = this.blR = this.brR = 0; 52 this.tlu = this.tru = this.blu = this.bru = ""; 53 this.antiAlias = true; // default true 54} 55curvyCnrSpec.prototype.setcorner = function(tb, lr, radius, unit) { 56 if (!tb) { // no corner specified 57 this.tlR = this.trR = this.blR = this.brR = parseInt(radius); 58 this.tlu = this.tru = this.blu = this.bru = unit; 59 } 60 else { // corner specified 61 propname = tb.charAt(0) + lr.charAt(0); 62 this[propname + 'R'] = parseInt(radius); 63 this[propname + 'u'] = unit; 64 } 65} 66/* 67 get(propstring) 68 where propstring is: 69 - 'tR' or 'bR' : returns top or bottom radius. 70 - 'tlR', 'trR', 'blR' or 'brR' : returns top/bottom left/right radius. 71 - 'tlu', 'tru', 'blr' or 'bru' : returns t/b l/r unit (px, em...) 72 - 'tRu' or 'bRu' : returns top/bottom radius+unit 73 - 'tlRu', 'trRu', 'blRu', 'brRu' : returns t/b l/r radius+unit 74*/ 75curvyCnrSpec.prototype.get = function(prop) { 76 if (/^(t|b)(l|r)(R|u)$/.test(prop)) return this[prop]; 77 if (/^(t|b)(l|r)Ru$/.test(prop)) { 78 var pname = prop.charAt(0) + prop.charAt(1); 79 return this[pname + 'R'] + this[pname + 'u']; 80 } 81 if (/^(t|b)Ru?$/.test(prop)) { 82 var tb = prop.charAt(0); 83 tb += this[tb + 'lR'] > this[tb + 'rR'] ? 'l' : 'r'; 84 var retval = this[tb + 'R']; 85 if (prop.length === 3 && prop.charAt(2) === 'u') 86 retval += this[tb = 'u']; 87 return retval; 88 } 89 throw new Error('Don\'t recognize property ' + prop); 90} 91curvyCnrSpec.prototype.radiusdiff = function(tb) { 92 if (tb !== 't' && tb !== 'b') throw new Error("Param must be 't' or 'b'"); 93 return Math.abs(this[tb + 'lR'] - this[tb + 'rR']); 94} 95curvyCnrSpec.prototype.setfrom = function(obj) { 96 this.tlu = this.tru = this.blu = this.bru = 'px'; // default to px 97 if ('tl' in obj) this.tlR = obj.tl.radius; 98 if ('tr' in obj) this.trR = obj.tr.radius; 99 if ('bl' in obj) this.blR = obj.bl.radius; 100 if ('br' in obj) this.brR = obj.br.radius; 101 if ('antiAlias' in obj) this.antiAlias = obj.antiAlias; 102}; 103curvyCnrSpec.prototype.cloneOn = function(box) { // not needed by IE 104 var props = ['tl', 'tr', 'bl', 'br']; 105 var converted = 0; 106 var i, propu; 107 108 for (i in props) if (!isNaN(i)) { 109 propu = this[props[i] + 'u']; 110 if (propu !== '' && propu !== 'px') { 111 converted = new curvyCnrSpec; 112 break; 113 } 114 } 115 if (!converted) 116 converted = this; // no need to clone 117 else { 118 var propi, propR, save = curvyBrowser.get_style(box, 'left'); 119 for (i in props) if (!isNaN(i)) { 120 propi = props[i]; 121 propu = this[propi + 'u']; 122 propR = this[propi + 'R']; 123 if (propu !== 'px') { 124 var save = box.style.left; 125 box.style.left = propR + propu; 126 propR = box.style.pixelLeft; 127 box.style.left = save; 128 } 129 converted[propi + 'R'] = propR; 130 converted[propi + 'u'] = 'px'; 131 } 132 box.style.left = save; 133 } 134 return converted; 135}
136curvyCnrSpec.prototype.radiusSum = function(tb) { 137 if (tb !== 't' && tb !== 'b') throw new Error("Param must be 't' or 'b'"); 138 return this[tb + 'lR'] + this[tb + 'rR']; 139} 140curvyCnrSpec.prototype.radiusCount = function(tb) { 141 var count = 0; 142 if (this[tb + 'lR']) ++count; 143 if (this[tb + 'rR']) ++count; 144 return count; 145} 146curvyCnrSpec.prototype.cornerNames = function() { 147 var ret = []; 148 if (this.tlR) ret.push('tl'); 149 if (this.trR) ret.push('tr'); 150 if (this.blR) ret.push('bl'); 151 if (this.brR) ret.push('br'); 152 return ret; 153} 154 155 156/* 157 Object that parses Opera CSS 158*/ 159function operasheet(sheetnumber) { 160 var txt = document.styleSheets.item(sheetnumber).ownerNode.text; 161 txt = txt.replace(/\/\*(\n|\r|.)*?\*\//g, ''); // strip comments 162 // this pattern extracts all border-radius-containing rulesets 163 // matches will be: 164 // [0] = the whole lot 165 // [1] = the selector text 166 // [2] = all the rule text between braces 167 // [3] = top/bottom and left/right parts if present (only if webkit/CSS3) 168 // [4] = top|bottom 169 // [5] = left|right 170 // .. but 3..5 are useless as they're only the first match. 171 var pat = new RegExp("^\\s*([\\w.#][-\\w.#, ]+)[\\n\\s]*\\{([^}]+border-((top|bottom)-(left|right)-)?radius[^}]*)\\}", "mg"); 172 var matches; 173 this.rules = []; 174 while ((matches = pat.exec(txt)) !== null) { 175 var pat2 = new RegExp("(..)border-((top|bottom)-(left|right)-)?radius:\\s*([\\d.]+)(in|em|px|ex|pt)", "g"); 176 var submatches, cornerspec = new curvyCnrSpec(matches[1]); 177 while ((submatches = pat2.exec(matches[2])) !== null) 178 if (submatches[1] !== "z-") 179 cornerspec.setcorner(submatches[3], submatches[4], submatches[5], submatches[6]); 180 this.rules.push(cornerspec); 181 } 182} 183// static class function to determine if the sheet is worth parsing 184operasheet.contains_border_radius = function(sheetnumber) { 185 return /border-((top|bottom)-(left|right)-)?radius/.test(document.styleSheets.item(sheetnumber).ownerNode.text); 186} 187 188/* 189Usage: 190 191 curvyCorners(settingsObj, "selectorStr"); 192 curvyCorners(settingsObj, domObj1[, domObj2[, domObj3[, . . . [, domObjN]]]]); 193 selectorStr::= "<complexSelector>[, <complexSelector>]..." 194 complexSelector::= <selector>[ <selector] 195 selector::= "[<elementname>].classname" | "#id" 196*/ 197 198function curvyCorners() { 199 var i, j, boxCol, settings, startIndex; 200 // Check parameters 201 if (typeof arguments[0] !== "object") throw curvyCorners.newError("First parameter of curvyCorners() must be an object."); 202 if (arguments[0] instanceof curvyCnrSpec) { 203 settings = arguments[0]; 204 if (!settings.selectorText && typeof arguments[1] === 'string') 205 settings.selectorText = arguments[1]; 206 } 207 else { 208 if (typeof arguments[1] !== "object" && typeof arguments[1] !== "string") throw curvyCorners.newError("Second parameter of curvyCorners() must be an object or a class name."); 209 j = arguments[1]; 210 if (typeof j !== 'string') j = ''; 211 if (j !== '' && j.charAt(0) !== '.' && 'autoPad' in arguments[0]) j = '.' + j; // for compatibility, prefix with dot 212 settings = new curvyCnrSpec(j); 213 settings.setfrom(arguments[0]); 214 } 215 216 // Get object(s) 217 if (settings.selectorText) { 218 startIndex = 0; 219 var args = settings.selectorText.replace(/\s+$/,'').split(/,\s*/); // handle comma-separated selector list 220 boxCol = new Array; 221 222 // converts div#mybox to #mybox 223 function idof(str) { 224 var ret = str.split('#'); 225 return (ret.length === 2 ? "#" : "") + ret.pop(); 226 } 227 228 for (i = 0; i < args.length; ++i) { 229 var arg = idof(args[i]); 230 var argbits = arg.split(' '); 231 switch (arg.charAt(0)) { 232 case '#' : // id 233 j = argbits.length === 1 ? arg : argbits[0]; 234 j = document.getElementById(j.substr(1)); 235 if (j === null) 236 curvyCorners.alert("No object with ID " + arg + " exists yet.\nCall curvyCorners(settings, obj) when it is created."); 237 else if (argbits.length === 1) 238 boxCol.push(j); 239 else 240 boxCol = boxCol.concat(curvyCorners.getElementsByClass(argbits[1], j)); 241 break; 242 default : 243 if (argbits.length === 1) 244 boxCol = boxCol.concat(curvyCorners.getElementsByClass(arg)); 245 else { 246 var encloser = curvyCorners.getElementsByClass(argbits[0]); 247 for (j = 0; j < encloser.length; ++j) { 248 boxCol = boxCol.concat(curvyCorners.getElementsByClass(argbits[1], encloser[j])); 249 } 250 } 251 //break; 252 } 253 } 254 } 255 else { 256 // Get objects 257 startIndex = 1; 258 boxCol = arguments; 259 } 260 261 // Loop through each argument 262 for (i = startIndex, j = boxCol.length; i < j; ++i) { 263 if (boxCol[i] && (!('IEborderRadius' in boxCol[i].style) || boxCol[i].style.IEborderRadius != 'set')) { 264 if (boxCol[i].className && boxCol[i].className.indexOf('curvyRedraw') !== -1) { 265 if (typeof curvyCorners.redrawList === 'undefined') curvyCorners.redrawList = new Array; 266 curvyCorners.redrawList.push({ 267 node : boxCol[i], 268 spec : settings, 269 copy : boxCol[i].cloneNode(false) 270 }); 271 } 272 boxCol[i].style.IEborderRadius = 'set'; 273 var obj = new curvyObject(settings, boxCol[i]); 274 obj.applyCorners(); 275 } 276 } 277} 278curvyCorners.prototype.applyCornersToAll = function () { // now redundant 279 throw curvyCorners.newError('This function is now redundant. Just call curvyCorners(). See documentation.'); 280}; 281 282curvyCorners.redraw = function() { 283 if (!curvyBrowser.isOp && !curvyBrowser.isIE) return; 284 if (!curvyCorners.redrawList) throw curvyCorners.newError('curvyCorners.redraw() has nothing to redraw.'); 285 var old_block_value = curvyCorners.block_redraw; 286 curvyCorners.block_redraw = true; 287 for (var i in curvyCorners.redrawList) { 288 if (isNaN(i)) continue; // in case of added prototype methods 289 var o = curvyCorners.redrawList[i]; 290 if (!o.node.clientWidth) continue; // don't resize hidden boxes 291 var newchild = o.copy.cloneNode(false); 292 for (var contents = o.node.firstChild; contents != null; contents = contents.nextSibling) 293 if (contents.className === 'autoPadDiv') break; 294 if (!contents) {
295 curvyCorners.alert('Couldn\'t find autoPad DIV'); 296 break; 297 } 298 o.node.parentNode.replaceChild(newchild, o.node); 299 // remove script elements, if any 300 var scripts = contents.getElementsByTagName('script'); 301 for (var j = scripts.length - 1; j >= 0; --j) 302 scripts[j].parentNode.removeChild(scripts[j]); 303 while (contents.firstChild) newchild.appendChild(contents.removeChild(contents.firstChild)); 304 o = new curvyObject(o.spec, o.node = newchild); 305 o.applyCorners(); 306 } 307 curvyCorners.block_redraw = old_block_value; 308} 309curvyCorners.adjust = function(obj, prop, newval) { 310 if (curvyBrowser.isOp || curvyBrowser.isIE) { 311 if (!curvyCorners.redrawList) throw curvyCorners.newError('curvyCorners.adjust() has nothing to adjust.'); 312 var i, j = curvyCorners.redrawList.length; 313 for (i = 0; i < j; ++i) if (curvyCorners.redrawList[i].node === obj) break; 314 if (i === j) throw curvyCorners.newError('Object not redrawable'); 315 obj = curvyCorners.redrawList[i].copy; 316 } 317 if (prop.indexOf('.') === -1) 318 obj[prop] = newval; 319 else eval('obj.' + prop + "='" + newval + "'"); 320} 321curvyCorners.handleWinResize = function() { 322 if (!curvyCorners.block_redraw) curvyCorners.redraw(); 323} 324curvyCorners.setWinResize = function(onoff) { 325 curvyCorners.block_redraw = !onoff; 326} 327curvyCorners.newError = function(errorMessage) { 328 return new Error("curvyCorners Error:\n" + errorMessage) 329} 330curvyCorners.alert = function(errorMessage) { 331 if (typeof curvyCornersVerbose === 'undefined' || curvyCornersVerbose) alert(errorMessage); 332} 333 334// curvyCorners object (can be called directly) 335 336function curvyObject() { 337 var boxDisp; 338 this.box = arguments[1]; 339 this.settings = arguments[0]; 340 this.topContainer = this.bottomContainer = this.shell = boxDisp = null; 341 var boxWidth = this.box.clientWidth; // browser-independent IE-emulation (NB includes padding) 342 343 if (('canHaveChildren' in this.box && !this.box.canHaveChildren) || this.box.tagName === 'TABLE') 344 throw new Error(this.errmsg("You cannot apply corners to " + this.box.tagName + " elements.", "Error")); 345 if (!boxWidth && curvyBrowser.isIE) { 346 this.box.style.zoom = 1; // can force IE to calculate width 347 boxWidth = this.box.clientWidth; 348 } 349 350 // try to handle attempts to style inline elements 351 352 if (!boxWidth && curvyBrowser.get_style(this.box, 'display') === 'inline') { 353 this.box.style.display = 'inline-block'; 354 curvyCorners.alert(this.errmsg("Converting inline element to inline-block", "warning")); 355 boxWidth = this.box.clientWidth; 356 } 357 358 359 // if still no clientWidth, maybe the box or a parent has 'display:none'. 360 361 if (!boxWidth) { 362 if (!this.box.parentNode) throw this.newError("box has no parent!"); // unlikely... 363 for (boxDisp = this.box; ; boxDisp = boxDisp.parentNode) { 364 if (!boxDisp || boxDisp.tagName === 'BODY') { // we've hit the buffers 365 this.applyCorners = function() {} // make the error benign 366 curvyCorners.alert(this.errmsg("zero-width box with no accountable parent", "warning")); 367 return; 368 } 369 if (curvyBrowser.get_style(boxDisp, 'display') === 'none') break; 370 } 371 // here, we've found the box whose display is set to 'none'. 372 var boxDispSave = boxDisp.style.display; 373 boxDisp.style.display = 'block'; // display in order to get browser to calculate clientWidth 374 boxWidth = this.box.clientWidth; 375 } 376 377 // all attempts have failed 378 379 if (!boxWidth) { 380 curvyCorners.alert(this.errmsg("zero-width box, cannot display", "error")); 381 this.applyCorners = function() {} // make the error harmless 382 return; 383 } 384 if (arguments[0] instanceof curvyCnrSpec) 385 this.spec = arguments[0].cloneOn(this.box); // convert non-pixel units 386 else { 387 this.spec = new curvyCnrSpec(''); 388 this.spec.setfrom(this.settings); // no need for unit conversion, use settings param. directly 389 } 390 391 // Get box formatting details 392 var borderWidth = curvyBrowser.get_style(this.box, "borderTopWidth"); 393 var borderWidthB = curvyBrowser.get_style(this.box, "borderBottomWidth"); 394 var borderWidthL = curvyBrowser.get_style(this.box, "borderLeftWidth"); 395 var borderWidthR = curvyBrowser.get_style(this.box, "borderRightWidth"); 396 var borderColour = curvyBrowser.get_style(this.box, "borderTopColor"); 397 var borderColourB = curvyBrowser.get_style(this.box, "borderBottomColor"); 398 var borderColourL = curvyBrowser.get_style(this.box, "borderLeftColor"); 399 var borderColourR = curvyBrowser.get_style(this.box, "borderRightColor"); 400 var borderStyle = curvyBrowser.get_style(this.box, "borderTopStyle"); 401 var borderStyleB = curvyBrowser.get_style(this.box, "borderBottomStyle"); 402 var borderStyleL = curvyBrowser.get_style(this.box, "borderLeftStyle"); 403 var borderStyleR = curvyBrowser.get_style(this.box, "borderRightStyle"); 404 405 var boxColour = curvyBrowser.get_style(this.box, "backgroundColor"); 406 var backgroundImage = curvyBrowser.get_style(this.box, "backgroundImage"); 407 var backgroundRepeat= curvyBrowser.get_style(this.box, "backgroundRepeat"); 408 if (this.box.currentStyle && this.box.currentStyle.backgroundPositionX) { 409 var backgroundPosX = curvyBrowser.get_style(this.box, "backgroundPositionX"); 410 var backgroundPosY = curvyBrowser.get_style(this.box, "backgroundPositionY"); 411 } 412 else { 413 var backgroundPosX = curvyBrowser.get_style(this.box, 'backgroundPosition'); 414 backgroundPosX = backgroundPosX.split(' '); 415 var backgroundPosY = backgroundPosX[1]; 416 backgroundPosX = backgroundPosX[0]; 417 } 418 var boxPosition = curvyBrowser.get_style(this.box, "position"); 419 var topPadding = curvyBrowser.get_style(this.box, "paddingTop"); 420 var bottomPadding = curvyBrowser.get_style(this.box, "paddingBottom"); 421 var leftPadding = curvyBrowser.get_style(this.box, "paddingLeft"); 422 var rightPadding = curvyBrowser.get_style(this.box, "paddingRight"); 423 var border = curvyBrowser.get_style(this.box, "border"); 424 var filter = curvyBrowser.ieVer > 7 ? curvyBrowser.get_style(this.box, 'filter') : null; // IE8 bug fix 425 426 var topMaxRadius = this.spec.get('tR'); 427 var botMaxRadius = this.spec.get('bR'); 428 var styleToNPx = function(val) { 429 if (typeof val === 'number') return val; 430 if (typeof val !== 'string') throw new Error('unexpected styleToNPx type ' + typeof val); 431 var matches = /^[-\d.]([a-z]+)$/.exec(val); 432 if (matches && matches[1] != 'px') throw new Error('Unexpected unit ' + matches[1]); 433 if (isNaN(val = parseInt(val))) val = 0; 434 return val; 435 } 436 var min0Px = function(val) { 437 return val <= 0 ? "0" : val + "px"; 438 } 439 440 // Set formatting properties 441 try { 442 this.borderWidth = styleToNPx(borderWidth); 443 this.borderWidthB = styleToNPx(borderWidthB); 444 this.borderWidthL = styleToNPx(borderWidthL); 445 this.borderWidthR = styleToNPx(borderWidthR); 446 this.boxColour = curvyObject.format_colour(boxColour); 447 this.topPadding = styleToNPx(topPadding); 448 this.bottomPadding = styleToNPx(bottomPadding); 449 this.leftPadding = styleToNPx(leftPadding); 450 this.rightPadding = styleToNPx(rightPadding); 451 this.boxWidth = boxWidth; 452 this.boxHeight = this.box.clientHeight; 453 this.borderColour = curvyObject.format_colour(borderColour); 454 this.borderColourB = curvyObject.format_colour(borderColourB); 455 this.borderColourL = curvyObject.format_colour(borderColourL); 456 this.borderColourR = curvyObject.format_colour(borderColourR); 457 this.borderString = this.borderWidth + "px" + " " + borderStyle + " " + this.borderColour; 458 this.borderStringB = this.borderWidthB + "px" + " " + borderStyleB + " " + this.borderColourB; 459 this.borderStringL = this.borderWidthL + "px" + " " + borderStyleL + " " + this.borderColourL; 460 this.borderStringR = this.borderWidthR + "px" + " " + borderStyleR + " " + this.borderColourR; 461 this.backgroundImage = ((backgroundImage != "none")? backgroundImage : ""); 462 this.backgroundRepeat= backgroundRepeat; 463 }
464 catch(e) { 465 throw this.newError(e.message); 466 } 467 var clientHeight = this.boxHeight; 468 var clientWidth = boxWidth; // save it as it gets trampled on later 469 if (curvyBrowser.isOp) { 470 backgroundPosX = styleToNPx(backgroundPosX); 471 backgroundPosY = styleToNPx(backgroundPosY); 472 if (backgroundPosX) { 473 var t = clientWidth + this.borderWidthL + this.borderWidthR; 474 if (backgroundPosX > t) backgroundPosX = t; 475 backgroundPosX = (t / backgroundPosX * 100) + '%'; // convert to percentage 476 } 477 if (backgroundPosY) { 478 var t = clientHeight + this.borderWidth + this.borderWidthB; 479 if (backgroundPosY > t) backgroundPosY = t; 480 backgroundPosY = (t / backgroundPosY * 100) + '%'; // convert to percentage 481 } 482 } 483 if (curvyBrowser.quirksMode) { 484 } 485 else { 486 this.boxWidth -= this.leftPadding + this.rightPadding; 487 this.boxHeight -= this.topPadding + this.bottomPadding; 488 } 489 490 // Create content container 491 this.contentContainer = document.createElement("div"); 492 if (filter) this.contentContainer.style.filter = filter; // IE8 bug fix 493 while (this.box.firstChild) this.contentContainer.appendChild(this.box.removeChild(this.box.firstChild)); 494 495 if (boxPosition != "absolute") this.box.style.position = "relative"; 496 this.box.style.padding = '0'; 497 this.box.style.border = this.box.style.backgroundImage = 'none'; 498 this.box.style.backgroundColor = 'transparent'; 499 500 this.box.style.width = (clientWidth + this.borderWidthL + this.borderWidthR) + 'px'; 501 this.box.style.height = (clientHeight + this.borderWidth + this.borderWidthB) + 'px'; 502 503 // Ok we add an inner div to actually put things into this will allow us to keep the height 504 505 var newMainContainer = document.createElement("div"); 506 newMainContainer.style.position = "absolute"; 507 if (filter) newMainContainer.style.filter = filter; // IE8 bug fix 508 if (curvyBrowser.quirksMode) { 509 newMainContainer.style.width = (clientWidth + this.borderWidthL + this.borderWidthR) + 'px'; 510 } else { 511 newMainContainer.style.width = clientWidth + 'px'; 512 } 513 newMainContainer.style.height = min0Px(clientHeight + this.borderWidth + this.borderWidthB - topMaxRadius - botMaxRadius); 514 newMainContainer.style.padding = "0"; 515 newMainContainer.style.top = topMaxRadius + "px"; 516 newMainContainer.style.left = "0"; 517 if (this.borderWidthL) 518 newMainContainer.style.borderLeft = this.borderStringL; 519 if (this.borderWidth && !topMaxRadius) 520 newMainContainer.style.borderTop = this.borderString; 521 if (this.borderWidthR) 522 newMainContainer.style.borderRight = this.borderStringR; 523 if (this.borderWidthB && !botMaxRadius) 524 newMainContainer.style.borderBottom = this.borderStringB; 525 newMainContainer.style.backgroundColor = boxColour; 526 newMainContainer.style.backgroundImage = this.backgroundImage; 527 newMainContainer.style.backgroundRepeat = this.backgroundRepeat; 528 newMainContainer.style.direction = 'ltr'; 529 this.shell = this.box.appendChild(newMainContainer); 530 531 boxWidth = curvyBrowser.get_style(this.shell, "width"); 532 if (boxWidth === "" || boxWidth === "auto" || boxWidth.indexOf("%") !== -1) throw this.newError('Shell width is ' + boxWidth); 533 this.boxWidth = (boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1) ? parseInt(boxWidth) : this.shell.clientWidth; 534 535 /* 536 This method creates the corners and 537 applies them to the div element. 538 */ 539 this.applyCorners = function() { 540 /* 541 Set up background offsets. This may need to be delayed until 542 the background image is loaded. 543 */ 544 this.backgroundPosX = this.backgroundPosY = 0; 545 if (this.backgroundObject) { 546 var bgOffset = function(style, imglen, boxlen) { 547 if (style === 0) return 0; 548 var retval; 549 if (style === 'right' || style === 'bottom') return boxlen - imglen; 550 if (style === 'center') return (boxlen - imglen) / 2; 551 if (style.indexOf('%') > 0) return (boxlen - imglen) * 100 / parseInt(style); 552 return styleToNPx(style); 553 } 554 this.backgroundPosX = bgOffset(backgroundPosX, this.backgroundObject.width, clientWidth); 555 this.backgroundPosY = bgOffset(backgroundPosY, this.backgroundObject.height, clientHeight); 556 } 557 else if (this.backgroundImage) { 558 this.backgroundPosX = styleToNPx(backgroundPosX); 559 this.backgroundPosY = styleToNPx(backgroundPosY); 560 } 561 /* 562 Create top and bottom containers. 563 These will be used as a parent for the corners and bars. 564 */ 565 // Build top bar only if a top corner is to be drawn 566 if (topMaxRadius) { 567 newMainContainer = document.createElement("div"); 568 newMainContainer.style.width = this.boxWidth + "px"; 569 newMainContainer.style.fontSize = "1px"; 570 newMainContainer.style.overflow = "hidden"; 571 newMainContainer.style.position = "absolute"; 572 newMainContainer.style.paddingLeft = this.borderWidth + "px"; 573 newMainContainer.style.paddingRight = this.borderWidth + "px"; 574 newMainContainer.style.height = topMaxRadius + "px"; 575 newMainContainer.style.top = -topMaxRadius + "px"; 576 newMainContainer.style.left = -this.borderWidthL + "px"; 577 this.topContainer = this.shell.appendChild(newMainContainer); 578 } 579 // Build bottom bar only if a bottom corner is to be drawn 580 if (botMaxRadius) { 581 var newMainContainer = document.createElement("div"); 582 newMainContainer.style.width = this.boxWidth + "px"; 583 newMainContainer.style.fontSize = "1px"; 584 newMainContainer.style.overflow = "hidden"; 585 newMainContainer.style.position = "absolute"; 586 newMainContainer.style.paddingLeft = this.borderWidthB + "px"; 587 newMainContainer.style.paddingRight = this.borderWidthB + "px"; 588 newMainContainer.style.height = botMaxRadius + "px"; 589 newMainContainer.style.bottom = -botMaxRadius + "px"; 590 newMainContainer.style.left = -this.borderWidthL + "px"; 591 this.bottomContainer = this.shell.appendChild(newMainContainer); 592 } 593 594 595 var corners = this.spec.cornerNames(); // array of available corners 596 597 /* 598 Loop for each corner 599 */ 600 for (var i in corners) if (!isNaN(i)) { 601 // Get current corner type from array 602 var cc = corners[i];
603 var specRadius = this.spec[cc + 'R']; 604 // Has the user requested the currentCorner be round? 605 // Code to apply correct color to top or bottom 606 var bwidth, bcolor, borderRadius, borderWidthTB; 607 if (cc == "tr" || cc == "tl") { 608 bwidth = this.borderWidth; 609 bcolor = this.borderColour; 610 borderWidthTB = this.borderWidth; 611 } else { 612 bwidth = this.borderWidthB; 613 bcolor = this.borderColourB; 614 borderWidthTB = this.borderWidthB; 615 } 616 borderRadius = specRadius - borderWidthTB; 617 var newCorner = document.createElement("div"); 618 newCorner.style.height = this.spec.get(cc + 'Ru'); 619 newCorner.style.width = this.spec.get(cc + 'Ru'); 620 newCorner.style.position = "absolute"; 621 newCorner.style.fontSize = "1px"; 622 newCorner.style.overflow = "hidden"; 623 // THE FOLLOWING BLOCK OF CODE CREATES A ROUNDED CORNER 624 // ---------------------------------------------------- TOP 625 var intx, inty, outsideColour; 626 var trans = filter ? parseInt(/alpha\(opacity.(\d+)\)/.exec(filter)[1]) : 100; // IE8 bug fix 627 // Cycle the x-axis 628 for (intx = 0; intx < specRadius; ++intx) { 629 // Calculate the value of y1 which identifies the pixels inside the border 630 var y1 = (intx + 1 >= borderRadius) ? -1 : Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow(intx + 1, 2))) - 1; 631 // Calculate y2 and y3 only if there is a border defined 632 if (borderRadius != specRadius) { 633 var y2 = (intx >= borderRadius) ? -1 : Math.ceil(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow(intx, 2))); 634 var y3 = (intx + 1 >= specRadius) ? -1 : Math.floor(Math.sqrt(Math.pow(specRadius, 2) - Math.pow((intx+1), 2))) - 1; 635 } 636 // Calculate y4 637 var y4 = (intx >= specRadius) ? -1 : Math.ceil(Math.sqrt(Math.pow(specRadius, 2) - Math.pow(intx, 2))); 638 // Draw bar on inside of the border with foreground colour 639 if (y1 > -1) this.drawPixel(intx, 0, this.boxColour, trans, (y1 + 1), newCorner, true, specRadius); 640 // Draw border/foreground antialiased pixels and border only if there is a border defined 641 if (borderRadius != specRadius) { 642 // Cycle the y-axis 643 if (this.spec.antiAlias) { 644 for (inty = y1 + 1; inty < y2; ++inty) { 645 // For each of the pixels that need anti aliasing between the foreground and border colour draw single pixel divs 646 if (this.backgroundImage != "") { 647 var borderFract = curvyObject.pixelFraction(intx, inty, borderRadius) * 100; 648 this.drawPixel(intx, inty, bcolor, trans, 1, newCorner, borderFract >= 30, specRadius); 649 } 650 else if (this.boxColour !== 'transparent') { 651 var pixelcolour = curvyObject.BlendColour(this.boxColour, bcolor, curvyObject.pixelFraction(intx, inty, borderRadius)); 652 this.drawPixel(intx, inty, pixelcolour, trans, 1, newCorner, false, specRadius); 653 } 654 else this.drawPixel(intx, inty, bcolor, trans >> 1, 1, newCorner, false, specRadius); 655 } 656 // Draw bar for the border 657 if (y3 >= y2) { 658 if (y2 == -1) y2 = 0; 659 this.drawPixel(intx, y2, bcolor, trans, (y3 - y2 + 1), newCorner, false, 0); 660 } 661 outsideColour = bcolor; // Set the colour for the outside AA curve 662 inty = y3; // start_pos - 1 for y-axis AA pixels 663 } 664 else { // no antiAlias 665 if (y3 > y1) { // NB condition was >=, changed to avoid zero-height divs 666 this.drawPixel(intx, (y1 + 1), bcolor, trans, (y3 - y1), newCorner, false, 0); 667 } 668 } 669 } 670 else { 671 outsideColour = this.boxColour; // Set the colour for the outside curve 672 inty = y1; // start_pos - 1 for y-axis AA pixels 673 } 674 // Draw aa pixels? 675 if (this.spec.antiAlias) { 676 // Cycle the y-axis and draw the anti aliased pixels on the outside of the curve 677 while (++inty < y4) { 678 // For each of the pixels that need anti aliasing between the foreground
678/border colour & background draw single pixel divs 679 this.drawPixel(intx, inty, outsideColour, (curvyObject.pixelFraction(intx, inty , specRadius) * trans), 1, newCorner, borderWidthTB <= 0, specRadius); 680 } 681 } 682 } 683 // END OF CORNER CREATION 684 // ---------------------------------------------------- END 685 686 /* 687 Now we have a new corner we need to reposition all the pixels unless 688 the current corner is the bottom right. 689 */ 690 // Loop through all children (pixel bars) 691 for (var t = 0, k = newCorner.childNodes.length; t < k; ++t) { 692 // Get current pixel bar 693 var pixelBar = newCorner.childNodes[t]; 694 // Get current top and left properties 695 var pixelBarTop = parseInt(pixelBar.style.top); 696 var pixelBarLeft = parseInt(pixelBar.style.left); 697 var pixelBarHeight = parseInt(pixelBar.style.height); 698 // Reposition pixels 699 if (cc == "tl" || cc == "bl") { 700 pixelBar.style.left = (specRadius - pixelBarLeft - 1) + "px"; // Left 701 } 702 if (cc == "tr" || cc == "tl"){ 703 pixelBar.style.top = (specRadius - pixelBarHeight - pixelBarTop) + "px"; // Top 704 } 705 pixelBar.style.backgroundRepeat = this.backgroundRepeat; 706 707 if (this.backgroundImage) switch(cc) { 708 case "tr": 709 pixelBar.style.backgroundPosition = (this.backgroundPosX - this.borderWidthL + specRadius - clientWidth - pixelBarLeft) + "px " + (this.backgroundPosY + pixelBarHeight + pixelBarTop + this.borderWidth - specRadius) + "px"; 710 break; 711 case "tl": 712 pixelBar.style.backgroundPosition = (this.backgroundPosX - specRadius + pixelBarLeft + 1 + this.borderWidthL) + "px " + (this.backgroundPosY - specRadius + pixelBarHeight + pixelBarTop + this.borderWidth) + "px"; 713 break; 714 case "bl": 715 pixelBar.style.backgroundPosition = (this.backgroundPosX - specRadius + pixelBarLeft + 1 + this.borderWidthL) + "px " + (this.backgroundPosY - clientHeight - this.borderWidth + (curvyBrowser.quirksMode ? pixelBarTop : -pixelBarTop) + specRadius) + "px"; 716 break; 717 case "br": 718 if (curvyBrowser.quirksMode) { 719 pixelBar.style.backgroundPosition = (this.backgroundPosX - this.borderWidthL - clientWidth + specRadius - pixelBarLeft) + "px " + (this.backgroundPosY - clientHeight - this.borderWidth + pixelBarTop + specRadius) + "px"; 720 } else { 721 pixelBar.style.backgroundPosition = (this.backgroundPosX - this.borderWidthL - clientWidth + specRadius - pixelBarLeft) + "px " + (this.backgroundPosY - clientHeight - this.borderWidth + specRadius - pixelBarTop) + "px"; 722 } 723 //break; 724 } 725 } 726 727 // Position the container 728 switch (cc) { 729 case "tl": 730 newCorner.style.top = newCorner.style.left = "0"; 731 this.topContainer.appendChild(newCorner); 732 break; 733 case "tr": 734 newCorner.style.top = newCorner.style.right = "0"; 735 this.topContainer.appendChild(newCorner); 736 break; 737 case "bl": 738 newCorner.style.bottom = newCorner.style.left = "0"; 739 this.bottomContainer.appendChild(newCorner); 740 break; 741 case "br": 742 newCorner.style.bottom = newCorner.style.right = "0"; 743 this.bottomContainer.appendChild(newCorner); 744 //break; 745 } 746 } 747 748 /* 749 The last thing to do is draw the rest of the filler DIVs. 750 */ 751 752 // Find out which corner has the bigger radius and get the difference amount 753 var radiusDiff = { 754 t : this.spec.radiusdiff('t'), 755 b : this.spec.radiusdiff('b') 756 }; 757 758 for (z in radiusDiff) { 759 if (typeof z === 'function') continue; // for prototype, mootools frameworks 760 if (!this.spec.get(z + 'R')) continue; // no need if no corners 761 if (radiusDiff[z]) { 762 // Get the type of corner that is the smaller one 763 var smallerCornerType = (this.spec[z + "lR"] < this.spec[z + "rR"]) ? z + "l" : z + "r"; 764 765 // First we need to create a DIV for the space under the smaller corner 766 var newFiller = document.createElement("div"); 767 newFiller.style.height = radiusDiff[z] + "px"; 768 newFiller.style.width = this.spec.get(smallerCornerType + 'Ru'); 769 newFiller.style.position = "absolute"; 770 newFiller.style.fontSize = "1px"; 771 newFiller.style.overflow = "hidden"; 772 newFiller.style.backgroundColor = this.boxColour;
773 if (filter) newFiller.style.filter = filter; // IE8 bug fix 774 // Set background image with original features 775 newFiller.style.backgroundImage = this.backgroundImage; 776 newFiller.style.backgroundRepeat = this.backgroundRepeat; 777 778 // Position filler 779 switch (smallerCornerType) { 780 case "tl": 781 newFiller.style.bottom = 782 newFiller.style.left = "0"; 783 newFiller.style.borderLeft = this.borderStringL; 784 // Set background image in original position 785 newFiller.style.backgroundPosition = this.backgroundPosX + "px " + (this.borderWidth + this.backgroundPosY - this.spec.tlR) + "px"; 786 this.topContainer.appendChild(newFiller); 787 break; 788 case "tr": 789 newFiller.style.bottom = 790 newFiller.style.right = "0"; 791 newFiller.style.borderRight = this.borderStringR; 792 // Set background image in original position 793 newFiller.style.backgroundPosition = (this.backgroundPosX - this.boxWidth + this.spec.trR) + "px " + (this.borderWidth + this.backgroundPosY - this.spec.trR) + "px"; 794 this.topContainer.appendChild(newFiller); 795 break; 796 case "bl": 797 newFiller.style.top = 798 newFiller.style.left = "0"; 799 newFiller.style.borderLeft = this.borderStringL; 800 // Set background image in original position 801 newFiller.style.backgroundPosition = this.backgroundPosX + "px " + (this.backgroundPosY - this.borderWidth - this.boxHeight + radiusDiff[z] + this.spec.blR) + "px"; 802 this.bottomContainer.appendChild(newFiller); 803 break; 804 case "br": 805 newFiller.style.top = 806 newFiller.style.right = "0"; 807 newFiller.style.borderRight = this.borderStringR; 808 // Set background image in original position. 809 newFiller.style.backgroundPosition = (this.borderWidthL + this.backgroundPosX - this.boxWidth + this.spec.brR) + "px " + (this.backgroundPosY - this.borderWidth - this.boxHeight + radiusDiff[z] + this.spec.brR) + "px"; 810 this.bottomContainer.appendChild(newFiller); 811 //break; 812 } 813 } 814 815 816 // Create the bar to fill the gap between each corner horizontally 817 var newFillerBar = document.createElement("div"); 818 if (filter) newFillerBar.style.filter = filter; // IE8 bug fix 819 newFillerBar.style.position = "relative"; 820 newFillerBar.style.fontSize = "1px"; 821 newFillerBar.style.overflow = "hidden"; 822 newFillerBar.style.width = this.fillerWidth(z); 823 newFillerBar.style.backgroundColor = this.boxColour; 824 newFillerBar.style.backgroundImage = this.backgroundImage; 825 newFillerBar.style.backgroundRepeat= this.backgroundRepeat; 826 827 switch (z) { 828 case "t": 829 // Top Bar 830 if (this.topContainer) { 831 if (curvyBrowser.quirksMode) { 832 newFillerBar.style.height = 100 + topMaxRadius + "px"; 833 } else { 834 newFillerBar.style.height = 100 + topMaxRadius - this.borderWidth + "px"; 835 } 836 newFillerBar.style.marginLeft = this.spec.tlR ? (this.spec.tlR - this.borderWidthL) + "px" : "0"; 837 newFillerBar.style.borderTop = this.borderString; 838 if (this.backgroundImage) { 839 var x_offset = this.spec.tlR ? 840 (this.borderWidthL + this.backgroundPosX - this.spec.tlR) + "px " : this.backgroundPosX + "px "; 841 newFillerBar.style.backgroundPosition = x_offset + this.backgroundPosY + "px"; 842 // Reposition the box's background image 843 this.shell.style.backgroundPosition = this.backgroundPosX + "px " + (this.backgroundPosY - topMaxRadius + this.borderWidthL) + "px"; 844 } 845 this.topContainer.appendChild(newFillerBar); 846 } 847 break; 848 case "b": 849 if (this.bottomContainer) { 850 // Bottom Bar 851 if (curvyBrowser.quirksMode) { 852 newFillerBar.style.height = botMaxRadius + "px"; 853 } else { 854 newFillerBar.style.height = botMaxRadius - this.borderWidthB + "px"; 855 } 856 newFillerBar.style.marginLeft = this.spec.blR ? (this.spec.blR - this.borderWidthL) + "px" : "0"; 857 newFillerBar.style.borderBottom = this.borderStringB; 858 if (this.backgroundImage) { 859 var x_offset = this.spec.blR ? 860 (this.backgroundPosX + this.borderWidthL - this.spec.blR) + "px " : this.backgroundPosX + "px "; 861 newFillerBar.style.backgroundPosition = x_offset + (this.backgroundPosY - clientHeight - this.borderWidth + botMaxRadius) + "px"; 862 } 863 this.bottomContainer.appendChild(newFillerBar); 864 } 865 //break; 866 } 867 } 868 869 // style content container 870 this.contentContainer.style.position = "absolute"; 871 // contentContainer.style.border = "1px dotted #000"; // DEBUG, comment for production 872 this.contentContainer.className = "autoPadDiv"; 873 this.contentContainer.style.left = this.borderWidthL + "px"; 874 // Get padding amounts 875 // Apply top padding 876 this.contentContainer.style.paddingTop = this.topPadding + "px"; 877 this.contentContainer.style.top = this.borderWidth + "px"; 878 // skip bottom padding - it doesn't show! 879 // Apply left and right padding 880 this.contentContainer.style.paddingLeft = this.leftPadding + "px"; 881 this.contentContainer.style.paddingRight = this.rightPadding + "px"; 882 z = clientWidth; 883 if (!curvyBrowser.quirksMode) z -= this.leftPadding + this.rightPadding; 884 this.contentContainer.style.width = z + "px"; 885 this.contentContainer.style.textAlign = curvyBrowser.get_style(this.box, 'textAlign'); 886 this.box.style.textAlign = 'left'; // important otherwise layout goes wild 887 888 this.box.appendChild(this.contentContainer); 889 if (boxDisp) boxDisp.style.display = boxDispSave; 890 } 891 if (this.backgroundImage) { 892 backgroundPosX = this.backgroundCheck(backgroundPosX); 893 backgroundPosY = this.backgroundCheck(backgroundPosY); 894 if (this.backgroundObject) { 895 this.backgroundObject.holdingElement = this; 896 this.dispatch = this.applyCorners; 897 this.applyCorners = function() { 898 if (this.backgroundObject.complete) 899 this.dispatch(); 900 else this.backgroundObject.onload = new Function('curvyObject.dispatch(this.holdingElement);'); 901 } 902 } 903 } 904} 905 906curvyObject.prototype.backgroundCheck = function(style) { 907 if (style === 'top' || style === 'left' || parseInt(style) === 0) return 0; 908 if (!(/^[-\d.]+px$/.test(style)) && !this.backgroundObject) { 909 this.backgroundObject = new Image; 910 var imgName = function(str) { 911 var matches = /url\("?([^'"]+)"?\)/.exec(str); 912 return (matches ? matches[1] : str); 913 } 914 this.backgroundObject.src = imgName(this.backgroundImage); 915 } 916 return style; 917} 918 919curvyObject.dispatch = function(obj) { 920 if ('dispatch' in obj) 921 obj.dispatch(); 922 else throw obj.newError('No dispatch function'); 923} 924 925// append a pixel DIV to newCorner 926 927curvyObject.prototype.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius) { 928 var pixel = document.createElement("div"); 929 pixel.style.height = height + "px"; 930 pixel.style.width = "1px"; 931 pixel.style.position = "absolute"; 932 pixel.style.fontSize = "1px"; 933 pixel.style.overflow = "hidden"; 934 var topMaxRadius = this.spec.get('tR'); 935 pixel.style.backgroundColor = colour; 936 // Don't apply background image to border pixels 937 if (image && this.backgroundImage != "") { 938 pixel.style.backgroundImage = this.backgroundImage; 939 pixel.style.backgroundPosition = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) - this.borderWidth) + "px"; 940 } 941 // Set opacity if the transparency is anything other than 100 942 if (transAmount != 100) curvyObject.setOpacity(pixel, transAmount); 943 // Set position 944 pixel.style.top = inty + "px"; 945 pixel.style.left = intx + "px"; 946 //pixel.nodeValue = ' '; 947 newCorner.appendChild(pixel); 948} 949 950curvyObject.prototype.fillerWidth = function(tb) { 951 var b_width, f_width; 952 b_width = curvyBrowser.quirksMode ? 0 : this.spec.radiusCount(tb) * this.borderWidthL; 953 if ((f_width = this.boxWidth - this.spec.radiusSum(tb) + b_width) < 0) 954 throw this.newError("Radius exceeds box width"); 955 return f_width + 'px'; 956} 957 958curvyObject.prototype.errmsg = function(msg, gravity) { 959 var extradata = "\ntag: " + this.box.tagName; 960 if (this.box.id) extradata += "\nid: " + this.box.id; 961 if (this.box.className) extradata += "\nclass: " + this.box.className; 962 var parent; 963 if ((parent = this.box.parentNode) === null) 964 extradata += "\n(box has no parent)"; 965 else { 966 extradata += "\nParent tag: " + parent.tagName;
967 if (parent.id) extradata += "\nParent ID: " + parent.id; 968 if (parent.className) extradata += "\nParent class: " + parent.className; 969 } 970 if (gravity === undefined) gravity = 'warning'; 971 return 'curvyObject ' + gravity + ":\n" + msg + extradata; 972} 973 974curvyObject.prototype.newError = function(msg) { 975 return new Error(this.errmsg(msg, 'exception')); 976} 977 978// ------------- UTILITY FUNCTIONS 979 980// Convert a number 0..255 to hex 981 982 983curvyObject.IntToHex = function(strNum) { 984 var hexdig = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ]; 985 986 return hexdig[strNum >>> 4] + '' + hexdig[strNum & 15]; 987} 988 989/* 990 Blends the two colours by the fraction 991 returns the resulting colour as a string in the format "#FFFFFF" 992*/ 993 994curvyObject.BlendColour = function(Col1, Col2, Col1Fraction) { 995 if (Col1 === 'transparent' || Col2 === 'transparent') throw this.newError('Cannot blend with transparent'); 996 if (Col1.charAt(0) !== '#') { 997 //curvyCorners.alert('Found colour1 ' + Col1 + ': please let us know you saw this report.'); 998 Col1 = curvyObject.format_colour(Col1); 999 } 1000 if (Col2.charAt(0) !== '#') { 1001 //curvyCorners.alert('Found colour2 ' + Col2 + ': please let us know you saw this report.'); 1002 Col2 = curvyObject.format_colour(Col2); 1003 } 1004 var red1 = parseInt(Col1.substr(1, 2), 16); 1005 var green1 = parseInt(Col1.substr(3, 2), 16); 1006 var blue1 = parseInt(Col1.substr(5, 2), 16); 1007 var red2 = parseInt(Col2.substr(1, 2), 16); 1008 var green2 = parseInt(Col2.substr(3, 2), 16); 1009 var blue2 = parseInt(Col2.substr(5, 2), 16); 1010 1011 if (Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; 1012 1013 var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); 1014 if (endRed > 255) endRed = 255; 1015 if (endRed < 0) endRed = 0; 1016 1017 1018 var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); 1019 if (endGreen > 255) endGreen = 255; 1020 if (endGreen < 0) endGreen = 0; 1021 1022 var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); 1023 if (endBlue > 255) endBlue = 255; 1024 if (endBlue < 0) endBlue = 0; 1025 1026 return "#" + curvyObject.IntToHex(endRed) + curvyObject.IntToHex(endGreen)+ curvyObject.IntToHex(endBlue); 1027} 1028 1029/* 1030 For a pixel cut by the line determines the fraction of the pixel on the 'inside' of the 1031 line. Returns a number between 0 and 1 1032*/ 1033 1034curvyObject.pixelFraction = function(x, y, r) { 1035 var fraction; 1036 var rsquared = r * r; 1037 1038 /* 1039 determine the co-ordinates of the two points on the perimeter of the pixel that the 1040 circle crosses 1041 */ 1042 var xvalues = new Array(2); 1043 var yvalues = new Array(2); 1044 var point = 0; 1045 var whatsides = ""; 1046 1047 // x + 0 = Left 1048 var intersect = Math.sqrt(rsquared - Math.pow(x, 2)); 1049 1050 if (intersect >= y && intersect < (y + 1)) { 1051 whatsides = "Left"; 1052 xvalues[point] = 0; 1053 yvalues[point] = intersect - y; 1054 ++point; 1055 } 1056 // y + 1 = Top 1057 intersect = Math.sqrt(rsquared - Math.pow(y + 1, 2)); 1058 1059 if (intersect >= x && intersect < (x + 1)) { 1060 whatsides += "Top"; 1061 xvalues[point] = intersect - x; 1062 yvalues[point] = 1; 1063 ++point; 1064 } 1065 // x + 1 = Right 1066 intersect = Math.sqrt(rsquared - Math.pow(x + 1, 2)); 1067 1068 if (intersect >= y && intersect < (y + 1)) { 1069 whatsides += "Right"; 1070 xvalues[point] = 1; 1071 yvalues[point] = intersect - y; 1072 ++point; 1073 } 1074 // y + 0 = Bottom 1075 intersect = Math.sqrt(rsquared - Math.pow(y, 2)); 1076 1077 if (intersect >= x && intersect < (x + 1)) { 1078 whatsides += "Bottom"; 1079 xvalues[point] = intersect - x; 1080 yvalues[point] = 0; 1081 } 1082 1083 /* 1084 depending on which sides of the perimeter of the pixel the circle crosses calculate the 1085 fraction of the pixel inside the circle 1086 */ 1087 switch (whatsides) { 1088 case "LeftRight": 1089 fraction = Math.min(yvalues[0], yvalues[1]) + ((Math.max(yvalues[0], yvalues[1]) - Math.min(yvalues[0], yvalues[1])) / 2); 1090 break; 1091 1092 case "TopRight": 1093 fraction = 1 - (((1 - xvalues[0]) * (1 - yvalues[1])) / 2); 1094 break; 1095 1096 case "TopBottom": 1097 fraction = Math.min(xvalues[0], xvalues[1]) + ((Math.max(xvalues[0], xvalues[1]) - Math.min(xvalues[0], xvalues[1])) / 2); 1098 break; 1099 1100 case "LeftBottom": 1101 fraction = yvalues[0] * xvalues[1] / 2; 1102 break; 1103 1104 default: 1105 fraction = 1; 1106 } 1107 1108 return fraction; 1109} 1110 1111// Returns an array of rgb values 1112 1113curvyObject.rgb2Array = function(rgbColour) { 1114 // Remove rgb() 1115 var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); 1116 1117 // Split RGB into array 1118 return rgbValues.split(", "); 1119} 1120 1121// This function converts CSS rgb(x, x, x) to hexadecimal 1122 1123curvyObject.rgb2Hex = function(rgbColour) { 1124 try { 1125 // Get array of RGB values 1126 var rgbArray = curvyObject.rgb2Array(rgbColour); 1127 1128 // Get RGB values 1129 var red = parseInt(rgbArray[0]); 1130 var green = parseInt(rgbArray[1]); 1131 var blue = parseInt(rgbArray[2]); 1132 1133 // Build hex colour code 1134 var hexColour = "#" + curvyObject.IntToHex(red) + curvyObject.IntToHex(green) + curvyObject.IntToHex(blue); 1135 }
1136 catch (e) { 1137 var msg = 'getMessage' in e ? e.getMessage() : e.message; 1138 throw new Error("Error (" + msg + ") converting RGB value to Hex in rgb2Hex"); 1139 } 1140 1141 return hexColour; 1142} 1143 1144/* 1145 Function by Simon Willison from sitepoint.com 1146 Modified by Cameron Cooke adding Safari's rgba support 1147*/ 1148 1149curvyObject.setOpacity = function(obj, opacity) { 1150 opacity = (opacity == 100) ? 99.999 : opacity; 1151 1152 if (curvyBrowser.isSafari && obj.tagName != "IFRAME") { 1153 // Get array of RGB values 1154 var rgbArray = curvyObject.rgb2Array(obj.style.backgroundColor); 1155 1156 // Get RGB values 1157 var red = parseInt(rgbArray[0]); 1158 var green = parseInt(rgbArray[1]); 1159 var blue = parseInt(rgbArray[2]); 1160 1161 // Safari using RGBA support 1162 obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")"; 1163 } 1164 else if (typeof obj.style.opacity !== "undefined") { // W3C 1165 obj.style.opacity = opacity / 100; 1166 } 1167 else if (typeof obj.style.MozOpacity !== "undefined") { // Older Mozilla 1168 obj.style.MozOpacity = opacity / 100; 1169 } 1170 else if (typeof obj.style.filter !== "undefined") { // IE 1171 obj.style.filter = "alpha(opacity=" + opacity + ")"; 1172 } 1173 else if (typeof obj.style.KHTMLOpacity !== "undefined") { // Older KHTML-based browsers 1174 obj.style.KHTMLOpacity = opacity / 100; 1175 } 1176} 1177 1178 1179// Cross browser add event wrapper 1180 1181curvyCorners.addEvent = function(elm, evType, fn, useCapture) { 1182 if (elm.addEventListener) { 1183 elm.addEventListener(evType, fn, useCapture); 1184 return true; 1185 } 1186 if (elm.attachEvent) return elm.attachEvent('on' + evType, fn); 1187 elm['on' + evType] = fn; 1188 return false; 1189} 1190if (typeof addEvent === 'undefined') addEvent = curvyCorners.addEvent; // only if necessary 1191 1192// Gets the computed colour. 1193curvyObject.getComputedColour = function(colour) { 1194 var d = document.createElement('DIV'); 1195 d.style.backgroundColor = colour; 1196 document.body.appendChild(d); 1197 1198 if (window.getComputedStyle) { // Mozilla, Opera, Chrome, Safari 1199 var rtn = document.defaultView.getComputedStyle(d, null).getPropertyValue('background-color'); 1200 d.parentNode.removeChild(d); 1201 if (rtn.substr(0, 3) === "rgb") rtn = curvyObject.rgb2Hex(rtn); 1202 return rtn; 1203 } 1204 else { // IE 1205 var rng = document.body.createTextRange(); 1206 rng.moveToElementText(d); 1207 rng.execCommand('ForeColor', false, colour); 1208 var iClr = rng.queryCommandValue('ForeColor'); 1209 var rgb = "rgb("+(iClr & 0xFF)+", "+((iClr & 0xFF00)>>8)+", "+((iClr & 0xFF0000)>>16)+")"; 1210 d.parentNode.removeChild(d); 1211 rng = null; 1212 return curvyObject.rgb2Hex(rgb); 1213 } 1214} 1215 1216// convert colour name, rgb() and #RGB to #RRGGBB 1217curvyObject.format_colour = function(colour) { 1218 // Make sure colour is set and not transparent 1219 if (colour != "" && colour != "transparent") { 1220 // RGB Value? 1221 if (colour.substr(0, 3) === "rgb") { 1222 // Get HEX aquiv. 1223 colour = curvyObject.rgb2Hex(colour); 1224 } 1225 else if (colour.charAt(0) !== '#') { 1226 // Convert colour name to hex value 1227 colour = curvyObject.getComputedColour(colour); 1228 } 1229 else if (colour.length === 4) { 1230 // 3 chr colour code add remainder 1231 colour = "#" + colour.charAt(1) + colour.charAt(1) + colour.charAt(2) + colour.charAt(2) + colour.charAt(3) + colour.charAt(3); 1232 } 1233 } 1234 return colour; 1235} 1236 1237 1238// Get elements by class by Dustin Diaz / CPKS 1239// NB if searchClass is a class name, it MUST be preceded by '.' 1240 1241curvyCorners.getElementsByClass = function(searchClass, node) { 1242 var classElements = new Array; 1243 if (node === undefined) node = document; 1244 searchClass = searchClass.split('.'); // see if there's a tag in there 1245 var tag = '*'; // prepare for no tag 1246 if (searchClass.length === 1) { 1247 tag = searchClass[0]; 1248 searchClass = false; 1249 } 1250 else { 1251 if (searchClass[0]) tag = searchClass[0]; 1252 searchClass = searchClass[1]; 1253 } 1254 var i, els, elsLen; 1255 if (tag.charAt(0) === '#') { 1256 els = document.getElementById(tag.substr(1)); 1257 if (els) classElements.push(els); 1258 } 1259 else { 1260 els = node.getElementsByTagName(tag); 1261 elsLen = els.length; 1262 if (searchClass) { 1263 var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)"); 1264 for (i = 0; i < elsLen; ++i) { 1265 if (pattern.test(els[i].className)) classElements.push(els[i]); 1266 } 1267 } 1268 else for (i = 0; i < elsLen; ++i) classElements.push(els[i]); 1269 } 1270 return classElements; 1271} 1272 1273if (curvyBrowser.isMoz || curvyBrowser.isWebKit) { 1274 var curvyCornersNoAutoScan = true; // it won't do anything anyway. 1275 curvyCorners.init = function() {}; // make it harmless 1276}
1276 1277else { 1278 1279 // autoscan code 1280 1281 curvyCorners.scanStyles = function() { 1282 function units(num) { 1283 if (!parseInt(num)) return 'px'; // '0' becomes '0px' for simplicity's sake 1284 var matches = /^[\d.]+(\w+)$/.exec(num); 1285 return matches[1]; 1286 } 1287 var t, i, j; 1288 1289 if (curvyBrowser.isIE) { 1290 function procIEStyles(rule) { 1291 var style = rule.style; 1292 1293 if (curvyBrowser.ieVer > 6.0) { 1294 var allR = style['-webkit-border-radius'] || 0; 1295 var tR = style['-webkit-border-top-right-radius'] || 0; 1296 var tL = style['-webkit-border-top-left-radius'] || 0; 1297 var bR = style['-webkit-border-bottom-right-radius'] || 0; 1298 var bL = style['-webkit-border-bottom-left-radius'] || 0; 1299 } 1300 else { 1301 var allR = style['webkit-border-radius'] || 0; 1302 var tR = style['webkit-border-top-right-radius'] || 0; 1303 var tL = style['webkit-border-top-left-radius'] || 0; 1304 var bR = style['webkit-border-bottom-right-radius'] || 0; 1305 var bL = style['webkit-border-bottom-left-radius'] || 0; 1306 } 1307 if (allR || tL || tR || bR || bL) { 1308 var settings = new curvyCnrSpec(rule.selectorText); 1309 if (allR) 1310 settings.setcorner(null, null, parseInt(allR), units(allR)); 1311 else { 1312 if (tR) settings.setcorner('t', 'r', parseInt(tR), units(tR)); 1313 if (tL) settings.setcorner('t', 'l', parseInt(tL), units(tL)); 1314 if (bL) settings.setcorner('b', 'l', parseInt(bL), units(bL)); 1315 if (bR) settings.setcorner('b', 'r', parseInt(bR), units(bR)); 1316 } 1317 curvyCorners(settings); 1318 } 1319 } 1320 for (t = 0; t < document.styleSheets.length; ++t) { 1321 try { 1322 if (document.styleSheets[t].imports) { 1323 for (i = 0; i < document.styleSheets[t].imports.length; ++i) 1324 for (j = 0; j < document.styleSheets[t].imports[i].rules.length; ++j) 1325 procIEStyles(document.styleSheets[t].imports[i].rules[j]); 1326 } 1327 for (i = 0; i < document.styleSheets[t].rules.length; ++i) 1328 procIEStyles(document.styleSheets[t].rules[i]); 1329 } 1330 catch (e) { 1331 if (typeof curvyCornersVerbose !== 'undefined' && curvyCornersVerbose) 1332 alert(e.message + " - ignored"); 1333 } // catch but ignore any permission error 1334 } 1335 } 1336 else if (curvyBrowser.isOp) { 1337 for (t = 0; t < document.styleSheets.length; ++t) { 1338 if (operasheet.contains_border_radius(t)) { 1339 j = new operasheet(t); 1340 for (i in j.rules) if (!isNaN(i)) 1341 curvyCorners(j.rules[i]); 1342 } 1343 } 1344 } 1345 else curvyCorners.alert('Scanstyles does nothing in Webkit/Firefox'); 1346 }; 1347 1348 // Dean Edwards/Matthias Miller/John Resig 1349 1350 curvyCorners.init = function() { 1351 // quit if this function has already been called 1352 if (arguments.callee.done) return; 1353 1354 // flag this function so we don't do the same thing twice 1355 arguments.callee.done = true; 1356 1357 // kill the timer 1358 if (curvyBrowser.isWebKit && curvyCorners.init.timer) { 1359 clearInterval(curvyCorners.init.timer); 1360 curvyCorners.init.timer = null; 1361 } 1362 1363 // do stuff 1364 curvyCorners.scanStyles(); 1365 }; 1366} 1367 1368if (typeof curvyCornersNoAutoScan === 'undefined' || curvyCornersNoAutoScan === false) { 1369 if (curvyBrowser.isOp) 1370 document.addEventListener("DOMContentLoaded", curvyCorners.init, false); 1371 else curvyCorners.addEvent(window, 'load', curvyCorners.init, false); 1372}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.