├── .gitattributes ├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── LICENSE.md ├── README-PARALLIA.md ├── README.md ├── bin ├── css-polyfills.js ├── css-polyfills.js.map ├── css-polyfills.min.js └── css-polyfills.min.js.map ├── demo └── css-grid │ ├── basic-hover-test.html │ ├── common.css │ ├── example1.html │ ├── example10.html │ ├── example11.html │ ├── example12.html │ ├── example13.html │ ├── example14.html │ ├── example15.html │ ├── example16.html │ ├── example17.html │ ├── example18.html │ ├── example19.html │ ├── example2.html │ ├── example3.html │ ├── example4.html │ ├── example5.html │ ├── example6.html │ ├── example7.html │ ├── example8.html │ ├── example9.html │ ├── gap-col.html │ ├── gap-row.html │ ├── gap.html │ ├── ie11bug.html │ ├── layout1.html │ ├── layout2.html │ ├── layout3.html │ ├── layout4.html │ ├── layout5.html │ ├── order-property.html │ ├── sroll-preservation-test.html │ ├── tests │ ├── snapshots.js │ ├── test-runner.html │ ├── test-runner.js │ ├── test-server.js │ └── update-snapshots.js │ └── zero-unit-test.html ├── doc ├── README.md ├── README[header].md ├── core │ ├── css-box.ts │ ├── css-cascade.ts │ ├── css-sizing.ts │ ├── css-style.ts │ ├── css-syntax.ts │ ├── css-units.ts │ └── dom-events.ts └── requirements.ts ├── package.json └── src ├── core ├── css-box.js ├── css-cascade.js ├── css-sizing.js ├── css-style.js ├── css-syntax.js ├── css-units.js ├── css-virtual-stylesheet-factory.js ├── dom-events.js ├── dom-experimental-event-streams.js ├── dom-get-common-ancestor.js ├── dom-query-selector-live.js ├── polyfill-dom-classList.js ├── polyfill-dom-console.js ├── polyfill-dom-matchMedia.js ├── polyfill-dom-requestAnimationFrame.js └── polyfill-dom-uniqueID.js ├── css-grid ├── lib │ └── grid-layout.js └── polyfill.js ├── requirements.js └── todo.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ========================= 2 | # My files 3 | # ========================= 4 | 5 | doc/*.js 6 | doc/**/*.js 7 | src/css-syntax-tab.js 8 | 9 | # ========================= 10 | # Grunt files 11 | # ========================= 12 | 13 | /node_modules/ 14 | 15 | 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # Windows image file caches 22 | Thumbs.db 23 | ehthumbs.db 24 | 25 | # Folder config file 26 | Desktop.ini 27 | 28 | # Recycle Bin used on file shares 29 | $RECYCLE.BIN/ 30 | 31 | # Windows Installer files 32 | *.cab 33 | *.msi 34 | *.msm 35 | *.msp 36 | 37 | # OSX 38 | # ========================= 39 | 40 | .DS_Store 41 | .AppleDouble 42 | .LSOverride 43 | 44 | # Icon must end with two \r 45 | Icon 46 | 47 | # Thumbnails 48 | ._* 49 | 50 | # Files that might appear on external disk 51 | .Spotlight-V100 52 | .Trashes 53 | 54 | # Directories potentially created on remote AFP share 55 | .AppleDB 56 | .AppleDesktop 57 | Network Trash Folder 58 | Temporary Items 59 | .apdisk 60 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true 14 | } 15 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | // Import the dependencies 6 | var url = require('url'); 7 | 8 | // Transform a require-uri into a canonical uri 9 | function resolveModuleUri(baseUri, relativeModuleUri) { 10 | 11 | // determine the url kind 12 | var indexOfSeparator = -1; 13 | if ((indexOfSeparator=relativeModuleUri.indexOf(':')) != -1) { 14 | var moduleUri = 'src/'+relativeModuleUri.substr(0,indexOfSeparator)+'/'+relativeModuleUri.substr(indexOfSeparator+1); 15 | } else { 16 | var moduleUri = url.resolve(baseUri, relativeModuleUri); 17 | } 18 | 19 | // potentially append .js 20 | if(!grunt.file.exists(moduleUri)) { moduleUri = moduleUri + '.js'; } 21 | 22 | // return the final value 23 | return moduleUri; 24 | } 25 | 26 | // Data storage 27 | var pkg = grunt.file.readJSON('package.json'); 28 | 29 | var code_wrapper_start = ( 30 | "\n"+ 31 | "!(function() { 'use strict';"+"\n"+ 32 | " var module = { exports:{} };"+"\n"+ 33 | " var require = (function() { var modules = {}; var require = function(m) { return modules[m]; }; require.define = function(m) { modules[m]=module.exports; module.exports={}; }; return require; })();" 34 | ); 35 | 36 | var code_wrapper_separator = "\n\n////////////////////////////////////////\n\n"; 37 | code_wrapper_start += code_wrapper_separator; 38 | 39 | var code_wrapper_end = ( 40 | "\n\n" + "window.cssPolyfills = { require: require };" + "\n\n" + "})();" 41 | ); 42 | 43 | 44 | // Project configuration. 45 | grunt.initConfig({ 46 | 47 | // 48 | // Metadata: 49 | // 50 | 51 | pkg: pkg, 52 | 53 | banner: 54 | '/*! <%= pkg.name.toUpperCase() %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %>' + '<%= pkg.homepage ? " - " + pkg.homepage : "" %>' + ' - Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +' <%= _.pluck(pkg.licenses, "type").join("- and ") %>-Licensed !*/\n', 55 | code_wrapper_start: 56 | code_wrapper_start, 57 | code_wrapper_end: 58 | code_wrapper_end, 59 | code_wrapper_separator: 60 | code_wrapper_separator, 61 | 62 | // 63 | // Task configuration: 64 | // 65 | 66 | findreq: { 67 | root: '<%= pkg.main =>' 68 | }, 69 | 70 | concat: { 71 | bin: { 72 | src: ['<%= pkg.main %>'], 73 | dest: 'bin/<%= pkg.name %>.js', 74 | options: { 75 | banner: '<%= banner %><%= code_wrapper_start %>', 76 | footer: '<%= code_wrapper_end %>', 77 | separator: '<%= code_wrapper_separator %>', 78 | stripBanners: true, 79 | sourceMap: true, 80 | process: function(src, filepath) { 81 | 82 | return src.replace(/(?:(?:\/\/|\/\*)[-_=a-zA-Z0-9 ]*)?require\((\'.*?\'|\"".*?\"")\)/g, function(str, match) { 83 | if(str.indexOf('require')==0) { 84 | var relativeModuleUri = match.substr(1, match.length-2); 85 | var moduleUri = resolveModuleUri(filepath, relativeModuleUri); 86 | return "require('"+moduleUri+"')"; 87 | } else { 88 | return str; 89 | } 90 | })+"\nrequire.define('" + filepath + "');"; 91 | 92 | } 93 | } 94 | }, 95 | doc: { 96 | src: ['doc/**/*.ts'], 97 | dest: 'doc/README.md', 98 | options: { 99 | old_banner: '<%= ""+(function() { var source = grunt.file.read("doc/README.md"), reg = /(\\r?\\n){3}/; reg=reg.exec(source)[0]; return source.substr(0, reg.lastIndex); })() %>', 100 | banner: '<%= grunt.file.read("doc/README[header].md") %>', 101 | separator: '', 102 | stripBanners: false, 103 | sourceMap: false, 104 | process: function(src, filepath) { 105 | if(filepath == "doc/requirements.ts") { return; } 106 | try { 107 | var fileurl = filepath.replace(/^(\.\/)?doc\/?/,'./'); grunt.log.writeln(fileurl); 108 | var filename = /\/([^\/]+)\.ts/i.exec(filepath)[1]; grunt.log.writeln(filename); 109 | 110 | var firstComment = /(?: |\t)\*(?: |\t)(.*?)(\r?\n)/.exec(src)[1].trimRight(); grunt.log.writeln(firstComment); 111 | src = src.replace(/^(?:.|\r|\n)*?\/\/\/\/ EXAMPLES [\/\r\n ]+/,'/'); 112 | var extractExamples = /\/\*+ (.*?)(?:\*+\/)[\r\n]+function ?[a-zA-Z0-9_]*\([a-zA-Z0-9_, ]*\) *\{[\r\n\t ]*\r?\n((.|\r|\n)*?)([\r\n]+\})/g; 113 | var example, examples=''; while(example = extractExamples.exec(src)) { 114 | examples = examples + '\r\n### '+example[1].trim() + '\r\n\r\n```javascript\r\n\t'+example[2].trim()+'\r\n```\r\n'; 115 | } 116 | 117 | return ( 118 | "\r\n\r\n"+ 119 | "["+filename.toUpperCase()+"]("+fileurl+")\r\n"+ 120 | "===================================\r\n"+ 121 | firstComment+"\r\n"+ 122 | examples 123 | ); 124 | 125 | } catch (ex) { 126 | 127 | grunt.log.writeln('[ERROR] Generating doc for ' + filepath + ' failled with message: ' + ex.message); 128 | return ''; 129 | 130 | } 131 | } 132 | } 133 | } 134 | }, 135 | 136 | uglify: { 137 | options: { 138 | banner: '<%= banner %>', 139 | sourceMap: true 140 | }, 141 | bin: { 142 | src: '<%= concat.bin.dest %>', 143 | dest: 'bin/<%= pkg.name %>.min.js' 144 | }, 145 | }, 146 | 147 | nodeunit: { 148 | files: ['test/**/*_test.js'] 149 | }, 150 | 151 | jshint: { 152 | options: { 153 | jshintrc: '.jshintrc' 154 | }, 155 | gruntfile: { 156 | src: 'Gruntfile.js' 157 | }, 158 | src: { 159 | options: { 160 | jshintrc: '.jshintrc' 161 | }, 162 | src: ['src/**/*.js'] 163 | }, 164 | test: { 165 | src: ['test/**/*.js'] 166 | }, 167 | }, 168 | 169 | watch: { 170 | gruntfile: { 171 | files: '<%= jshint.gruntfile.src %>', 172 | tasks: ['jshint:gruntfile'] 173 | }, 174 | src: { 175 | files: '<%= jshint.src.src %>', 176 | tasks: ['jshint:src', 'nodeunit'] 177 | }, 178 | test: { 179 | files: '<%= jshint.test.src %>', 180 | tasks: ['jshint:test', 'nodeunit'] 181 | }, 182 | }, 183 | 184 | }); 185 | 186 | 187 | // These plugins provide some necessary tasks. 188 | grunt.loadNpmTasks('grunt-contrib-concat-sourcemaps'); //grunt.loadNpmTasks('grunt-contrib-concat'); 189 | grunt.loadNpmTasks('grunt-contrib-uglify'); 190 | grunt.loadNpmTasks('grunt-contrib-nodeunit'); 191 | grunt.loadNpmTasks('grunt-contrib-jshint'); 192 | grunt.loadNpmTasks('grunt-contrib-watch'); 193 | 194 | // Define the special 'findreq' task 195 | grunt.registerTask('findreq', 'Automatically determines the order in which the source files have to be concatened', function() { 196 | 197 | var modules = []; 198 | var importModule = function(rootUri, baseUri, relativeModuleUri) { 199 | 200 | // find out the canonical name of the module 201 | var moduleUri = resolveModuleUri(baseUri, relativeModuleUri); 202 | if(!grunt.file.exists(moduleUri)) { moduleUri += '.js'; } 203 | grunt.log.writeln('importing: '+moduleUri); 204 | 205 | // check that the module hasn't already been loaded before 206 | if(modules.indexOf(moduleUri) >= 0) { return; } 207 | 208 | // load the file content from the disk 209 | var fileContent = grunt.file.read(moduleUri); 210 | 211 | // find all dependencies 212 | var dependencyPattern = /(?:(?:\/\/|\/\*)[-_=a-zA-Z0-9 ]*)?require\((\'.*?\'|\"".*?\"")\)/g; 213 | var match; while(match = dependencyPattern.exec(fileContent)) { 214 | 215 | // check we are not in a comment 216 | if(match[0].indexOf('require') == 0) { 217 | 218 | // get the relative uri 219 | match = match[1]; match = match.substr(1, match.length-2); 220 | grunt.log.writeln('depencendy: '+match); 221 | 222 | // import the module 223 | importModule(rootUri, moduleUri, match); 224 | 225 | } 226 | 227 | } 228 | 229 | // mark the module as ready 230 | modules.push(moduleUri); 231 | 232 | } 233 | 234 | importModule(pkg.main, '.', pkg.main); 235 | 236 | grunt.config.merge({ 237 | concat: { 238 | bin: { 239 | src: modules 240 | } 241 | } 242 | }); 243 | }); 244 | 245 | // Default task. 246 | grunt.registerTask('default', [ /*'jshint', 'nodeunit', */'findreq', 'concat', 'uglify']); 247 | 248 | }; -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 François REMY 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README-PARALLIA.md: -------------------------------------------------------------------------------- 1 | # CSS-Polyfills-Framework (Parallia) 2 | 3 | The goal of this project is to create a central repository and a background framework for css polyfills. 4 | 5 | By using a modular approach, the Grunt setup associated to this project allows you to create customized builds by disabling the features you don't need, as we will explain later. 6 | 7 | ## Getting Started 8 | 9 | ### Including Parallia on your website 10 | If you want all features to be enabled: 11 | 12 | 1. Simply download the [production version][min] or the [development version][max]. 13 | 14 | 2. You can then reference it in your web page from your server, just before either the `````` or the `````` tag: 15 | 16 | ```html 17 | 18 | ``` 19 | 20 | [min]: https://raw.github.com/FremyCompany/css-polyfills/master/bin/css-polyfills.min.js 21 | [max]: https://raw.github.com/FremyCompany/css-polyfills/master/bin/css-polyfills.js 22 | 23 | If you only want some features to be enabled: 24 | 25 | 1. Clone this repository on your device. 26 | 27 | 2. Modify the ```src/requirements.js``` file to fit your needs (see next chapter) 28 | 29 | 3. Run Grunt to generate the new build. 30 | 31 | 4. You can then reference it in your web page from your server, just before either the `````` or the `````` tag: 32 | 33 | ```html 34 | 35 | ``` 36 | 37 | 38 | ### Creating a custom build 39 | If you don't need all the features of this library, which I believe will be the case for most of you, I highly recommend you to modify the ```src/requirements.js``` file to only include the modules you need. 40 | 41 | Then, open your command line and execute the ```grunt``` command on the root directory of this repository (once you have NodeJS and Grunt installed). This will create a custom binary for you. 42 | 43 | Don't forget to enable GZipping on your server to make further savings on javascript transfers. 44 | 45 | 46 | 47 | ## Examples 48 | 49 | Here's a simple example adding a simple 'hidden' property to CSS: 50 | 51 | ```javascript 52 | !(function(window, document) { 53 | 54 | var cssCascade = require('core:css-cascade'), cssStyle = require('core:css-style'); 55 | var onHiddenChanged = function(element, rule) { 56 | 57 | var hiddenValue = cssCascade.getSpecifiedStyle(element, 'hidden').toString().trim(); 58 | if(hiddenValue == 'yes') { 59 | if(element.cssHiddenBackup == undefined) { 60 | element.cssHiddenBackup = cssStyle.enforceStyle(element, 'visibility', 'hidden'); 61 | } 62 | } else { 63 | if(element.cssHiddenBackup != undefined) { 64 | cssStyle.restoreStyle(element, element.cssHiddenBackup); 65 | element.cssHiddenBackup = undefined; 66 | } 67 | } 68 | 69 | }; 70 | cssCascade.startMonitoringProperties(['hidden'], { onupdate: onHiddenChanged }); 71 | 72 | })(window, document); 73 | ``` 74 | 75 | Please also have a look at the non-core directories in the src folder for more interesting examples. 76 | 77 | 78 | 79 | ## Documentation 80 | 81 | ### Use the friendly documentation 82 | Please have a look at the [friendly documentation](./doc/README.md). This documentation was specifically created to answer your questions, or point you directly to a more precise documentation of the API. 83 | 84 | ### Review the API summary 85 | _(Dense format coming soon, without any type annotations)_ 86 | 87 | ### Have a look at the code 88 | Please don't forget that if your questions weren't answered by the previously introduced documents, you may also have a look to the source code. It is usually well-documented from the inside, which may help you grasp implementation details. 89 | 90 | 91 | 92 | ## Contributing 93 | Please feel free to contribute to this project, either by fixing bugs in the core libraries or by adding new polyfills. 94 | 95 | If you work on a new polyfill, make sure it lives under its own directory in the ```src``` folder, and has a ```polyfill.js``` file that can be required in the ```src/requirements.js``` file to initialize your polyfill. We recommend putting all other files in a ```lib``` subdirectory. If you use grunt to build the ```polyfill.js``` file, please include your ```gruntfile``` in the repository, but not the downloaded ```node_modules``` (add the folder to ```.gitignore``` if necessary). 96 | 97 | In lieu of a formal styleguide, we will simply ask you to take care to maintain the existing coding style. For instance, please: 98 | * use tabs for indentation at the beginning of lines. 99 | * put opening braces on the same line as the block definition. 100 | * avoid if or else statements without braces. 101 | 102 | _Also, please don't edit files in the "bin" subdirectory as they are generated via Grunt. You'll find source code in the "src" subdirectory!_ 103 | 104 | 105 | 106 | ## Release History 107 | 108 | The aim of this section is to report the major milestones of the project: 109 | 110 | * 2014-09-21: First release of the framework, with a rough prototype css-grid polyfill. 111 | * 2014-10-11: Pushed a nearly-final v1.0 documentation of core components. 112 | 113 | 114 | 115 | ## License 116 | Copyright (c) 2014 François REMY 117 | Licensed under the MIT license. Some sections may have an Apache license applied to them. 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSS-Grid-Polyfill 2 | 3 | > IMPORTANT NOTE: The Grid specification has undergone several major changes since this polyfill was written, and I have not had time to work on keeping the polyfill up to date. I welcome contributions and am ready to help, but I do not have time to commit on fixing issues myself at this time. 4 | 5 | Welcome to this first version of the CSS-Grid-Polyfill. The goal of this project is to provide a working implementation of css grids for current browsers, for prototyping purposes. 6 | 7 | 8 | 9 | ## What’s in for you? 10 | You are now ready to try out css grids in IE 9+ and probably most other recent browsers, with the simple addition of a script on your page – and to the condition your style sheets are located on your own server (or accessible via CORS). 11 | 12 | The polyfill’s css parser was built by following the CSS Syntax 3 specification, the polyfill should be able to process any css stylesheet. It can react to dynamic pseudo-classes like ‘:hover’, to media queries changes or window resize events. It also detects changes to the DOM that may affect the layout of your grid. 13 | 14 | Most features of the css grid spec are in. For instance, the polyfill support more features than the IE’s implementation, as well as all the features implemented in Chrome Canary under a flag today, and actually renders more accurately than Chrome in most cases. [Edit: As of May 2015, this is no longer true as bugs I reported were fixed, and Chrome added new features] 15 | 16 | Use any of the possible ways you can define a grid (rows/columns, grid lines, areas, …) and mix them as you wish, with the caveat that you align items to the right edge of the grid using negative indexes, or with fixed row/column-end and a span value as row/column-start. 17 | 18 | Automatic placement is supported with both the ‘normal’ and the ‘dense’ algorithms. Each one comes in both the ‘row’ and ‘column’ flavors (which allow you to choose the direction in which the automatic algorithm progress, from left to right or from top to bottom). 19 | 20 | Fraction sizes (the ‘fr’ unit) are also supported, and are indented to work exactly as the spec says it should. 21 | 22 | 23 | 24 | ## Show me some demos! 25 | I guess you should be somewhat impressed at this point, but wonder if things are really as beautiful as painted before, so let’s move to actual demos! 26 | 27 | * [Bootstrap 16-columns grid](https://rawgit.com/FremyCompany/css-grid-polyfill/master/demo/css-grid/layout4.html) 28 | * [Responsive blog design](https://rawgit.com/FremyCompany/css-grid-polyfill/master/demo/css-grid/layout3.html) 29 | * [Mixing cell-positioned and non-cell-positioned items](https://rawgit.com/FremyCompany/css-grid-polyfill/master/demo/css-grid/example19.html) 30 | * [Z-Index support](https://rawgit.com/FremyCompany/css-grid-polyfill/master/demo/css-grid/example17.html) 31 | * [Basic Hover Test](https://rawgit.com/FremyCompany/css-grid-polyfill/master/demo/css-grid/basic-hover-test.html) 32 | 33 | NOTE: most of those demos are coming from “[Grid By Example](http://gridbyexample.com/)”, a website from Rachel Andrew. 34 | 35 | 36 | 37 | ## What’s not working right now? 38 | As always, there has to be gotchas. 39 | 40 | Because the layout is done asynchronously, the polyfill may play badly with other libraries that expect layout to be performed synchronously. This is particularly true if you plan to animate your grid. 41 | 42 | The whole polyfill is very sensitive to changes to the “box-sizing” property (and many frameworks like Bootstrap do make use of it); again, this will be ironed out soon but you have to be aware. 43 | 44 | The polyfill doesn’t like fixed/absolutely positioned grid items. If you want to use them, just put them in a dummy wrapper, it will work fine. 45 | 46 | Like IE and Chrome, the polyfill does not support the “subgrid” feature, and (similarly) doesn’t like when a grid-item is a grid itself. I hope to solve this someday using a CSS Layout Polyfill Infrastructure but this will require some background work I don’t expect to have time to do in the immediate future. 47 | 48 | Also, I’m you’ll find other bugs I didn’t mention. Please bear with me ^_^ 49 | 50 | 51 | 52 | ## Should I use that in production? 53 | Your call. I wouldn’t say this polyfill is slow by any measure, but your mileage may vary on mobile devices. My advice would be to use the polyfill only on tablets and desktops at the moment, after you have tested the compatibility and performance extensively on a representative number of devices. 54 | 55 | To the contrary of my previous CSS Regions Polyfill, I didn’t carry such a broad compatibility and performance testing myself at the moment because I still expect to change the code significantly in the future, so that would be wasted time. That doesn’t mean you can’t do it on your own, and report any issue you did find ;-) 56 | 57 | 58 | 59 | 60 | ## Can I contribute? 61 | Sure! Please report bugs here, and feel free to make pull requests! 62 | 63 | The code is globally pretty readable, and if it isn’t you can report it as a bug! Maintaining a good code quality is a requirement for this project, and I take this very seriously. 64 | 65 | 66 | 67 | ## Contributing 68 | Please feel free to contribute to this project, either by fixing bugs in the core libraries or by fixing the css-grid polyfill. 69 | 70 | In lieu of a formal styleguide, we will simply ask you to take care to maintain the existing coding style. For instance, please: 71 | * use tabs for indentation at the beginning of lines. 72 | * put opening braces on the same line as the block definition. 73 | * avoid if or else statements without braces. 74 | 75 | _Also, please don't edit files in the "bin" subdirectory as they are generated via Grunt. You'll find source code in the "src" subdirectory!_ 76 | 77 | ### Testing 78 | Rather than have to test your changes manually, you can add an example page to the `demo/` directory and run `npm run update-snapshots`. Then you can run the test server using `npm run test` and open `localhost:4743` in your browser. 79 | 80 | `npm run update-snapshots` - this will 'snapshot' how the newest version of Chromium lays out the elements inside a `.wrapper` element 81 | 82 | `npm run test` runs a server which serves a html file on the root path that will open all the html pages in the `demo/` directory in iframes and compare how they are laid out to the snapshots taken from Chromium. You can open this page in any browser to test how your changes work cross-browser. 83 | 84 | ## Release History 85 | 86 | The aim of this section is to report the major milestones of the project: 87 | 88 | * 2015-06-19: Added 'order' property, fixed bugs, and support the updated syntax 89 | * 2014-11-01: First release of the css-grid-polyfill 90 | 91 | You can follow the release or install them using bower from there: 92 | 93 | https://github.com/FremyCompany/css-grid-polyfill-binaries. 94 | 95 | 96 | ## License 97 | Copyright (c) 2014 François REMY 98 | Licensed under the MIT license. Some sections may have an Apache license applied to them. 99 | -------------------------------------------------------------------------------- /demo/css-grid/basic-hover-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Testing code 5 | 15 | 16 | 17 | 18 |
19 | 20 | 1: This very long text will maybe span across multiple lines 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /demo/css-grid/common.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 20px; 4 | color: #333; 5 | background-color: #efefef; 6 | font: 87.5%/1.4 HelveticaNeue, "Helvetica Neue", Helvetica, Arial, sans-serif; 7 | } 8 | 9 | img { 10 | max-width: 100%; 11 | display: block; 12 | height: auto; 13 | } 14 | 15 | figure { 16 | margin: 0; 17 | padding: 0; 18 | } 19 | 20 | figcaption { 21 | font-family: "Georgia","Times New Roman",serif; 22 | text-align: center; 23 | padding: 0.5em 0 1em 0; 24 | } 25 | 26 | h1, h2, h3, h4, h5, h6 { 27 | font-family: "Georgia","Times New Roman",serif; 28 | font-weight: normal; 29 | padding: 0; 30 | margin: 0; 31 | } 32 | 33 | h1 { 34 | font-size: 328.571%; 35 | margin-bottom: 0.2em; 36 | } 37 | 38 | h1.title { 39 | text-align: center; 40 | } 41 | 42 | h2 { 43 | font-size: 250%; 44 | margin-bottom: 0.2em; 45 | } 46 | 47 | h3 { 48 | font-size: 150%; 49 | margin-bottom: 0.2em; 50 | } 51 | 52 | p { 53 | margin:0; 54 | padding: 0 0 1em 0; 55 | } 56 | 57 | .wrapper { 58 | background-color: #fff; 59 | color: #444; 60 | padding: 1em 3% 1em 3%; 61 | margin: 0 auto 1em auto; 62 | 63 | } 64 | 65 | .mainnav ul { 66 | margin: 0; 67 | padding: 0; 68 | list-style: none; 69 | font-size: 120%; 70 | } 71 | 72 | .mainnav a:link, .mainnav a:visited { 73 | text-decoration: none; 74 | color: #444; 75 | } 76 | 77 | .quote { 78 | font: 150%/1.4 "Georgia","Times New Roman",serif; 79 | padding: 0; 80 | margin: 0; 81 | } -------------------------------------------------------------------------------- /demo/css-grid/example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 1 5 | 6 | 30 | 31 | 32 | 33 | 34 |
35 |
A
36 |
B
37 |
C
38 |
D
39 |
E
40 |
F
41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /demo/css-grid/example10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 10 5 | 6 | 52 | 53 | 54 | 55 | 56 |
57 |
A
58 |
B
59 |
C
60 |
D
61 |
E
62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /demo/css-grid/example11.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 11 5 | 6 | 51 | 52 | 53 | 54 | 55 |
56 |
Header
57 | 58 |
Content
59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /demo/css-grid/example12.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 12 5 | 6 | 56 | 57 | 58 | 59 | 60 |
61 |
Header
62 | 63 |
Content 64 |
More content than we had before so this column is now quite tall.
65 | 66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /demo/css-grid/example13.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 13 5 | 6 | 82 | 83 | 84 | 85 | 86 |
87 |
Header
88 | 89 |
Sidebar 2
90 |
Content 91 |
More content than we had before so this column is now quite tall.
92 | 93 |
94 | 95 | 96 | -------------------------------------------------------------------------------- /demo/css-grid/example14.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 14 5 | 6 | 53 | 54 | 55 | 56 | 57 |
58 |
59 |

