PageRenderTime 59ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/files/jquery.css3finalize/3.4.0/jquery.css3finalize.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 556 lines | 435 code | 60 blank | 61 comment | 142 complexity | 0504b5ebcc380b370e76c3bfb691d5fb MD5 | raw file
  1. /*! CSS3 Finalize - v3.4.0 - 2013-03-29 - Automatically add vendor prefixes.
  2. * https://github.com/codler/jQuery-Css3-Finalize
  3. * Copyright (c) 2013 Han Lin Yap http://yap.nu; http://creativecommons.org/licenses/by-sa/3.0/ */
  4. (function ($) {
  5. // Prevent to read twice
  6. if ($.cssFinalize) {
  7. return;
  8. }
  9. $.cssFinalizeSetup = {
  10. // Which node CSS3 Finalize should read and add vendor prefixes
  11. node : 'style,link',
  12. // If it should add the vendor prefixes
  13. append : true,
  14. // This will be called for each nodes after vendor prefixes have been appended
  15. callback : function(css) {}
  16. };
  17. $.fn.cssFinalize = function(options) {
  18. if (!options || typeof options != 'object') {
  19. options = {};
  20. }
  21. options.node = this;
  22. $.cssFinalize(options);
  23. return this;
  24. };
  25. $.cssFinalize = function(options) {
  26. var div = document.createElement('div');
  27. div.style.cssText = 'background-image:linear-gradient(#9f9, white);';
  28. options = $.extend({}, $.cssFinalizeSetup, options);
  29. var deCamelCase = function(str) {
  30. return str.replace(/[A-Z]/g, function($0) { return '-' + $0.toLowerCase() });
  31. }
  32. // PropertyRules
  33. var supportRules = [];
  34. // Get current vendor prefix
  35. var currentPrefix;
  36. if (window.getComputedStyle) {
  37. var styles = getComputedStyle(document.documentElement, null);
  38. if (styles.length) {
  39. for(var i = 0; i < styles.length ; i++) {
  40. if (styles[i].charAt(0) === '-') {
  41. var pos = styles[i].indexOf('-',1);
  42. supportRules.push(styles[i].substr(pos+1));
  43. currentPrefix = styles[i].substr(1, pos-1);
  44. }
  45. }
  46. } else {
  47. // In Opera CSSStyleDeclaration objects returned by getComputedStyle have length 0
  48. for(var i in styles) {
  49. var style = deCamelCase(i);
  50. if (style.indexOf('-o-') === 0) {
  51. supportRules.push(style.substr(3));
  52. }
  53. }
  54. currentPrefix = 'o';
  55. }
  56. } else {
  57. // No vendor prefix in <ie 8
  58. return true;
  59. }
  60. // IE9 do have transform but the code above didnt detect it so I added manually
  61. if (currentPrefix == 'ms' && supportRules.indexOf('transform') === -1) {
  62. supportRules.push('transform');
  63. supportRules.push('transform-origin');
  64. } else if (currentPrefix == 'webkit') {
  65. // IE9 dont have transition and only webkit need prefixes
  66. /*
  67. supportRules.push('animation');
  68. supportRules.push('marquee');
  69. supportRules.push('text-stroke');
  70. supportRules.push('transition');
  71. supportRules.push('transition-property');
  72. */
  73. for (var i in div.style) {
  74. if (i.indexOf('webkit') === 0) {
  75. var style = deCamelCase(i);
  76. if ($.inArray(style.substr(7), supportRules) === -1) {
  77. supportRules.push(style.substr(7));
  78. }
  79. }
  80. }
  81. }
  82. function cssCamelCase(css) {
  83. var s = $.camelCase(css);
  84. return (currentPrefix == 'ms') ? s.charAt(0).toLowerCase() + s.substr(1) : s;
  85. }
  86. function cleanCss(css) {
  87. // strip multiline comment
  88. css = css.replace(/\/\*((?:[^\*]|\*[^\/])*)\*\//g, '');
  89. // remove newline
  90. css = css.replace(/\n/g, '');
  91. css = css.replace(/\r/g, '');
  92. // remove @import - Future TODO read if css was imported and parse it.
  93. css = css.replace(/\@import[^;]*;/g, '');
  94. return css;
  95. }
  96. function appendStyle(element, cssObj) {
  97. element.after('<style class="css-finalized" ' + ((element.attr('media') && element.attr('media').length > 0) ? 'media="'+element.attr('media')+'"' : '') + '>' + $.cssFinalize.cssObjToText(cssObj) + '</style>');
  98. }
  99. function parseFinalize(element, cssText) {
  100. cssText = cleanCss(cssText);
  101. if ($.trim(cssText) === '') {
  102. return;
  103. }
  104. var objCss = cssTextToObj(cssText);
  105. var cssFinalize = [];
  106. cssFinalize = addNeededAttributes(objCss);
  107. function addNeededAttributes(objCss) {
  108. var cssFinalize = [];
  109. // Look for needed attributes and add to cssFinalize
  110. $.each(objCss, function (i, block) {
  111. if (block.attributes) {
  112. var neededAttributes = findNeededAttributes(block.attributes);
  113. if (!$.isEmptyObject(neededAttributes)) {
  114. cssFinalize.push({
  115. // Selector Rules
  116. 'selector': selectorRules(block.selector),
  117. 'attributes' : neededAttributes
  118. });
  119. } else if (selectorRules(block.selector) != block.selector) {
  120. cssFinalize.push({
  121. // Selector Rules
  122. 'selector': selectorRules(block.selector),
  123. 'attributes' : findNeededAttributes(block.attributes, true)
  124. });
  125. // Recursive
  126. } else if ((neededAttributes = addNeededAttributes(block.attributes)) && neededAttributes.length > 0) {
  127. cssFinalize.push({
  128. 'selector': block.selector,
  129. 'attributes' : neededAttributes
  130. });
  131. }
  132. }
  133. });
  134. return cssFinalize;
  135. }
  136. // Mark as read
  137. element.addClass('css-finalize-read');
  138. // Append the prefixes
  139. if (cssFinalize.length > 0 && options.append) {
  140. appendStyle(element, cssFinalize);
  141. }
  142. // Callback to user
  143. if ($.isFunction(options.callback)) {
  144. options.callback.call(element, cssFinalize);
  145. }
  146. }
  147. function cssTextToObj(text) {
  148. var block = text.split(/({[^{}]*})/);
  149. // fixes recursive block at end
  150. if (block[block.length-1].indexOf('}') == -1) {
  151. block.pop();
  152. }
  153. var objCss = [];
  154. var recusiveBlock = false;
  155. var t;
  156. var tt = 0;
  157. var ttt;
  158. var i = 0;
  159. while(i < block.length) {
  160. if (i % 2 === 0) {
  161. var selector = $.trim(block[i]);
  162. if (recusiveBlock) {
  163. if (selector.indexOf('}') != -1) {
  164. selector = selector.substr(1);
  165. block[i] = selector;
  166. ttt = block.splice(tt, i - tt);
  167. ttt.shift();
  168. ttt.unshift(t[1]);
  169. objCss[objCss.length-1].attributes = cssTextToObj(ttt.join(''));
  170. recusiveBlock = false;
  171. i = tt;
  172. continue;
  173. }
  174. } else {
  175. if (selector.indexOf('{') != -1) {
  176. t = selector.split('{');
  177. selector = $.trim(t[0]);
  178. recusiveBlock = true;
  179. tt = i;
  180. }
  181. if (selector !== "") {
  182. objCss.push({'selector': selector});
  183. }
  184. }
  185. } else {
  186. if (!recusiveBlock) {
  187. objCss[objCss.length-1].attributes = cssTextAttributeToObj(block[i].substr(1, block[i].length-2));
  188. }
  189. }
  190. i++;
  191. }
  192. return objCss;
  193. }
  194. function cssTextAttributeToObj(text) {
  195. // Data URI fix
  196. var attribute;
  197. text = text.replace( /url\(([^)]+)\)/g, function(url){
  198. return url.replace( /;/g, '[cssFinalize]' );
  199. });
  200. attribute = text.split(/(:[^;]*;?)/);
  201. attribute.pop();
  202. var objAttribute = {};
  203. $.map(attribute, function(n, i) {
  204. if (i % 2 == 1) {
  205. objAttribute[$.trim(attribute[i-1])] = $.trim(n.substr(1).replace(';', '').replace( /url\(([^)]+)\)/g, function(url){
  206. return url.replace( /\[cssFinalize\]/g, ';' );
  207. }));
  208. }
  209. });
  210. return objAttribute;
  211. }
  212. function findNeededAttributes(attributes, returnAll) {
  213. // attributes is an array only if it is recursive blocks. skip those attributes.
  214. if ($.isArray(attributes)) {
  215. if (returnAll) {
  216. return $.map(attributes, function (n, i) {
  217. return {
  218. 'selector' : n.selector,
  219. 'attributes' : findNeededAttributes(n.attributes, returnAll)
  220. }
  221. });
  222. } else {
  223. return {};
  224. }
  225. }
  226. var newAttributes = {};
  227. $.each(attributes, function(property, value) {
  228. var isset = false;
  229. // Property Rules
  230. var newProperty = propertyRules(property);
  231. if (newProperty) {
  232. isset = true;
  233. newAttributes[newProperty] = value;
  234. }
  235. // Value Rules
  236. var newValue = valuesRules(property, value, newProperty);
  237. if (newValue) {
  238. isset = true;
  239. newAttributes[(newProperty) ? newProperty : property] = newValue;
  240. }
  241. // PropertyValue Rules
  242. var newPropertyValue = propertyValuesRules(property, value);
  243. if (newPropertyValue) {
  244. isset = true;
  245. $.each(newPropertyValue, function(key, value) {
  246. if (key == 'filter' && newAttributes[key]) {
  247. newAttributes[key] += ' ' + value;
  248. } else {
  249. newAttributes[key] = value;
  250. }
  251. });
  252. }
  253. if (returnAll && !isset) {
  254. newAttributes[property] = value;
  255. }
  256. });
  257. return newAttributes;
  258. }
  259. function propertyRules(property) {
  260. if ($.inArray(property, supportRules) > -1) {
  261. // Checks if the property exists in style
  262. if (!(cssCamelCase(property) in div.style)) {
  263. // Checks if vendor prefix property exists in style
  264. if (cssCamelCase('-' + currentPrefix + '-' + property) in div.style) {
  265. return '-' + currentPrefix + '-' + property;
  266. }
  267. }
  268. }
  269. return false;
  270. }
  271. function valuesRules(property, value, newProperty) {
  272. newProperty = newProperty || property;
  273. if (property == 'transition' ||
  274. property == 'transition-property') {
  275. var keys = value.split(/\s?,\s?/);
  276. var newValue = [];
  277. $.each(keys, function(keyProperty) {
  278. var v, t;
  279. if (property == 'transition') {
  280. v = keys[keyProperty].split(' ')[0];
  281. } else {
  282. v = keys[keyProperty];
  283. }
  284. if ((t = propertyRules(v)) !== false) {
  285. newValue.push(t + keys[keyProperty].substr(v.length));
  286. } else {
  287. newValue.push(keys[keyProperty]);
  288. }
  289. });
  290. return newValue.join(',');
  291. }
  292. // Only apply for webkit
  293. if (currentPrefix == 'webkit') {
  294. // calc
  295. if (value.indexOf('calc') === 0) {
  296. return '-webkit-' + value;
  297. }
  298. }
  299. // Only apply for firefox
  300. if (currentPrefix == 'moz') {
  301. // element - CSS4
  302. if (value.indexOf('element') === 0) {
  303. return '-moz-' + value;
  304. }
  305. }
  306. if (property == 'display') {
  307. // flex - Convert newer standard to IE compability
  308. if (currentPrefix == 'ms' && 'msFlexWrap' in div.style) {
  309. if (value.indexOf('flex') === 0) {
  310. return '-ms-flexbox';
  311. }
  312. if (value.indexOf('inline-flex') === 0) {
  313. return '-ms-inline-flexbox';
  314. }
  315. }
  316. if (value.indexOf('grid') === 0 ||
  317. value.indexOf('inline-grid') === 0 ||
  318. // Old - IE10 - http://www.w3.org/TR/2012/WD-css3-flexbox-20120322/
  319. value.indexOf('flexbox') === 0 ||
  320. value.indexOf('inline-flexbox') === 0 ||
  321. // W3C Candidate Recommendation, 18 September 2012 - http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/
  322. value.indexOf('flex') === 0 ||
  323. value.indexOf('inline-flex') === 0
  324. ) {
  325. return '-' + currentPrefix + '-' + value;
  326. }
  327. }
  328. if (property == 'background' ||
  329. property == 'background-image') {
  330. if (value.indexOf('linear-gradient') === 0) {
  331. // Only for IE9 - border-radius + gradient bug
  332. // http://stackoverflow.com/questions/4692686/ie9-border-radius-and-background-gradient-bleeding
  333. if (currentPrefix == 'ms' && div.style.backgroundImage.indexOf('gradient') === -1) {
  334. // Example
  335. // value = linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, .5))
  336. var da = value.replace(/^linear-gradient\s?\(\s?(.*?)\s?\)$/, '$1'),
  337. dc = [1, 1];
  338. // da = "rgba(0, 0, 0, 1), rgba(0, 0, 0, .5)"
  339. if (da.indexOf('rgba') === 0) {
  340. da = da.split(/rgba\s?\(\s?(.*?)\s?\)/);
  341. // da = ["", "0, 0, 0, 1", ", ", "0, 0, 0, .5", ""]
  342. da[1] = da[1].split(/,\s?/);
  343. da[3] = da[3].split(/,\s?/);
  344. dc[0] = da[1].pop();
  345. dc[1] = da[3].pop();
  346. da = ['rgb(' + da[1].join(',') + ')', 'rgb(' + da[3].join(',') + ')'];
  347. } else {
  348. da = da.split(/,\s?/);
  349. }
  350. if (da.length == 2) {
  351. var g = '<svg xmlns="http://www.w3.org/2000/svg" version="1.0"><defs><linearGradient id="gradient" x1="0" y1="0" x2="0" y2="100%"><stop offset="0%" style="stop-color: ' + da[0] + ';stop-opacity:' + dc[0] + '"/><stop offset="100%" style="stop-color: ' + da[1] + ';stop-opacity:' + dc[1] + '"/></linearGradient></defs><rect x="0" y="0" fill="url(#gradient)" width="100%" height="100%" /></svg>';
  352. return 'url(data:image/svg+xml,' + escape(g) + ')';
  353. }
  354. } else if (currentPrefix == 'webkit') {
  355. return '-' + currentPrefix + '-' + value;
  356. }
  357. } else if (value.indexOf('linear-gradient') > -1) {
  358. if (currentPrefix == 'webkit') {
  359. return value.replace(RegExp('(\\s|:|,)(linear-gradient)\\s*\\(', 'gi'), '$1' + '-webkit-' + '$2(');
  360. }
  361. }
  362. }
  363. return false;
  364. }
  365. // return { property : value }
  366. function propertyValuesRules(property, value) {
  367. return false;
  368. }
  369. function selectorRules(selector) {
  370. switch (currentPrefix) {
  371. case 'moz' :
  372. // ::selection
  373. selector = selector.replace('::selection', '::-moz-selection');
  374. // :input-placeholder
  375. selector = selector.replace(':input-placeholder', ':-moz-placeholder');
  376. break;
  377. case 'webkit' :
  378. // @keyframes
  379. selector = selector.replace('@keyframes', '@-webkit-keyframes');
  380. // :input-placeholder
  381. selector = selector.replace(':input-placeholder', '::-webkit-input-placeholder');
  382. break;
  383. case 'ms' :
  384. // :input-placeholder
  385. selector = selector.replace(':input-placeholder', ':-ms-input-placeholder');
  386. // @viewport
  387. selector = selector.replace('@viewport', '@-ms-viewport');
  388. break;
  389. case 'o' :
  390. // @viewport
  391. selector = selector.replace('@viewport', '@-o-viewport');
  392. break;
  393. }
  394. return selector;
  395. }
  396. if (!(options.node instanceof jQuery)) {
  397. options.node = $(options.node);
  398. }
  399. options.node.each(function(index, element) {
  400. var $this = $(this);
  401. if ($this.hasClass('css-finalize-read') || $this.hasClass('css-finalized')) {
  402. return true;
  403. }
  404. // link-tags
  405. if (this.tagName == 'LINK' && $this.attr('rel') == 'stylesheet') {
  406. load(this.href, $this);
  407. } else if(this.tagName == 'TEXTAREA') {
  408. parseFinalize($this, $this.val());
  409. } else {
  410. parseFinalize($this, $this.html());
  411. }
  412. });
  413. function load(url, element) {
  414. var loc = document.location,
  415. protocol = loc.protocol || "http:";
  416. var parts = /^(\w+:)\/\/([^\/?#:]+)(?::(\d+))?/.exec( url.toLowerCase() );
  417. var crossDomain = !!( parts &&
  418. ( parts[ 1 ] != protocol || parts[ 2 ] != loc.hostname ||
  419. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
  420. ( loc.port || ( protocol === "http:" ? 80 : 443 ) ) )
  421. );
  422. if (crossDomain) {
  423. return;
  424. }
  425. try {
  426. $('<div />').load(url, function(data) {
  427. if (data) {
  428. parseFinalize(element, data);
  429. }
  430. });
  431. } catch(e){}
  432. }
  433. var valueRules = 'background background-image transition transition-property'.split(' ');
  434. $.each(valueRules, function(property) {
  435. if ($.inArray(valueRules[property], supportRules) === -1) {
  436. setCssHook(valueRules[property], valueRules[property]);
  437. }
  438. });
  439. function setCssHook(property, newProperty) {
  440. newProperty = cssCamelCase(newProperty);
  441. $.cssHooks[cssCamelCase(property)] = {
  442. get: function( elem, computed, extra ) {
  443. if (!computed) {
  444. return elem.style[newProperty];
  445. }
  446. },
  447. set: function( elem, value ) {
  448. var newValue = valuesRules(property, value, newProperty);
  449. try {
  450. elem.style[newProperty] = (newValue) ? newValue : value;
  451. } catch (e) {}
  452. var newPropertyValue = propertyValuesRules(property, value)
  453. if (newPropertyValue) {
  454. $.each(newPropertyValue, function(key, value) {
  455. try {
  456. if (key == 'filter' && elem.style[key]) {
  457. elem.style[key] += ' ' + value;
  458. } else {
  459. elem.style[key] = value;
  460. }
  461. } catch (e) {}
  462. });
  463. }
  464. }
  465. };
  466. }
  467. };
  468. $.cssFinalize.cssObjToText = function(obj, prettyfy, indentLevel) {
  469. var text = '';
  470. prettyfy = prettyfy || false;
  471. indentLevel = indentLevel || 1;
  472. $.each(obj, function(i, block) {
  473. if (prettyfy) text += Array(indentLevel).join(' ');
  474. text += block.selector + '{';
  475. if ($.isArray(block.attributes)) {
  476. if (prettyfy) text += '\r\n' + Array(indentLevel).join(' ');
  477. text += $.cssFinalize.cssObjToText(block.attributes, prettyfy, indentLevel+1);
  478. } else {
  479. $.each(block.attributes, function(property, value) {
  480. if (prettyfy) text += '\r\n' + Array(indentLevel + 1).join(' ');
  481. text += property + ':' + value + ';';
  482. });
  483. if (prettyfy) text += '\r\n' + Array(indentLevel).join(' ');
  484. }
  485. text += '}';
  486. if (prettyfy) text += '\r\n';
  487. });
  488. return text;
  489. }
  490. $(function() {
  491. // Let user decide to parse on load or not.
  492. if (window.cssFinalize!==false) {
  493. $.cssFinalize();
  494. }
  495. });
  496. })(jQuery);