jquery.corners.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*!
  2. * jQuery Corners 0.3
  3. * Copyright (c) 2008 David Turnbull, Steven Wittens
  4. * Dual licensed under the MIT (MIT-LICENSE.txt)
  5. * and GPL (GPL-LICENSE.txt) licenses.
  6. */
  7. jQuery.fn.corners = function(options) {
  8. var doneClass = 'rounded_by_jQuery_corners'; /* To prevent double rounding */
  9. var settings = parseOptions(options);
  10. var webkitAvailable = false;
  11. try {
  12. webkitAvailable = (document.body.style.WebkitBorderRadius !== undefined);
  13. /* Google Chrome corners look awful */
  14. var versionIndex = navigator.userAgent.indexOf('Chrome');
  15. if (versionIndex >= 0) webkitAvailable = false;
  16. } catch(err) {}
  17. var mozillaAvailable = false;
  18. try {
  19. mozillaAvailable = (document.body.style.MozBorderRadius !== undefined);
  20. /* Firefox 2 corners look worse */
  21. var versionIndex = navigator.userAgent.indexOf('Firefox');
  22. if (versionIndex >= 0 && parseInt(navigator.userAgent.substring(versionIndex+8)) < 3) mozillaAvailable = false;
  23. } catch(err) {}
  24. return this.each(function(i,e){
  25. $e = jQuery(e);
  26. if ($e.hasClass(doneClass)) return;
  27. $e.addClass(doneClass);
  28. var classScan = /{(.*)}/.exec(e.className);
  29. var s = classScan ? parseOptions(classScan[1], settings) : settings;
  30. var nodeName = e.nodeName.toLowerCase();
  31. if (nodeName=='input') e = changeInput(e);
  32. if (webkitAvailable && s.webkit) roundWebkit(e, s);
  33. else if(mozillaAvailable && s.mozilla && (s.sizex == s.sizey)) roundMozilla(e, s);
  34. else {
  35. var bgColor = backgroundColor(e.parentNode);
  36. var fgColor = backgroundColor(e);
  37. switch (nodeName) {
  38. case 'a':
  39. case 'input':
  40. roundLink(e, s, bgColor, fgColor);
  41. break;
  42. default:
  43. roundDiv(e, s, bgColor, fgColor);
  44. break;
  45. }
  46. }
  47. });
  48. function roundWebkit(e, s) {
  49. var radius = '' + s.sizex + 'px ' + s.sizey + 'px';
  50. var $e = jQuery(e);
  51. if (s.tl) $e.css('WebkitBorderTopLeftRadius', radius);
  52. if (s.tr) $e.css('WebkitBorderTopRightRadius', radius);
  53. if (s.bl) $e.css('WebkitBorderBottomLeftRadius', radius);
  54. if (s.br) $e.css('WebkitBorderBottomRightRadius', radius);
  55. }
  56. function roundMozilla(e, s)
  57. {
  58. var radius = '' + s.sizex + 'px';
  59. var $e = jQuery(e);
  60. if (s.tl) $e.css('-moz-border-radius-topleft', radius);
  61. if (s.tr) $e.css('-moz-border-radius-topright', radius);
  62. if (s.bl) $e.css('-moz-border-radius-bottomleft', radius);
  63. if (s.br) $e.css('-moz-border-radius-bottomright', radius);
  64. }
  65. function roundLink(e, s, bgColor, fgColor) {
  66. var table = tableElement("table");
  67. var tbody = tableElement("tbody");
  68. table.appendChild(tbody);
  69. var tr1 = tableElement("tr");
  70. var td1 = tableElement("td", "top");
  71. tr1.appendChild(td1);
  72. var tr2 = tableElement("tr");
  73. var td2 = relocateContent(e, s, tableElement("td"));
  74. tr2.appendChild(td2);
  75. var tr3 = tableElement("tr");
  76. var td3 = tableElement("td", "bottom");
  77. tr3.appendChild(td3);
  78. if (s.tl||s.tr) {
  79. tbody.appendChild(tr1);
  80. addCorners(td1, s, bgColor, fgColor, true);
  81. }
  82. tbody.appendChild(tr2);
  83. if (s.bl||s.br) {
  84. tbody.appendChild(tr3);
  85. addCorners(td3, s, bgColor, fgColor, false);
  86. }
  87. e.appendChild(table);
  88. /* Clicking on $('a>table') in IE will trigger onclick but not the href */
  89. if (jQuery.browser.msie) table.onclick = ieLinkBypass;
  90. /* Firefox 2 will render garbage unless we hide the overflow here */
  91. e.style.overflow = 'hidden';
  92. }
  93. function ieLinkBypass() {
  94. if (!this.parentNode.onclick) this.parentNode.click();
  95. }
  96. function changeInput(e) {
  97. var a1 = document.createElement("a");
  98. a1.id = e.id;
  99. a1.className = e.className;
  100. if (e.onclick) {
  101. a1.href = 'javascript:'
  102. a1.onclick = e.onclick;
  103. } else {
  104. jQuery(e).parent('form').each(function() {a1.href = this.action;});
  105. a1.onclick = submitForm;
  106. }
  107. var a2 = document.createTextNode(e.value);
  108. a1.appendChild(a2);
  109. e.parentNode.replaceChild(a1, e);
  110. return a1;
  111. }
  112. function submitForm() {
  113. jQuery(this).parent('form').each(function() {this.submit()});
  114. return false;
  115. }
  116. function roundDiv(e, s, bgColor, fgColor) {
  117. var div = relocateContent(e, s, document.createElement('div'));
  118. e.appendChild(div);
  119. if (s.tl||s.tr) addCorners(e, s, bgColor, fgColor, true);
  120. if (s.bl||s.br) addCorners(e, s, bgColor, fgColor, false);
  121. }
  122. function relocateContent(e, s, d) {
  123. var $e = jQuery(e);
  124. var c;
  125. while(c=e.firstChild) d.appendChild(c);
  126. if (e.style.height) {
  127. var h = parseInt($e.css('height'));
  128. d.style.height = h + 'px';
  129. h += parseInt($e.css('padding-top')) + parseInt($e.css('padding-bottom'));
  130. e.style.height = h + 'px';
  131. }
  132. if (e.style.width) {
  133. var w = parseInt($e.css('width'));
  134. d.style.width = w + 'px';
  135. w += parseInt($e.css('padding-left')) + parseInt($e.css('padding-right'));
  136. e.style.width = w + 'px';
  137. }
  138. d.style.paddingLeft = $e.css('padding-left');
  139. d.style.paddingRight = $e.css('padding-right');
  140. if (s.tl||s.tr) {
  141. d.style.paddingTop = adjustedPadding(e, s, $e.css('padding-top'), true);
  142. } else {
  143. d.style.paddingTop = $e.css('padding-top');
  144. }
  145. if (s.bl||s.br) {
  146. d.style.paddingBottom = adjustedPadding(e, s, $e.css('padding-bottom'), false);
  147. } else {
  148. d.style.paddingBottom = $e.css('padding-bottom');
  149. }
  150. e.style.padding = 0;
  151. return d;
  152. }
  153. function adjustedPadding(e, s, pad, top) {
  154. if (pad.indexOf("px") < 0) {
  155. try {
  156. //TODO Make this check work otherwise remove it
  157. console.error('%s padding not in pixels', (top ? 'top' : 'bottom'), e);
  158. }
  159. catch(err) {}
  160. pad = s.sizey + 'px';
  161. }
  162. pad = parseInt(pad);
  163. if (pad - s.sizey < 0) {
  164. try {
  165. console.error('%s padding is %ipx for %ipx corner:', (top ? 'top' : 'bottom'), pad, s.sizey, e);
  166. }
  167. catch(err) {}
  168. pad = s.sizey;
  169. }
  170. return pad - s.sizey + 'px';
  171. }
  172. function tableElement(kind, valign) {
  173. var e = document.createElement(kind)
  174. e.style.border = 'none';
  175. e.style.borderCollapse = 'collapse';
  176. e.style.borderSpacing = 0;
  177. e.style.padding = 0;
  178. e.style.margin = 0;
  179. if (valign) e.style.verticalAlign = valign;
  180. return e;
  181. }
  182. function backgroundColor(e) {
  183. try {
  184. var c = jQuery.css(e, "background-color");
  185. if ( c.match(/^(transparent|rgba\(0,\s*0,\s*0,\s*0\))$/i) && e.parentNode )
  186. return backgroundColor(e.parentNode);
  187. if (c==null)
  188. return "#ffffff";
  189. if (c.indexOf("rgb") > -1)
  190. c = rgb2hex(c);
  191. if (c.length == 4)
  192. c = hexShort2hex(c);
  193. return c;
  194. } catch(err) {
  195. return "#ffffff";
  196. }
  197. }
  198. function hexShort2hex(c) {
  199. return '#' +
  200. c.substring(1,2) +
  201. c.substring(1,2) +
  202. c.substring(2,3) +
  203. c.substring(2,3) +
  204. c.substring(3,4) +
  205. c.substring(3,4);
  206. }
  207. function rgb2hex(c) {
  208. var x = 255;
  209. var hex = '';
  210. var i;
  211. var regexp=/([0-9]+)[, ]+([0-9]+)[, ]+([0-9]+)/;
  212. var array=regexp.exec(c);
  213. for(i=1;i<4;i++) hex += ('0'+parseInt(array[i]).toString(16)).slice(-2);
  214. return '#'+hex;
  215. }
  216. function parseOptions(options, settings) {
  217. var options = options || '';
  218. var s = {sizex:5, sizey:5, tl: false, tr: false, bl: false, br: false, webkit:true, mozilla: true, transparent:false};
  219. if (settings) {
  220. s.sizex = settings.sizex;
  221. s.sizey = settings.sizey;
  222. s.webkit = settings.webkit;
  223. s.transparent = settings.transparent;
  224. s.mozilla = settings.mozilla;
  225. }
  226. var sizex_set = false;
  227. var corner_set = false;
  228. jQuery.each(options.split(' '), function(idx, option) {
  229. option = option.toLowerCase();
  230. var i = parseInt(option);
  231. if (i > 0 && option == i + 'px') {
  232. s.sizey = i;
  233. if (!sizex_set) s.sizex = i;
  234. sizex_set = true;
  235. } else switch (option) {
  236. case 'no-native': s.webkit = s.mozilla = false; break;
  237. case 'webkit': s.webkit = true; break;
  238. case 'no-webkit': s.webkit = false; break;
  239. case 'mozilla': s.mozilla = true; break;
  240. case 'no-mozilla': s.mozilla = false; break;
  241. case 'anti-alias': s.transparent = false; break;
  242. case 'transparent': s.transparent = true; break;
  243. case 'top': corner_set = s.tl = s.tr = true; break;
  244. case 'right': corner_set = s.tr = s.br = true; break;
  245. case 'bottom': corner_set = s.bl = s.br = true; break;
  246. case 'left': corner_set = s.tl = s.bl = true; break;
  247. case 'top-left': corner_set = s.tl = true; break;
  248. case 'top-right': corner_set = s.tr = true; break;
  249. case 'bottom-left': corner_set = s.bl = true; break;
  250. case 'bottom-right': corner_set = s.br = true; break;
  251. }
  252. });
  253. if (!corner_set) {
  254. if (!settings) {
  255. s.tl = s.tr = s.bl = s.br = true;
  256. } else {
  257. s.tl = settings.tl;
  258. s.tr = settings.tr;
  259. s.bl = settings.bl;
  260. s.br = settings.br;
  261. }
  262. }
  263. return s;
  264. }
  265. function alphaBlend(a, b, alpha) {
  266. var ca = Array(
  267. parseInt('0x' + a.substring(1, 3)),
  268. parseInt('0x' + a.substring(3, 5)),
  269. parseInt('0x' + a.substring(5, 7))
  270. );
  271. var cb = Array(
  272. parseInt('0x' + b.substring(1, 3)),
  273. parseInt('0x' + b.substring(3, 5)),
  274. parseInt('0x' + b.substring(5, 7))
  275. );
  276. r = '0' + Math.round(ca[0] + (cb[0] - ca[0])*alpha).toString(16);
  277. g = '0' + Math.round(ca[1] + (cb[1] - ca[1])*alpha).toString(16);
  278. b = '0' + Math.round(ca[2] + (cb[2] - ca[2])*alpha).toString(16);
  279. return '#'
  280. + r.substring(r.length - 2)
  281. + g.substring(g.length - 2)
  282. + b.substring(b.length - 2);
  283. }
  284. function addCorners(e, s, bgColor, fgColor, top) {
  285. if (s.transparent) addTransparentCorners(e, s, bgColor, top);
  286. else addAntiAliasedCorners(e, s, bgColor, fgColor, top);
  287. }
  288. function addAntiAliasedCorners(e, s, bgColor, fgColor, top) {
  289. var i, j;
  290. var d = document.createElement("div");
  291. d.style.fontSize = '1px';
  292. d.style.backgroundColor = bgColor;
  293. var lastarc = 0;
  294. for (i = 1; i <= s.sizey; i++) {
  295. var coverage, arc2, arc3;
  296. // Find intersection of arc with bottom of pixel row
  297. arc = Math.sqrt(1.0 - Math.pow(1.0 - i / s.sizey, 2)) * s.sizex;
  298. // Calculate how many pixels are bg, fg and blended.
  299. var n_bg = s.sizex - Math.ceil(arc);
  300. var n_fg = Math.floor(lastarc);
  301. var n_aa = s.sizex - n_bg - n_fg;
  302. // Create pixel row wrapper
  303. var x = document.createElement("div");
  304. var y = d;
  305. x.style.margin = "0px " + n_bg + "px";
  306. x.style.height = '1px';
  307. x.style.overflow = 'hidden';
  308. // Create the pixel divs for a row (at least one)
  309. for (j = 1; j <= n_aa; j++) {
  310. // Calculate coverage per pixel (approximates arc within the pixel)
  311. if (j == 1) {
  312. if (j == n_aa) {
  313. // Single pixel
  314. coverage = ((arc + lastarc) * .5) - n_fg;
  315. }
  316. else {
  317. // First in a run
  318. arc2 = Math.sqrt(1.0 - Math.pow(1.0 - (n_bg + 1) / s.sizex, 2)) * s.sizey;
  319. coverage = (arc2 - (s.sizey - i)) * (arc - n_fg - n_aa + 1) * .5;
  320. }
  321. }
  322. else if (j == n_aa) {
  323. // Last in a run
  324. arc2 = Math.sqrt(1.0 - Math.pow((s.sizex - n_bg - j + 1) / s.sizex, 2)) * s.sizey;
  325. coverage = 1.0 - (1.0 - (arc2 - (s.sizey - i))) * (1.0 - (lastarc - n_fg)) * .5;
  326. }
  327. else {
  328. // Middle of a run
  329. arc3 = Math.sqrt(1.0 - Math.pow((s.sizex - n_bg - j) / s.sizex, 2)) * s.sizey;
  330. arc2 = Math.sqrt(1.0 - Math.pow((s.sizex - n_bg - j + 1) / s.sizex, 2)) * s.sizey;
  331. coverage = ((arc2 + arc3) * .5) - (s.sizey - i);
  332. }
  333. addCornerDiv(s, x, y, top, alphaBlend(bgColor, fgColor, coverage));
  334. y = x;
  335. var x = y.cloneNode(false);
  336. x.style.margin = "0px 1px";
  337. }
  338. addCornerDiv(s, x, y, top, fgColor);
  339. lastarc = arc;
  340. }
  341. if (top)
  342. e.insertBefore(d, e.firstChild);
  343. else
  344. e.appendChild(d);
  345. }
  346. function addCornerDiv(s, x, y, top, color) {
  347. if (top && !s.tl) x.style.marginLeft = 0;
  348. if (top && !s.tr) x.style.marginRight = 0;
  349. if (!top && !s.bl) x.style.marginLeft = 0;
  350. if (!top && !s.br) x.style.marginRight = 0;
  351. x.style.backgroundColor = color;
  352. if (top)
  353. y.appendChild(x);
  354. else
  355. y.insertBefore(x, y.firstChild);
  356. }
  357. function addTransparentCorners(e, s, bgColor, top) {
  358. var d = document.createElement("div");
  359. d.style.fontSize = '1px';
  360. var strip = document.createElement('div');
  361. strip.style.overflow = 'hidden';
  362. strip.style.height = '1px';
  363. strip.style.borderColor = bgColor;
  364. strip.style.borderStyle = 'none solid';
  365. var sizex = s.sizex-1;
  366. var sizey = s.sizey-1;
  367. if (!sizey) sizey = 1; /* hint for 1x1 */
  368. for (var i=0; i < s.sizey; i++) {
  369. var w = sizex - Math.floor(Math.sqrt(1.0 - Math.pow(1.0 - i / sizey, 2)) * sizex);
  370. if (i==2 && s.sizex==6 && s.sizey==6) w = 2; /* hint for 6x6 */
  371. var x = strip.cloneNode(false);
  372. x.style.borderWidth = '0 '+ w +'px';
  373. if (top) x.style.borderWidth = '0 '+(s.tr?w:0)+'px 0 '+(s.tl?w:0)+'px';
  374. else x.style.borderWidth = '0 '+(s.br?w:0)+'px 0 '+(s.bl?w:0)+'px';
  375. top ? d.appendChild(x) : d.insertBefore(x, d.firstChild);
  376. }
  377. if (top)
  378. e.insertBefore(d, e.firstChild);
  379. else
  380. e.appendChild(d);
  381. }
  382. }