In our urban and suburban houses what should we do without cats? In our sitting or bedrooms, our libraries, in our kitchens and storerooms, our farms, barns, and rickyards, in our docks, our granaries, our ships, and our wharves, in our corn markets, meat markets, and other places too numerous to mention, how useful they are! In our ships, however, the rats oft set them at defiance; still they are of great service.

60 |
61 |
62 |

How wonderfully patient is the cat when watching for rats or mice, awaiting their egress from their place of refuge or that which is their home! How well Shakespeare in Pericles, Act iii., describes this keen attention of the cat to its natural pursuit!

63 | 64 | 65 |
66 |
67 | 68 |

A slight rustle, and the fugitive comes forth; a quick, sharp, resolute motion, and the cat has proved its usefulness. Let any one have a plague of rats and mice, as I once had, and let them be delivered therefrom by cats, as I was, and they will have a lasting and kind regard for them.

69 | 70 | 71 |
72 |
Advert!
73 |
Another lovely advert!
74 |
75 | 76 | 77 | -------------------------------------------------------------------------------- /demo/css-grid/example15.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 15 5 | 6 | 60 | 61 | 62 | 63 | 64 |
65 |
A
66 |
B
67 |
C
68 |
D
69 |
E
70 |
F
71 |
72 | 73 | 74 | -------------------------------------------------------------------------------- /demo/css-grid/example16.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 16 5 | 6 | 78 | 79 | 80 | 81 | 82 |
83 |
Header
84 | 85 |
Content 86 |
The four arrows are inline images inside the content area. 87 | top left 88 | top right 89 | bottom left 90 | bottom right
91 | 92 |
93 | 94 | 95 | -------------------------------------------------------------------------------- /demo/css-grid/example17.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 17 5 | 6 | 36 | 37 | 38 | 39 | 40 |
41 |
1
42 |
2
43 |
3
44 |
4
45 |
5
46 |
6
47 |
7
48 |
8
49 |
9
50 |
10
51 |
11
52 |
12
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /demo/css-grid/example18.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 18 5 | 6 | 36 | 37 | 38 | 39 | 40 |
41 |
1
42 |
2
43 |
3
44 |
4
45 |
5
46 |
6
47 |
7
48 |
8
49 |
9
50 |
10
51 |
11
52 |
12
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /demo/css-grid/example19.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 18 5 | 6 | 41 | 42 | 43 | 44 | 45 |
46 |
1
47 |
2
48 |
3
49 |
4
50 |
5
51 |
6
52 |
7
53 |
8
54 |
9
55 |
10
56 |
11
57 |
12
58 |
59 | 60 | 61 | -------------------------------------------------------------------------------- /demo/css-grid/example2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 2 5 | 6 | 68 | 69 | 70 | 71 | 72 |
73 |
A
74 |
B
75 |
C
76 |
D
77 |
E
78 |
F
79 |
80 | 81 | 82 | -------------------------------------------------------------------------------- /demo/css-grid/example3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 3 5 | 6 | 54 | 55 | 56 | 57 | 58 |
59 |
A
60 |
B
61 |
C
62 |
D
63 |
E
64 |
F
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /demo/css-grid/example4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 4 5 | 6 | 48 | 49 | 50 | 51 | 52 |
53 |
A
54 |
B
55 |
C
56 |
D
57 |
E
58 |
F
59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /demo/css-grid/example5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 5 5 | 6 | 47 | 48 | 49 | 50 | 51 |
52 |
A
53 |
B
54 |
C
55 |
D
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /demo/css-grid/example6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 6 5 | 6 | 47 | 48 | 49 | 50 | 51 |
52 |
A
53 |
B
54 |
C
55 |
D
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /demo/css-grid/example7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 7 5 | 6 | 47 | 48 | 49 | 50 | 51 |
52 |
A
53 |
B
54 |
C
55 |
D
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /demo/css-grid/example8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 8 5 | 6 | 52 | 53 | 54 | 55 | 56 |
57 |
A
58 |
B
59 |
C
60 |
D
61 |
E
62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /demo/css-grid/example9.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 9 5 | 6 | 52 | 53 | 54 | 55 | 56 |
57 |
A
58 |
B
59 |
C
60 |
D
61 |
E
62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /demo/css-grid/gap-col.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 15 5 | 6 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
A
36 |
B
37 |
C
38 |
D
39 |
E
40 |
F
41 |
G
42 |
H
43 |
I
44 |
45 | 46 | 47 |
48 |
A
49 |
B
50 |
C
51 |
D
52 |
E
53 |
F
54 |
G
55 |
H
56 |
I
57 |
58 | 59 | 60 |
61 |
A
62 |
B
63 |
C
64 |
D
65 |
E
66 |
F
67 |
G
68 |
H
69 |
I
70 |
71 | 72 | 79 |
80 |
A
81 |
B
82 |
C
83 |
D
84 |
E
85 |
F
86 |
G
87 |
H
88 |
I
89 |
J
90 |
K
91 |
L
92 |
93 | 94 | 95 | -------------------------------------------------------------------------------- /demo/css-grid/gap-row.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 15 5 | 6 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
A
36 |
B
37 |
C
38 |
D
39 |
E
40 |
F
41 |
G
42 |
H
43 |
I
44 |
45 | 46 | 47 |
48 |
A
49 |
B
50 |
C
51 |
D
52 |
E
53 |
F
54 |
G
55 |
H
56 |
I
57 |
58 | 59 | 60 |
61 |
A
62 |
B
63 |
C
64 |
D
65 |
E
66 |
F
67 |
G
68 |
H
69 |
I
70 |
71 | 72 | 79 |
80 |
A
81 |
B
82 |
C
83 |
D
84 |
E
85 |
F
86 |
G
87 |
H
88 |
I
89 |
J
90 |
K
91 |
L
92 |
93 | 94 | 95 | -------------------------------------------------------------------------------- /demo/css-grid/gap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Example 15 5 | 6 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
A
36 |
B
37 |
C
38 |
D
39 |
E
40 |
F
41 |
G
42 |
H
43 |
I
44 |
45 | 46 | 47 |
48 |
A
49 |
B
50 |
C
51 |
D
52 |
E
53 |
F
54 |
G
55 |
H
56 |
I
57 |
58 | 59 | 60 |
61 |
A
62 |
B
63 |
C
64 |
D
65 |
E
66 |
F
67 |
G
68 |
H
69 |
I
70 |
71 | 72 | 79 |
80 |
A
81 |
B
82 |
C
83 |
D
84 |
E
85 |
F
86 |
G
87 |
H
88 |
I
89 |
J
90 |
K
91 |
L
92 |
93 | 94 | 95 | -------------------------------------------------------------------------------- /demo/css-grid/ie11bug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | grid layout dynamic class IE11 bug example 10 | 11 | 12 | 100 | 101 | 102 | 103 |
104 |

