├── .bowerrc
├── .editorconfig
├── .gitignore
├── Gruntfile.js
├── LICENSE
├── README.md
├── bower.json
├── calc.js
├── dist
├── calc.js
└── calc.min.js
├── package.json
└── testcase
├── import.css
├── index.html
├── index.selectivizr.html
└── styles.css
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory" : "libs"
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = tab
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [{package.json,.scss-lint.yml}, *.hbs]
13 | indent_style = space
14 | indent_size = 2
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | libs
3 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.initConfig({
4 | pkg: grunt.file.readJSON('package.json'),
5 | uglify: {
6 | options: {
7 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
8 | },
9 | dist: {
10 | files: [
11 | {
12 | expand: true,
13 | cwd: 'dist/',
14 | src: ['**/*.js'],
15 | dest: 'dist/',
16 | ext: '.min.js'
17 | }
18 | ]
19 | }
20 | },
21 | jshint: {
22 | files: ['Gruntfile.js', 'calc.js'],
23 | options: {
24 | evil: true,
25 | // options here to override JSHint defaults
26 | globals: {
27 | console: true,
28 | module: true,
29 | document: true
30 | }
31 | }
32 | },
33 | includes: {
34 | options: {
35 | includeRegexp: /^\s*?\/\/\s*import\s+['"]?([^'"]+)['"]?\s*$/,
36 | duplicates: false,
37 | flatten: false
38 | },
39 | dist: {
40 | files: [
41 | {
42 | expand: true,
43 | src: ['calc.js', '!libs/**/*.js'],
44 | dest: 'dist/',
45 | ext: '.js'
46 | }
47 | ]
48 | }
49 | },
50 | watch: {
51 | options: {
52 | spawn: true
53 | },
54 | js: {
55 | files: ['calc.js', '!libs/**/*.js'],
56 | tasks: ['jshint', 'includes:dist', 'uglify:dist']
57 | }
58 | },
59 |
60 | });
61 |
62 | grunt.loadNpmTasks('grunt-contrib-uglify');
63 | grunt.loadNpmTasks('grunt-contrib-jshint');
64 | grunt.loadNpmTasks('grunt-contrib-watch');
65 | grunt.loadNpmTasks('grunt-includes');
66 |
67 | grunt.registerTask('default', ['jshint', 'includes:dist', 'uglify:dist']);
68 |
69 | };
70 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Robert Weber
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # A Polyfill for CSS3 calc()
2 |
3 |
4 | This is a javascript poly fill for the CSS3 [calc-function](https://developer.mozilla.org/de/docs/Web/CSS/calc).
5 |
6 | Inspired by:
7 |
8 | - [selectivizr](http://selectivizr.com/)
9 | - the original poly fill: [CJKay/PolyCalc](https://github.com/CJKay/PolyCalc)
10 | - more recently by [css.js](https://github.com/jotform/css.js)
11 |
12 | ## Usage
13 |
14 | Simply drop the link like this after you included your CSS:
15 |
16 |
17 |
18 | A test for the support if calc() is integrated based on the [Modernizr test](https://github.com/Modernizr/Modernizr/blob/924c7611c170ef2dc502582e5079507aff61e388/feature-detects/css/calc.js)
19 |
20 | Tested on Internet Explorer 8 and Android 4.0.3
21 |
22 | ## Dependencies
23 |
24 | * support for ``document.querySelectorAll``
25 | * for media queries ``window.matchMedia``
26 |
27 | ## Remarks
28 |
29 | ### Specificity
30 |
31 | This polyfill does not take specificity into account when applying styles for calc().
32 |
33 | For example if you have to rules:
34 |
35 |
36 | .element div {
37 | width: calc(50% - 230px);
38 | }
39 |
40 | div {
41 | width: calc(50% - 100px);
42 | }
43 |
44 | The first rule would apply for the ``
`` element because of higher specificity. The CSS is parsed from top to bottom and therefore the polyfill would apply the styles of the second rule. Just keep that in mind.
45 |
46 | ### Resetting
47 |
48 | This polyfill also does not detect any resetting of calc():
49 |
50 |
51 | .element div {
52 | width: calc(50% - 230px);
53 | }
54 |
55 | div {
56 | width: 50%;
57 | }
58 |
59 | The polyfill will apply the rules from the first as it is not detecting the resetting of the width in the second.
60 |
61 | ### Inline Styles
62 |
63 | Support for polyfilling inline styles is integrated. However right now there seems no way to get the unparsed contents of a ```` element in IE8 and therefore the polyfill will not work there. IF you find a way to do this let me now or make a PR.
64 |
65 | ### Media-Queries
66 |
67 | There is currently no support for libs like [respond.js](https://github.com/scottjehl/Respond) and it is not planned to add support. However the polyfill uses ``window.matchMedia`` to test for media queries. If you wish to add support for media queries for IE8 include a [polyfill](https://github.com/paulirish/matchMedia.js/) before the calc-polyfill.
68 |
69 | ## To Do
70 |
71 | * more Android testing
72 | * consider imported CSS files wie ``@import``
73 |
74 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calc-polyfill",
3 | "version": "0.1.1",
4 | "homepage": "https://github.com/closingtag/calc-polyfill",
5 | "authors": [
6 | "Robert Weber "
7 | ],
8 | "description": "A Polyfill for CSS3 calc()",
9 | "main": "dist/calc.min.js",
10 | "keywords": [
11 | "css3",
12 | "calc",
13 | "polyfill",
14 | "javascript"
15 | ],
16 | "license": "MIT",
17 | "ignore": [
18 | "**/.*",
19 | "node_modules",
20 | "bower_components",
21 | "test",
22 | "tests"
23 | ],
24 | "devDependencies": {
25 | "jquery": "1.12.0",
26 | "contentloaded": "*",
27 | "requestAnimationFrame": "~0.0.22",
28 | "selectivizr": "https://raw.githubusercontent.com/keithclark/selectivizr/master/selectivizr.js"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/calc.js:
--------------------------------------------------------------------------------
1 | /*
2 | fillcalc v0.1.0 - (c) Robert Weber, freely distributable under the terms of the MIT license.
3 | */
4 |
5 | (function (win, doc) {
6 |
7 | 'use strict';
8 |
9 | // Avoid `console` errors in browsers that lack a console.
10 | (function() {
11 | var method;
12 | var noop = function () {};
13 | var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error','exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log','markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd','timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'];
14 |
15 | var length = methods.length;
16 | var console = (window.console = window.console || {});
17 |
18 | while (length--) {
19 | method = methods[length];
20 |
21 | // Only stub undefined methods.
22 | if (!console[method]) {
23 | console[method] = noop;
24 | }
25 | }
26 | }());
27 |
28 | // We need document.querySelectorAll as we do not want to depend on any lib
29 |
30 | if (!doc.querySelectorAll) {
31 | return false;
32 | }
33 |
34 | var
35 |
36 | EMPTY = '',
37 | CALC_RULE = '^(\\s*?[\\s\\S]*):(\\s*?[\\s\\S]*?((\\-(webkit|moz)\\-)?calc\\(([\\s\\S]+)\\))[\\s\\S]*)?$',
38 | CSSRULES = '((\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})',
39 |
40 | KEYFRAMES = new RegExp('((@(-webkit-)?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})', 'gi'),
41 | FONTFACE = new RegExp('((@font-face\\s*?){([\\s\\S]*?)})', 'gi'),
42 | COMMENTS = new RegExp('(\\/\\*[\\s\\S]*?\\*\\/)', 'gi'),
43 | IMPORTS = new RegExp('@import .*?;', 'gi'),
44 | CHARSET = new RegExp('@charset .*?;', 'gi'),
45 |
46 | PERCENT = /[\d\.]+%/,
47 | PT = /\d+pt/,
48 | PIXEL = /(\d+)px/g,
49 | REMEM = /[\d\.]+r?em/,
50 | REM = /[\d\.]+rem/,
51 | EM = /[\d\.]+em/,
52 | MATH_EXP = /[\+\-\/\*]?[\d\.]+(px|%|em|rem)?/g,
53 | PLACEHOLDER = '$1',
54 | ONLYNUMBERS = /[\s\-0-9]/g,
55 |
56 | FONTSIZE = 'font-size',
57 | ADDMEDIA = '@media',
58 |
59 | onTextResize = [],
60 | onWindowResize = [],
61 | cssTexts = [],
62 | docLoaded = false
63 | ;
64 |
65 | var utilities = {
66 |
67 | camelize: function ( str ) {
68 |
69 | return str.replace(/\-(\w)/g, function ( str, letter ) {
70 |
71 | return letter.toUpperCase();
72 | });
73 | },
74 |
75 | trim: function ( str ) {
76 |
77 | var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
78 |
79 | return !String.prototype.trim ? str.replace(rtrim, '') : str.trim();
80 | },
81 |
82 | indexOf: function ( arr, el, from ) {
83 |
84 | var len = arr.length >>> 0;
85 |
86 | from = Number(from) || 0;
87 | from = (from < 0) ? Math.ceil(from) : Math.floor(from);
88 |
89 | if (from < 0) {
90 | from += len;
91 | }
92 |
93 | for (; from < len; from++) {
94 | if (from in arr && arr[from] === el)
95 | return from;
96 | }
97 |
98 | return -1;
99 | },
100 |
101 | // http://www.quirksmode.org/dom/getstyles.html
102 | getStyle: function ( el, prop ) {
103 |
104 | if (el.currentStyle) {
105 |
106 | return el.currentStyle[utilities.camelize(prop)];
107 | } else if (doc.defaultView && doc.defaultView.getComputedStyle) {
108 |
109 | return doc.defaultView.getComputedStyle(el,null).getPropertyValue(prop);
110 |
111 | } else {
112 |
113 | return el.style[utilities.camelize(prop)];
114 | }
115 | },
116 |
117 | // http://stackoverflow.com/questions/1955048/get-computed-font-size-for-dom-element-in-js
118 | getFontsize: function (obj) {
119 | var size;
120 | var test = doc.createElement('span');
121 |
122 | test.innerHTML = ' ';
123 | test.style.position = 'absolute';
124 | test.style.lineHeight = '1em';
125 | test.style.fontSize = '1em';
126 |
127 | obj.appendChild(test);
128 | size = test.offsetHeight;
129 | obj.removeChild(test);
130 |
131 | return size;
132 | },
133 |
134 | addEvent: function ( el, type, fn ){
135 |
136 | if (doc.addEventListener){
137 |
138 | el.addEventListener(type, fn, false);
139 | } else {
140 |
141 | el.attachEvent('on' + type, fn);
142 | }
143 | },
144 |
145 | // http://alistapart.com/article/fontresizing
146 | // http://www.truerwords.net/articles/web-tech/custom_events.html
147 | // https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
148 |
149 | textResize: function(cb) {
150 |
151 | var el, currentSize;
152 |
153 | var createControlElement = function () {
154 |
155 | el = doc.createElement('span');
156 | el.id = 'text-resize-control';
157 | el.innerHTML = ' ';
158 | el.style.position = 'absolute';
159 | el.style.left = '-9999px';
160 | el.style.lineHeight = '1em';
161 | el.style.fontSize = '1em';
162 |
163 | doc.body.insertBefore(el, doc.body.firstChild);
164 | currentSize = el.offsetHeight;
165 | },
166 |
167 | detectChange = function () {
168 |
169 | var now = el.offsetHeight;
170 |
171 | if ( currentSize === now ) {
172 |
173 | win.requestAnimationFrame(detectChange);
174 |
175 | return false;
176 | }
177 |
178 | currentSize = now;
179 |
180 | if ( cb && typeof cb === 'function' ) {
181 |
182 | cb();
183 | }
184 |
185 | win.requestAnimationFrame(detectChange);
186 | };
187 |
188 | createControlElement();
189 | win.requestAnimationFrame(detectChange);
190 | }
191 | };
192 |
193 | var calcTest = function() {
194 |
195 | var el = document.createElement('div');
196 |
197 | el.style.cssText = 'width: -moz-calc(10px); width: -webkit-calc(10px); width: calc(10px)';
198 |
199 | return !!el.style.length;
200 | },
201 |
202 |
203 | getStyleSheets = function () {
204 |
205 | var stylesheets = [];
206 | var index = 0;
207 | var len = doc.styleSheets.length;
208 | var stylesheet;
209 |
210 | for (; index < len; index++) {
211 |
212 | stylesheet = doc.styleSheets[index];
213 | cssTexts[index] = '';
214 |
215 | if (stylesheet.href && stylesheet.href !== EMPTY) {
216 |
217 | // selectivzr support - see issue #23
218 | // http://selectivizr.com/tests/respond/
219 | if (stylesheet.rawCssText && stylesheet.rawCssText !== EMPTY) {
220 |
221 | cssTexts[index] = stylesheet.rawCssText;
222 | }
223 | else {
224 |
225 | stylesheets.push(stylesheet.href);
226 | }
227 | }
228 | else if ( stylesheet.ownerNode && stylesheet.ownerNode.nodeName.toLowerCase() === 'style' ) {
229 |
230 | cssTexts[index] = stylesheet.ownerNode.textContent;
231 | }
232 | }
233 |
234 |
235 | if ( stylesheets.length > 0 || cssTexts.length > 0 ) {
236 |
237 | loadStylesheets(stylesheets);
238 | }
239 | },
240 |
241 | loadStylesheets = function(urls){
242 | var xhr;
243 | var index = 0;
244 | var len = urls.length;
245 |
246 | if ( win.XMLHttpRequest ) {
247 |
248 | xhr = new XMLHttpRequest();
249 | }
250 | else {
251 |
252 | try {
253 |
254 | xhr = new ActiveXObject('Microsoft.XMLHTTP');
255 |
256 | } catch(e) {
257 |
258 | xhr = null;
259 | }
260 | }
261 |
262 | if (xhr) {
263 |
264 | for (; index < len; index++) {
265 |
266 | try {
267 |
268 | xhr.open('GET', urls[index], false);
269 | xhr.send();
270 |
271 | if ( xhr.status === 200 ) {
272 | cssTexts[index] = xhr.responseText;
273 | }
274 |
275 | } catch(e) {
276 | console.log('Error making request for file ' + urls[index] + ': ' + e.message);
277 | }
278 |
279 | }
280 | }
281 |
282 | if (cssTexts.length > 0 ) {
283 |
284 | parseStylesheets(cssTexts);
285 | }
286 | },
287 |
288 | parseStylesheets = function(texts) {
289 | var index = 0;
290 | var len = texts.length;
291 |
292 | for (; index < len; index++) {
293 |
294 | if ( texts[index].length ) {
295 |
296 | texts[index] = texts[index].replace(COMMENTS, EMPTY).replace(CHARSET, EMPTY).replace(IMPORTS, EMPTY).replace(KEYFRAMES, EMPTY).replace(FONTFACE, EMPTY);
297 |
298 | dotheCalc( parseCSS(texts[index]) );
299 | }
300 | }
301 | },
302 |
303 | removeStyles = function ( elements ) {
304 | var index = 0;
305 | var len = elements.length;
306 |
307 | for (; index < len; index++) {
308 |
309 | if ( !JSON.parse(elements[index].getAttribute('data-calced')) ) {
310 |
311 | elements[index].removeAttribute('style');
312 | }
313 | }
314 | },
315 |
316 | parseCSS = function( css, media ) {
317 |
318 | var index, len, regex, result, selector, rules, calc, elements, obj, mediaQueryStyleSheet, refSheet;
319 | var arr = [];
320 |
321 | media = media || '';
322 |
323 | regex = new RegExp(CSSRULES, 'gi');
324 |
325 | while ( true ) {
326 |
327 | result = regex.exec(css);
328 |
329 | if ( result === null ) {
330 | break;
331 | }
332 |
333 | selector = utilities.trim( ( result[2] || result[5] ).split('\r\n').join('\n') );
334 |
335 | if ( selector.indexOf( ADDMEDIA ) !== -1 ) {
336 |
337 | rules = result[3] + '\n}';
338 |
339 | arr = arr.concat(parseCSS(rules, selector.replace( ADDMEDIA, '')));
340 | }
341 | else {
342 |
343 | rules = result[6].split('\r\n').join('\n').split(';');
344 |
345 | index = 0;
346 | len = rules.length;
347 |
348 | for (; index < len; index++) {
349 |
350 | calc = new RegExp(CALC_RULE, 'gi').exec(rules[index]);
351 |
352 | try {
353 | elements = doc.querySelectorAll(selector);
354 | }
355 | catch(e) {
356 | console.log('Error trying to select "' + selector + '": ' + e.message);
357 | break;
358 | }
359 |
360 | if ( calc !== null && elements.length ) {
361 |
362 | obj = {
363 | elements: elements,
364 | media: media,
365 | values: utilities.trim( calc[2] ),
366 | formula: calc[6],
367 | prop: utilities.trim( calc[1] ),
368 | placholder: utilities.trim( calc[3] )
369 | };
370 |
371 | if ( obj.formula.match(PERCENT) ) {
372 | obj.onresize = true;
373 | }
374 |
375 | if ( obj.formula.match(REMEM) ) {
376 | obj.ontextresize = true;
377 | }
378 |
379 | arr.push(obj);
380 | }
381 | }
382 |
383 | }
384 | }
385 |
386 | return arr;
387 | },
388 |
389 | dotheCalc = function( calcRules ){
390 | var index = 0;
391 | var len = calcRules.length;
392 | var obj;
393 |
394 | var calc = function( obj ) {
395 | var i = 0;
396 | var len = obj.elements.length;
397 | var refValue, modifier, matches, l, j, result, formula;
398 |
399 | for (; i < len; i++) {
400 |
401 | formula = obj.formula.replace(PIXEL, PLACEHOLDER);
402 | matches = formula.match(MATH_EXP);
403 | l = matches.length;
404 | j = 0;
405 |
406 | for (; j < l; j++) {
407 |
408 | modifier = null;
409 |
410 | if ( matches[j].match(PERCENT) ) {
411 |
412 | refValue = obj.elements[i].parentNode.clientWidth;
413 |
414 | modifier = parseFloat(matches[j], 10) / 100;
415 | }
416 |
417 | if ( matches[j].match(EM) ) {
418 |
419 | refValue = obj.elements[i].currentStyle ? utilities.getFontsize(obj.elements[i]) : parseInt( utilities.getStyle( obj.elements[i], FONTSIZE).replace(/px/, EMPTY ), 10);
420 |
421 | if ( refValue.match && refValue.match(PT) ) {
422 |
423 | refValue = Math.round( parseInt(refValue.replace(/pt/, ''), 10) * 1.333333333 );
424 | }
425 |
426 | modifier = parseFloat(matches[j], 10);
427 | }
428 |
429 | if ( matches[j].match(REM) ) {
430 |
431 | if ( utilities.getStyle( doc.body , FONTSIZE ).match(PERCENT) ) {
432 |
433 | refValue = 16 * parseInt( utilities.getStyle( doc.body , FONTSIZE).replace(/%/, EMPTY), 10) / 100;
434 | }
435 | else if ( utilities.getStyle( doc.body , FONTSIZE ).match(PT) ) {
436 |
437 | refValue = Math.round( parseInt(utilities.getStyle( doc.body , FONTSIZE).replace(/pt/, ''), 10) * 1.333333333 );
438 | }
439 | else {
440 |
441 | refValue = parseInt( utilities.getStyle( doc.body , FONTSIZE).replace(/px/, EMPTY ), 10);
442 | }
443 |
444 | modifier = parseFloat(matches[j], 10);
445 | }
446 |
447 | if ( modifier ) {
448 | formula = formula.replace(matches[j], refValue * modifier);
449 | }
450 |
451 | }
452 |
453 | try {
454 |
455 | if ( formula.match(ONLYNUMBERS) ) {
456 |
457 | result = eval( formula );
458 |
459 | obj.elements[i].style[ utilities.trim( utilities.camelize(obj.prop) ) ] = obj.values.replace(obj.placholder, result + 'px');
460 | obj.elements[i].setAttribute('data-calced', true);
461 | }
462 | }
463 | catch(e) {}
464 |
465 | }
466 | };
467 |
468 | for (; index < len; index++) {
469 |
470 | obj = calcRules[index];
471 |
472 | if ( obj.onresize && utilities.indexOf( onWindowResize, obj ) === -1 ) {
473 |
474 | onWindowResize.push(obj);
475 | }
476 |
477 | if ( obj.ontextresize && utilities.indexOf( onTextResize, obj ) === -1 ) {
478 |
479 | onTextResize.push(obj);
480 | }
481 |
482 | if ( obj.media !== EMPTY ) {
483 |
484 | if ( win.matchMedia && win.matchMedia(obj.media).matches ) {
485 |
486 | calc(obj);
487 | }
488 | else {
489 |
490 | removeStyles( obj.elements );
491 | }
492 | }
493 | else {
494 |
495 | calc(obj);
496 | }
497 | }
498 |
499 | };
500 |
501 | // Public interface
502 | win.dotheCalc = function() {
503 |
504 | if (cssTexts.length > 0 && docLoaded) {
505 |
506 | parseStylesheets(cssTexts);
507 | }
508 | };
509 |
510 |
511 | contentLoaded(win, function(){
512 |
513 | if ( calcTest() ) {
514 | return;
515 | }
516 |
517 | docLoaded = true;
518 |
519 | getStyleSheets();
520 |
521 | if ( onTextResize.length > 0 ) {
522 |
523 | utilities.textResize(function(){
524 |
525 | dotheCalc( onTextResize );
526 | });
527 | }
528 |
529 | if ( onWindowResize.length > 0 ) {
530 |
531 | utilities.addEvent(win, 'resize', function (){
532 |
533 | dotheCalc( onWindowResize );
534 | });
535 | }
536 | });
537 |
538 | // Libs and Helpers
539 |
540 | // import libs/contentloaded/src/contentloaded.js
541 | // import libs/requestAnimationFrame/app/requestAnimationFrame.js
542 |
543 |
544 | })(window, document);
545 |
--------------------------------------------------------------------------------
/dist/calc.js:
--------------------------------------------------------------------------------
1 | /*
2 | fillcalc v0.1.0 - (c) Robert Weber, freely distributable under the terms of the MIT license.
3 | */
4 |
5 | (function (win, doc) {
6 |
7 | 'use strict';
8 |
9 | // Avoid `console` errors in browsers that lack a console.
10 | (function() {
11 | var method;
12 | var noop = function () {};
13 | var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error','exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log','markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd','timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'];
14 |
15 | var length = methods.length;
16 | var console = (window.console = window.console || {});
17 |
18 | while (length--) {
19 | method = methods[length];
20 |
21 | // Only stub undefined methods.
22 | if (!console[method]) {
23 | console[method] = noop;
24 | }
25 | }
26 | }());
27 |
28 | // We need document.querySelectorAll as we do not want to depend on any lib
29 |
30 | if (!doc.querySelectorAll) {
31 | return false;
32 | }
33 |
34 | var
35 |
36 | EMPTY = '',
37 | CALC_RULE = '^(\\s*?[\\s\\S]*):(\\s*?[\\s\\S]*?((\\-(webkit|moz)\\-)?calc\\(([\\s\\S]+)\\))[\\s\\S]*)?$',
38 | CSSRULES = '((\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})',
39 |
40 | KEYFRAMES = new RegExp('((@(-webkit-)?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})', 'gi'),
41 | FONTFACE = new RegExp('((@font-face\\s*?){([\\s\\S]*?)})', 'gi'),
42 | COMMENTS = new RegExp('(\\/\\*[\\s\\S]*?\\*\\/)', 'gi'),
43 | IMPORTS = new RegExp('@import .*?;', 'gi'),
44 | CHARSET = new RegExp('@charset .*?;', 'gi'),
45 |
46 | PERCENT = /[\d\.]+%/,
47 | PT = /\d+pt/,
48 | PIXEL = /(\d+)px/g,
49 | REMEM = /[\d\.]+r?em/,
50 | REM = /[\d\.]+rem/,
51 | EM = /[\d\.]+em/,
52 | MATH_EXP = /[\+\-\/\*]?[\d\.]+(px|%|em|rem)?/g,
53 | PLACEHOLDER = '$1',
54 | ONLYNUMBERS = /[\s\-0-9]/g,
55 |
56 | FONTSIZE = 'font-size',
57 | ADDMEDIA = '@media',
58 |
59 | onTextResize = [],
60 | onWindowResize = [],
61 | cssTexts = [],
62 | docLoaded = false
63 | ;
64 |
65 | var utilities = {
66 |
67 | camelize: function ( str ) {
68 |
69 | return str.replace(/\-(\w)/g, function ( str, letter ) {
70 |
71 | return letter.toUpperCase();
72 | });
73 | },
74 |
75 | trim: function ( str ) {
76 |
77 | var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
78 |
79 | return !String.prototype.trim ? str.replace(rtrim, '') : str.trim();
80 | },
81 |
82 | indexOf: function ( arr, el, from ) {
83 |
84 | var len = arr.length >>> 0;
85 |
86 | from = Number(from) || 0;
87 | from = (from < 0) ? Math.ceil(from) : Math.floor(from);
88 |
89 | if (from < 0) {
90 | from += len;
91 | }
92 |
93 | for (; from < len; from++) {
94 | if (from in arr && arr[from] === el)
95 | return from;
96 | }
97 |
98 | return -1;
99 | },
100 |
101 | // http://www.quirksmode.org/dom/getstyles.html
102 | getStyle: function ( el, prop ) {
103 |
104 | if (el.currentStyle) {
105 |
106 | return el.currentStyle[utilities.camelize(prop)];
107 | } else if (doc.defaultView && doc.defaultView.getComputedStyle) {
108 |
109 | return doc.defaultView.getComputedStyle(el,null).getPropertyValue(prop);
110 |
111 | } else {
112 |
113 | return el.style[utilities.camelize(prop)];
114 | }
115 | },
116 |
117 | // http://stackoverflow.com/questions/1955048/get-computed-font-size-for-dom-element-in-js
118 | getFontsize: function (obj) {
119 | var size;
120 | var test = doc.createElement('span');
121 |
122 | test.innerHTML = ' ';
123 | test.style.position = 'absolute';
124 | test.style.lineHeight = '1em';
125 | test.style.fontSize = '1em';
126 |
127 | obj.appendChild(test);
128 | size = test.offsetHeight;
129 | obj.removeChild(test);
130 |
131 | return size;
132 | },
133 |
134 | addEvent: function ( el, type, fn ){
135 |
136 | if (doc.addEventListener){
137 |
138 | el.addEventListener(type, fn, false);
139 | } else {
140 |
141 | el.attachEvent('on' + type, fn);
142 | }
143 | },
144 |
145 | // http://alistapart.com/article/fontresizing
146 | // http://www.truerwords.net/articles/web-tech/custom_events.html
147 | // https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
148 |
149 | textResize: function(cb) {
150 |
151 | var el, currentSize;
152 |
153 | var createControlElement = function () {
154 |
155 | el = doc.createElement('span');
156 | el.id = 'text-resize-control';
157 | el.innerHTML = ' ';
158 | el.style.position = 'absolute';
159 | el.style.left = '-9999px';
160 | el.style.lineHeight = '1em';
161 | el.style.fontSize = '1em';
162 |
163 | doc.body.insertBefore(el, doc.body.firstChild);
164 | currentSize = el.offsetHeight;
165 | },
166 |
167 | detectChange = function () {
168 |
169 | var now = el.offsetHeight;
170 |
171 | if ( currentSize === now ) {
172 |
173 | win.requestAnimationFrame(detectChange);
174 |
175 | return false;
176 | }
177 |
178 | currentSize = now;
179 |
180 | if ( cb && typeof cb === 'function' ) {
181 |
182 | cb();
183 | }
184 |
185 | win.requestAnimationFrame(detectChange);
186 | };
187 |
188 | createControlElement();
189 | win.requestAnimationFrame(detectChange);
190 | }
191 | };
192 |
193 | var calcTest = function() {
194 |
195 | var el = document.createElement('div');
196 |
197 | el.style.cssText = 'width: -moz-calc(10px); width: -webkit-calc(10px); width: calc(10px)';
198 |
199 | return !!el.style.length;
200 | },
201 |
202 |
203 | getStyleSheets = function () {
204 |
205 | var stylesheets = [];
206 | var index = 0;
207 | var len = doc.styleSheets.length;
208 | var stylesheet;
209 |
210 | for (; index < len; index++) {
211 |
212 | stylesheet = doc.styleSheets[index];
213 | cssTexts[index] = '';
214 |
215 | if (stylesheet.href && stylesheet.href !== EMPTY) {
216 |
217 | // selectivzr support - see issue #23
218 | // http://selectivizr.com/tests/respond/
219 | if (stylesheet.rawCssText && stylesheet.rawCssText !== EMPTY) {
220 |
221 | cssTexts[index] = stylesheet.rawCssText;
222 | }
223 | else {
224 |
225 | stylesheets.push(stylesheet.href);
226 | }
227 | }
228 | else if ( stylesheet.ownerNode && stylesheet.ownerNode.nodeName.toLowerCase() === 'style' ) {
229 |
230 | cssTexts[index] = stylesheet.ownerNode.textContent;
231 | }
232 | }
233 |
234 |
235 | if ( stylesheets.length > 0 || cssTexts.length > 0 ) {
236 |
237 | loadStylesheets(stylesheets);
238 | }
239 | },
240 |
241 | loadStylesheets = function(urls){
242 | var xhr;
243 | var index = 0;
244 | var len = urls.length;
245 |
246 | if ( win.XMLHttpRequest ) {
247 |
248 | xhr = new XMLHttpRequest();
249 | }
250 | else {
251 |
252 | try {
253 |
254 | xhr = new ActiveXObject('Microsoft.XMLHTTP');
255 |
256 | } catch(e) {
257 |
258 | xhr = null;
259 | }
260 | }
261 |
262 | if (xhr) {
263 |
264 | for (; index < len; index++) {
265 |
266 | try {
267 |
268 | xhr.open('GET', urls[index], false);
269 | xhr.send();
270 |
271 | if ( xhr.status === 200 ) {
272 | cssTexts[index] = xhr.responseText;
273 | }
274 |
275 | } catch(e) {
276 | console.log('Error making request for file ' + urls[index] + ': ' + e.message);
277 | }
278 |
279 | }
280 | }
281 |
282 | if (cssTexts.length > 0 ) {
283 |
284 | parseStylesheets(cssTexts);
285 | }
286 | },
287 |
288 | parseStylesheets = function(texts) {
289 | var index = 0;
290 | var len = texts.length;
291 |
292 | for (; index < len; index++) {
293 |
294 | if ( texts[index].length ) {
295 |
296 | texts[index] = texts[index].replace(COMMENTS, EMPTY).replace(CHARSET, EMPTY).replace(IMPORTS, EMPTY).replace(KEYFRAMES, EMPTY).replace(FONTFACE, EMPTY);
297 |
298 | dotheCalc( parseCSS(texts[index]) );
299 | }
300 | }
301 | },
302 |
303 | removeStyles = function ( elements ) {
304 | var index = 0;
305 | var len = elements.length;
306 |
307 | for (; index < len; index++) {
308 |
309 | if ( !JSON.parse(elements[index].getAttribute('data-calced')) ) {
310 |
311 | elements[index].removeAttribute('style');
312 | }
313 | }
314 | },
315 |
316 | parseCSS = function( css, media ) {
317 |
318 | var index, len, regex, result, selector, rules, calc, elements, obj, mediaQueryStyleSheet, refSheet;
319 | var arr = [];
320 |
321 | media = media || '';
322 |
323 | regex = new RegExp(CSSRULES, 'gi');
324 |
325 | while ( true ) {
326 |
327 | result = regex.exec(css);
328 |
329 | if ( result === null ) {
330 | break;
331 | }
332 |
333 | selector = utilities.trim( ( result[2] || result[5] ).split('\r\n').join('\n') );
334 |
335 | if ( selector.indexOf( ADDMEDIA ) !== -1 ) {
336 |
337 | rules = result[3] + '\n}';
338 |
339 | arr = arr.concat(parseCSS(rules, selector.replace( ADDMEDIA, '')));
340 | }
341 | else {
342 |
343 | rules = result[6].split('\r\n').join('\n').split(';');
344 |
345 | index = 0;
346 | len = rules.length;
347 |
348 | for (; index < len; index++) {
349 |
350 | calc = new RegExp(CALC_RULE, 'gi').exec(rules[index]);
351 |
352 | try {
353 | elements = doc.querySelectorAll(selector);
354 | }
355 | catch(e) {
356 | console.log('Error trying to select "' + selector + '": ' + e.message);
357 | break;
358 | }
359 |
360 | if ( calc !== null && elements.length ) {
361 |
362 | obj = {
363 | elements: elements,
364 | media: media,
365 | values: utilities.trim( calc[2] ),
366 | formula: calc[6],
367 | prop: utilities.trim( calc[1] ),
368 | placholder: utilities.trim( calc[3] )
369 | };
370 |
371 | if ( obj.formula.match(PERCENT) ) {
372 | obj.onresize = true;
373 | }
374 |
375 | if ( obj.formula.match(REMEM) ) {
376 | obj.ontextresize = true;
377 | }
378 |
379 | arr.push(obj);
380 | }
381 | }
382 |
383 | }
384 | }
385 |
386 | return arr;
387 | },
388 |
389 | dotheCalc = function( calcRules ){
390 | var index = 0;
391 | var len = calcRules.length;
392 | var obj;
393 |
394 | var calc = function( obj ) {
395 | var i = 0;
396 | var len = obj.elements.length;
397 | var refValue, modifier, matches, l, j, result, formula;
398 |
399 | for (; i < len; i++) {
400 |
401 | formula = obj.formula.replace(PIXEL, PLACEHOLDER);
402 | matches = formula.match(MATH_EXP);
403 | l = matches.length;
404 | j = 0;
405 |
406 | for (; j < l; j++) {
407 |
408 | modifier = null;
409 |
410 | if ( matches[j].match(PERCENT) ) {
411 |
412 | refValue = obj.elements[i].parentNode.clientWidth;
413 |
414 | modifier = parseFloat(matches[j], 10) / 100;
415 | }
416 |
417 | if ( matches[j].match(EM) ) {
418 |
419 | refValue = obj.elements[i].currentStyle ? utilities.getFontsize(obj.elements[i]) : parseInt( utilities.getStyle( obj.elements[i], FONTSIZE).replace(/px/, EMPTY ), 10);
420 |
421 | if ( refValue.match && refValue.match(PT) ) {
422 |
423 | refValue = Math.round( parseInt(refValue.replace(/pt/, ''), 10) * 1.333333333 );
424 | }
425 |
426 | modifier = parseFloat(matches[j], 10);
427 | }
428 |
429 | if ( matches[j].match(REM) ) {
430 |
431 | if ( utilities.getStyle( doc.body , FONTSIZE ).match(PERCENT) ) {
432 |
433 | refValue = 16 * parseInt( utilities.getStyle( doc.body , FONTSIZE).replace(/%/, EMPTY), 10) / 100;
434 | }
435 | else if ( utilities.getStyle( doc.body , FONTSIZE ).match(PT) ) {
436 |
437 | refValue = Math.round( parseInt(utilities.getStyle( doc.body , FONTSIZE).replace(/pt/, ''), 10) * 1.333333333 );
438 | }
439 | else {
440 |
441 | refValue = parseInt( utilities.getStyle( doc.body , FONTSIZE).replace(/px/, EMPTY ), 10);
442 | }
443 |
444 | modifier = parseFloat(matches[j], 10);
445 | }
446 |
447 | if ( modifier ) {
448 | formula = formula.replace(matches[j], refValue * modifier);
449 | }
450 |
451 | }
452 |
453 | try {
454 |
455 | if ( formula.match(ONLYNUMBERS) ) {
456 |
457 | result = eval( formula );
458 |
459 | obj.elements[i].style[ utilities.trim( utilities.camelize(obj.prop) ) ] = obj.values.replace(obj.placholder, result + 'px');
460 | obj.elements[i].setAttribute('data-calced', true);
461 | }
462 | }
463 | catch(e) {}
464 |
465 | }
466 | };
467 |
468 | for (; index < len; index++) {
469 |
470 | obj = calcRules[index];
471 |
472 | if ( obj.onresize && utilities.indexOf( onWindowResize, obj ) === -1 ) {
473 |
474 | onWindowResize.push(obj);
475 | }
476 |
477 | if ( obj.ontextresize && utilities.indexOf( onTextResize, obj ) === -1 ) {
478 |
479 | onTextResize.push(obj);
480 | }
481 |
482 | if ( obj.media !== EMPTY ) {
483 |
484 | if ( win.matchMedia && win.matchMedia(obj.media).matches ) {
485 |
486 | calc(obj);
487 | }
488 | else {
489 |
490 | removeStyles( obj.elements );
491 | }
492 | }
493 | else {
494 |
495 | calc(obj);
496 | }
497 | }
498 |
499 | };
500 |
501 | // Public interface
502 | win.dotheCalc = function() {
503 |
504 | if (cssTexts.length > 0 && docLoaded) {
505 |
506 | parseStylesheets(cssTexts);
507 | }
508 | };
509 |
510 |
511 | contentLoaded(win, function(){
512 |
513 | if ( calcTest() ) {
514 | return;
515 | }
516 |
517 | docLoaded = true;
518 |
519 | getStyleSheets();
520 |
521 | if ( onTextResize.length > 0 ) {
522 |
523 | utilities.textResize(function(){
524 |
525 | dotheCalc( onTextResize );
526 | });
527 | }
528 |
529 | if ( onWindowResize.length > 0 ) {
530 |
531 | utilities.addEvent(win, 'resize', function (){
532 |
533 | dotheCalc( onWindowResize );
534 | });
535 | }
536 | });
537 |
538 | // Libs and Helpers
539 |
540 | /*!
541 | * contentloaded.js
542 | *
543 | * Author: Diego Perini (diego.perini at gmail.com)
544 | * Summary: cross-browser wrapper for DOMContentLoaded
545 | * Updated: 20101020
546 | * License: MIT
547 | * Version: 1.2
548 | *
549 | * URL:
550 | * http://javascript.nwbox.com/ContentLoaded/
551 | * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
552 | *
553 | */
554 |
555 | // @win window reference
556 | // @fn function reference
557 | function contentLoaded(win, fn) {
558 |
559 | var done = false, top = true,
560 |
561 | doc = win.document,
562 | root = doc.documentElement,
563 | modern = doc.addEventListener,
564 |
565 | add = modern ? 'addEventListener' : 'attachEvent',
566 | rem = modern ? 'removeEventListener' : 'detachEvent',
567 | pre = modern ? '' : 'on',
568 |
569 | init = function(e) {
570 | if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
571 | (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
572 | if (!done && (done = true)) fn.call(win, e.type || e);
573 | },
574 |
575 | poll = function() {
576 | try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
577 | init('poll');
578 | };
579 |
580 | if (doc.readyState == 'complete') fn.call(win, 'lazy');
581 | else {
582 | if (!modern && root.doScroll) {
583 | try { top = !win.frameElement; } catch(e) { }
584 | if (top) poll();
585 | }
586 | doc[add](pre + 'DOMContentLoaded', init, false);
587 | doc[add](pre + 'readystatechange', init, false);
588 | win[add](pre + 'load', init, false);
589 | }
590 |
591 | }
592 |
593 | /**
594 | * requestAnimationFrame version: "0.0.17" Copyright (c) 2011-2012, Cyril Agosta ( cyril.agosta.dev@gmail.com) All Rights Reserved.
595 | * Available via the MIT license.
596 | * see: http://github.com/cagosta/requestAnimationFrame for details
597 | *
598 | * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
599 | * http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
600 | * requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
601 | * MIT license
602 | *
603 | */
604 |
605 |
606 | ( function( global ) {
607 |
608 |
609 | ( function() {
610 |
611 |
612 | if ( global.requestAnimationFrame ) {
613 |
614 | return;
615 |
616 | }
617 |
618 | if ( global.webkitRequestAnimationFrame ) { // Chrome <= 23, Safari <= 6.1, Blackberry 10
619 |
620 | global.requestAnimationFrame = global[ 'webkitRequestAnimationFrame' ];
621 | global.cancelAnimationFrame = global[ 'webkitCancelAnimationFrame' ] || global[ 'webkitCancelRequestAnimationFrame' ];
622 |
623 | }
624 |
625 | // IE <= 9, Android <= 4.3, very old/rare browsers
626 |
627 | var lastTime = 0;
628 |
629 | global.requestAnimationFrame = function( callback ) {
630 |
631 | var currTime = new Date().getTime();
632 |
633 | var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
634 |
635 | var id = global.setTimeout( function() {
636 |
637 | callback( currTime + timeToCall );
638 |
639 | }, timeToCall );
640 |
641 | lastTime = currTime + timeToCall;
642 |
643 | return id; // return the id for cancellation capabilities
644 |
645 | };
646 |
647 | global.cancelAnimationFrame = function( id ) {
648 |
649 | clearTimeout( id );
650 |
651 | };
652 |
653 | } )();
654 |
655 | if ( typeof define === 'function' ) {
656 |
657 | define( function() {
658 |
659 | return global.requestAnimationFrame;
660 |
661 | } );
662 |
663 | }
664 |
665 | } )( window );
666 |
667 |
668 | })(window, document);
669 |
--------------------------------------------------------------------------------
/dist/calc.min.js:
--------------------------------------------------------------------------------
1 | /*! calc-polyfill 25-01-2016 */
2 | !function(win,doc){"use strict";function contentLoaded(a,b){var c=!1,d=!0,e=a.document,f=e.documentElement,g=e.addEventListener,h=g?"addEventListener":"attachEvent",i=g?"removeEventListener":"detachEvent",j=g?"":"on",k=function(d){("readystatechange"!=d.type||"complete"==e.readyState)&&(("load"==d.type?a:e)[i](j+d.type,k,!1),!c&&(c=!0)&&b.call(a,d.type||d))},l=function(){try{f.doScroll("left")}catch(a){return void setTimeout(l,50)}k("poll")};if("complete"==e.readyState)b.call(a,"lazy");else{if(!g&&f.doScroll){try{d=!a.frameElement}catch(m){}d&&l()}e[h](j+"DOMContentLoaded",k,!1),e[h](j+"readystatechange",k,!1),a[h](j+"load",k,!1)}}if(function(){for(var a,b=function(){},c=["assert","clear","count","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeline","timelineEnd","timeStamp","trace","warn"],d=c.length,e=window.console=window.console||{};d--;)a=c[d],e[a]||(e[a]=b)}(),!doc.querySelectorAll)return!1;var EMPTY="",CALC_RULE="^(\\s*?[\\s\\S]*):(\\s*?[\\s\\S]*?((\\-(webkit|moz)\\-)?calc\\(([\\s\\S]+)\\))[\\s\\S]*)?$",CSSRULES="((\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})",KEYFRAMES=new RegExp("((@(-webkit-)?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})","gi"),FONTFACE=new RegExp("((@font-face\\s*?){([\\s\\S]*?)})","gi"),COMMENTS=new RegExp("(\\/\\*[\\s\\S]*?\\*\\/)","gi"),IMPORTS=new RegExp("@import .*?;","gi"),CHARSET=new RegExp("@charset .*?;","gi"),PERCENT=/[\d\.]+%/,PT=/\d+pt/,PIXEL=/(\d+)px/g,REMEM=/[\d\.]+r?em/,REM=/[\d\.]+rem/,EM=/[\d\.]+em/,MATH_EXP=/[\+\-\/\*]?[\d\.]+(px|%|em|rem)?/g,PLACEHOLDER="$1",ONLYNUMBERS=/[\s\-0-9]/g,FONTSIZE="font-size",ADDMEDIA="@media",onTextResize=[],onWindowResize=[],cssTexts=[],docLoaded=!1,utilities={camelize:function(a){return a.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()})},trim:function(a){var b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;return String.prototype.trim?a.trim():a.replace(b,"")},indexOf:function(a,b,c){var d=a.length>>>0;for(c=Number(c)||0,c=0>c?Math.ceil(c):Math.floor(c),0>c&&(c+=d);d>c;c++)if(c in a&&a[c]===b)return c;return-1},getStyle:function(a,b){return a.currentStyle?a.currentStyle[utilities.camelize(b)]:doc.defaultView&&doc.defaultView.getComputedStyle?doc.defaultView.getComputedStyle(a,null).getPropertyValue(b):a.style[utilities.camelize(b)]},getFontsize:function(a){var b,c=doc.createElement("span");return c.innerHTML=" ",c.style.position="absolute",c.style.lineHeight="1em",c.style.fontSize="1em",a.appendChild(c),b=c.offsetHeight,a.removeChild(c),b},addEvent:function(a,b,c){doc.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},textResize:function(a){var b,c,d=function(){b=doc.createElement("span"),b.id="text-resize-control",b.innerHTML=" ",b.style.position="absolute",b.style.left="-9999px",b.style.lineHeight="1em",b.style.fontSize="1em",doc.body.insertBefore(b,doc.body.firstChild),c=b.offsetHeight},e=function(){var d=b.offsetHeight;return c===d?(win.requestAnimationFrame(e),!1):(c=d,a&&"function"==typeof a&&a(),void win.requestAnimationFrame(e))};d(),win.requestAnimationFrame(e)}},calcTest=function(){var a=document.createElement("div");return a.style.cssText="width: -moz-calc(10px); width: -webkit-calc(10px); width: calc(10px)",!!a.style.length},getStyleSheets=function(){for(var a,b=[],c=0,d=doc.styleSheets.length;d>c;c++)a=doc.styleSheets[c],cssTexts[c]="",a.href&&a.href!==EMPTY?a.rawCssText&&a.rawCssText!==EMPTY?cssTexts[c]=a.rawCssText:b.push(a.href):a.ownerNode&&"style"===a.ownerNode.nodeName.toLowerCase()&&(cssTexts[c]=a.ownerNode.textContent);(b.length>0||cssTexts.length>0)&&loadStylesheets(b)},loadStylesheets=function(a){var b,c=0,d=a.length;if(win.XMLHttpRequest)b=new XMLHttpRequest;else try{b=new ActiveXObject("Microsoft.XMLHTTP")}catch(e){b=null}if(b)for(;d>c;c++)try{b.open("GET",a[c],!1),b.send(),200===b.status&&(cssTexts[c]=b.responseText)}catch(e){console.log("Error making request for file "+a[c]+": "+e.message)}cssTexts.length>0&&parseStylesheets(cssTexts)},parseStylesheets=function(a){for(var b=0,c=a.length;c>b;b++)a[b].length&&(a[b]=a[b].replace(COMMENTS,EMPTY).replace(CHARSET,EMPTY).replace(IMPORTS,EMPTY).replace(KEYFRAMES,EMPTY).replace(FONTFACE,EMPTY),dotheCalc(parseCSS(a[b])))},removeStyles=function(a){for(var b=0,c=a.length;c>b;b++)JSON.parse(a[b].getAttribute("data-calced"))||a[b].removeAttribute("style")},parseCSS=function(a,b){var c,d,e,f,g,h,i,j,k,l=[];for(b=b||"",e=new RegExp(CSSRULES,"gi");;){if(f=e.exec(a),null===f)break;if(g=utilities.trim((f[2]||f[5]).split("\r\n").join("\n")),-1!==g.indexOf(ADDMEDIA))h=f[3]+"\n}",l=l.concat(parseCSS(h,g.replace(ADDMEDIA,"")));else for(h=f[6].split("\r\n").join("\n").split(";"),c=0,d=h.length;d>c;c++){i=new RegExp(CALC_RULE,"gi").exec(h[c]);try{j=doc.querySelectorAll(g)}catch(m){console.log('Error trying to select "'+g+'": '+m.message);break}null!==i&&j.length&&(k={elements:j,media:b,values:utilities.trim(i[2]),formula:i[6],prop:utilities.trim(i[1]),placholder:utilities.trim(i[3])},k.formula.match(PERCENT)&&(k.onresize=!0),k.formula.match(REMEM)&&(k.ontextresize=!0),l.push(k))}}return l},dotheCalc=function(calcRules){for(var index=0,len=calcRules.length,obj,calc=function(obj){for(var i=0,len=obj.elements.length,refValue,modifier,matches,l,j,result,formula;len>i;i++){for(formula=obj.formula.replace(PIXEL,PLACEHOLDER),matches=formula.match(MATH_EXP),l=matches.length,j=0;l>j;j++)modifier=null,matches[j].match(PERCENT)&&(refValue=obj.elements[i].parentNode.clientWidth,modifier=parseFloat(matches[j],10)/100),matches[j].match(EM)&&(refValue=obj.elements[i].currentStyle?utilities.getFontsize(obj.elements[i]):parseInt(utilities.getStyle(obj.elements[i],FONTSIZE).replace(/px/,EMPTY),10),refValue.match&&refValue.match(PT)&&(refValue=Math.round(1.333333333*parseInt(refValue.replace(/pt/,""),10))),modifier=parseFloat(matches[j],10)),matches[j].match(REM)&&(refValue=utilities.getStyle(doc.body,FONTSIZE).match(PERCENT)?16*parseInt(utilities.getStyle(doc.body,FONTSIZE).replace(/%/,EMPTY),10)/100:utilities.getStyle(doc.body,FONTSIZE).match(PT)?Math.round(1.333333333*parseInt(utilities.getStyle(doc.body,FONTSIZE).replace(/pt/,""),10)):parseInt(utilities.getStyle(doc.body,FONTSIZE).replace(/px/,EMPTY),10),modifier=parseFloat(matches[j],10)),modifier&&(formula=formula.replace(matches[j],refValue*modifier));try{formula.match(ONLYNUMBERS)&&(result=eval(formula),obj.elements[i].style[utilities.trim(utilities.camelize(obj.prop))]=obj.values.replace(obj.placholder,result+"px"),obj.elements[i].setAttribute("data-calced",!0))}catch(e){}}};len>index;index++)obj=calcRules[index],obj.onresize&&-1===utilities.indexOf(onWindowResize,obj)&&onWindowResize.push(obj),obj.ontextresize&&-1===utilities.indexOf(onTextResize,obj)&&onTextResize.push(obj),obj.media!==EMPTY?win.matchMedia&&win.matchMedia(obj.media).matches?calc(obj):removeStyles(obj.elements):calc(obj)};win.dotheCalc=function(){cssTexts.length>0&&docLoaded&&parseStylesheets(cssTexts)},contentLoaded(win,function(){calcTest()||(docLoaded=!0,getStyleSheets(),onTextResize.length>0&&utilities.textResize(function(){dotheCalc(onTextResize)}),onWindowResize.length>0&&utilities.addEvent(win,"resize",function(){dotheCalc(onWindowResize)}))}),function(a){!function(){if(!a.requestAnimationFrame){a.webkitRequestAnimationFrame&&(a.requestAnimationFrame=a.webkitRequestAnimationFrame,a.cancelAnimationFrame=a.webkitCancelAnimationFrame||a.webkitCancelRequestAnimationFrame);var b=0;a.requestAnimationFrame=function(c){var d=(new Date).getTime(),e=Math.max(0,16-(d-b)),f=a.setTimeout(function(){c(d+e)},e);return b=d+e,f},a.cancelAnimationFrame=function(a){clearTimeout(a)}}}(),"function"==typeof define&&define(function(){return a.requestAnimationFrame})}(window)}(window,document);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calc-polyfill",
3 | "version": "0.1.0",
4 | "description": "A Polyfill for CSS3 calc()",
5 | "main": "Gruntfile.js",
6 | "directories": {},
7 | "dependencies": {},
8 | "devDependencies": {
9 | "grunt": "^0.4.5",
10 | "grunt-contrib-concat": "^0.5.0",
11 | "grunt-contrib-jshint": "^0.10.0",
12 | "grunt-contrib-uglify": "^0.7.0",
13 | "grunt-contrib-watch": "^0.6.1"
14 | },
15 | "scripts": {},
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/closingtag/calc-polyfill"
19 | },
20 | "author": "Robert Weber",
21 | "license": "MIT",
22 | "bugs": {
23 | "url": "https://github.com/closingtag/calc-polyfill/issues"
24 | },
25 | "homepage": "https://github.com/closingtag/calc-polyfill"
26 | }
27 |
--------------------------------------------------------------------------------
/testcase/import.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/closingtag/calc-polyfill/c6611a33de5f36ec00e9f963d4647df398fb98b7/testcase/import.css
--------------------------------------------------------------------------------
/testcase/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Polyfill for calc() test case
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Polyfill for calc() test case
31 |
32 |
33 |
Element with only px values in calc for width
34 |
35 |
36 |
37 |
38 |
Element with px and percent values in calc for width
39 |
40 |
41 |
42 |
43 |
Element with px and em values in calc for width
44 |
45 |
46 |
47 |
48 |
Element with px and rem values in calc for width
49 |
50 |
51 |
52 |
53 |
Element with only px values in calc for width, but a selector which IE8 does not understand.
54 |
55 |
56 |
57 |
58 |
Element with px and percent values in calc for width in media query
59 |
60 |
61 |
62 |
63 |
Element with decimal percentages and multiplication and division
64 |
65 |
66 |
67 |
68 |
Element with px and em values in calc for width. Inline style
69 |
70 |
71 |
72 |
73 |
126 |
127 |
--------------------------------------------------------------------------------
/testcase/index.selectivizr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Polyfill for calc() test case
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Polyfill for calc() test case
33 |
34 |
35 |
Element with only px values in calc for width
36 |
37 |
38 |
39 |
40 |
Element with px and percent values in calc for width
41 |
42 |
43 |
44 |
45 |
Element with px and em values in calc for width
46 |
47 |
48 |
49 |
50 |
Element with px and rem values in calc for width
51 |
52 |
53 |
54 |
55 |
Element with only px values in calc for width, but a selector which IE8 does not understand.
56 |
57 |
58 |
59 |
60 |
Element with px and percent values in calc for width in media query
61 |
62 |
63 |
64 |
65 |
Element with decimal percentages and multiplication and division
66 |
67 |
68 |
69 |
70 |
Element with px and em values in calc for width. Inline style
71 |
72 |
73 |
74 |
75 |
128 |
129 |
--------------------------------------------------------------------------------
/testcase/styles.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @import "import.css";
4 |
5 | @font-face{
6 | font-family: 'CalligraphyFLFRegular';
7 | src: url('CalligraphyFLF.eot');
8 | src: local('CalligraphyFLF Regular'), local('CalligraphyFLF'), url('CalligraphyFLF.ttf') format('truetype');
9 | }
10 |
11 |
12 | @-webkit-keyframes fade-in {
13 | 0% { opacity: 0; }
14 | 100% { opacity: 1; }
15 | }
16 | @keyframes fade-in {
17 | 0% { opacity: 0; }
18 | 100% { opacity: 1; }
19 | }
20 |
21 | body {
22 | margin: 0;
23 | padding: 0;
24 | font-family: sans-serif;
25 | }
26 |
27 | h2 {
28 | padding: 20px;
29 | color: white;
30 | }
31 |
32 | .element {
33 | height: 200px;
34 | width: 500px;
35 | margin-bottom: 100px;
36 | padding: 0;
37 | text-align: center;
38 | border: 1px solid red;
39 | }
40 |
41 | .element1 {
42 | width: calc(600px - 100px);
43 | background: #ff6347;
44 | }
45 |
46 | .element9,
47 | .element2 {
48 | width: calc(600px - 20%);
49 | background: green;
50 | }
51 |
52 | .element3 {
53 | font-size: 10px;
54 | width: calc(600px - 15em);
55 | background: blue;
56 | }
57 |
58 | .element4 {
59 | width: calc(600px - 15rem);
60 | padding: 20px calc(12px + 2em);
61 | background: purple;
62 | }
63 |
64 | .element6 {
65 | width: calc(200px + 75%);
66 | background: #0f0;
67 | }
68 |
69 | .element7 {
70 | width: calc(50.5% / 2);
71 | padding: 20px calc(2% * 2);
72 | background: purple;
73 | }
74 |
75 | /* .element5 */
76 |
77 | .element:nth-of-type(5) {
78 | width: calc(500px + 100px);
79 | background: #cc0;
80 | }
81 |
82 | /* Comment for testing */
83 |
84 | @media screen and (max-width: 780px) {
85 | .element6 {
86 | width: calc(200px + 50%);
87 | background: #0f0;
88 | }
89 | }
90 |
91 | @media screen and (min-width: 840px) {
92 | .element6 {
93 | width: calc(200px + 30%);
94 | background: #0f0;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------