works on Chrome, doesn't work on IE11

105 | 107 |
108 | 110 | 112 | 114 | 116 |
117 | 119 |
120 | 121 |
122 |
01
123 |
02
124 |
03
125 |
04
126 |
127 | 128 | 156 | 157 | 166 | 167 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /demo/css-grid/layout1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout 1 7 | 8 | 47 | 48 | 49 |

Extracts from "Our Cats, by Harrison Weir"

50 | 51 |
52 | 53 | 62 |

Usefulness of cats

63 |
64 | 65 |

In our urban and suburban houses what should we do without cats? In our sitting or bedrooms, our libraries, in our kitchens and storerooms, our farms, barns, and rickyards, in our docks, our granaries, our ships, and our wharves, in our corn markets, meat markets, and other places too numerous to mention, how useful they are! In our ships, however, the rats oft set them at defiance; still they are of great service.

66 | 67 |

How wonderfully patient is the cat when watching for rats or mice, awaiting their egress from their place of refuge or that which is their home! How well Shakespeare in Pericles, Act iii., describes this keen attention of the cat to its natural pursuit!

68 | 69 |

The cat, with eyne of burning coal, Now crouches from (before) the mouse's hole.

70 | 71 | 72 |
73 | 74 |
75 |

Let any one have a plague of rats and mice, as I once had, and let them be delivered therefrom by cats, as I was, and they will have a lasting and kind regard for them.

76 |
77 | 78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /demo/css-grid/layout2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout 2 7 | 8 | 96 | 97 | 98 |

Extracts from "Our Cats, by Harrison Weir"

99 | 100 |
101 | 102 | 111 |

Usefulness of cats

112 |
113 | 114 |

In our urban and suburban houses what should we do without cats? In our sitting or bedrooms, our libraries, in our kitchens and storerooms, our farms, barns, and rickyards, in our docks, our granaries, our ships, and our wharves, in our corn markets, meat markets, and other places too numerous to mention, how useful they are! In our ships, however, the rats oft set them at defiance; still they are of great service.

115 | 116 |

How wonderfully patient is the cat when watching for rats or mice, awaiting their egress from their place of refuge or that which is their home! How well Shakespeare in Pericles, Act iii., describes this keen attention of the cat to its natural pursuit!

117 | 118 |

The cat, with eyne of burning coal, Now crouches from (before) the mouse's hole.

119 | 120 |

A slight rustle, and the fugitive comes forth; a quick, sharp, resolute motion, and the cat has proved its usefulness. Let any one have a plague of rats and mice, as I once had, and let them be delivered therefrom by cats, as I was, and they will have a lasting and kind regard for them.

121 | 122 | 123 |
124 | 125 |
126 |

Let any one have a plague of rats and mice, as I once had, and let them be delivered therefrom by cats, as I was, and they will have a lasting and kind regard for them.

127 |
128 | 129 |
130 | 131 | 132 | -------------------------------------------------------------------------------- /demo/css-grid/layout3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout 3 7 | 8 | 9 | 76 | 77 | 78 |

Extracts from "Our Cats, by Harrison Weir"

79 | 80 |
81 | 82 | 91 |

Usefulness of cats

92 |
93 | 94 |

In our urban and suburban houses what should we do without cats? In our sitting or bedrooms, our libraries, in our kitchens and storerooms, our farms, barns, and rickyards, in our docks, our granaries, our ships, and our wharves, in our corn markets, meat markets, and other places too numerous to mention, how useful they are! In our ships, however, the rats oft set them at defiance; still they are of great service.

95 | 96 |

How wonderfully patient is the cat when watching for rats or mice, awaiting their egress from their place of refuge or that which is their home! How well Shakespeare in Pericles, Act iii., describes this keen attention of the cat to its natural pursuit!

97 | 98 |

The cat, with eyne of burning coal, Now crouches from (before) the mouse's hole.

99 | 100 |

A slight rustle, and the fugitive comes forth; a quick, sharp, resolute motion, and the cat has proved its usefulness. Let any one have a plague of rats and mice, as I once had, and let them be delivered therefrom by cats, as I was, and they will have a lasting and kind regard for them.

101 | 102 | 103 |
104 | 105 |
106 |

Let any one have a plague of rats and mice, as I once had, and let them be delivered therefrom by cats, as I was, and they will have a lasting and kind regard for them.

107 |
108 | 109 | Fluffy the cat 110 | 111 |
112 | 113 | 114 | -------------------------------------------------------------------------------- /demo/css-grid/layout4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout 4 7 | 110 | 111 | 112 |

Flexible Grid

113 | 114 |
115 |
01
116 |
02
117 |
03
118 |
04
119 |
05
120 |
06
121 |
07
122 |
08
123 |
09
124 |
10
125 |
11
126 |
12
127 |
13
128 |
14
129 |
15
130 |
16
131 | 132 |
17
133 |
18
134 |
19
135 |
20
136 |
21
137 |
22
138 |
23
139 |
24
140 | 141 |
25
142 |
26
143 |
27
144 |
28
145 |
29
146 | 147 | 148 |
30
149 |
31
150 |
32
151 |
33
152 | 153 | 154 |
155 | 156 | 157 | -------------------------------------------------------------------------------- /demo/css-grid/layout5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout 5 7 | 96 | 97 | 98 |

Flexible Grid

99 | 100 |
101 |

Usefulness of Cats

102 | 103 |
104 |

In our urban and suburban houses what should we do without cats? In our sitting or bedrooms, our libraries, in our kitchens and storerooms, our farms, barns, and rickyards, in our docks, our granaries, our ships, and our wharves, in our corn markets, meat markets, and other places too numerous to mention, how useful they are! In our ships, however, the rats oft set them at defiance; still they are of great service.

105 | 106 |

How wonderfully patient is the cat when watching for rats or mice, awaiting their egress from their place of refuge or that which is their home! How well Shakespeare in Pericles, Act iii., describes this keen attention of the cat to its natural pursuit!

107 | 108 |
109 | 110 | 111 |
112 | 113 | 114 | -------------------------------------------------------------------------------- /demo/css-grid/order-property.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test for the order property 5 | 6 | 33 | 34 | 35 | 36 | 37 |
38 |
F
39 |
D
40 |
E
41 |
B
42 |
C
43 |
A
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /demo/css-grid/sroll-preservation-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Scroll preseveration 5 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |
22 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /demo/css-grid/tests/test-runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CSS Grid Polyfill Test Runner 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /demo/css-grid/tests/test-runner.js: -------------------------------------------------------------------------------- 1 | 2 | function compare( document, selectorStyleMap, errorPrefix ) { 3 | 4 | var selectorDiffStyleMap = {}; 5 | 6 | Object.keys( selectorStyleMap ).forEach( function(selector) { 7 | 8 | var el = document.body.querySelector(selector); 9 | var wrapper = el.parentElement; 10 | var { top: elTop, left: elLeft, width, height } = el.getBoundingClientRect(); 11 | var { top: wTop, left: wLeft } = wrapper.getBoundingClientRect(); 12 | var top = elTop - wTop; 13 | var left = elLeft - wLeft; 14 | 15 | var expectedStyles = selectorStyleMap[selector]; 16 | var actualStyles = { top, left, width, height }; 17 | var diffStyles = selectorDiffStyleMap[selector] = {}; 18 | 19 | matchOrStoreDiff('top'); 20 | matchOrStoreDiff('left'); 21 | matchOrStoreDiff('width'); 22 | matchOrStoreDiff('height'); 23 | 24 | function matchOrStoreDiff(prop) { 25 | 26 | var actual = actualStyles[prop]; 27 | var expected = expectedStyles[prop]; 28 | var min_expected = expected - actual * 0.05; 29 | var max_expected = expected + actual * 0.05; 30 | 31 | if( actual < min_expected || actual > max_expected ) { 32 | diffStyles[prop] = { actual, expected }; 33 | } 34 | } 35 | }); 36 | 37 | deleteEmptyObjectProps(selectorDiffStyleMap, 2); 38 | 39 | return selectorDiffStyleMap; 40 | } 41 | 42 | function deleteEmptyObjectProps( obj, depth) { 43 | depth = depth || 1; 44 | 45 | Object.keys( obj ).forEach( function(key) { 46 | if( Object.keys(obj[key]).length === 0 ) 47 | delete obj[key]; 48 | else if( depth > 1 ) 49 | deleteEmptyObjectProps(obj[key], depth - 1); 50 | }); 51 | 52 | return obj; 53 | } 54 | 55 | function test( iframeDoc, selectorStyleMap, filename, width ) { 56 | var result = document.createElement('div'); 57 | result.innerText = 'Pending... ($filename x$width)'.replace('$filename', filename).replace('$width', width); 58 | document.body.appendChild(result); 59 | 60 | var selectorDiffStyleMap = compare( iframeDoc, selectorStyleMap, [filename, width].join(' ') ); 61 | 62 | if( Object.keys(selectorDiffStyleMap).length === 0 ) { 63 | result.innerText = 'Passed ($filename x$width)'.replace('$filename', filename).replace('$width', width); 64 | result.style.color = 'green'; 65 | } 66 | else { 67 | result.innerText = 'Failed ($filename x$width)'.replace('$filename', filename).replace('$width', width); 68 | result.style.color = 'red'; 69 | 70 | var diff = document.createElement('pre'); 71 | diff.innerText = JSON.stringify(selectorDiffStyleMap, null, 2); 72 | diff.style.color = 'red'; 73 | diff.style.marginLeft = '2em'; 74 | document.body.appendChild(diff); 75 | } 76 | } 77 | 78 | function testAll() { 79 | 80 | const container = document.querySelector('#iframes'); 81 | 82 | Object.keys( snapshots ).forEach( function(filename) { 83 | 84 | Object.keys( snapshots[filename] ).forEach( function(width) { 85 | 86 | var iframe = document.createElement('iframe'); 87 | iframe.width = width; 88 | iframe.height = width; 89 | iframe.src = '../' + filename; 90 | 91 | iframe.addEventListener('load', function() { 92 | var window = iframe.contentWindow; 93 | var document = iframe.contentDocument; 94 | 95 | test( document, snapshots[filename][width], filename, width ); 96 | }); 97 | 98 | container.appendChild(iframe); 99 | }); 100 | }); 101 | } 102 | 103 | testAll(); 104 | -------------------------------------------------------------------------------- /demo/css-grid/tests/test-server.js: -------------------------------------------------------------------------------- 1 | 2 | const http = require('http'); 3 | const fs = require('fs'); 4 | 5 | // rudimentatary server to run tests 6 | // required to allow access into iframes with cross-origin error 7 | // reads files from disk synchronously - sorry, not sorry 8 | const server = http.createServer( (req, res) => { 9 | 10 | const sendFile = filepath => fs.createReadStream(__dirname + '/' + filepath).pipe(res).on('error', console.error); 11 | 12 | switch( req.url ) { 13 | case '/favicon.ico': return res.end(); 14 | case '/': return sendFile('./test-runner.html'); 15 | case '/snapshots.js': return sendFile('./snapshots.js'); 16 | case '/test-runner.js': return sendFile('./test-runner.js'); 17 | default: 18 | if( req.url.startsWith('/bin/') ) return sendFile('../../..' + req.url); 19 | else return sendFile('..' + req.url); 20 | } 21 | }).listen(4743, () => console.log('Listening on port 4743')); 22 | -------------------------------------------------------------------------------- /demo/css-grid/tests/update-snapshots.js: -------------------------------------------------------------------------------- 1 | 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const puppeteer = require('puppeteer'); 5 | 6 | const screen_sizes = [320, 720, 1480]; 7 | 8 | const writeFile = (filename, content) => new Promise( (resolve, reject) => 9 | fs.writeFile( filename, content, 'utf-8', err => err ? reject(err) : resolve() ) 10 | ); 11 | 12 | (async () => { 13 | 14 | const browser = await puppeteer.launch({ headless: false, slowMo: 1000 }); console.log('launched'); 15 | 16 | const dirpath = path.resolve('..'); 17 | const snapshots = {}; 18 | 19 | await Promise.all( 20 | fs.readdirSync(dirpath).map( async filename => { 21 | 22 | if( filename.endsWith('.html') ) { 23 | 24 | snapshots[filename] = {}; 25 | 26 | await Promise.all( 27 | screen_sizes.map( async width => { 28 | 29 | const page = await browser.newPage(); 30 | await page.setViewport({ width, height: width }); 31 | await page.goto(`file:///${ dirpath }/${ filename }`); 32 | await new Promise(resolve => setTimeout(resolve, 100)); 33 | 34 | snapshots[filename][width] = await page.evaluate(getStyles); 35 | 36 | await page.close(); 37 | }) 38 | ); 39 | } 40 | }) 41 | ).catch(console.error); 42 | 43 | deleteEmptyObjectProps(snapshots, 2); 44 | 45 | await writeFile( './snapshots.js', 'var snapshots = ' + JSON.stringify(snapshots, null, 2) ); 46 | 47 | console.log('Updated snapshots.js') 48 | console.log('Review the changes and commit them to the repo'); 49 | 50 | await browser.close(); 51 | })(); 52 | 53 | function deleteEmptyObjectProps( obj, depth = 1) { 54 | 55 | Object.keys( obj ).forEach( function(key) { 56 | if( Object.keys(obj[key]).length === 0 ) 57 | delete obj[key]; 58 | else if( depth > 1 ) 59 | deleteEmptyObjectProps(obj[key], depth - 1); 60 | }); 61 | 62 | return obj; 63 | } 64 | 65 | function getStyles() { 66 | 67 | const selectorStyleMap = {}; 68 | 69 | for( let wrapper of document.body.querySelectorAll('.wrapper') ) { 70 | 71 | const wrapperSelector = '.' + Array.from(wrapper.classList).join('.'); 72 | const { top: wTop, left: wLeft } = wrapper.getBoundingClientRect(); 73 | 74 | Array.from( wrapper.children ).forEach( (el, i) => { 75 | if( el.classList.length === 0 ) return; 76 | 77 | const selector = wrapperSelector + ' .' + Array.from(el.classList).join('.') + ':nth-child(' + (i+1) + ')'; 78 | const { top: elTop, left: elLeft, width, height } = el.getBoundingClientRect(); 79 | const top = elTop - wTop; 80 | const left = elLeft - wLeft; 81 | 82 | selectorStyleMap[selector] = { top, left, width, height }; 83 | }); 84 | } 85 | 86 | return selectorStyleMap; 87 | } 88 | -------------------------------------------------------------------------------- /demo/css-grid/zero-unit-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Zero Unit Test 5 | 6 | 42 | 43 | 44 | 45 | 47 |
48 |
1
49 |
2
50 |
3
51 |
4
52 |
5
53 |
6
54 |
7
55 |
8
56 |
9
57 |
10
58 |
11
59 |
12
60 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | CSS Polyfills (Parallia Framework) 2 | =================================== 3 | 4 | The goal of this project is to serve as a stable and efficient base for many css polyfills. 5 | 6 | To make this objective a working thing, the project is divided into modules which can be loaded on demand. 7 | 8 | This documentation is only a beginning, please feel free to improve it while you discover new useful things. Please note this file is automatically generated from the typescript files in this folder, so please edit those files, and run "grunt concat:doc" to update this one. 9 | 10 | 11 | 12 | [CSS-BOX](./core/css-box.ts) 13 | =================================== 14 | Provides an easier way to deal with the different css style objects of an element. 15 | 16 | ### How do you get the border-box of an element? 17 | 18 | ```javascript 19 | var cssBox = require('core:css-box'); 20 | var box = cssBox.getBox(document.body, 'border-box'); 21 | return { top: box.top, left: box.left, right: box.left+box.width, bottom: box.top+box.height }; 22 | ``` 23 | 24 | ### How do you get the content-box of an element? 25 | 26 | ```javascript 27 | var cssBox = require('core:css-box'); 28 | var box = cssBox.getBox(document.body, 'content-box'); 29 | return { top: box.top, left: box.left, right: box.left+box.width, bottom: box.top+box.height }; 30 | ``` 31 | 32 | ### What kind of boxes can you get for an element? 33 | 34 | ```javascript 35 | return ["content-box", "padding-box", "border-box", "margin-box"]; 36 | ``` 37 | 38 | 39 | [CSS-CASCADE](./core/css-cascade.ts) 40 | =================================== 41 | Provide helpers to interact with or simulate the css cascading engine. 42 | 43 | ### How do you start monitoring a css property? 44 | 45 | ```javascript 46 | var cssCascade = require('core:css-cascade'); 47 | cssCascade.startMonitoringProperties( 48 | ["-css-grid", "-css-grid-row", "css-grid-col"], 49 | { 50 | onupdate: function(element, rule) { 51 | // TODO: update the layout of "element" 52 | } 53 | } 54 | ); 55 | ``` 56 | 57 | ### How do you find out the specified style for a property? 58 | 59 | ```javascript 60 | var cssCascade = require('core:css-cascade'); 61 | return cssCascade.getSpecifiedStyle(document.body, 'poly-grid') 62 | ``` 63 | 64 | ### How do you find out the specified style for multiple properties? 65 | 66 | ```javascript 67 | var cssCascade = require('core:css-cascade'); 68 | var rules = cssCascade.findAllMatchingRules(document.body); 69 | var row = cssCascade.getSpecifiedStyle(document.body, 'poly-grid-row', rules); 70 | var col = cssCascade.getSpecifiedStyle(document.body, 'poly-grid-col', rules); 71 | return [row, col]; 72 | ``` 73 | 74 | ### How do you polyfill a property style getter/setter? 75 | 76 | ```javascript 77 | var cssCascade = require('core:css-cascade'); 78 | cssCascade.polyfillStyleInterface('poly-grid'); 79 | 80 | var cssStyle = require('core:css-style').valueOf(); 81 | var style = cssStyle.usedStyleOf(document.body); 82 | return style.polyGrid; 83 | ``` 84 | 85 | ### How do you manually choose which stylesheets to polyfill? 86 | 87 | ```javascript 88 | // BEFORE LOADING THE POLYFILL: 89 | window['no_auto_stylesheet_detection'] = true; 90 | 91 | // AFTER LOADING THE POLYFILL: 92 | var cssCascade = require('core:css-cascade'); 93 | cssCascade.loadStyleSheet("* { color: red; }"); 94 | cssCascade.loadStyleSheetTag(document.querySelector('style.polyfill').valueOf()); 95 | ``` 96 | 97 | 98 | [CSS-SIZING](./core/css-sizing.ts) 99 | =================================== 100 | Provides a way to obtain some intrinsic size info out of displayed HTML Elements. 101 | 102 | ### How do you convert a value to pixels ? 103 | 104 | ```javascript 105 | var cssSizing = require('core:css-sizing'); 106 | var min = cssSizing.minWidthOf(document.body); 107 | var max = cssSizing.maxWidthOf(document.body); 108 | return [min, max]; 109 | ``` 110 | 111 | 112 | [CSS-STYLE](./core/css-style.ts) 113 | =================================== 114 | Provides an easier way to deal with the different css style objects of an element. 115 | 116 | ### How do you obtain the used value of a property? 117 | 118 | ```javascript 119 | var cssStyle = require('core:css-style'); 120 | return cssStyle.usedStyleOf(document.body).alignContent; 121 | ``` 122 | 123 | ### How do you override a style temporarily? 124 | 125 | ```javascript 126 | var cssStyle = require('core:css-style'); 127 | 128 | // set the runtime style 129 | var backup = cssStyle.enforceStyle(document.body, "color", "red"); 130 | 131 | // reset the previous value 132 | cssStyle.restoreStyle(document.body, backup); 133 | ``` 134 | 135 | 136 | [CSS-SYNTAX](./core/css-syntax.ts) 137 | =================================== 138 | Provides a "css-syntax-3" css parser. 139 | 140 | ### How do you transform a css text into tokens? 141 | 142 | ```javascript 143 | var cssSyntax = require('core:css-syntax'); 144 | return cssSyntax.tokenize("* { color: red; }"); 145 | ``` 146 | 147 | ### How do you parse a css stylesheet?? 148 | 149 | ```javascript 150 | var cssSyntax = require('core:css-syntax'); 151 | return cssSyntax.parse("* { color: red; }"); 152 | ``` 153 | 154 | ### How do you transform a css text into tokens? 155 | 156 | ```javascript 157 | var cssSyntax = require('core:css-syntax'); 158 | return cssSyntax.parseCSSValue("url('bg.png')"); 159 | ``` 160 | 161 | 162 | [CSS-UNITS](./core/css-units.ts) 163 | =================================== 164 | Provides a basic css unit converter. 165 | 166 | ### How do you convert a value to pixels ? 167 | 168 | ```javascript 169 | var cssUnits = require('core:css-units'); 170 | return cssUnits.convertToPixels("33%", document.body, { 171 | boxType: "content-box", 172 | isHeightRelated: true 173 | }); 174 | ``` 175 | 176 | ### How do you convert a value from pixels ? 177 | 178 | ```javascript 179 | var cssUnits = require('core:css-units'); 180 | return cssUnits.convertFromPixels(550/*px*/, /*to*/"em", document.body, { 181 | boxType: "content-box", 182 | isHeightRelated: true 183 | }); 184 | ``` 185 | 186 | 187 | [DOM-EVENTS](./core/dom-events.ts) 188 | =================================== 189 | Provides helpers for dealing with events in your code. 190 | 191 | ### How do you add support for events on a custom object ? 192 | 193 | ```javascript 194 | function SomeObject() { 195 | // init a new SomeObject 196 | } 197 | 198 | var domEvents = require('core:dom-events'); 199 | domEvents.EventTarget.implementsIn(SomeObject); 200 | ``` 201 | 202 | ### How do you retarget an existing event object ? 203 | 204 | ```javascript 205 | var domEvents = require('core:dom-events'); 206 | document.body.onclick = function(e) { 207 | 208 | // do as if we just clicked on #some-element instead 209 | var someEvent = domEvents.cloneEvent(e); 210 | var someElement = document.querySelector("#some-element"); 211 | someElement.dispatchEvent(someEvent); 212 | 213 | }; 214 | ``` 215 | -------------------------------------------------------------------------------- /doc/README[header].md: -------------------------------------------------------------------------------- 1 | CSS Polyfills (Parallia Framework) 2 | =================================== 3 | 4 | The goal of this project is to serve as a stable and efficient base for many css polyfills. 5 | 6 | To make this objective a working thing, the project is divided into modules which can be loaded on demand. 7 | 8 | This documentation is only a beginning, please feel free to improve it while you discover new useful things. Please note this file is automatically generated from the typescript files in this folder, so please edit those files, and run "grunt concat:doc" to update this one. 9 | 10 | -------------------------------------------------------------------------------- /doc/core/css-box.ts: -------------------------------------------------------------------------------- 1 | /// 2 | interface ModuleHub { (file: 'core:css-box'): CSSBox.CSSBoxModule; } 3 | module CSSBox { 4 | 5 | /** 6 | * Provides an easier way to deal with the different css style objects of an element. 7 | */ 8 | export interface CSSBoxModule extends Object { 9 | 10 | /** 11 | * Computes the local distance between the various boxes of an element (only works properly if the element has only one box). 12 | * 13 | * @param element The element for which the box is computed. 14 | * @param boxType of one: "content-box", "padding-box", "border-box" and "margin-box". 15 | * @return {top/left/width/height} for 'content/padding/border/margin-box' (relative to the border box top-left corner). 16 | */ 17 | getBox( 18 | element: HTMLElement, 19 | boxType: string 20 | ) 21 | : Box 22 | 23 | } 24 | 25 | export interface Box { 26 | top: number 27 | left: number 28 | width: number 29 | height: number 30 | } 31 | } 32 | 33 | 34 | 35 | ///////////////////////////////////////////////////////////////////////// 36 | //// EXAMPLES /////////////////////////////////////////////////////////// 37 | ///////////////////////////////////////////////////////////////////////// 38 | 39 | 40 | 41 | /** How do you get the border-box of an element? */ 42 | function get_border_box_of_element() { 43 | 44 | var cssBox = require('core:css-box'); 45 | var box = cssBox.getBox(document.body, 'border-box'); 46 | return { top: box.top, left: box.left, right: box.left+box.width, bottom: box.top+box.height }; 47 | 48 | } 49 | 50 | 51 | 52 | /** How do you get the content-box of an element? */ 53 | function get_content_box_of_element() { 54 | 55 | var cssBox = require('core:css-box'); 56 | var box = cssBox.getBox(document.body, 'content-box'); 57 | return { top: box.top, left: box.left, right: box.left+box.width, bottom: box.top+box.height }; 58 | 59 | } 60 | 61 | 62 | 63 | 64 | /** What kind of boxes can you get for an element? */ 65 | function get_boxes_kinds_of_element() { 66 | 67 | return ["content-box", "padding-box", "border-box", "margin-box"]; 68 | 69 | } 70 | -------------------------------------------------------------------------------- /doc/core/css-cascade.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | interface ModuleHub { (file: 'core:css-cascade'): CSSCascade.CSSCascadeModule; } 4 | module CSSCascade { 5 | 6 | 7 | /** 8 | * Provide helpers to interact with or simulate the css cascading engine. 9 | * This module is almost a necessary requirement for any css polyfill. 10 | */ 11 | export interface CSSCascadeModule extends Object { 12 | 13 | /** 14 | * Computes the priority of a CSS Selector given as a string. 15 | * 16 | * @param selector The CSS Selector to analyze; this cannot include multiple selectors separated by a comma. 17 | * @return A positive integer whose value becomes higher with the priority. 18 | */ 19 | computeSelectorPriorityOf( 20 | selector: string 21 | ) 22 | : number; 23 | 24 | /** 25 | * Finds all rules which match a specific element. 26 | * 27 | * Please note you will rarely need this function as most of this work is done by the library. 28 | * @param element The HTML element the rules will be matched against. We assume it is part of the DOM. 29 | * @return A list of CSS Style Rule which did match the provided element. 30 | */ 31 | findAllMatchingRules( 32 | element: HTMLElement 33 | ) 34 | : CSSSyntax.SpecializedTokenList; 35 | 36 | 37 | /** 38 | * Returns the specified style of a property on the provided element. 39 | * 40 | * The last two parameters will enable optimizations: 41 | * - matchedRules: allow you to mutualize the findAllMatchingRules call 42 | * --- PLEASE NOTE THIS IS OFTEN NOT NECESSARY IF YOU MONITOR THIS PROPERTY 43 | * - stringOnly: allow you to skip tokenization (a fake TokenList will be returned) 44 | * --- THIS WILL RETURN YOU A BUGGY TOKENLIST, BE WISE 45 | * 46 | * @param element The HTML element the rules will be matched against. We assume it is part of the DOM. 47 | * @param cssPropertyName The CSS property whose value will be returned. 48 | * @return A CSS TokenList containing the property value. 49 | */ 50 | getSpecifiedStyle( 51 | element: HTMLElement, 52 | cssPropertyName: string, 53 | matchedRules?: CSSSyntax.SpecializedTokenList, 54 | stringOnly?: boolean 55 | ) 56 | : CSSSyntax.TokenList 57 | 58 | 59 | /** 60 | * Sets up a listener for property changes on an element 61 | * 62 | * NOTE: the event may fire even if the property didn't really change, plan optimizations such as: 63 | * - DETECT NOOP CHANGES (when the final value didn't change as a result) 64 | * - DEBOUNCING UPDATES (you may get many events for an element during on single frame) 65 | * 66 | * @param properties An array of string containing the css properties to monitor 67 | * @param handler An object whose "onupdate" method will be called 68 | */ 69 | startMonitoringProperties( 70 | properties: Array, 71 | handler: OnElementRuleMatchChanged 72 | ) 73 | : void 74 | 75 | /** 76 | * Polyfills element.myStyle.propertyName and start monitoring a css property 77 | * 78 | * NOTE: it is recommended you use "cssStyle.styleOf(element)" instead of the "element.myStyle" property 79 | * @param cssPropertyName The property to emulate 80 | * 81 | */ 82 | polyfillStyleInterface( 83 | cssPropertyName: string 84 | ) 85 | : void 86 | 87 | /** 88 | * Load a polyfilled stylesheet via its css text 89 | * 90 | * @param cssText The content of the stylesheet 91 | * @param i The position of the stylesheet in the document (you should leave this undefined) 92 | */ 93 | loadStyleSheet( 94 | cssText: string, 95 | i?: number 96 | ) 97 | : void 98 | 99 | /** 100 | * Load a polyfilled stylesheet via its html element 101 | * 102 | * @param cssText The content of the stylesheet 103 | * @param i The position of the stylesheet in the document (you should leave this undefined) 104 | */ 105 | loadStyleSheetTag( 106 | element: HTMLElement, 107 | i?: number 108 | ) 109 | : void 110 | 111 | } 112 | 113 | export interface OnElementRuleMatchChanged { 114 | onupdate(element: HTMLElement, rule: CSSSyntax.StyleRule) : void 115 | } 116 | 117 | } 118 | 119 | interface HTMLElement { 120 | myStyle: CSSStyleDeclaration 121 | } 122 | 123 | ///////////////////////////////////////////////////////////////////////// 124 | //// EXAMPLES /////////////////////////////////////////////////////////// 125 | ///////////////////////////////////////////////////////////////////////// 126 | 127 | 128 | 129 | /** How do you start monitoring a css property? */ 130 | function monitor_some_property() { 131 | 132 | var cssCascade = require('core:css-cascade'); 133 | cssCascade.startMonitoringProperties( 134 | ["-css-grid", "-css-grid-row", "css-grid-col"], 135 | { 136 | onupdate: function(element, rule) { 137 | // TODO: update the layout of "element" 138 | } 139 | } 140 | ); 141 | 142 | } 143 | 144 | 145 | 146 | /** How do you find out the specified style for a property? */ 147 | function obtain_specified_style() { 148 | 149 | var cssCascade = require('core:css-cascade'); 150 | return cssCascade.getSpecifiedStyle(document.body, 'poly-grid') 151 | 152 | } 153 | 154 | 155 | 156 | /** How do you find out the specified style for multiple properties? */ 157 | function obtain_specified_styles() { 158 | 159 | var cssCascade = require('core:css-cascade'); 160 | var rules = cssCascade.findAllMatchingRules(document.body); 161 | var row = cssCascade.getSpecifiedStyle(document.body, 'poly-grid-row', rules); 162 | var col = cssCascade.getSpecifiedStyle(document.body, 'poly-grid-col', rules); 163 | return [row, col]; 164 | 165 | } 166 | 167 | 168 | 169 | /** How do you polyfill a property style getter/setter? */ 170 | function polyfill_property_getters() { 171 | 172 | var cssCascade = require('core:css-cascade'); 173 | cssCascade.polyfillStyleInterface('poly-grid'); 174 | 175 | var cssStyle = require('core:css-style').valueOf(); 176 | var style = cssStyle.usedStyleOf(document.body); 177 | return style.polyGrid; 178 | 179 | } 180 | 181 | 182 | 183 | /** How do you manually choose which stylesheets to polyfill? */ 184 | function manually_load_stylesheets() { 185 | 186 | // BEFORE LOADING THE POLYFILL: 187 | window['no_auto_stylesheet_detection'] = true; 188 | 189 | // AFTER LOADING THE POLYFILL: 190 | var cssCascade = require('core:css-cascade'); 191 | cssCascade.loadStyleSheet("* { color: red; }"); 192 | cssCascade.loadStyleSheetTag(document.querySelector('style.polyfill').valueOf()); 193 | 194 | } -------------------------------------------------------------------------------- /doc/core/css-sizing.ts: -------------------------------------------------------------------------------- 1 |  /// 2 | interface ModuleHub { (file: 'core:css-sizing'): CSSSizing.CSSSizingModule; } 3 | module CSSSizing { 4 | 5 | /** 6 | * Provides a way to obtain some intrinsic size info out of displayed HTML Elements. 7 | */ 8 | export interface CSSSizingModule extends Object { 9 | 10 | /* 11 | * Returns the size an element would have under normal conditions with a "width: 0px" parent. 12 | */ 13 | minWidthOf(element: HTMLElement) : number 14 | 15 | /* 16 | * Returns the size an element would have when absolutely positiioned without contraints 17 | */ 18 | maxWidthOf(element: HTMLElement) : number 19 | 20 | /* 21 | * Returns the size an element would have under a "width: 0px" constraint (right padding/border merged with overflow). 22 | * Usually, you want the result of "minWidthOf". When in doubt, use "minWidthOf". 23 | */ 24 | absoluteMinWidthOf(element: HTMLElement) : number 25 | 26 | /* 27 | * Returns the same value as maxWidthOf, but takes extra precautions before the computation. 28 | * Prefer "maxWidthOf" to this function, unless you are sure it may return a wrong value in some cases. 29 | */ 30 | absoluteMaxWidthOf(element: HTMLElement) : number 31 | 32 | } 33 | } 34 | 35 | 36 | 37 | ///////////////////////////////////////////////////////////////////////// 38 | //// EXAMPLES /////////////////////////////////////////////////////////// 39 | ///////////////////////////////////////////////////////////////////////// 40 | 41 | 42 | 43 | /** How do you convert a value to pixels ? */ 44 | function compute_min_max_width_element() { 45 | 46 | var cssSizing = require('core:css-sizing'); 47 | var min = cssSizing.minWidthOf(document.body); 48 | var max = cssSizing.maxWidthOf(document.body); 49 | return [min, max]; 50 | 51 | } -------------------------------------------------------------------------------- /doc/core/css-style.ts: -------------------------------------------------------------------------------- 1 | /// 2 | interface ModuleHub { (file: 'core:css-style'): CSSStyle.CSSStyleModule; } 3 | module CSSStyle { 4 | 5 | /** 6 | * Provides an easier way to deal with the different css style objects of an element. 7 | */ 8 | export interface CSSStyleModule extends Object { 9 | 10 | /** 11 | * Returns the available css style the closest possible to the used style of an element. 12 | * 13 | * NOTE: polyfilled properties from cssCascade.polyfillStyleInterface should work on this object. 14 | * @param element The element for which the style should be returned. 15 | */ 16 | usedStyleOf(element : HTMLElement) : CSSStyleDeclaration 17 | 18 | /** 19 | * Returns the available css style the closest possible to the cascaded style of an element. 20 | * 21 | * NOTE: polyfilled properties from cssCascade.polyfillStyleInterface should work on this object. 22 | * @param element The element for which the style should be returned. 23 | */ 24 | currentStyleOf(element : HTMLElement) : CSSStyleDeclaration 25 | 26 | /** 27 | * Returns the available css style the closest possible to the override style of an element. 28 | * 29 | * NOTE: polyfilled properties from cssCascade.polyfillStyleInterface should work on this object. 30 | * @param element The element for which the style should be returned. 31 | */ 32 | styleOf(element : HTMLElement) : CSSStyleDeclaration 33 | 34 | /** 35 | * Returns the available css style the closest possible to the runtime style of an element. 36 | * 37 | * NOTE: polyfilled properties from cssCascade.polyfillStyleInterface should work on this object. 38 | * @param element The element for which the style should be returned. 39 | */ 40 | runtimeStyleOf(element : HTMLElement) : CSSStyleDeclaration 41 | 42 | /** 43 | * Sets the runtime style of an element to the specified value, and return a backup for restore with restoreStyle. 44 | * 45 | * @param element The element for which the style should be modified. 46 | * @param property The (css) name of the property to override. 47 | * @param value The value the property will be set to. 48 | */ 49 | enforceStyle( 50 | element : HTMLElement, 51 | property : string, 52 | value : string 53 | ) 54 | : StyleBackup 55 | 56 | /** 57 | * Sets the runtime style of an element to the specified values, and return a backup for restore with restoreStyles. 58 | * 59 | * @param element The element for which the style should be modified. 60 | * @param propertyValues A dictionnary whose names represent css property names, and whose value will be used for that property. 61 | */ 62 | enforceStyles( 63 | element : HTMLElement, 64 | propertyValues : Object 65 | ) : Array 66 | 67 | /** 68 | * Restore the runtime style of an element to the specified value. 69 | * 70 | * @param element The element for which the style should be modified. 71 | * @param backup The backup obtained from enforceStyle. 72 | */ 73 | restoreStyle( 74 | element: HTMLElement, 75 | backup: StyleBackup 76 | ) 77 | : void 78 | 79 | /** 80 | * Restore the runtime style of an element to the specified values. 81 | * 82 | * @param element The element for which the style should be modified. 83 | * @param backup The backup obtained from enforceStyles. 84 | */ 85 | restoreStyles( 86 | element: HTMLElement, 87 | backup: Array 88 | ) 89 | : void 90 | 91 | } 92 | 93 | export interface StyleBackup { 94 | property : string 95 | value : string 96 | priority: string 97 | } 98 | 99 | } 100 | 101 | 102 | 103 | ///////////////////////////////////////////////////////////////////////// 104 | //// EXAMPLES /////////////////////////////////////////////////////////// 105 | ///////////////////////////////////////////////////////////////////////// 106 | 107 | 108 | 109 | /** How do you obtain the used value of a property? */ 110 | function obtain_css_value() { 111 | 112 | var cssStyle = require('core:css-style'); 113 | return cssStyle.usedStyleOf(document.body).alignContent; 114 | 115 | } 116 | 117 | 118 | 119 | /** How do you override a style temporarily? */ 120 | function override_css_value() { 121 | 122 | var cssStyle = require('core:css-style'); 123 | 124 | // set the runtime style 125 | var backup = cssStyle.enforceStyle(document.body, "color", "red"); 126 | 127 | // reset the previous value 128 | cssStyle.restoreStyle(document.body, backup); 129 | 130 | } 131 | -------------------------------------------------------------------------------- /doc/core/css-syntax.ts: -------------------------------------------------------------------------------- 1 | /// 2 | interface ModuleHub { (file: 'core:css-syntax'): CSSSyntax.CSSSyntaxModule; } 3 | module CSSSyntax { 4 | 5 | /** 6 | * Provides a "css-syntax-3" css parser. 7 | */ 8 | export interface CSSSyntaxModule extends Object { 9 | 10 | /** 11 | * Transforms a CSS String into a raw token list. 12 | * 13 | * @param cssValue The CSS String to tokenize. 14 | */ 15 | tokenize(cssValue: string): TokenList 16 | 17 | /** 18 | * Transforms a CSS String into a parsed Stylesheet. 19 | * 20 | * @param cssValue The CSS String to parse. 21 | */ 22 | parse(cssValue: string): StyleSheet 23 | 24 | /** 25 | * Transforms a CSS String into a parsed declaration value. 26 | * 27 | * @param cssValue The CSS String to parse. 28 | */ 29 | parseCSSValue(cssValue: string): TokenList 30 | 31 | TokenList: Constructor 32 | 33 | CSSParserToken: Constructor 34 | BadStringToken: Constructor 35 | BadURLToken: Constructor 36 | WhitespaceToken: Constructor 37 | CDOToken: Constructor 38 | CDCToken: Constructor 39 | ColonToken: Constructor 40 | SemicolonToken: Constructor 41 | OpenCurlyToken: Constructor 42 | CloseCurlyToken: Constructor 43 | OpenSquareToken: Constructor 44 | CloseSquareToken: Constructor 45 | OpenParenToken: Constructor 46 | CloseParenToken: Constructor 47 | EOFToken: Constructor 48 | DelimToken: Constructor 49 | IdentifierToken: Constructor 50 | FunctionToken: Constructor 51 | AtKeywordToken: Constructor 52 | HashToken: Constructor 53 | StringToken: Constructor 54 | NumberToken: Constructor 55 | PercentageToken: Constructor 56 | DimensionToken: Constructor 57 | UnicodeRangeToken: Constructor 58 | 59 | CSSParserRule: Constructor 60 | AtRule : Constructor> 61 | StyleRule : Constructor 62 | Declaration : Constructor 63 | SimpleBlock : Constructor 64 | Func : Constructor 65 | FuncArg: Constructor 66 | 67 | } 68 | 69 | 70 | 71 | /*=========================================================*/ /** 72 | Stores a list of css tokens */ 73 | export interface SpecializedTokenList< T > extends Array { 74 | 75 | /*=========================================================*/ /** 76 | Returns the original css string that generated this token list. */ 77 | toString(): string 78 | 79 | } 80 | 81 | /*=========================================================*/ /** 82 | Stores a list of css tokens */ 83 | export interface TokenList extends SpecializedTokenList { 84 | 85 | /*=========================================================*/ /** 86 | Returns the original css string that generated this token list. */ 87 | toString(): string 88 | 89 | } 90 | 91 | 92 | 93 | 94 | /*=========================================================*/ /** 95 | Represents a single css token */ 96 | export interface CSSParserToken extends Object { 97 | 98 | /*=========================================================*/ /** 99 | Returns the type of this css token. */ 100 | tokenType: string 101 | 102 | /*=========================================================*/ /** 103 | Returns the original css string that generated this token. */ 104 | toString(): string 105 | 106 | /*=========================================================*/ /** 107 | Returns a CSS representation of the object, as a string. */ 108 | toCSSString(): string 109 | 110 | } 111 | 112 | export interface BadStringToken extends CSSParserToken { } 113 | export interface BadURLToken extends CSSParserToken { } 114 | export interface WhitespaceToken extends CSSParserToken { } 115 | export interface CDOToken extends CSSParserToken { } 116 | export interface CDCToken extends CSSParserToken { } 117 | export interface ColonToken extends CSSParserToken { } 118 | export interface SemicolonToken extends CSSParserToken { } 119 | export interface OpenCurlyToken extends CSSParserToken { } 120 | export interface CloseCurlyToken extends CSSParserToken { } 121 | export interface OpenSquareToken extends CSSParserToken { } 122 | export interface CloseSquareToken extends CSSParserToken { } 123 | export interface OpenParenToken extends CSSParserToken { } 124 | export interface CloseParenToken extends CSSParserToken { } 125 | export interface EOFToken extends CSSParserToken { } 126 | export interface DelimToken extends CSSParserToken { /** The char value */ value: string } 127 | export interface IdentifierToken extends CSSParserToken { /** The identifier name */ value: string } 128 | export interface FunctionToken extends CSSParserToken { /** The function name */ value: string } 129 | export interface AtKeywordToken extends CSSParserToken { /** The @token name */ value: string } 130 | export interface HashToken extends CSSParserToken { /** The #token name */ value: string } 131 | export interface StringToken extends CSSParserToken { /** The string value */ value: string } 132 | export interface NumberToken extends CSSParserToken { /** The number value */ value: number; /** The number, as a string */ repr: string; /** Either integer or number */ type: string } 133 | export interface PercentageToken extends CSSParserToken { /** The number value */ value: number; /** The number, as a string */ repr: string; } 134 | export interface DimensionToken extends CSSParserToken { /** The number value */ num: number; /** The full dimension, as a string */ repr: string; /** The unit, as a string */ unit: string } 135 | export interface UnicodeRangeToken extends CSSParserToken { start: number; end: number; } 136 | 137 | /*=========================================================*/ /** 138 | Represents a single css rule */ 139 | export interface CSSParserRule extends CSSParserToken { 140 | 141 | /*=========================================================*/ /** 142 | Returns the type of the elements found in this rule. */ 143 | fillType: string 144 | 145 | /*=========================================================*/ /** 146 | Returns a JSON representation of the object, as a string. */ 147 | toString(): string 148 | 149 | /*=========================================================*/ /** 150 | Returns a CSS representation of the object, as a string. */ 151 | toCSSString(): string 152 | 153 | } 154 | 155 | /*=========================================================*/ /** 156 | Represents a single css rule */ 157 | export interface AtRule< T extends CSSParserToken > extends CSSParserRule { 158 | 159 | /*=========================================================*/ /** 160 | Returns the @name of the rule. */ 161 | name: string 162 | 163 | /*=========================================================*/ /** 164 | Returns a list of tokens following. */ 165 | prelude: DOMTokenList 166 | 167 | /*=========================================================*/ /** 168 | Returns the tokens or declarations found in this rule. */ 169 | value: Array 170 | 171 | } 172 | 173 | /*=========================================================*/ /** 174 | Represents a single css rule */ 175 | export interface StyleRule extends CSSParserRule { 176 | 177 | /*=========================================================*/ /** 178 | Returns the @name of the rule. */ 179 | name: string 180 | 181 | /*=========================================================*/ /** 182 | Returns the declarations found in this rule. */ 183 | value: SpecializedTokenList 184 | 185 | } 186 | 187 | /*=========================================================*/ /** 188 | Represents a single css declaration. */ 189 | export interface Declaration extends CSSParserRule { 190 | 191 | /*=========================================================*/ /** 192 | Returns the name of the property being declared. */ 193 | name: string 194 | 195 | /*=========================================================*/ /** 196 | Returns the tokens found in the value part of this declaration. */ 197 | value: TokenList 198 | 199 | } 200 | 201 | /*=========================================================*/ /** 202 | Represents a single css block. */ 203 | export interface SimpleBlock extends CSSParserRule { 204 | 205 | /*=========================================================*/ /** 206 | Returns the opening char; one of '(', '{' or '['. */ 207 | name: string 208 | 209 | /*=========================================================*/ /** 210 | Returns the tokens found in the value part of this declaration. */ 211 | value: TokenList 212 | 213 | } 214 | 215 | /*=========================================================*/ /** 216 | Represents a single css function-call. */ 217 | export interface Func extends CSSParserRule { 218 | 219 | /*=========================================================*/ /** 220 | Returns the opening char; one of '(', '{' or '['. */ 221 | name: string 222 | 223 | /*=========================================================*/ /** 224 | Returns the arguments of this function call. */ 225 | value: SpecializedTokenList 226 | 227 | } 228 | 229 | /*=========================================================*/ /** 230 | Represents a single css function-call. */ 231 | export interface FuncArg extends CSSParserRule { 232 | 233 | /*=========================================================*/ /** 234 | Returns the arguments of this function call. */ 235 | value: TokenList 236 | 237 | } 238 | 239 | } 240 | 241 | 242 | ///////////////////////////////////////////////////////////////////////// 243 | //// EXAMPLES /////////////////////////////////////////////////////////// 244 | ///////////////////////////////////////////////////////////////////////// 245 | 246 | 247 | 248 | /** How do you transform a css text into tokens? */ 249 | function tokenize_some_css() { 250 | 251 | var cssSyntax = require('core:css-syntax'); 252 | return cssSyntax.tokenize("* { color: red; }"); 253 | 254 | } 255 | 256 | 257 | 258 | /** How do you parse a css stylesheet?? */ 259 | function parse_some_css() { 260 | 261 | var cssSyntax = require('core:css-syntax'); 262 | return cssSyntax.parse("* { color: red; }"); 263 | 264 | } 265 | 266 | 267 | 268 | /** How do you transform a css text into tokens? */ 269 | function parse_some_css_vaue() { 270 | 271 | var cssSyntax = require('core:css-syntax'); 272 | return cssSyntax.parseCSSValue("url('bg.png')"); 273 | 274 | } -------------------------------------------------------------------------------- /doc/core/css-units.ts: -------------------------------------------------------------------------------- 1 |  /// 2 | interface ModuleHub { (file: 'core:css-units'): CSSUnits.CSSUnitsModule; } 3 | module CSSUnits { 4 | 5 | /** 6 | * Provides a basic css unit converter. 7 | */ 8 | export interface CSSUnitsModule extends Object { 9 | 10 | /** 11 | * Converts "cssLength" from its inherent unit to pixels, and returns the result as a float 12 | * 13 | * @param cssLength A string representing the value to convert 14 | * @param element The element from which the relative values will be computed (default: the root element) 15 | * @param opts Additionnal options such as "boxType" and "isHeightRelated" (default: border-box & isWidthRelated). 16 | */ 17 | convertToPixels( 18 | cssLength : string, 19 | element? : HTMLElement, 20 | opts? : PixelConvertOptions 21 | ) 22 | : number 23 | 24 | /** 25 | * Converts "pixelLength" from pixels to "destinUnit", and returns the result as a float 26 | * 27 | * @param pixelLength A string representing the value to convert 28 | * @param destinUnit A string value representing the unit name 29 | * @param element The element from which the relative values will be computed (default: the root element) 30 | * @param opts Additionnal options such as "boxType" and "isHeightRelated" (default: border-box & isWidthRelated). 31 | */ 32 | convertFromPixels( 33 | pixelLength : number, 34 | destinUnit : string, 35 | element? : HTMLElement, 36 | opts? : PixelConvertOptions 37 | ) 38 | : number 39 | 40 | } 41 | 42 | export interface PixelConvertOptions { 43 | boxType?: string 44 | isWidthRelated?: boolean 45 | isHeightRelated?: boolean 46 | isRadiusRelated?: boolean 47 | } 48 | 49 | } 50 | 51 | 52 | 53 | ///////////////////////////////////////////////////////////////////////// 54 | //// EXAMPLES /////////////////////////////////////////////////////////// 55 | ///////////////////////////////////////////////////////////////////////// 56 | 57 | 58 | 59 | /** How do you convert a value to pixels ? */ 60 | function convert_value_to_pixels() { 61 | 62 | var cssUnits = require('core:css-units'); 63 | return cssUnits.convertToPixels("33%", document.body, { 64 | boxType: "content-box", 65 | isHeightRelated: true 66 | }); 67 | 68 | } 69 | 70 | /** How do you convert a value from pixels ? */ 71 | function convert_value_from_pixels() { 72 | 73 | var cssUnits = require('core:css-units'); 74 | return cssUnits.convertFromPixels(550/*px*/, /*to*/"em", document.body, { 75 | boxType: "content-box", 76 | isHeightRelated: true 77 | }); 78 | 79 | } -------------------------------------------------------------------------------- /doc/core/dom-events.ts: -------------------------------------------------------------------------------- 1 |  /// 2 | interface ModuleHub { (file: 'core:dom-events'): DOMEvents.DOMEventsModule; } 3 | module DOMEvents { 4 | 5 | /** 6 | * Provides helpers for dealing with events in your code. 7 | */ 8 | export interface DOMEventsModule extends Object { 9 | 10 | /** 11 | * Helps to use DOM-like events in your code 12 | */ 13 | EventTarget: EventTargetHelper 14 | 15 | /** 16 | * Clones a native event object, so you can modify it and dispatch it again. 17 | * 18 | * @param event The native event object to clone 19 | * @return A native event object similar to the one given as argument. 20 | */ 21 | cloneEvent(e: TEvent) : TEvent 22 | 23 | } 24 | 25 | export interface EventTargetHelper { 26 | 27 | /** 28 | * Add the event methods to all instance of the given class. 29 | * This includes "addEventListener", "removeEventListener" and "dispatchEvent". 30 | */ 31 | implementsIn(constructor: Function) : void 32 | 33 | } 34 | } 35 | 36 | 37 | 38 | ///////////////////////////////////////////////////////////////////////// 39 | //// EXAMPLES /////////////////////////////////////////////////////////// 40 | ///////////////////////////////////////////////////////////////////////// 41 | 42 | 43 | 44 | /** How do you add support for events on a custom object ? */ 45 | function implement_dom_events() { 46 | 47 | function SomeObject() { 48 | // init a new SomeObject 49 | } 50 | 51 | var domEvents = require('core:dom-events'); 52 | domEvents.EventTarget.implementsIn(SomeObject); 53 | 54 | } 55 | 56 | 57 | /** How do you retarget an existing event object ? */ 58 | function retarget_existing_event() { 59 | 60 | var domEvents = require('core:dom-events'); 61 | document.body.onclick = function(e) { 62 | 63 | // do as if we just clicked on #some-element instead 64 | var someEvent = domEvents.cloneEvent(e); 65 | var someElement = document.querySelector("#some-element"); 66 | someElement.dispatchEvent(someEvent); 67 | 68 | }; 69 | 70 | } -------------------------------------------------------------------------------- /doc/requirements.ts: -------------------------------------------------------------------------------- 1 | /** This hub allows you to retrieve any previously loaded module: */ 2 | interface ModuleHub { 3 | (file: string): Object; 4 | } 5 | 6 | /** All the modules available to this project are stored here: */ 7 | var require: ModuleHub; 8 | 9 | 10 | /** This interface wraps the constructor type for any generic type */ 11 | interface Constructor extends Function { 12 | new() : T 13 | } 14 | 15 | /** unsafe js wrapper */ 16 | interface Object { valueOf(): any } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-polyfills", 3 | "codeName": "css-parallia", 4 | "description": "Creates a background framework for effective css polyfilling", 5 | "version": "0.1.0", 6 | "homepage": "https://github.com/FremyCompany/css-polyfills", 7 | "author": { 8 | "name": "François REMY", 9 | "email": "francois.remy.dev@outlook.com", 10 | "url": "http://fremycompany.com/" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/FremyCompany/css-polyfills.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/FremyCompany/css-polyfills/issues" 18 | }, 19 | "licenses": [ 20 | { 21 | "type": "MIT", 22 | "url": "https://github.com/FremyCompany/css-polyfills/blob/master/LICENSE-MIT" 23 | } 24 | ], 25 | "main": "src/requirements.js", 26 | "engines": { 27 | "node": ">= 0.10.0" 28 | }, 29 | "scripts": { 30 | "build": "grunt", 31 | "test": "node demo/css-grid/tests/test-server.js", 32 | "update-snapshots": "node demo/css-grid/tests/update-snapshots.js" 33 | }, 34 | "devDependencies": { 35 | "grunt": "^0.4.5", 36 | "grunt-contrib-concat": "^0.3.0", 37 | "grunt-contrib-concat-sourcemaps": "git://github.com/Krinkle/grunt-contrib-concat-sourcemaps.git", 38 | "grunt-contrib-jshint": "^0.6.0", 39 | "grunt-contrib-nodeunit": "^0.2.0", 40 | "grunt-contrib-uglify": "^0.6.0", 41 | "grunt-contrib-watch": "^0.4.0", 42 | "puppeteer": "^0.10.2" 43 | }, 44 | "keywords": [] 45 | } 46 | -------------------------------------------------------------------------------- /src/core/css-box.js: -------------------------------------------------------------------------------- 1 | // 2 | // The Box module defines algorithms for dealing with css boxes 3 | // 4 | module.exports = (function(window, document) { 5 | 6 | // Original code licensed by Adobe Systems Incorporated under the Apache License 2.0. 7 | // https://github.com/adobe-webplatform/brackets-css-shapes-editor/blob/master/thirdparty/CSSShapesEditor.js#L442 8 | 9 | var cssBox = cssBox || {}; 10 | cssBox.getBox = 11 | 12 | // returns {top/left/bottom/right} for 'content/padding/border/margin-box' relative to the border box top-left corner. 13 | function getBox(element, boxType){ 14 | var width = element.offsetWidth, 15 | height = element.offsetHeight, 16 | 17 | style = getComputedStyle(element), 18 | 19 | leftBorder = parseFloat(style.borderLeftWidth), 20 | rightBorder = parseFloat(style.borderRightWidth), 21 | topBorder = parseFloat(style.borderTopWidth), 22 | bottomBorder = parseFloat(style.borderBottomWidth), 23 | 24 | leftPadding = parseFloat(style.paddingLeft), 25 | rightPadding = parseFloat(style.paddingRight), 26 | topPadding = parseFloat(style.paddingTop), 27 | bottomPadding = parseFloat(style.paddingBottom), 28 | 29 | leftMargin = parseFloat(style.marginLeft), 30 | rightMargin = parseFloat(style.marginRight), 31 | topMargin = parseFloat(style.marginTop), 32 | bottomMargin = parseFloat(style.marginBottom); 33 | 34 | var box = { 35 | top: 0, 36 | left: 0, 37 | width: 0, 38 | height: 0 39 | }; 40 | 41 | switch (boxType||'border-box'){ 42 | case 'content-box': 43 | box.top = topBorder + topPadding; 44 | box.left = leftBorder + leftPadding; 45 | box.width = width - leftBorder - leftPadding - rightPadding - rightBorder; 46 | box.height = height - topBorder - topPadding - bottomPadding - bottomBorder; 47 | break; 48 | 49 | case 'padding-box': 50 | box.top = topPadding; 51 | box.left = leftPadding; 52 | box.width = width - leftBorder - rightBorder; 53 | box.height = height - topBorder - bottomBorder; 54 | break; 55 | 56 | case 'border-box': 57 | box.top = 0; 58 | box.left = 0; 59 | box.width = width; 60 | box.height = height; 61 | break; 62 | 63 | case 'margin-box': 64 | box.top = 0 - topMargin; 65 | box.left = 0 - leftMargin; 66 | box.width = width + leftMargin + rightMargin; 67 | box.height = height + topMargin + bottomMargin; 68 | break; 69 | 70 | default: 71 | throw new TypeError('Invalid parameter, boxType: ' + boxType); 72 | } 73 | 74 | return box; 75 | }; 76 | 77 | return cssBox; 78 | 79 | })(window, document); -------------------------------------------------------------------------------- /src/core/css-sizing.js: -------------------------------------------------------------------------------- 1 | module.exports = (function(window, document) { 2 | 3 | // import dependencies 4 | var cssStyle = require('css-style'), 5 | usedStyleOf = cssStyle.usedStyleOf, 6 | currentStyleOf = cssStyle.currentStyleOf, 7 | enforceStyle = cssStyle.enforceStyle, 8 | restoreStyle = cssStyle.restoreStyle; 9 | 10 | // define the module 11 | var cssSizing = { 12 | 13 | absoluteMinWidthOf: function(element) { 14 | 15 | // 16 | // make the parent a relative container (if necessary) 17 | // 18 | var parentPositionBackup = enforceStyle(element.parentNode, "position", "relative"); 19 | 20 | // 21 | // remove the element from the flow (if necessary) 22 | // 23 | var positionBackup = enforceStyle(element, "position", "absolute"); 24 | 25 | // 26 | // put impossible sizing constraints to the element 27 | // 28 | var widthBackup = enforceStyle(element, "width", "0px"); 29 | var minWidthBackup = enforceStyle(element, "min-width", "0px"); 30 | 31 | // 32 | // see what size is finally being used 33 | // 34 | var result = element.offsetWidth; 35 | 36 | // 37 | // restore styling where needed 38 | // 39 | restoreStyle(element, minWidthBackup); 40 | restoreStyle(element, widthBackup); 41 | restoreStyle(element, positionBackup); 42 | restoreStyle(element.parentNode, parentPositionBackup); 43 | 44 | // 45 | // return the result 46 | // 47 | return result; 48 | 49 | }, 50 | 51 | minWidthOf: function(element) { 52 | 53 | // 54 | // make the parent an infinite relative container (if necessary) 55 | // 56 | var parentPositionBackup = enforceStyle(element.parentNode, "position", "relative"); 57 | var parentWidthBackup = enforceStyle(element.parentNode, "width", "0px"); 58 | var parentMinWidthBackup = enforceStyle(element.parentNode, "min-width", "0px"); 59 | var parentMaxWidthBackup = enforceStyle(element.parentNode, "max-width", "0px"); 60 | 61 | // 62 | // remove the element from the flow (if necessary) 63 | // 64 | var positionBackup = enforceStyle(element, "position", "absolute"); 65 | 66 | // 67 | // put impossible sizing constraints to the element 68 | // 69 | var widthBackup = enforceStyle(element, "width", "auto"); 70 | 71 | // 72 | // see what size is finally being used 73 | // 74 | var result = element.offsetWidth; 75 | 76 | // 77 | // restore styling where needed 78 | // 79 | restoreStyle(element, widthBackup); 80 | restoreStyle(element, positionBackup); 81 | restoreStyle(element.parentNode, parentWidthBackup); 82 | restoreStyle(element.parentNode, parentMaxWidthBackup); 83 | restoreStyle(element.parentNode, parentMinWidthBackup); 84 | restoreStyle(element.parentNode, parentPositionBackup); 85 | 86 | // 87 | // return the result 88 | // 89 | return result; 90 | }, 91 | 92 | maxWidthOf: function(element) { 93 | 94 | // 95 | // make the parent a relative container (if necessary) 96 | // 97 | var parentPositionBackup = enforceStyle(element.parentNode, "position", "relative"); 98 | 99 | // 100 | // remove the element from the flow (if necessary) 101 | // 102 | var positionBackup = enforceStyle(element, "position", "absolute"); 103 | 104 | // 105 | // put impossible sizing constraints to the element 106 | // 107 | var widthBackup = enforceStyle(element, "width", "auto"); 108 | 109 | // 110 | // see what size is finally being used 111 | // 112 | var result = element.offsetWidth; 113 | 114 | // 115 | // restore styling where needed 116 | // 117 | restoreStyle(element, widthBackup); 118 | restoreStyle(element, positionBackup); 119 | restoreStyle(element.parentNode, parentPositionBackup); 120 | 121 | // 122 | // return the result 123 | // 124 | return result; 125 | }, 126 | 127 | absoluteMaxWidthOf: function(element) { 128 | 129 | // 130 | // make the parent an infinite relative container (if necessary) 131 | // 132 | var parentPositionBackup = enforceStyle(element.parentNode, "position", "relative"); 133 | var parentWidthBackup = enforceStyle(element.parentNode, "width", "9999px"); 134 | var parentMinWidthBackup = enforceStyle(element.parentNode, "min-width", "9999px"); 135 | 136 | // 137 | // remove the element from the flow (if necessary) 138 | // 139 | var positionBackup = enforceStyle(element, "position", "absolute"); 140 | 141 | // 142 | // put impossible sizing constraints to the element 143 | // 144 | var widthBackup = enforceStyle(element, "width", "auto"); 145 | 146 | // 147 | // see what size is finally being used 148 | // 149 | var result = element.offsetWidth; 150 | 151 | // 152 | // restore styling where needed 153 | // 154 | restoreStyle(element, widthBackup); 155 | restoreStyle(element, positionBackup); 156 | restoreStyle(element.parentNode, parentWidthBackup); 157 | restoreStyle(element.parentNode, parentMinWidthBackup); 158 | restoreStyle(element.parentNode, parentPositionBackup); 159 | 160 | // 161 | // return the result 162 | // 163 | return result; 164 | }, 165 | 166 | }; 167 | 168 | return cssSizing; 169 | 170 | })(window, document) -------------------------------------------------------------------------------- /src/core/css-style.js: -------------------------------------------------------------------------------- 1 | // 2 | // The CSS Style module attempts to provide helpers to deal with Style Declarations and elements 3 | // [0] http://lists.w3.org/Archives/Public/www-style/2013Sep/0283.html 4 | // 5 | module.exports = (function(window, document) { "use strict"; 6 | 7 | function usedStyleOf(element) { 8 | var style = element.usedStyle || getComputedStyle(element); 9 | if(!style.parentElement) { style.parentElement = element; } 10 | return style; 11 | } 12 | 13 | function currentStyleOf(element) { 14 | var style = element.cascadedStyle || element.specifiedStyle || element.currentStyle || getComputedStyle(element); // TODO: check CSSOM spec for real name 15 | if(!style.parentElement) { style.parentElement = element; } 16 | return style; 17 | } 18 | 19 | function styleOf(element) { 20 | var style = element.style; 21 | if(!style.parentElement) { style.parentElement = element; } 22 | return style; 23 | } 24 | 25 | function runtimeStyleOf(element) { 26 | var style = /*element.runtimeStyle || */element.style; 27 | if(!style.parentElement) { style.parentElement = element; } 28 | return style; 29 | } 30 | 31 | function enforceStyle(element, property, value) { 32 | 33 | var propertyBackup = null; 34 | var usedValue = usedStyleOf(element).getPropertyValue(property); 35 | if(value instanceof Array) { 36 | if(value.indexOf(usedValue) >= 0) return null; 37 | value = ''+value[0]; 38 | } else { 39 | value = ''+value; 40 | } 41 | 42 | if(usedValue != value) { 43 | var style = runtimeStyleOf(element); 44 | propertyBackup = { 45 | value: style.getPropertyValue(property), 46 | priority: style.getPropertyPriority(property), 47 | property: property 48 | }; 49 | style.setProperty(property, "", ""); // reset [0] 50 | style.setProperty(property, "" + value, "important"); 51 | } 52 | 53 | return propertyBackup; 54 | 55 | } 56 | 57 | function enforceStyles(element, propertyValues, backups) { 58 | var backups = backups || []; 59 | for(var property in propertyValues) { if(propertyValues.hasOwnProperty(key)) { 60 | var currentBackup = enforceStyle(element, property, propertyValues[property]); 61 | if(currentBackup) { backups.push(currentBackup) } 62 | }} 63 | return backups; 64 | } 65 | 66 | function restoreStyle(element, backup) { 67 | 68 | if(backup) { 69 | 70 | // get the element runtime style 71 | var style = runtimeStyleOf(element); 72 | 73 | // reset [0] 74 | style.setProperty(backup.property, "", ""); 75 | 76 | // restore 77 | if(backup.value) { 78 | style.setProperty(backup.property, backup.value, ""); 79 | style.setProperty(backup.property, backup.value, backup.priority); 80 | } 81 | 82 | } 83 | 84 | } 85 | 86 | function restoreStyles(element, backups) { 87 | if(!backups || !(backups.length > 0)) { return; } 88 | for(var i=backups.length; i--;) { 89 | restoreStyle(element, backups[i]); 90 | } 91 | } 92 | 93 | var cssStyle = { 94 | styleOf: styleOf, 95 | usedStyleOf: usedStyleOf, 96 | currentStyleOf: currentStyleOf, 97 | runtimeStyleOf: runtimeStyleOf, 98 | enforceStyle: enforceStyle, 99 | enforceStyles: enforceStyles, 100 | restoreStyle: restoreStyle, 101 | restoreStyles: restoreStyles, 102 | }; 103 | 104 | return cssStyle; 105 | 106 | })(window); -------------------------------------------------------------------------------- /src/core/css-units.js: -------------------------------------------------------------------------------- 1 | // 2 | // The CSS Units module is handling conversions between units 3 | // 4 | module.exports = (function(window, document) { 5 | 6 | // import dependencies 7 | var getBox = require('css-box').getBox; 8 | 9 | // define the module 10 | var cssUnits = { 11 | 12 | // converts "cssLength" from its inherent unit to pixels, and returns the result as a float 13 | convertToPixels: function convertToPixels(cssLength, element, opts) { 14 | 15 | if(typeof cssLength == "string") { 16 | 17 | var match = cssLength.match(/^\s*(-?\d+(?:\.\d+)?)(\S*)\s*$/); 18 | var currentLength = match ? parseFloat(match[1]) : 0.0; 19 | var currentUnit = match ? match[2] : ''; 20 | 21 | } else { 22 | 23 | var currentLength = cssLength.value; 24 | var currentUnit = cssLength.unit; 25 | 26 | } 27 | 28 | var converter = convertToPixels.converters[currentUnit]; 29 | if (!converter) throw new Error("No suitable conversion from unit '"+currentUnit+"' to unit 'px'"); 30 | 31 | var convertedLength = converter.call(null, currentLength, element||document.documentElement, opts) 32 | return Math.round(20*convertedLength)/20; 33 | 34 | }, 35 | 36 | // converts "pixelLength" from pixels to "destinUnit", and returns the result as a float 37 | convertFromPixels: function convertFromPixels(pixelLength, destinUnit, element, opts) { 38 | 39 | var converter = convertFromPixels.converters[destinUnit]; 40 | if (!converter) throw new Error("No suitable conversion to unit '"+destinUnit+"' from unit 'px'"); 41 | 42 | var convertedLength = converter.call(null, pixelLength, element||document.documentElement, opts) 43 | return Math.round(20*convertedLength)/20; 44 | 45 | }, 46 | 47 | } 48 | 49 | cssUnits.convertToPixels.converters = { 50 | 'px' : function(x) { return x; }, 51 | 'in' : function(x) { return x * 96; }, 52 | 'cm' : function(x) { return x / 0.02645833333; }, 53 | 'mm' : function(x) { return x / 0.26458333333; }, 54 | 'pt' : function(x) { return x / 0.75; }, 55 | 'pc' : function(x) { return x / 0.0625; }, 56 | 'em' : function(x, e) { return x*parseFloat(e?getComputedStyle(e).fontSize:16); }, 57 | 'rem': function(x, e) { return x*parseFloat(e?getComputedStyle(e.ownerDocument.documentElement).fontSize:16); }, 58 | 'vw' : function(x, e) { return x/100*window.innerWidth; }, 59 | 'vh' : function(x, e) { return x/100*window.innerHeight; }, 60 | '%' : function(x, e, opts) { 61 | opts = opts || {}; 62 | 63 | // get the box from which to compute the percentages 64 | var box = e ? getBox(e, opts.boxType) : { 65 | top: 0, 66 | left: 0, 67 | width: 0, 68 | height: 0 69 | }; 70 | 71 | // now apply the conversion algorithm 72 | switch(true) { 73 | case opts.isRadius: 74 | var radius = Math.sqrt( box.height*box.height + box.width*box.width ) / Math.sqrt(2); 75 | return Math.round(x/100*radius); 76 | 77 | case opts.isHeightRelated: 78 | return x/100*box.height; 79 | 80 | case opts.isWidthRelated: default: 81 | return x/100*box.width; 82 | 83 | } 84 | 85 | } 86 | } 87 | 88 | cssUnits.convertFromPixels.converters = { 89 | 'px' : function(x) { return x; }, 90 | 'in' : function(x) { return x / 96; }, 91 | 'cm' : function(x) { return x * 0.02645833333; }, 92 | 'mm' : function(x) { return x * 0.26458333333; }, 93 | 'pt' : function(x) { return x * 0.75; }, 94 | 'pc' : function(x) { return x * 0.0625; }, 95 | 'em' : function(x, e) { return x/parseFloat(e?getComputedStyle(e).fontSize:16); }, 96 | 'rem': function(x, e) { return x/parseFloat(e?getComputedStyle(e.ownerDocument.documentElement).fontSize:16); }, 97 | 'vw' : function(x, e) { return x*100/window.innerWidth; }, 98 | 'vh' : function(x, e) { return x*100/window.innerHeight; }, 99 | '%' : function(x, e, opts) { 100 | opts = opts || {}; 101 | 102 | // get the box from which to compute the percentages 103 | var box = e ? getBox(e, opts.boxType) : { 104 | top: 0, 105 | left: 0, 106 | width: 0, 107 | height: 0 108 | }; 109 | 110 | // now apply the conversion algorithm 111 | switch(true) { 112 | case opts.isRadius: 113 | var radius = Math.sqrt( box.height*box.height + box.width*box.width ) / Math.sqrt(2); 114 | return Math.round(x*100/radius); 115 | 116 | case opts.isHeightRelated: 117 | return x*100/box.height; 118 | 119 | case opts.isWidthRelated: default: 120 | return x*100/box.width; 121 | 122 | } 123 | 124 | 125 | } 126 | }; 127 | 128 | return cssUnits; 129 | 130 | })(window, document); -------------------------------------------------------------------------------- /src/core/css-virtual-stylesheet-factory.js: -------------------------------------------------------------------------------- 1 | module.exports = (function(window, document) { "use strict"; 2 | 3 | var VSS_COUNT = 0; 4 | function VirtualStylesheetFactory() { 5 | var This = this || Object.create(VirtualStylesheet.prototype); 6 | 7 | // create the style sheet 8 | var styleElement = document.createElement('style'); 9 | styleElement.id = "virtual-stylesheet-" + (VSS_COUNT++); 10 | styleElement.setAttribute('data-no-css-polyfill', 'true'); 11 | styleElement.appendChild(document.createTextNode('')); 12 | document.querySelector(':root > head').appendChild(styleElement); 13 | 14 | // grab its stylesheet object 15 | var ss = styleElement.sheet; 16 | if(!ss.cssRules) ss.cssRules = ss.rules; 17 | ss.removeRule = ss.removeRule || function(i) { 18 | return ss.deleteRule(i); 19 | } 20 | ss.addRule = ss.addRule || function(s,d,i) { 21 | var rule = s+'{'+d+'}' 22 | var index = typeof(i)=='number' ? i : ss.cssRules.length; 23 | return ss.insertRule(rule, index); 24 | } 25 | 26 | // create the mapping table 27 | var rules = []; 28 | 29 | // add the factory 30 | 31 | This.stylesheets = Object.create(null); 32 | This.createStyleSheet = function(name) { 33 | return This.stylesheets[name] || (This.stylesheets[name] = new VirtualStylesheet(this, name)); 34 | } 35 | 36 | // add the methods 37 | 38 | This.addRule = function(selector, declarations, stylesheet, enabled) { 39 | 40 | // convert selector & declarations to a non-empty string 41 | selector = '' + selector + ' '; 42 | declarations = '' + declarations + ' '; 43 | 44 | // add the rule to the known rules 45 | rules.push({ stylesheet: stylesheet, selector: selector, declarations: declarations, enabled: enabled }); 46 | 47 | // add the rule to the enabled stylesheet, if needed 48 | if(enabled) { 49 | ss.addRule(selector, declarations); 50 | } 51 | 52 | } 53 | 54 | This.disableAllRules = function(stylesheet) { 55 | var ssIndex = ss.cssRules.length; 56 | for(var i = rules.length; i--;) { var rule = rules[i]; 57 | if(rule.enabled) { 58 | ssIndex--; 59 | if(rule.stylesheet == stylesheet) { 60 | ss.removeRule(ssIndex); 61 | rule.enabled = false; 62 | } 63 | } 64 | } 65 | } 66 | 67 | This.enableAllRules = function(stylesheet) { 68 | var ssIndex = 0; 69 | for(var i = 0; i= 0 && index < listeners.length) { 28 | listeners[index] = function() {}; 29 | } 30 | }; 31 | 32 | } 33 | 34 | // setImmediate 35 | if(!window.setImmediate) { 36 | window.setImmediate = function(f) { return setTimeout(f, 0) }; 37 | window.cancelImmediate = window.clearImmediate = clearTimeout; 38 | } 39 | 40 | }(); 41 | -------------------------------------------------------------------------------- /src/core/polyfill-dom-uniqueID.js: -------------------------------------------------------------------------------- 1 | void function() { 2 | if(!('uniqueID' in document.documentElement)) { 3 | var uniqueID_counter = 0; 4 | Object.defineProperty(Element.prototype, 'uniqueID', {get: function() { 5 | if(this.id) { 6 | return(this.id); 7 | } else { 8 | return(this.id = ("EL__"+(++uniqueID_counter)+"__")); 9 | } 10 | }}); 11 | } 12 | }(); -------------------------------------------------------------------------------- /src/css-grid/polyfill.js: -------------------------------------------------------------------------------- 1 | // TODO: document the "no_auto_css_grid" flag? 2 | // TOOD: document the "no_ms_grid_implementation" flag? 3 | 4 | !(function(window, document) { "use strict"; 5 | 6 | if("gridRow" in document.body.style) { console.warn('Polyfill skipped'); return; } 7 | 8 | require('core:polyfill-dom-console'); 9 | var cssCascade = require('core:css-cascade'); 10 | var cssGrid = require('lib/grid-layout'); 11 | 12 | var enabled = false; 13 | var enablePolyfill = function() { if(enabled) { return; } else { enabled = true; } 14 | 15 | // 16 | // [0] define css properties 17 | // those properties can now be set using Element.myStyle.xyz if they weren't already 18 | // 19 | 20 | var gridProperties = ['grid','grid-template','grid-template-rows','grid-template-columns','grid-template-areas','grid-areas','grid-auto-flow','grid-row-gap','grid-column-gap','grid-gap']; 21 | var gridItemProperties = ['grid-area','grid-row','grid-column','grid-row-start','grid-row-end','grid-column-start','grid-column-end','order']; 22 | for(var i=gridProperties.length; i--;) { cssCascade.polyfillStyleInterface(gridProperties[i]); } 23 | for(var i=gridItemProperties.length; i--;) { cssCascade.polyfillStyleInterface(gridItemProperties[i]); } 24 | 25 | // 26 | // [1] when any update happens: 27 | // construct new content and region flow pairs 28 | // restart the region layout algorithm for the modified pairs 29 | // 30 | 31 | cssCascade.startMonitoringProperties( 32 | gridProperties, 33 | { 34 | onupdate: function onupdate(element, rule) { 35 | 36 | // log some message in the console for debug 37 | cssConsole.dir({message:"onupdate",element:element,selector:rule.selector.toCSSString(),rule:rule}); 38 | 39 | // check if the element already has a grid or grid-item layout 40 | if(element.gridLayout) { 41 | 42 | // the layout must be recomputed 43 | element.gridLayout.scheduleRelayout(); 44 | 45 | } else { 46 | 47 | // setup a new grid model, and schedule a relayout 48 | element.gridLayout = new cssGrid.GridLayout(element); 49 | element.gridLayout.scheduleRelayout(); 50 | 51 | // TODO: watch DOM for updates in the element? 52 | if("MutationObserver" in window) { 53 | // non-attribute-related changes 54 | void function() { 55 | var observer = new MutationObserver(function(e) { 56 | element.gridLayout.scheduleRelayout(); return; 57 | //debugger; console.log(e); 58 | }); 59 | var target = document.documentElement; 60 | var config = { 61 | subtree: true, 62 | attributes: false, 63 | childList: true, 64 | characterData: true 65 | }; 66 | observer.observe(target, config); 67 | }(); 68 | // attribute-related changes 69 | void function() { 70 | var observer = new MutationObserver(function(e) { 71 | element.gridLayout.scheduleRelayout(); return; 72 | //debugger; console.log(e); 73 | //for(var i = e.length; i--;) { 74 | // var attr = e[i].attributeName; 75 | // if(attr=='class' || attr=='style') { 76 | // element.gridLayout.scheduleRelayout(); return; 77 | // } 78 | //} 79 | }); 80 | var target = element; 81 | var config = { 82 | subtree: true, 83 | attributes: true, 84 | attributeFilter: ['class', 'style', 'width', 'height', 'src'], 85 | childList: false, 86 | characterData: false 87 | }; 88 | }(); 89 | 90 | } else if("MutationEvent" in window) { 91 | element.addEventListener('DOMSubtreeModified', function() { 92 | if(!element.gridLayout.isLayoutScheduled) { element.gridLayout.scheduleRelayout(); } 93 | }, true); 94 | } 95 | // TODO: watch resize events for relayout? 96 | var lastWidth = element.offsetWidth; 97 | var lastHeight = element.offsetHeight; 98 | var updateOnResize = function() { 99 | if(!element.gridLayout) { return; } 100 | if(lastWidth != element.offsetWidth || lastHeight != element.offsetHeight) { 101 | // update last known size 102 | lastWidth = element.offsetWidth; 103 | lastHeight = element.offsetHeight; 104 | // relayout (and prevent double-dispatch) 105 | element.gridLayout.scheduleRelayout(); 106 | } 107 | requestAnimationFrame(updateOnResize); 108 | } 109 | requestAnimationFrame(updateOnResize); 110 | // TODO: watch the load event for relayout? 111 | window.addEventListener('load', function(){element.gridLayout&&element.gridLayout.scheduleRelayout()}); 112 | var images = element.querySelectorAll('img'); 113 | for(var i = images.length; i--;) { 114 | images[i].addEventListener('load', function(){element.gridLayout&&element.gridLayout.scheduleRelayout()}); 115 | } 116 | 117 | } 118 | 119 | } 120 | } 121 | ); 122 | 123 | cssCascade.startMonitoringProperties( 124 | gridItemProperties, 125 | { 126 | onupdate: function onupdate(element, rule) { 127 | 128 | // log some message in the console for debug 129 | cssConsole.dir({message:"onupdate",element:element,selector:rule.selector.toCSSString(),rule:rule}); 130 | 131 | // check if the element already has a grid or grid-item layout 132 | if(element.parentGridLayout) { 133 | 134 | // the parent layout must be recomputed 135 | element.parentGridLayout.scheduleRelayout(); 136 | 137 | } 138 | 139 | } 140 | } 141 | ); 142 | 143 | } 144 | 145 | // expose the enabler 146 | cssGrid.enablePolyfill = enablePolyfill; 147 | 148 | // enable the polyfill automatically 149 | try { 150 | if(!("no_auto_css_grid" in window)) { enablePolyfill(); } 151 | } catch (ex) { 152 | setImmediate(function() { throw ex; }); 153 | } 154 | 155 | // return the module 156 | return cssGrid; 157 | 158 | })(window, document); -------------------------------------------------------------------------------- /src/requirements.js: -------------------------------------------------------------------------------- 1 | /** please require the necessary modules here **/ 2 | //require('core:dom-matchMedia-polyfill'); 3 | //require('core:dom-classList-polyfill'); 4 | require('css-grid:polyfill'); -------------------------------------------------------------------------------- /src/todo.js: -------------------------------------------------------------------------------- 1 | // TODO: include an IE polyfill for getComputedStyle? 2 | // TODO: review every usage of usedStyleOf vs currentStyleOf --------------------------------------------------------------------------------