├── .gitignore ├── package.json ├── demos ├── autoprefixed │ ├── signup.scss │ ├── css │ │ └── signup.css │ └── index.html ├── flexie │ ├── signup.scss │ ├── css │ │ └── signup.css │ ├── index.html │ └── flexie.js ├── latest_syntax_only │ ├── css │ │ └── signup.css │ ├── signup.scss │ └── index.html └── progressive_enhancement │ ├── signup.scss │ ├── css │ └── signup.css │ └── index.html ├── signup.scss ├── Gruntfile.js ├── index.html └── flexie.js /.gitignore: -------------------------------------------------------------------------------- 1 | /signup.css 2 | /css/signup.css -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "engines": { 3 | "node": ">= 0.10.0" 4 | }, 5 | "devDependencies": { 6 | "grunt": "~0.4.2", 7 | "grunt-contrib-jshint": "~0.7.2", 8 | "grunt-contrib-watch": "~0.5.3", 9 | "grunt-contrib-qunit": "~0.3.0", 10 | "grunt-contrib-concat": "~0.3.0", 11 | "grunt-contrib-uglify": "~0.2.7", 12 | "grunt-autoprefixer": "~0.7.2", 13 | "grunt-sass": "~0.11.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /demos/autoprefixed/signup.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Layout */ 3 | body { 4 | padding: 20px 0; 5 | } 6 | 7 | .outer { 8 | max-width: 730px; 9 | margin: 0 auto; 10 | } 11 | 12 | .jumbotron { 13 | text-align: center; 14 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 15 | } 16 | 17 | .plans { 18 | display: flex; 19 | 20 | > div { 21 | flex: 1 1 33%; 22 | display: flex; 23 | flex-direction: column; 24 | align-items: flex-start; 25 | 26 | .stretch { 27 | width: 100%; 28 | flex: 1 0 auto; 29 | } 30 | 31 | a { 32 | margin-top: 16px; 33 | margin-top: 1rem; 34 | } 35 | } 36 | 37 | } 38 | 39 | .marketing { 40 | margin-bottom: 6 * 16px; 41 | margin-bottom: 6rem; 42 | } 43 | 44 | .well form .inputs{ 45 | display: flex; 46 | 47 | #email { 48 | flex: 1 0 auto; 49 | } 50 | .btn { 51 | width: 25 * 10px; 52 | width: 25rem; 53 | margin-left: 16px; 54 | margin-left: 1rem; 55 | } 56 | } 57 | 58 | .footer { 59 | border-top: 1px solid #eee; 60 | padding-top: 2 * 16px; 61 | padding-top: 2rem; 62 | display: flex; 63 | p { 64 | flex: 1 0 auto; 65 | } 66 | a { 67 | padding-left: 16px; 68 | padding-left: 1rem; 69 | } 70 | } -------------------------------------------------------------------------------- /signup.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Layout */ 3 | body { 4 | padding: 20px 0; 5 | } 6 | 7 | .outer { 8 | max-width: 730px; 9 | margin: 0 auto; 10 | } 11 | 12 | .jumbotron { 13 | text-align: center; 14 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 15 | } 16 | 17 | .plans { 18 | display: flex; 19 | 20 | > div { 21 | width: 33%; 22 | flex: 1 1 0; 23 | display: flex; 24 | flex-direction: column; 25 | align-items: flex-start; 26 | 27 | .stretch { 28 | width: 100%; 29 | flex: 1 0 auto; 30 | } 31 | 32 | a { 33 | margin-top: 16px; 34 | margin-top: 1rem; 35 | } 36 | } 37 | 38 | } 39 | 40 | .marketing { 41 | margin-bottom: 6 * 16px; 42 | margin-bottom: 6rem; 43 | } 44 | 45 | .well form .inputs{ 46 | display: flex; 47 | 48 | #email { 49 | flex: 1 0 auto; 50 | } 51 | .btn { 52 | width: 25 * 10px; 53 | width: 25rem; 54 | margin-left: 16px; 55 | margin-left: 1rem; 56 | } 57 | } 58 | 59 | .footer { 60 | border-top: 1px solid #eee; 61 | padding-top: 2 * 16px; 62 | padding-top: 2rem; 63 | display: flex; 64 | p { 65 | flex: 1 0 auto; 66 | } 67 | a { 68 | padding-left: 16px; 69 | padding-left: 1rem; 70 | } 71 | } -------------------------------------------------------------------------------- /demos/flexie/signup.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Layout */ 3 | body { 4 | padding: 20px 0; 5 | } 6 | 7 | .outer { 8 | max-width: 730px; 9 | margin: 0 auto; 10 | } 11 | 12 | .jumbotron { 13 | text-align: center; 14 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 15 | } 16 | 17 | .plans { 18 | display: flex; 19 | 20 | > div { 21 | width: 33%; 22 | flex: 1 1 0; 23 | display: flex; 24 | flex-direction: column; 25 | align-items: flex-start; 26 | 27 | .stretch { 28 | width: 100%; 29 | flex: 1 0 auto; 30 | } 31 | 32 | a { 33 | margin-top: 16px; 34 | margin-top: 1rem; 35 | } 36 | } 37 | 38 | } 39 | 40 | .marketing { 41 | margin-bottom: 6 * 16px; 42 | margin-bottom: 6rem; 43 | } 44 | 45 | .well form .inputs{ 46 | display: flex; 47 | 48 | #email { 49 | flex: 1 0 auto; 50 | } 51 | .btn { 52 | width: 25 * 10px; 53 | width: 25rem; 54 | margin-left: 16px; 55 | margin-left: 1rem; 56 | } 57 | } 58 | 59 | .footer { 60 | border-top: 1px solid #eee; 61 | padding-top: 2 * 16px; 62 | padding-top: 2rem; 63 | display: flex; 64 | p { 65 | flex: 1 0 auto; 66 | } 67 | a { 68 | padding-left: 16px; 69 | padding-left: 1rem; 70 | } 71 | } -------------------------------------------------------------------------------- /demos/latest_syntax_only/css/signup.css: -------------------------------------------------------------------------------- 1 | /* Layout */ 2 | body { 3 | padding: 20px 0; } 4 | 5 | .outer { 6 | max-width: 730px; 7 | margin: 0 auto; } 8 | 9 | .jumbotron { 10 | text-align: center; 11 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } 12 | 13 | .plans { 14 | display: -webkit-flex; 15 | display: flex; } 16 | .plans > div { 17 | width: 33%; 18 | -webkit-flex: 1 1 0; 19 | flex: 1 1 0; 20 | display: -webkit-flex; 21 | display: flex; 22 | -webkit-flex-direction: column; 23 | flex-direction: column; 24 | -webkit-align-items: flex-start; 25 | align-items: flex-start; } 26 | .plans > div .stretch { 27 | width: 100%; 28 | margin-bottom: 16px; 29 | margin-bottom: 1rem; } 30 | .plans > div a { 31 | margin-top: auto; } 32 | 33 | .marketing { 34 | margin-bottom: 96px; 35 | margin-bottom: 6rem; } 36 | 37 | .well form .inputs { 38 | display: -webkit-flex; 39 | display: flex; } 40 | .well form .inputs #email { 41 | -webkit-flex: 1 0 auto; 42 | flex: 1 0 auto; } 43 | .well form .inputs .btn { 44 | width: 250px; 45 | width: 25rem; 46 | margin-left: 16px; 47 | margin-left: 1rem; } 48 | 49 | .footer { 50 | border-top: 1px solid #eee; 51 | padding-top: 32px; 52 | padding-top: 2rem; 53 | display: -webkit-flex; 54 | display: flex; } 55 | .footer p { 56 | -webkit-flex: 1 0 auto; 57 | flex: 1 0 auto; } 58 | .footer a { 59 | padding-left: 16px; 60 | padding-left: 1rem; } 61 | -------------------------------------------------------------------------------- /demos/progressive_enhancement/signup.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Layout */ 3 | body { 4 | padding: 20px 0; 5 | } 6 | 7 | .outer { 8 | max-width: 730px; 9 | margin: 0 auto; 10 | } 11 | 12 | .jumbotron { 13 | text-align: center; 14 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 15 | } 16 | 17 | .plans { 18 | display: flex; 19 | 20 | > div { 21 | width: 33%; 22 | float: left; 23 | flex: 1 1 0; 24 | display: flex; 25 | flex-direction: column; 26 | align-items: flex-start; 27 | 28 | .stretch { 29 | width: 100%; 30 | flex: 1 1 auto; 31 | } 32 | 33 | a { 34 | margin-top: 16px; 35 | margin-top: 1rem; 36 | } 37 | } 38 | 39 | } 40 | 41 | .marketing { 42 | margin-bottom: 6 * 16px; 43 | margin-bottom: 6rem; 44 | } 45 | 46 | .well form .inputs{ 47 | display: flex; 48 | 49 | #email { 50 | width: 50%; 51 | display: inline; 52 | flex: 1 0 auto; 53 | } 54 | .btn { 55 | width: 25 * 10px; 56 | width: 25rem; 57 | margin-left: 16px; 58 | margin-left: 1rem; 59 | } 60 | } 61 | 62 | .footer { 63 | border-top: 1px solid #eee; 64 | padding-top: 2 * 16px; 65 | padding-top: 2rem; 66 | display: flex; 67 | p { 68 | float: left; 69 | flex: 1 0 auto; 70 | } 71 | > a { 72 | float: right; 73 | padding-left: 16px; 74 | padding-left: 1rem; 75 | } 76 | } -------------------------------------------------------------------------------- /demos/latest_syntax_only/signup.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Layout */ 3 | body { 4 | padding: 20px 0; 5 | } 6 | 7 | .outer { 8 | max-width: 730px; 9 | margin: 0 auto; 10 | } 11 | 12 | .jumbotron { 13 | text-align: center; 14 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 15 | } 16 | 17 | .plans { 18 | display: -webkit-flex; 19 | display: flex; 20 | 21 | > div { 22 | width: 33%; 23 | -webkit-flex: 1 1 0; 24 | flex: 1 1 0; 25 | display: -webkit-flex; 26 | display: flex; 27 | -webkit-flex-direction: column; 28 | flex-direction: column; 29 | -webkit-align-items: flex-start; 30 | align-items: flex-start; 31 | 32 | .stretch { 33 | width: 100%; 34 | margin-bottom: 16px; 35 | margin-bottom: 1rem; 36 | } 37 | 38 | a { 39 | margin-top: auto; 40 | } 41 | } 42 | 43 | } 44 | 45 | .marketing { 46 | margin-bottom: 6 * 16px; 47 | margin-bottom: 6rem; 48 | } 49 | 50 | .well form .inputs{ 51 | display: -webkit-flex; 52 | display: flex; 53 | 54 | #email { 55 | -webkit-flex: 1 0 auto; 56 | flex: 1 0 auto; 57 | } 58 | .btn { 59 | width: 25 * 10px; 60 | width: 25rem; 61 | margin-left: 16px; 62 | margin-left: 1rem; 63 | } 64 | } 65 | 66 | .footer { 67 | border-top: 1px solid #eee; 68 | padding-top: 2 * 16px; 69 | padding-top: 2rem; 70 | display: -webkit-flex; 71 | display: flex; 72 | p { 73 | -webkit-flex: 1 0 auto; 74 | flex: 1 0 auto; 75 | } 76 | a { 77 | padding-left: 16px; 78 | padding-left: 1rem; 79 | } 80 | } -------------------------------------------------------------------------------- /demos/autoprefixed/css/signup.css: -------------------------------------------------------------------------------- 1 | /* Layout */ 2 | body { 3 | padding: 20px 0; } 4 | 5 | .outer { 6 | max-width: 730px; 7 | margin: 0 auto; } 8 | 9 | .jumbotron { 10 | text-align: center; 11 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } 12 | 13 | .plans { 14 | display: -webkit-box; 15 | display: -webkit-flex; 16 | display: -ms-flexbox; 17 | display: flex; } 18 | .plans > div { 19 | -webkit-box-flex: 1; 20 | -webkit-flex: 1 1 33%; 21 | -ms-flex: 1 1 33%; 22 | flex: 1 1 33%; 23 | display: -webkit-box; 24 | display: -webkit-flex; 25 | display: -ms-flexbox; 26 | display: flex; 27 | -webkit-box-orient: vertical; 28 | -webkit-box-direction: normal; 29 | -webkit-flex-direction: column; 30 | -ms-flex-direction: column; 31 | flex-direction: column; 32 | -webkit-box-align: start; 33 | -webkit-align-items: flex-start; 34 | -ms-flex-align: start; 35 | align-items: flex-start; } 36 | .plans > div .stretch { 37 | width: 100%; 38 | -webkit-box-flex: 1; 39 | -webkit-flex: 1 0 auto; 40 | -ms-flex: 1 0 auto; 41 | flex: 1 0 auto; } 42 | .plans > div a { 43 | margin-top: 16px; 44 | margin-top: 1rem; } 45 | 46 | .marketing { 47 | margin-bottom: 96px; 48 | margin-bottom: 6rem; } 49 | 50 | .well form .inputs { 51 | display: -webkit-box; 52 | display: -webkit-flex; 53 | display: -ms-flexbox; 54 | display: flex; } 55 | .well form .inputs #email { 56 | -webkit-box-flex: 1; 57 | -webkit-flex: 1 0 auto; 58 | -ms-flex: 1 0 auto; 59 | flex: 1 0 auto; } 60 | .well form .inputs .btn { 61 | width: 250px; 62 | width: 25rem; 63 | margin-left: 16px; 64 | margin-left: 1rem; } 65 | 66 | .footer { 67 | border-top: 1px solid #eee; 68 | padding-top: 32px; 69 | padding-top: 2rem; 70 | display: -webkit-box; 71 | display: -webkit-flex; 72 | display: -ms-flexbox; 73 | display: flex; } 74 | .footer p { 75 | -webkit-box-flex: 1; 76 | -webkit-flex: 1 0 auto; 77 | -ms-flex: 1 0 auto; 78 | flex: 1 0 auto; } 79 | .footer a { 80 | padding-left: 16px; 81 | padding-left: 1rem; } 82 | -------------------------------------------------------------------------------- /demos/flexie/css/signup.css: -------------------------------------------------------------------------------- 1 | /* Layout */ 2 | body { 3 | padding: 20px 0; } 4 | 5 | .outer { 6 | max-width: 730px; 7 | margin: 0 auto; } 8 | 9 | .jumbotron { 10 | text-align: center; 11 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } 12 | 13 | .plans { 14 | display: -webkit-box; 15 | display: -webkit-flex; 16 | display: -ms-flexbox; 17 | display: flex; } 18 | .plans > div { 19 | width: 33%; 20 | -webkit-box-flex: 1; 21 | -webkit-flex: 1 1 0; 22 | -ms-flex: 1 1 0; 23 | flex: 1 1 0; 24 | display: -webkit-box; 25 | display: -webkit-flex; 26 | display: -ms-flexbox; 27 | display: flex; 28 | -webkit-box-orient: vertical; 29 | -webkit-box-direction: normal; 30 | -webkit-flex-direction: column; 31 | -ms-flex-direction: column; 32 | flex-direction: column; 33 | -webkit-box-align: start; 34 | -webkit-align-items: flex-start; 35 | -ms-flex-align: start; 36 | align-items: flex-start; } 37 | .plans > div .stretch { 38 | width: 100%; 39 | -webkit-box-flex: 1; 40 | -webkit-flex: 1 0 auto; 41 | -ms-flex: 1 0 auto; 42 | flex: 1 0 auto; } 43 | .plans > div a { 44 | margin-top: 16px; 45 | margin-top: 1rem; } 46 | 47 | .marketing { 48 | margin-bottom: 96px; 49 | margin-bottom: 6rem; } 50 | 51 | .well form .inputs { 52 | display: -webkit-box; 53 | display: -webkit-flex; 54 | display: -ms-flexbox; 55 | display: flex; } 56 | .well form .inputs #email { 57 | -webkit-box-flex: 1; 58 | -webkit-flex: 1 0 auto; 59 | -ms-flex: 1 0 auto; 60 | flex: 1 0 auto; } 61 | .well form .inputs .btn { 62 | width: 250px; 63 | width: 25rem; 64 | margin-left: 16px; 65 | margin-left: 1rem; } 66 | 67 | .footer { 68 | border-top: 1px solid #eee; 69 | padding-top: 32px; 70 | padding-top: 2rem; 71 | display: -webkit-box; 72 | display: -webkit-flex; 73 | display: -ms-flexbox; 74 | display: flex; } 75 | .footer p { 76 | -webkit-box-flex: 1; 77 | -webkit-flex: 1 0 auto; 78 | -ms-flex: 1 0 auto; 79 | flex: 1 0 auto; } 80 | .footer a { 81 | padding-left: 16px; 82 | padding-left: 1rem; } 83 | -------------------------------------------------------------------------------- /demos/progressive_enhancement/css/signup.css: -------------------------------------------------------------------------------- 1 | /* Layout */ 2 | body { 3 | padding: 20px 0; } 4 | 5 | .outer { 6 | max-width: 730px; 7 | margin: 0 auto; } 8 | 9 | .jumbotron { 10 | text-align: center; 11 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } 12 | 13 | .plans { 14 | display: -webkit-box; 15 | display: -webkit-flex; 16 | display: -ms-flexbox; 17 | display: flex; } 18 | .plans > div { 19 | width: 33%; 20 | float: left; 21 | -webkit-box-flex: 1; 22 | -webkit-flex: 1 1 0; 23 | -ms-flex: 1 1 0; 24 | flex: 1 1 0; 25 | display: -webkit-box; 26 | display: -webkit-flex; 27 | display: -ms-flexbox; 28 | display: flex; 29 | -webkit-box-orient: vertical; 30 | -webkit-box-direction: normal; 31 | -webkit-flex-direction: column; 32 | -ms-flex-direction: column; 33 | flex-direction: column; 34 | -webkit-box-align: start; 35 | -webkit-align-items: flex-start; 36 | -ms-flex-align: start; 37 | align-items: flex-start; } 38 | .plans > div .stretch { 39 | width: 100%; 40 | -webkit-box-flex: 1; 41 | -webkit-flex: 1 1 auto; 42 | -ms-flex: 1 1 auto; 43 | flex: 1 1 auto; } 44 | .plans > div a { 45 | margin-top: 16px; 46 | margin-top: 1rem; } 47 | 48 | .marketing { 49 | margin-bottom: 96px; 50 | margin-bottom: 6rem; } 51 | 52 | .well form .inputs { 53 | display: -webkit-box; 54 | display: -webkit-flex; 55 | display: -ms-flexbox; 56 | display: flex; } 57 | .well form .inputs #email { 58 | width: 50%; 59 | display: inline; 60 | -webkit-box-flex: 1; 61 | -webkit-flex: 1 0 auto; 62 | -ms-flex: 1 0 auto; 63 | flex: 1 0 auto; } 64 | .well form .inputs .btn { 65 | width: 250px; 66 | width: 25rem; 67 | margin-left: 16px; 68 | margin-left: 1rem; } 69 | 70 | .footer { 71 | border-top: 1px solid #eee; 72 | padding-top: 32px; 73 | padding-top: 2rem; 74 | display: -webkit-box; 75 | display: -webkit-flex; 76 | display: -ms-flexbox; 77 | display: flex; } 78 | .footer p { 79 | float: left; 80 | -webkit-box-flex: 1; 81 | -webkit-flex: 1 0 auto; 82 | -ms-flex: 1 0 auto; 83 | flex: 1 0 auto; } 84 | .footer > a { 85 | float: right; 86 | padding-left: 16px; 87 | padding-left: 1rem; } 88 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function(grunt) { 3 | 4 | // Project configuration. 5 | grunt.initConfig({ 6 | // Metadata. 7 | pkg: grunt.file.readJSON('package.json'), 8 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + 9 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 10 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' + 11 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + 12 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n', 13 | // Task configuration. 14 | concat: { 15 | options: { 16 | banner: '<%= banner %>', 17 | stripBanners: true 18 | }, 19 | dist: { 20 | src: ['lib/<%= pkg.name %>.js'], 21 | dest: 'dist/<%= pkg.name %>.js' 22 | } 23 | }, 24 | uglify: { 25 | options: { 26 | banner: '<%= banner %>' 27 | }, 28 | dist: { 29 | src: '<%= concat.dist.dest %>', 30 | dest: 'dist/<%= pkg.name %>.min.js' 31 | } 32 | }, 33 | jshint: { 34 | options: { 35 | curly: true, 36 | eqeqeq: true, 37 | immed: true, 38 | latedef: true, 39 | newcap: true, 40 | noarg: true, 41 | sub: true, 42 | undef: true, 43 | unused: true, 44 | boss: true, 45 | eqnull: true, 46 | browser: true, 47 | globals: {} 48 | }, 49 | gruntfile: { 50 | src: 'Gruntfile.js' 51 | }, 52 | lib_test: { 53 | src: ['lib/**/*.js', 'test/**/*.js'] 54 | } 55 | }, 56 | qunit: { 57 | files: ['test/**/*.html'] 58 | }, 59 | autoprefixer: { 60 | // prefix all files 61 | multiple_files: { 62 | expand: true, 63 | flatten: true, 64 | src: '*.css', 65 | dest: 'css/' 66 | } 67 | }, 68 | sass: { 69 | dist: { 70 | files: { 71 | 'signup.css': 'signup.scss' 72 | } 73 | } 74 | }, 75 | watch: { 76 | sass: { 77 | files: ['*.scss'], 78 | tasks: ['sass', 'autoprefixer'], 79 | options: { 80 | spawn: false, 81 | livereload: true 82 | } 83 | }, 84 | html: { 85 | files: ['*.html'], 86 | options: { 87 | spawn: false, 88 | livereload: true 89 | } 90 | } 91 | } 92 | }); 93 | 94 | // These plugins provide necessary tasks. 95 | grunt.loadNpmTasks('grunt-contrib-watch'); 96 | grunt.loadNpmTasks('grunt-autoprefixer'); 97 | grunt.loadNpmTasks('grunt-sass'); 98 | 99 | // Default task. 100 | grunt.registerTask('default', ['watch', 'autoprefixer', 'sass']); 101 | 102 | }; 103 | -------------------------------------------------------------------------------- /demos/latest_syntax_only/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Pagesnap - Take monthly screenshots of any URL 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |

Pagesnap

25 |

Take monthly screenshots of any URL - automatically

26 |
27 | 28 |
29 |
30 |

Basic

31 |

$10 $5 per year

32 |

Monthly snaps

33 |

Up to two URLs

34 |

Perfect for occasional bloggers

35 | Start Now 36 |
37 |
38 |

Pro

39 |

$59 $49 per year

40 |

Daily, Weekly or Monthly snaps

41 |

Up to 50 URLs

42 |

Great for professional blogs, news sites, and more

43 | Start Now 44 |
45 |
46 |

Business

47 |

$299 $249 per year

48 |

Daily, Weekly or Monthly snaps

49 |

Up to 500 URLs

50 |

Designed with business and agencies in mind. Upsell your clients by giving them a piece of their history.

51 | Start Now 52 |
53 |
54 | 55 |
56 |
57 |

Signup

58 |

We're not quite ready for people to sign up yet. If you'd like to get an email when we go live, put your address in below.

59 |
60 |
61 | 62 |
63 | 64 | 65 |
66 |
67 | We won't send you spam. Unsubscribe at any time. 68 |
69 |
70 |
71 | 72 | 78 | 79 |
80 | 81 | 82 | -------------------------------------------------------------------------------- /demos/autoprefixed/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Pagesnap - Take monthly screenshots of any URL 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 |
27 |
28 |

Pagesnap

29 |

Take monthly screenshots of any URL - automatically

30 |
31 | 32 |
33 |
34 |

Basic

35 |

$10 $5 per year

36 |

Monthly snaps

37 |

Up to two URLs

38 |

Perfect for occasional bloggers

39 | Start Now 40 |
41 |
42 |

Pro

43 |

$59 $49 per year

44 |

Daily, Weekly or Monthly snaps

45 |

Up to 50 URLs

46 |

Great for professional blogs, news sites, and more

47 | Start Now 48 |
49 |
50 |

Business

51 |

$299 $249 per year

52 |

Daily, Weekly or Monthly snaps

53 |

Up to 500 URLs

54 |

Designed with business and agencies in mind. Upsell your clients by giving them a piece of their history.

55 | Start Now 56 |
57 |
58 | 59 |
60 |
61 |

Signup

62 |

We're not quite ready for people to sign up yet. If you'd like to get an email when we go live, put your address in below.

63 |
64 |
65 | 66 |
67 | 68 | 69 |
70 |
71 | We won't send you spam. Unsubscribe at any time. 72 |
73 |
74 |
75 | 76 | 82 | 83 |
84 | 85 | 86 | -------------------------------------------------------------------------------- /demos/progressive_enhancement/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Pagesnap - Take monthly screenshots of any URL 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 |
27 |
28 |

Pagesnap

29 |

Take monthly screenshots of any URL - automatically

30 |
31 | 32 |
33 |
34 |

Basic

35 |

$10 $5 per year

36 |

Monthly snaps

37 |

Up to two URLs

38 |

Perfect for occasional bloggers

39 | Start Now 40 |
41 |
42 |

Pro

43 |

$59 $49 per year

44 |

Daily, Weekly or Monthly snaps

45 |

Up to 50 URLs

46 |

Great for professional blogs, news sites, and more

47 | Start Now 48 |
49 |
50 |

Business

51 |

$299 $249 per year

52 |

Daily, Weekly or Monthly snaps

53 |

Up to 500 URLs

54 |

Designed with business and agencies in mind. Upsell your clients by giving them a piece of their history.

55 | Start Now 56 |
57 |
58 | 59 |
60 |
61 |

Signup

62 |

We're not quite ready for people to sign up yet. If you'd like to get an email when we go live, put your address in below.

63 |
64 |
65 | 66 |
67 | 68 | 69 |
70 |
71 | We won't send you spam. Unsubscribe at any time. 72 |
73 |
74 |
75 | 76 | 82 | 83 |
84 | 85 | 86 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Pagesnap - Take monthly screenshots of any URL 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |

Pagesnap

31 |

Take monthly screenshots of any URL - automatically

32 |
33 | 34 |
35 |
36 |

Basic

37 |

$10 $5 per year

38 |

Monthly snaps

39 |

Up to two URLs

40 |

Perfect for occasional bloggers

41 | Start Now 42 |
43 |
44 |

Pro

45 |

$59 $49 per year

46 |

Daily, Weekly or Monthly snaps

47 |

Up to 50 URLs

48 |

Great for professional blogs, news sites, and more

49 | Start Now 50 |
51 |
52 |

Business

53 |

$299 $249 per year

54 |

Daily, Weekly or Monthly snaps

55 |

Up to 500 URLs

56 |

Designed with business and agencies in mind. Upsell your clients by giving them a piece of their history.

57 | Start Now 58 |
59 |
60 | 61 |
62 |
63 |

Signup

64 |

We're not quite ready for people to sign up yet. If you'd like to get an email when we go live, put your address in below.

65 |
66 |
67 | 68 |
69 | 70 | 71 |
72 |
73 | We won't send you spam. Unsubscribe at any time. 74 |
75 |
76 |
77 | 78 | 84 | 85 |
86 | 87 | 88 | -------------------------------------------------------------------------------- /demos/flexie/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Pagesnap - Take monthly screenshots of any URL 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |

Pagesnap

31 |

Take monthly screenshots of any URL - automatically

32 |
33 | 34 |
35 |
36 |

Basic

37 |

$10 $5 per year

38 |

Monthly snaps

39 |

Up to two URLs

40 |

Perfect for occasional bloggers

41 | Start Now 42 |
43 |
44 |

Pro

45 |

$59 $49 per year

46 |

Daily, Weekly or Monthly snaps

47 |

Up to 50 URLs

48 |

Great for professional blogs, news sites, and more

49 | Start Now 50 |
51 |
52 |

Business

53 |

$299 $249 per year

54 |

Daily, Weekly or Monthly snaps

55 |

Up to 500 URLs

56 |

Designed with business and agencies in mind. Upsell your clients by giving them a piece of their history.

57 | Start Now 58 |
59 |
60 | 61 |
62 |
63 |

Signup

64 |

We're not quite ready for people to sign up yet. If you'd like to get an email when we go live, put your address in below.

65 |
66 |
67 | 68 |
69 | 70 | 71 |
72 |
73 | We won't send you spam. Unsubscribe at any time. 74 |
75 |
76 |
77 | 78 | 84 | 85 |
86 | 87 | 88 | -------------------------------------------------------------------------------- /flexie.js: -------------------------------------------------------------------------------- 1 | /* 2 | File: flexie.js 3 | 4 | About: Version 5 | 1.0.3 6 | 7 | Project: Flexie 8 | 9 | Description: 10 | Legacy support for the CSS3 Flexible Box Model 11 | 12 | License: 13 | The MIT License 14 | 15 | Copyright (c) 2010 Richard Herrera 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in 25 | all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | */ 35 | 36 | /* 37 | Class: Flexie 38 | Scoped to the Flexie Global Namespace 39 | */ 40 | 41 | /*jslint evil: true, regexp: false, plusplus: false */ 42 | /*global window, document */ 43 | 44 | var Flexie = (function (win, doc) { 45 | 46 | // Scope public properties 47 | var FLX = {}, 48 | 49 | // Each Flexie-modified DOM node gets a unique identifier 50 | FLX_DOM_ID = 0, 51 | FLX_DOM_ATTR = "data-flexie-id", 52 | FLX_PARENT_ATTR = "data-flexie-parent", 53 | 54 | // Store support for flexbox 55 | SUPPORT, 56 | 57 | // Store reference to engine 58 | ENGINE, 59 | 60 | ENGINES = { 61 | "NW" : { 62 | s : "*.Dom.select" 63 | }, 64 | "DOMAssistant" : { 65 | s : "*.$", 66 | m : "*.DOMReady" 67 | }, 68 | "Prototype" : { 69 | s : "$$", 70 | m : "document.observe", 71 | p : "dom:loaded", 72 | c : "document" 73 | }, 74 | "YAHOO" : { 75 | s : "*.util.Selector.query", 76 | m : "*.util.Event.onDOMReady", 77 | c : "*.util.Event" 78 | }, 79 | "MooTools" : { 80 | s : "$$", 81 | m : "window.addEvent", 82 | p : "domready" 83 | }, 84 | "Sizzle" : { 85 | s : "*" 86 | }, 87 | "jQuery" : { 88 | s : "*", 89 | m : "*(document).ready" 90 | }, 91 | "dojo" : { 92 | s : "*.query", 93 | m : "*.addOnLoad" 94 | } 95 | }, 96 | 97 | // Store reference to library 98 | LIBRARY, 99 | 100 | // Regular Expressions 101 | PIXEL = /^-?\d+(?:px)?$/i, 102 | NUMBER = /^-?\d/, 103 | SIZES = /width|height|margin|padding|border/, 104 | MSIE = /(msie) ([\w.]+)/, 105 | WHITESPACE_CHARACTERS = /\t|\n|\r/g, 106 | RESTRICTIVE_PROPERTIES = /^max\-([a-z]+)/, 107 | PROTOCOL = /^https?:\/\//i, 108 | LEADINGTRIM = /^\s\s*/, 109 | TRAILINGTRIM = /\s\s*$/, 110 | ONLY_WHITESPACE = /^\s*$/, 111 | CSS_SELECTOR = /\s?(\#|\.|\[|\:(\:)?[^first\-(line|letter)|before|after]+)/g, 112 | 113 | // String constants 114 | EMPTY_STRING = "", 115 | SPACE_STRING = " ", 116 | PLACEHOLDER_STRING = "$1", 117 | PADDING_RIGHT = "paddingRight", 118 | PADDING_BOTTOM = "paddingBottom", 119 | PADDING_LEFT = "paddingLeft", 120 | PADDING_TOP = "paddingTop", 121 | BORDER_RIGHT = "borderRightWidth", 122 | BORDER_BOTTOM = "borderBottomWidth", 123 | BORDER_LEFT = "borderLeftWidth", 124 | BORDER_TOP = "borderTopWidth", 125 | HORIZONTAL = "horizontal", 126 | VERTICAL = "vertical", 127 | INLINE_AXIS = "inline-axis", 128 | BLOCK_AXIS = "block-axis", 129 | INHERIT = "inherit", 130 | LEFT = "left", 131 | 132 | END_MUSTACHE = "}", 133 | 134 | PREFIXES = " -o- -moz- -ms- -webkit- -khtml- ".split(SPACE_STRING), 135 | 136 | DEFAULTS = { 137 | orient : HORIZONTAL, 138 | align : "stretch", 139 | direction : INHERIT, 140 | pack : "start" 141 | }, 142 | 143 | // Global reference objects 144 | FLEX_BOXES = [], 145 | POSSIBLE_FLEX_CHILDREN = [], 146 | DOM_ORDERED, 147 | 148 | RESIZE_LISTENER, 149 | 150 | // Minification optimizations 151 | TRUE = true, 152 | FALSE = false, 153 | NULL = null, 154 | UNDEFINED, 155 | 156 | // If IE, which version? 157 | BROWSER = { 158 | IE : (function () { 159 | var ie, ua = win.navigator.userAgent, 160 | match = (MSIE).exec(ua.toLowerCase()); 161 | 162 | if (match) { 163 | ie = parseInt(match[2], 10); 164 | } 165 | 166 | return ie; 167 | }()) 168 | }, 169 | 170 | /* 171 | selectivizr v1.0.0 - (c) Keith Clark, freely distributable under the terms 172 | of the MIT license. 173 | 174 | selectivizr.com 175 | */ 176 | selectivizrEngine; 177 | 178 | function trim (string) { 179 | if (string) { 180 | string = string.replace(LEADINGTRIM, EMPTY_STRING).replace(TRAILINGTRIM, EMPTY_STRING); 181 | } 182 | 183 | return string; 184 | } 185 | 186 | // --[ determineSelectorMethod() ]-------------------------------------- 187 | // walks through the engines object testing for an suitable 188 | // selector engine. 189 | 190 | // Moving outside Selectivizr scope because detection is needed before running selectivizrEngine 191 | function determineSelectorMethod() { 192 | // compatiable selector engines in order of CSS3 support 193 | var engines = ENGINES, method, 194 | engine, obj; 195 | 196 | for (engine in engines) { 197 | if (engines.hasOwnProperty(engine)) { 198 | obj = engines[engine]; 199 | 200 | if (win[engine] && !method) { 201 | method = eval(obj.s.replace("*", engine)); 202 | 203 | if (method) { 204 | ENGINE = engine; 205 | break; 206 | } 207 | } 208 | } 209 | } 210 | 211 | return method; 212 | } 213 | 214 | // Event handler for onload/onresize events 215 | function addEvent(type, func) { 216 | type = "on" + type; 217 | var oldevent = win[type]; 218 | 219 | if (typeof win[type] !== "function") { 220 | win[type] = func; 221 | } else { 222 | win[type] = function () { 223 | if (oldevent) { 224 | oldevent(); 225 | } 226 | func(); 227 | }; 228 | } 229 | } 230 | 231 | function attachLoadMethod(handler) { 232 | if (!ENGINE) { 233 | LIBRARY = determineSelectorMethod(); 234 | } 235 | 236 | // compatiable selector engines in order of CSS3 support 237 | var engines = ENGINES, 238 | method, caller, args, 239 | engine, obj; 240 | 241 | for (engine in engines) { 242 | if (engines.hasOwnProperty(engine)) { 243 | obj = engines[engine]; 244 | 245 | if (win[engine] && !method && obj.m) { 246 | method = eval(obj.m.replace("*", engine)); 247 | caller = obj.c ? eval(obj.c.replace("*", engine)) : win; 248 | args = []; 249 | 250 | if (method && caller) { 251 | if (obj.p) { 252 | args.push(obj.p); 253 | } 254 | args.push(handler); 255 | method.apply(caller, args); 256 | break; 257 | } 258 | } 259 | } 260 | } 261 | 262 | if (!method) { 263 | addEvent("load", handler); 264 | } 265 | } 266 | 267 | function buildSelector (node) { 268 | var selector = node.nodeName.toLowerCase(); 269 | 270 | if (node.id) { 271 | selector += "#" + node.id; 272 | } else if (node.FLX_DOM_ID) { 273 | selector += "[" + FLX_DOM_ATTR + "='" + node.FLX_DOM_ID + "']"; 274 | } 275 | 276 | return selector; 277 | } 278 | 279 | function setFlexieId (node) { 280 | if (!node.FLX_DOM_ID) { 281 | FLX_DOM_ID = (FLX_DOM_ID + 1); 282 | 283 | node.FLX_DOM_ID = FLX_DOM_ID; 284 | node.setAttribute(FLX_DOM_ATTR, node.FLX_DOM_ID); 285 | } 286 | } 287 | 288 | function buildSelectorTree(text) { 289 | var rules = [], ruletext, rule, 290 | match, selector, proptext, splitprop, properties, 291 | i, j, x; 292 | 293 | // Tabs, Returns 294 | text = text.replace(WHITESPACE_CHARACTERS, EMPTY_STRING); 295 | 296 | // Leading / Trailing Whitespace 297 | text = text.replace(/\s?(\{|\:|\})\s?/g, PLACEHOLDER_STRING); 298 | 299 | ruletext = text.split(END_MUSTACHE); 300 | 301 | for (i in ruletext) { 302 | if (ruletext.hasOwnProperty(i)) { 303 | text = ruletext[i]; 304 | 305 | if (text) { 306 | rule = [text, END_MUSTACHE].join(EMPTY_STRING); 307 | 308 | match = (/(\@media[^\{]+\{)?(.*)\{(.*)\}/).exec(rule); 309 | 310 | if (match && match[3]) { 311 | selector = match[2]; 312 | proptext = match[3].split(";"); 313 | properties = []; 314 | 315 | for (j in proptext) { 316 | if (proptext.hasOwnProperty(j)) { 317 | x = proptext[j]; 318 | splitprop = x.split(":"); 319 | 320 | if (splitprop.length && splitprop[1]) { 321 | properties.push({ 322 | property : splitprop[0], 323 | value : splitprop[1] 324 | }); 325 | } 326 | } 327 | } 328 | 329 | if (selector && properties.length) { 330 | rules.push({ 331 | selector : selector, 332 | properties : properties 333 | }); 334 | } 335 | } 336 | } 337 | } 338 | } 339 | 340 | return rules; 341 | } 342 | 343 | function findFlexboxElements(rules) { 344 | var selectors, properties, 345 | property, value, shortProp, 346 | selectorSplit = /\s?,\s?/, 347 | createUniqueObject, addRules, key, 348 | uniqueChildren = {}, uniqueBoxes = {}, 349 | i, j, rule, k, l, selector, m, n, prop; 350 | 351 | createUniqueObject = function (selector, rules, prop, value) { 352 | var unique, i, j, rule; 353 | 354 | unique = { 355 | selector : trim(selector), 356 | properties : [] 357 | }; 358 | 359 | for (i = 0, j = rules.properties.length; i < j; i++) { 360 | rule = rules.properties[i]; 361 | 362 | unique.properties.push({ 363 | property : trim(rule.property), 364 | value : trim(rule.value) 365 | }); 366 | } 367 | 368 | if (prop && value) { 369 | unique[prop] = value; 370 | } 371 | 372 | return unique; 373 | }; 374 | 375 | addRules = function (selector, rules, prop, value) { 376 | var box = (prop && value) ? uniqueChildren[selector] : uniqueBoxes[selector], 377 | exists, x, i, j, rule, k, l; 378 | 379 | if (box) { 380 | for (i = 0, j = rules.properties.length; i < j; i++) { 381 | rule = rules.properties[i]; 382 | 383 | for (k = 0, l = box.properties.length; k < l; k++) { 384 | x = box.properties[k]; 385 | 386 | if (rule.property === x.property) { 387 | exists = k; 388 | return false; 389 | } 390 | } 391 | 392 | if (exists) { 393 | box.properties[exists] = rule; 394 | } else { 395 | box.properties.push(rule); 396 | } 397 | } 398 | 399 | if (prop && value) { 400 | box[prop] = value; 401 | } 402 | } else { 403 | if (prop && value) { 404 | uniqueChildren[selector] = createUniqueObject(selector, rules, prop, value); 405 | } else { 406 | uniqueBoxes[selector] = createUniqueObject(selector, rules, NULL, NULL); 407 | } 408 | } 409 | }; 410 | 411 | for (i = 0, j = rules.length; i < j; i++) { 412 | rule = rules[i]; 413 | 414 | selectors = trim(rule.selector).replace(selectorSplit, ",").split(selectorSplit); 415 | 416 | for (k = 0, l = selectors.length; k < l; k++) { 417 | selector = trim(selectors[k]); 418 | properties = rule.properties; 419 | 420 | for (m = 0, n = properties.length; m < n; m++) { 421 | prop = properties[m]; 422 | property = trim(prop.property); 423 | value = trim(prop.value); 424 | 425 | // if you use the new syntax along with the old 426 | if (property && property !== "flex") { 427 | 428 | shortProp = property.replace("box-", EMPTY_STRING); 429 | shortProp = property.replace("-webkit-box-", EMPTY_STRING); 430 | 431 | switch (shortProp) { 432 | case "display" : 433 | if (value === "box" || value === "-webkit-box") { 434 | addRules(selector, rule, NULL, NULL); 435 | } 436 | break; 437 | 438 | case "orient" : 439 | case "align" : 440 | case "direction" : 441 | case "pack" : 442 | addRules(selector, rule, NULL, NULL); 443 | break; 444 | 445 | case "flex" : 446 | case "flex-group" : 447 | case "ordinal-group" : 448 | addRules(selector, rule, shortProp, value); 449 | break; 450 | } 451 | } 452 | } 453 | } 454 | } 455 | 456 | for (key in uniqueBoxes) { 457 | if (uniqueBoxes.hasOwnProperty(key)) { 458 | FLEX_BOXES.push(uniqueBoxes[key]); 459 | } 460 | } 461 | 462 | for (key in uniqueChildren) { 463 | if (uniqueChildren.hasOwnProperty(key)) { 464 | POSSIBLE_FLEX_CHILDREN.push(uniqueChildren[key]); 465 | } 466 | } 467 | 468 | return { 469 | boxes : FLEX_BOXES, 470 | children : POSSIBLE_FLEX_CHILDREN 471 | }; 472 | } 473 | 474 | function matchFlexChildren(parent, lib, possibleChildren) { 475 | var caller, unique, matches = [], 476 | i, j, child, 477 | k, l, node, 478 | key; 479 | 480 | for (i = 0, j = possibleChildren.length; i < j; i++) { 481 | child = possibleChildren[i]; 482 | 483 | if (child.selector) { 484 | caller = lib(child.selector); 485 | caller = caller[0] ? caller : [caller]; 486 | 487 | if (caller[0]) { 488 | 489 | for (k = 0, l = caller.length; k < l; k++) { 490 | node = caller[k]; 491 | 492 | if (node.nodeName !== UNDEFINED) { 493 | switch (node.nodeName.toLowerCase()) { 494 | case "script" : 495 | case "style" : 496 | case "link" : 497 | break; 498 | 499 | default : 500 | if (node.parentNode === parent) { 501 | // Flag each unique node with FLX_DOM_ID 502 | setFlexieId(node); 503 | 504 | unique = {}; 505 | 506 | for (key in child) { 507 | if (child.hasOwnProperty(key)) { 508 | unique[key] = child[key]; 509 | } 510 | } 511 | 512 | unique.match = node; 513 | matches.push(unique); 514 | } 515 | break; 516 | } 517 | } 518 | } 519 | } 520 | } else { 521 | // Flag each unique node with FLX_DOM_ID 522 | setFlexieId(child); 523 | 524 | matches.push({ 525 | match : child, 526 | selector : buildSelector(child) 527 | }); 528 | } 529 | } 530 | 531 | return matches; 532 | } 533 | 534 | function getParams(params) { 535 | var key; 536 | 537 | for (key in params) { 538 | if (params.hasOwnProperty(key)) { 539 | params[key] = params[key] || DEFAULTS[key]; 540 | } 541 | } 542 | 543 | return params; 544 | } 545 | 546 | function buildFlexieCall(flexers) { 547 | var selector, properties, property, value, shortProp, 548 | display, orient, align, direction, pack, 549 | lib, caller, children, 550 | box, params, flexboxes = {}, 551 | match, childMatch, nestedFlexboxes, 552 | flexieParentSelector = "[" + FLX_PARENT_ATTR + "]", 553 | i, j, flex, k, l, prop, 554 | target, key, m, n, child, o, p, existing; 555 | 556 | // No boxflex? No dice. 557 | if (!flexers) { 558 | return; 559 | } 560 | 561 | for (i = 0, j = flexers.boxes.length; i < j; i++) { 562 | flex = flexers.boxes[i]; 563 | flex.selector = trim(flex.selector); 564 | 565 | selector = flex.selector; 566 | properties = flex.properties; 567 | 568 | display = orient = align = direction = pack = NULL; 569 | 570 | for (k = 0, l = properties.length; k < l; k++) { 571 | prop = properties[k]; 572 | 573 | property = trim(prop.property); 574 | value = trim(prop.value); 575 | 576 | if (property && property !== "flex") { 577 | shortProp = property.replace("box-", EMPTY_STRING); 578 | shortProp = property.replace("-webkit-box-", EMPTY_STRING); 579 | 580 | switch (shortProp) { 581 | case "display" : 582 | if (value === "box" || value === "-webkit-box") { 583 | display = "box"; 584 | } 585 | break; 586 | 587 | case "orient" : 588 | orient = value; 589 | break; 590 | 591 | case "align" : 592 | align = value; 593 | break; 594 | 595 | case "direction" : 596 | direction = value; 597 | break; 598 | 599 | case "pack" : 600 | pack = value; 601 | break; 602 | } 603 | } 604 | } 605 | 606 | // Determine library 607 | lib = LIBRARY; 608 | 609 | // Call it. 610 | caller = lib(flex.selector); 611 | 612 | // In an array? 613 | caller = caller[0] ? caller : [caller]; 614 | 615 | for (k = 0, l = caller.length; k < l; k++) { 616 | target = caller[k]; 617 | 618 | // If is DOM object 619 | if (target.nodeType) { 620 | // Flag each unique node with FLX_DOM_ID 621 | setFlexieId(target); 622 | 623 | // Find possible child node matches 624 | children = matchFlexChildren(target, lib, flexers.children); 625 | 626 | // Find any nested flexbox elements 627 | nestedFlexboxes = selector + " " + flexieParentSelector; 628 | 629 | // Make sure there is some value associated with box properties 630 | params = { 631 | target : target, 632 | selector : selector, 633 | properties : properties, 634 | children : children, 635 | display : display, 636 | orient : orient, 637 | align : align, 638 | direction: direction, 639 | pack : pack, 640 | nested : nestedFlexboxes 641 | }; 642 | 643 | match = flexboxes[target.FLX_DOM_ID]; 644 | 645 | if (match) { 646 | for (key in params) { 647 | if (params.hasOwnProperty(key)) { 648 | value = params[key]; 649 | 650 | switch (key) { 651 | case "selector" : 652 | if (value && !(new RegExp(value).test(match[key]))) { 653 | match[key] += ", " + value; 654 | } 655 | break; 656 | 657 | case "children" : 658 | for (m = 0, n = params[key].length; m < n; m++) { 659 | child = params[key][m]; 660 | childMatch = FALSE; 661 | 662 | for (o = 0, p = match[key].length; o < p; o++) { 663 | existing = match[key][o]; 664 | 665 | if (child.match.FLX_DOM_ID === existing.match.FLX_DOM_ID) { 666 | childMatch = TRUE; 667 | } 668 | } 669 | 670 | if (!childMatch) { 671 | match[key].push(child); 672 | } 673 | } 674 | break; 675 | 676 | default : 677 | if (value) { 678 | match[key] = value; 679 | } 680 | break; 681 | } 682 | } 683 | } 684 | } else { 685 | flexboxes[target.FLX_DOM_ID] = getParams(params); 686 | flexboxes[target.FLX_DOM_ID].target.setAttribute(FLX_PARENT_ATTR, TRUE); 687 | } 688 | } 689 | } 690 | } 691 | 692 | DOM_ORDERED = LIBRARY(flexieParentSelector); 693 | FLEX_BOXES = {}; 694 | 695 | for (i = 0, j = DOM_ORDERED.length; i < j; i++) { 696 | target = DOM_ORDERED[i]; 697 | 698 | FLEX_BOXES[target.FLX_DOM_ID] = flexboxes[target.FLX_DOM_ID]; 699 | } 700 | 701 | // Loop through each match, initialize constructor 702 | for (key in FLEX_BOXES) { 703 | if (FLEX_BOXES.hasOwnProperty(key)) { 704 | flex = FLEX_BOXES[key]; 705 | 706 | // One final check to ensure each flexbox has a display property 707 | if (flex.display === "box") { 708 | // Constructor 709 | box = new FLX.box(flex); 710 | } 711 | } 712 | } 713 | } 714 | 715 | function calcPx(element, props, dir) { 716 | var dim = dir.replace(dir.charAt(0), dir.charAt(0).toUpperCase()), 717 | value = element["offset" + dim] || 0, 718 | i, j, prop; 719 | 720 | if (value) { 721 | for (i = 0, j = props.length; i < j; i++) { 722 | prop = parseFloat(element.currentStyle[props[i]]); 723 | 724 | if (!isNaN(prop)) { 725 | value -= prop; 726 | } 727 | } 728 | } 729 | 730 | return value; 731 | } 732 | 733 | function getTrueValue(element, name) { 734 | var left, rsLeft, 735 | ret = element.currentStyle && element.currentStyle[name], 736 | style = element.style; 737 | 738 | if (!PIXEL.test(ret) && NUMBER.test(ret)) { 739 | 740 | // Remember the original values 741 | left = style.left; 742 | rsLeft = element.runtimeStyle.left; 743 | 744 | // Put in the new values to get a computed value out 745 | element.runtimeStyle.left = element.currentStyle.left; 746 | style.left = ret || 0; 747 | ret = style.pixelLeft + "px"; 748 | 749 | // Revert the changed values 750 | style.left = left || 0; 751 | element.runtimeStyle.left = rsLeft; 752 | } 753 | 754 | return ret; 755 | } 756 | 757 | function unAuto(element, prop, name) { 758 | var props; 759 | 760 | switch (name) { 761 | case "width" : 762 | props = [PADDING_LEFT, PADDING_RIGHT, BORDER_LEFT, BORDER_RIGHT]; 763 | prop = calcPx(element, props, name); 764 | break; 765 | 766 | case "height" : 767 | props = [PADDING_TOP, PADDING_BOTTOM, BORDER_TOP, BORDER_BOTTOM]; 768 | prop = calcPx(element, props, name); 769 | break; 770 | 771 | default : 772 | prop = getTrueValue(element, name); 773 | break; 774 | } 775 | 776 | return prop; 777 | } 778 | 779 | function getPixelValue(element, prop, name) { 780 | if (PIXEL.test(prop)) { 781 | return prop; 782 | } 783 | 784 | // if property is auto, do some messy appending 785 | if (prop === "auto" || prop === "medium") { 786 | prop = unAuto(element, prop, name); 787 | } else { 788 | prop = getTrueValue(element, name); 789 | } 790 | 791 | return prop; 792 | } 793 | 794 | function getComputedStyle(element, property, returnAsInt) { 795 | var value; 796 | 797 | if (element === UNDEFINED) { 798 | return; 799 | } 800 | 801 | if (win.getComputedStyle) { 802 | value = win.getComputedStyle(element, NULL)[property]; 803 | } else { 804 | if (SIZES.test(property)) { 805 | value = getPixelValue(element, (element && element.currentStyle) ? element.currentStyle[property] : 0, property); 806 | } else { 807 | value = element.currentStyle[property]; 808 | } 809 | } 810 | 811 | if (returnAsInt) { 812 | value = parseInt(value, 10); 813 | 814 | if (isNaN(value)) { 815 | value = 0; 816 | } 817 | } 818 | 819 | return value; 820 | } 821 | 822 | function clientWidth(element) { 823 | return element.innerWidth || element.clientWidth; 824 | } 825 | 826 | function clientHeight(element) { 827 | return element.innerHeight || element.clientHeight; 828 | } 829 | 830 | function appendProperty(target, prop, value, prefixName) { 831 | var cssText = [], 832 | i, j, prefix; 833 | 834 | for (i = 0, j = PREFIXES.length; i < j; i++) { 835 | prefix = PREFIXES[i]; 836 | cssText.push((prefixName ? prefix : EMPTY_STRING) + prop + ":" + (!prefixName ? prefix : EMPTY_STRING) + value); 837 | } 838 | 839 | target.style.cssText += cssText.join(";"); 840 | return target; 841 | } 842 | 843 | function appendPixelValue(target, prop, value) { 844 | var targets = target && target[0] ? target : [target], 845 | i, j; 846 | 847 | for (i = 0, j = targets.length; i < j; i++) { 848 | target = targets[i]; 849 | 850 | if (target && target.style) { 851 | target.style[prop] = (value ? (value + "px") : EMPTY_STRING); 852 | } 853 | } 854 | } 855 | 856 | function calculateSpecificity (selector) { 857 | var selectorGrid, matrix, total, 858 | i, j, chunk; 859 | 860 | selectorGrid = selector.replace(CSS_SELECTOR, function (e, f) { 861 | return "%" + f; 862 | }).replace(/\s|\>|\+|\~/g, "%").split(/%/g); 863 | 864 | matrix = { 865 | _id : 100, 866 | _class : 10, 867 | _tag : 1 868 | }; 869 | 870 | // Start with rule index position 871 | total = 0; 872 | 873 | // Add each selector value to total. 874 | for (i = 0, j = selectorGrid.length; i < j; i++) { 875 | chunk = selectorGrid[i]; 876 | 877 | if ((/#/).test(chunk)) { 878 | total += matrix._id; 879 | } else if ((/\.|\[|\:/).test(chunk)) { 880 | total += matrix._class; 881 | } else if ((/[a-zA-Z]+/).test(chunk)) { 882 | total += matrix._tag; 883 | } 884 | } 885 | 886 | return total; 887 | } 888 | 889 | function filterDuplicates (matches, children, type) { 890 | var filteredMatches = [], exists, 891 | spec = (type ? "ordinal" : "flex") + "Specificity", 892 | i, j, x, k, l, f; 893 | 894 | for (i = 0, j = matches.length; i < j; i++) { 895 | x = matches[i]; 896 | 897 | if ((!type && x.flex) || (type && x["ordinal-group"])) { 898 | x[spec] = x[spec] || calculateSpecificity(x.selector); 899 | 900 | exists = FALSE; 901 | 902 | for (k = 0, l = filteredMatches.length; k < l; k++) { 903 | f = filteredMatches[k]; 904 | 905 | if (f.match === x.match) { 906 | if (f[spec] < x[spec]) { 907 | filteredMatches[j] = x; 908 | } 909 | 910 | exists = TRUE; 911 | return FALSE; 912 | } 913 | } 914 | 915 | if (!exists) { 916 | filteredMatches.push(x); 917 | } 918 | } 919 | } 920 | 921 | return filteredMatches; 922 | } 923 | 924 | function createMatchMatrix(matches, children, type) { 925 | var groups = {}, keys = [], totalRatio = 0, 926 | group, order = "ordinal-group", 927 | BoxOrdinalAttr = "data-" + order, 928 | i, j, kid, k, l, x, key; 929 | 930 | // Filter dupes 931 | matches = filterDuplicates(matches, children, type); 932 | 933 | for (i = 0, j = children.length; i < j; i++) { 934 | kid = children[i]; 935 | 936 | for (k = 0, l = matches.length; k < l; k++) { 937 | x = matches[k]; 938 | 939 | if (type) { 940 | // If no value declared, it's the default. 941 | group = x[order] || "1"; 942 | 943 | if (x.match === kid) { 944 | x.match.setAttribute(BoxOrdinalAttr, group); 945 | 946 | groups[group] = groups[group] || []; 947 | groups[group].push(x); 948 | } 949 | } else { 950 | // If no value declared, it's the default. 951 | group = x.flex || "0"; 952 | 953 | if (x.match === kid && (!x[group] || (x[group] && parseInt(x[group], 10) <= 1))) { 954 | totalRatio += parseInt(group, 10); 955 | 956 | groups[group] = groups[group] || []; 957 | groups[group].push(x); 958 | } 959 | } 960 | } 961 | 962 | if (type && !kid.getAttribute(BoxOrdinalAttr)) { 963 | group = "1"; 964 | kid.setAttribute(BoxOrdinalAttr, group); 965 | 966 | groups[group] = groups[group] || []; 967 | groups[group].push({ 968 | match : kid 969 | }); 970 | } 971 | } 972 | 973 | for (key in groups) { 974 | if (groups.hasOwnProperty(key)) { 975 | keys.push(key); 976 | } 977 | } 978 | 979 | keys.sort(function (a, b) { 980 | return b - a; 981 | }); 982 | 983 | return { 984 | keys : keys, 985 | groups : groups, 986 | total : totalRatio 987 | }; 988 | } 989 | 990 | function attachResizeListener(construct, params) { 991 | if (!RESIZE_LISTENER) { 992 | var storedWidth, storedHeight, 993 | currentWidth, currentHeight, 994 | docBody = doc.body, 995 | docEl = doc.documentElement, 996 | resizeTimer, 997 | innerWidth = "innerWidth", innerHeight = "innerHeight", 998 | clientWidth = "clientWidth", clientHeight = "clientHeight"; 999 | 1000 | addEvent("resize", function () { 1001 | if (resizeTimer) { 1002 | window.clearTimeout(resizeTimer); 1003 | } 1004 | 1005 | resizeTimer = window.setTimeout(function () { 1006 | currentWidth = win[innerWidth] || docEl[innerWidth] || docEl[clientWidth] || docBody[clientWidth]; 1007 | currentHeight = win[innerHeight] || docEl[innerHeight] || docEl[clientHeight] || docBody[clientHeight]; 1008 | 1009 | if (storedWidth !== currentWidth || storedHeight !== currentHeight) { 1010 | FLX.updateInstance(NULL, NULL); 1011 | 1012 | storedWidth = currentWidth; 1013 | storedHeight = currentHeight; 1014 | } 1015 | }, 250); 1016 | }); 1017 | 1018 | RESIZE_LISTENER = TRUE; 1019 | } 1020 | } 1021 | 1022 | function cleanPositioningProperties (children) { 1023 | var i, j, kid, w, h; 1024 | 1025 | for (i = 0, j = children.length; i < j; i++) { 1026 | kid = children[i]; 1027 | 1028 | w = kid.style.width; 1029 | h = kid.style.height; 1030 | 1031 | kid.style.cssText = EMPTY_STRING; 1032 | 1033 | kid.style.width = w; 1034 | kid.style.height = h; 1035 | } 1036 | } 1037 | 1038 | function sanitizeChildren (target, nodes) { 1039 | var children = [], node, i, j; 1040 | 1041 | for (i = 0, j = nodes.length; i < j; i++) { 1042 | node = nodes[i]; 1043 | 1044 | if (node) { 1045 | switch (node.nodeName.toLowerCase()) { 1046 | case "script" : 1047 | case "style" : 1048 | case "link" : 1049 | break; 1050 | 1051 | default : 1052 | if (node.nodeType === 1) { 1053 | children.push(node); 1054 | } else if ((node.nodeType === 3) && (node.isElementContentWhitespace || (ONLY_WHITESPACE).test(node.data))) { 1055 | target.removeChild(node); 1056 | i--; 1057 | } 1058 | break; 1059 | } 1060 | } 1061 | } 1062 | 1063 | return children; 1064 | } 1065 | 1066 | function parentFlex (target) { 1067 | var totalFlex = 0, 1068 | parent = target.parentNode, 1069 | obj, 1070 | matrix, 1071 | isNested; 1072 | 1073 | while (parent.FLX_DOM_ID) { 1074 | obj = FLEX_BOXES[parent.FLX_DOM_ID]; 1075 | matrix = createMatchMatrix(obj.children, sanitizeChildren(parent, parent.childNodes), NULL); 1076 | 1077 | totalFlex += matrix.total; 1078 | isNested = TRUE; 1079 | 1080 | parent = parent.parentNode; 1081 | } 1082 | 1083 | return { 1084 | nested : isNested, 1085 | flex : totalFlex 1086 | }; 1087 | } 1088 | 1089 | function dimensionValues (target, prop) { 1090 | var parent = target.parentNode, 1091 | obj, dimension, i, j, rule; 1092 | 1093 | if (parent.FLX_DOM_ID) { 1094 | obj = FLEX_BOXES[parent.FLX_DOM_ID]; 1095 | 1096 | for (i = 0, j = obj.properties.length; i < j; i++) { 1097 | rule = obj.properties[i]; 1098 | 1099 | if ((new RegExp(prop)).test(rule.property)) { 1100 | dimension = TRUE; 1101 | return FALSE; 1102 | } 1103 | } 1104 | } 1105 | 1106 | return dimension; 1107 | } 1108 | 1109 | function updateChildValues (params) { 1110 | var i, j, x; 1111 | 1112 | if (params.flexMatrix) { 1113 | for (i = 0, j = params.children.length; i < j; i++) { 1114 | x = params.children[i]; 1115 | x.flex = params.flexMatrix[i]; 1116 | } 1117 | } 1118 | 1119 | if (params.ordinalMatrix) { 1120 | for (i = 0, j = params.children.length; i < j; i++) { 1121 | x = params.children[i]; 1122 | x["ordinal-group"] = params.ordinalMatrix[i]; 1123 | } 1124 | } 1125 | 1126 | return params; 1127 | } 1128 | 1129 | function ensureStructuralIntegrity (params, instance) { 1130 | var target = params.target; 1131 | 1132 | if (!target.FLX_DOM_ID) { 1133 | target.FLX_DOM_ID = target.FLX_DOM_ID || (++FLX_DOM_ID); 1134 | } 1135 | 1136 | if (!params.nodes) { 1137 | params.nodes = sanitizeChildren(target, target.childNodes); 1138 | } 1139 | 1140 | if (!params.selector) { 1141 | params.selector = buildSelector(target); 1142 | target.setAttribute(FLX_PARENT_ATTR, TRUE); 1143 | } 1144 | 1145 | if (!params.properties) { 1146 | params.properties = []; 1147 | } 1148 | 1149 | if (!params.children) { 1150 | params.children = matchFlexChildren(target, LIBRARY, sanitizeChildren(target, target.childNodes)); 1151 | } 1152 | 1153 | if (!params.nested) { 1154 | params.nested = params.selector + " [" + FLX_PARENT_ATTR + "]"; 1155 | } 1156 | 1157 | params.target = target; 1158 | params._instance = instance; 1159 | 1160 | return params; 1161 | } 1162 | 1163 | selectivizrEngine = (function () { 1164 | var RE_COMMENT = /(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)\s*?/g, 1165 | RE_IMPORT = /@import\s*(?:(?:(?:url\(\s*(['"]?)(.*)\1)\s*\))|(?:(['"])(.*)\3))\s*([^;]*);/g, 1166 | RE_ASSET_URL = /(behavior\s*?:\s*)?\burl\(\s*(["']?)(?!data:)([^"')]+)\2\s*\)/g, 1167 | RE_SELECTOR_GROUP = /((?:^|(?:\s*\})+)(?:\s*@media[^\{]+\{)?)\s*([^\{]*?[\[:][^{]+)/g, 1168 | 1169 | // Whitespace normalization regexp's 1170 | RE_TIDY_TRAILING_WHITESPACE = /([(\[+~])\s+/g, 1171 | RE_TIDY_LEADING_WHITESPACE = /\s+([)\]+~])/g, 1172 | RE_TIDY_CONSECUTIVE_WHITESPACE = /\s+/g, 1173 | RE_TIDY_TRIM_WHITESPACE = /^\s*((?:[\S\s]*\S)?)\s*$/; 1174 | 1175 | // --[ trim() ]--------------------------------------------------------- 1176 | // removes leading, trailing whitespace from a string 1177 | function trim(text) { 1178 | return text.replace(RE_TIDY_TRIM_WHITESPACE, PLACEHOLDER_STRING); 1179 | } 1180 | 1181 | // --[ normalizeWhitespace() ]------------------------------------------ 1182 | // removes leading, trailing and consecutive whitespace from a string 1183 | function normalizeWhitespace(text) { 1184 | return trim(text).replace(RE_TIDY_CONSECUTIVE_WHITESPACE, SPACE_STRING); 1185 | } 1186 | 1187 | // --[ normalizeSelectorWhitespace() ]---------------------------------- 1188 | // tidys whitespace around selector brackets and combinators 1189 | function normalizeSelectorWhitespace(selectorText) { 1190 | return normalizeWhitespace(selectorText.replace(RE_TIDY_TRAILING_WHITESPACE, PLACEHOLDER_STRING).replace(RE_TIDY_LEADING_WHITESPACE, PLACEHOLDER_STRING)); 1191 | } 1192 | 1193 | // --[ patchStyleSheet() ]---------------------------------------------- 1194 | // Scans the passed cssText for selectors that require emulation and 1195 | // creates one or more patches for each matched selector. 1196 | function patchStyleSheet(cssText) { 1197 | return cssText.replace(RE_SELECTOR_GROUP, function (m, prefix, selectorText) { 1198 | var selectorGroups, selector, 1199 | i, j, group; 1200 | 1201 | selectorGroups = selectorText.split(","); 1202 | 1203 | for (i = 0, j = selectorGroups.length; i < j; i++) { 1204 | group = selectorGroups[i]; 1205 | selector = normalizeSelectorWhitespace(group) + SPACE_STRING; 1206 | } 1207 | 1208 | return prefix + selectorGroups.join(","); 1209 | }); 1210 | } 1211 | 1212 | // --[ getXHRObject() ]------------------------------------------------- 1213 | function getXHRObject() { 1214 | if (win.XMLHttpRequest) { 1215 | return new win.XMLHttpRequest(); 1216 | } 1217 | 1218 | try { 1219 | return new win.ActiveXObject("Microsoft.XMLHTTP"); 1220 | } catch (e) { 1221 | return NULL; 1222 | } 1223 | } 1224 | 1225 | function parseInlineStyles ( text ) { 1226 | var reg = /]*>([^<>]*)<\/style[\s]?>/img, 1227 | match = reg.exec(text), 1228 | stylesheets = [], 1229 | rawCSSText; 1230 | 1231 | while (match) { 1232 | rawCSSText = match[1]; 1233 | 1234 | if (rawCSSText) { 1235 | stylesheets.push(rawCSSText); 1236 | } 1237 | 1238 | match = reg.exec(text); 1239 | } 1240 | 1241 | return stylesheets.join("\n\n"); 1242 | } 1243 | 1244 | // --[ loadStyleSheet() ]----------------------------------------------- 1245 | function loadStyleSheet(url) { 1246 | var xhr = getXHRObject(), 1247 | responseText; 1248 | 1249 | xhr.open("GET", url, FALSE); 1250 | xhr.send(); 1251 | 1252 | responseText = (xhr.status === 200) ? xhr.responseText : EMPTY_STRING; 1253 | 1254 | if (url === window.location.href) { 1255 | responseText = parseInlineStyles(responseText); 1256 | } 1257 | 1258 | return responseText; 1259 | } 1260 | 1261 | // --[ resolveUrl() ]--------------------------------------------------- 1262 | // Converts a URL fragment to a fully qualified URL using the specified 1263 | // context URL. Returns null if same-origin policy is broken 1264 | function resolveUrl(url, contextUrl) { 1265 | 1266 | // IE9 returns a false positive sometimes(?) 1267 | if (!url) { 1268 | return; 1269 | } 1270 | 1271 | function getProtocolAndHost(url) { 1272 | return url.substring(0, url.indexOf("/", 8)); 1273 | } 1274 | 1275 | // absolute path 1276 | if (PROTOCOL.test(url)) { 1277 | return getProtocolAndHost(contextUrl) === getProtocolAndHost(url) ? url : NULL; 1278 | } 1279 | 1280 | // root-relative path 1281 | if (url.charAt(0) === "/") { 1282 | return getProtocolAndHost(contextUrl) + url; 1283 | } 1284 | 1285 | // relative path 1286 | var contextUrlPath = contextUrl.split("?")[0]; // ignore query string in the contextUrl 1287 | if (url.charAt(0) !== "?" && contextUrlPath.charAt(contextUrlPath.length - 1) !== "/") { 1288 | contextUrlPath = contextUrlPath.substring(0, contextUrlPath.lastIndexOf("/") + 1); 1289 | } 1290 | 1291 | return contextUrlPath + url; 1292 | } 1293 | 1294 | // --[ parseStyleSheet() ]---------------------------------------------- 1295 | // Downloads the stylesheet specified by the URL, removes it's comments 1296 | // and recursivly replaces @import rules with their contents, ultimately 1297 | // returning the full cssText. 1298 | function parseStyleSheet( url ) { 1299 | if (url) { 1300 | return loadStyleSheet(url).replace(RE_COMMENT, EMPTY_STRING). 1301 | replace(RE_IMPORT, function( match, quoteChar, importUrl, quoteChar2, importUrl2, media ) { 1302 | var cssText = parseStyleSheet(resolveUrl(importUrl || importUrl2, url)); 1303 | return (media) ? "@media " + media + " {" + cssText + "}" : cssText; 1304 | }). 1305 | replace(RE_ASSET_URL, function( match, isBehavior, quoteChar, assetUrl ) { 1306 | quoteChar = quoteChar || EMPTY_STRING; 1307 | return isBehavior ? match : " url(" + quoteChar + resolveUrl(assetUrl, url, true) + quoteChar + ") "; 1308 | }); 1309 | } 1310 | return EMPTY_STRING; 1311 | } 1312 | 1313 | // --[ init() ]--------------------------------------------------------- 1314 | return function () { 1315 | // honour the tag 1316 | var url, stylesheets = [], stylesheet, i, j, 1317 | baseTags = doc.getElementsByTagName("BASE"), 1318 | baseUrl = (baseTags.length > 0) ? baseTags[0].href : doc.location.href, 1319 | externalStyles = doc.styleSheets, 1320 | cssText, tree, flexers; 1321 | 1322 | for (i = 0, j = externalStyles.length; i < j; i++) { 1323 | stylesheet = externalStyles[i]; 1324 | 1325 | if (stylesheet != NULL) { 1326 | stylesheets.push(stylesheet); 1327 | } 1328 | } 1329 | 1330 | // Add self to test for inline styles 1331 | stylesheets.push(window.location); 1332 | 1333 | for (i = 0, j = stylesheets.length; i < j; i++) { 1334 | stylesheet = stylesheets[i]; 1335 | 1336 | if (stylesheet) { 1337 | url = resolveUrl(stylesheet.href, baseUrl); 1338 | 1339 | if (url) { 1340 | cssText = patchStyleSheet(parseStyleSheet(url)); 1341 | } 1342 | 1343 | if (cssText) { 1344 | tree = buildSelectorTree(cssText); 1345 | flexers = findFlexboxElements(tree); 1346 | } 1347 | } 1348 | } 1349 | 1350 | buildFlexieCall(flexers); 1351 | }; 1352 | }()); 1353 | 1354 | // Flexie box constructor 1355 | FLX.box = function (params) { 1356 | return this.renderModel(params); 1357 | }; 1358 | 1359 | FLX.box.prototype = { 1360 | properties : { 1361 | boxModel : function (target, children, params) { 1362 | var selectors, stylesheet, paddingFix, generatedRules, 1363 | i, j, selector; 1364 | 1365 | target.style.display = "block"; 1366 | 1367 | if (BROWSER.IE === 8) { 1368 | target.style.overflow = "hidden"; 1369 | } 1370 | 1371 | // We'll be using floats, so the easiest way to retain layout 1372 | // is the dreaded clear fix: 1373 | if (!params.cleared) { 1374 | selectors = params.selector.split(/\s?,\s?/); 1375 | stylesheet = doc.styleSheets; 1376 | stylesheet = stylesheet[stylesheet.length - 1]; 1377 | paddingFix = "padding-top:" + (getComputedStyle(target, PADDING_TOP, NULL) || "0.1px;"); 1378 | 1379 | generatedRules = [ 1380 | "content: '.'", 1381 | "display: block", 1382 | "height: 0", 1383 | "overflow: hidden" 1384 | ].join(";"); 1385 | 1386 | for (i = 0, j = selectors.length; i < j; i++) { 1387 | selector = selectors[i]; 1388 | 1389 | if (stylesheet.addRule) { 1390 | if (BROWSER.IE < 8) { 1391 | target.style.zoom = "1"; 1392 | 1393 | if (BROWSER.IE === 6) { 1394 | stylesheet.addRule(selector.replace(/\>|\+|\~/g, ""), paddingFix + "zoom:1;", 0); 1395 | } else if (BROWSER.IE === 7) { 1396 | stylesheet.addRule(selector, paddingFix + "display:inline-block;", 0); 1397 | } 1398 | } else { 1399 | stylesheet.addRule(selector, paddingFix, 0); 1400 | stylesheet.addRule(selector + ":before", generatedRules, 0); 1401 | stylesheet.addRule(selector + ":after", generatedRules + ";clear:both;", 0); 1402 | } 1403 | } else if (stylesheet.insertRule) { 1404 | stylesheet.insertRule(selector + "{" + paddingFix + "}", 0); 1405 | stylesheet.insertRule(selector + ":after{" + generatedRules + ";clear:both;}", 0); 1406 | } 1407 | } 1408 | 1409 | params.cleared = TRUE; 1410 | } 1411 | }, 1412 | 1413 | boxDirection : function (target, children, params) { 1414 | var nestedSelector, nested, 1415 | i, j, kid, node; 1416 | 1417 | if ((params.direction === "reverse" && !params.reversed) || (params.direction === "normal" && params.reversed)) { 1418 | children = children.reverse(); 1419 | 1420 | for (i = 0, j = children.length; i < j; i++) { 1421 | kid = children[i]; 1422 | target.appendChild(kid); 1423 | } 1424 | 1425 | // box-direction is inheritable. 1426 | // We need to see if there are any nested flexbox elements 1427 | nestedSelector = LIBRARY(params.nested); 1428 | 1429 | for (i = 0, j = nestedSelector.length; i < j; i++) { 1430 | node = nestedSelector[i]; 1431 | 1432 | nested = FLEX_BOXES[node.FLX_DOM_ID]; 1433 | 1434 | if (nested && nested.direction === INHERIT) { 1435 | nested.direction = params.direction; 1436 | } 1437 | } 1438 | 1439 | params.reversed = !params.reversed; 1440 | } 1441 | }, 1442 | 1443 | boxOrient : function (target, children, params) { 1444 | var self = this, wide, high, 1445 | i, j, kid; 1446 | 1447 | wide = { 1448 | pos : "marginLeft", 1449 | opp : "marginRight", 1450 | dim : "width", 1451 | out : "offsetWidth", 1452 | func : clientWidth, 1453 | pad : [PADDING_LEFT, PADDING_RIGHT, BORDER_LEFT, BORDER_RIGHT] 1454 | }; 1455 | 1456 | high = { 1457 | pos : "marginTop", 1458 | opp : "marginBottom", 1459 | dim : "height", 1460 | out : "offsetHeight", 1461 | func : clientHeight, 1462 | pad : [PADDING_TOP, PADDING_BOTTOM, BORDER_TOP, BORDER_BOTTOM] 1463 | }; 1464 | 1465 | if (!SUPPORT) { 1466 | for (i = 0, j = children.length; i < j; i++) { 1467 | kid = children[i]; 1468 | 1469 | kid.style[(BROWSER.IE >= 9) ? "cssFloat" : "styleFloat"] = LEFT; 1470 | 1471 | if (params.orient === VERTICAL || params.orient === BLOCK_AXIS) { 1472 | kid.style.clear = LEFT; 1473 | } 1474 | 1475 | if (BROWSER.IE === 6) { 1476 | kid.style.display = "inline"; 1477 | } 1478 | } 1479 | } 1480 | 1481 | switch (params.orient) { 1482 | case VERTICAL : 1483 | case BLOCK_AXIS: 1484 | self.props = high; 1485 | self.anti = wide; 1486 | break; 1487 | 1488 | default : 1489 | self.props = wide; 1490 | self.anti = high; 1491 | break; 1492 | } 1493 | }, 1494 | 1495 | boxOrdinalGroup : function (target, children, params) { 1496 | var organizeChildren, 1497 | matrix; 1498 | 1499 | if (!children.length) { 1500 | return; 1501 | } 1502 | 1503 | organizeChildren = function (matrix) { 1504 | var keys = matrix.keys, 1505 | iterator = params.reversed ? keys : keys.reverse(), 1506 | i, j, key, k, l, kid; 1507 | 1508 | for (i = 0, j = iterator.length; i < j; i++) { 1509 | key = iterator[i]; 1510 | 1511 | for (k = 0, l = children.length; k < l; k++) { 1512 | kid = children[k]; 1513 | 1514 | if (key === kid.getAttribute("data-ordinal-group")) { 1515 | target.appendChild(kid); 1516 | } 1517 | } 1518 | } 1519 | }; 1520 | 1521 | matrix = createMatchMatrix(params.children, children, TRUE); 1522 | 1523 | if (matrix.keys.length > 1) { 1524 | organizeChildren(matrix); 1525 | } 1526 | }, 1527 | 1528 | boxFlex : function (target, children, params) { 1529 | var self = this, 1530 | testForRestrictiveProperties, 1531 | findTotalWhitespace, 1532 | distributeRatio, 1533 | matrix, 1534 | restrict, 1535 | whitespace, 1536 | distro; 1537 | 1538 | if (!children.length) { 1539 | return; 1540 | } 1541 | 1542 | testForRestrictiveProperties = function (matrix) { 1543 | var flexers = matrix.groups, 1544 | keys = matrix.keys, 1545 | max, i, j, key, 1546 | k, l, x, m, n, rule; 1547 | 1548 | for (i = 0, j = keys.length; i < j; i++) { 1549 | key = keys[i]; 1550 | 1551 | for (k = 0, l = flexers[key].length; k < l; k++) { 1552 | x = flexers[key][k]; 1553 | max = NULL; 1554 | 1555 | for (m = 0, n = x.properties.length; m < n; m++) { 1556 | rule = x.properties[m]; 1557 | 1558 | if ((RESTRICTIVE_PROPERTIES).test(rule.property)) { 1559 | max = parseFloat(rule.value); 1560 | } 1561 | } 1562 | 1563 | if (!max || x.match[self.props.out] > max) { 1564 | appendPixelValue(x.match, self.props.pos, NULL); 1565 | } 1566 | 1567 | } 1568 | } 1569 | }; 1570 | 1571 | findTotalWhitespace = function (matrix) { 1572 | var groupDimension = 0, 1573 | whitespace, 1574 | ration, 1575 | i, j, kid, 1576 | k, l, pad; 1577 | 1578 | for (i = 0, j = children.length; i < j; i++) { 1579 | kid = children[i]; 1580 | 1581 | groupDimension += getComputedStyle(kid, self.props.dim, TRUE); 1582 | 1583 | for (k = 0, l = self.props.pad.length; k < l; k++) { 1584 | pad = self.props.pad[k]; 1585 | 1586 | groupDimension += getComputedStyle(kid, pad, TRUE); 1587 | } 1588 | 1589 | groupDimension += getComputedStyle(kid, self.props.pos, TRUE); 1590 | groupDimension += getComputedStyle(kid, self.props.opp, TRUE); 1591 | } 1592 | 1593 | whitespace = target[self.props.out] - groupDimension; 1594 | 1595 | for (i = 0, j = self.props.pad.length; i < j; i++) { 1596 | pad = self.props.pad[i]; 1597 | whitespace -= getComputedStyle(target, pad, TRUE); 1598 | } 1599 | 1600 | ration = (whitespace / matrix.total); 1601 | 1602 | return { 1603 | whitespace : whitespace, 1604 | ration : ration 1605 | }; 1606 | }; 1607 | 1608 | distributeRatio = function (matrix, whitespace) { 1609 | var flexers = matrix.groups, 1610 | keys = matrix.keys, 1611 | flex, specificity, 1612 | ration = whitespace.ration, 1613 | widthRation, trueDim, newDimension, 1614 | i, j, key, k, l, x; 1615 | 1616 | for (i = 0, j = keys.length; i < j; i++) { 1617 | key = keys[i]; 1618 | widthRation = (ration * key); 1619 | 1620 | for (k = 0, l = flexers[key].length; k < l; k++) { 1621 | x = flexers[key][k]; 1622 | 1623 | if (x.match) { 1624 | flex = x.match.getAttribute("data-flex"); 1625 | specificity = x.match.getAttribute("data-specificity"); 1626 | 1627 | if (!flex || (specificity <= x.flexSpecificity)) { 1628 | x.match.setAttribute("data-flex", key); 1629 | x.match.setAttribute("data-specificity", x.flexSpecificity); 1630 | 1631 | trueDim = getComputedStyle(x.match, self.props.dim, TRUE); 1632 | newDimension = Math.max(0, (trueDim + widthRation)); 1633 | appendPixelValue(x.match, self.props.dim, newDimension); 1634 | } 1635 | } 1636 | } 1637 | } 1638 | }; 1639 | 1640 | matrix = createMatchMatrix(params.children, children, NULL); 1641 | 1642 | if (matrix.total) { 1643 | params.hasFlex = TRUE; 1644 | 1645 | restrict = testForRestrictiveProperties(matrix); 1646 | whitespace = findTotalWhitespace(matrix); 1647 | 1648 | // Distribute the calculated ratios among the children 1649 | distro = distributeRatio(matrix, whitespace); 1650 | } 1651 | }, 1652 | 1653 | boxAlign : function (target, children, params) { 1654 | var self = this, 1655 | targetDimension, 1656 | kidDimension, 1657 | flexCheck = parentFlex(target), 1658 | i, j, pad, k, l, kid; 1659 | 1660 | if (!SUPPORT && !flexCheck.flex && (params.orient === VERTICAL || params.orient === BLOCK_AXIS)) { 1661 | if (!dimensionValues(target, self.anti.dim)) { 1662 | appendPixelValue(target, self.anti.dim, NULL); 1663 | } 1664 | appendPixelValue(children, self.anti.dim, NULL); 1665 | } 1666 | 1667 | // Remove padding / border from target dimension 1668 | targetDimension = target[self.anti.out]; 1669 | 1670 | for (i = 0, j = self.anti.pad.length; i < j; i++) { 1671 | pad = self.anti.pad[i]; 1672 | targetDimension -= getComputedStyle(target, pad, TRUE); 1673 | } 1674 | 1675 | switch (params.align) { 1676 | case "start" : 1677 | break; 1678 | 1679 | case "end" : 1680 | for (i = 0, j = children.length; i < j; i++) { 1681 | kid = children[i]; 1682 | 1683 | kidDimension = targetDimension - kid[self.anti.out]; 1684 | kidDimension -= getComputedStyle(kid, self.anti.opp, TRUE); 1685 | appendPixelValue(kid, self.anti.pos, kidDimension); 1686 | } 1687 | break; 1688 | 1689 | case "center" : 1690 | for (i = 0, j = children.length; i < j; i++) { 1691 | kid = children[i]; 1692 | 1693 | kidDimension = (targetDimension - kid[self.anti.out]) / 2; 1694 | appendPixelValue(kid, self.anti.pos, kidDimension); 1695 | } 1696 | break; 1697 | 1698 | default : 1699 | for (i = 0, j = children.length; i < j; i++) { 1700 | kid = children[i]; 1701 | 1702 | switch (kid.nodeName.toLowerCase()) { 1703 | case "button" : 1704 | case "input" : 1705 | case "select" : 1706 | break; 1707 | 1708 | default : 1709 | var subtract = 0; 1710 | 1711 | for (k = 0, l = self.anti.pad.length; k < l; k++) { 1712 | pad = self.anti.pad[k]; 1713 | 1714 | subtract += getComputedStyle(kid, pad, TRUE); 1715 | subtract += getComputedStyle(target, pad, TRUE); 1716 | } 1717 | 1718 | kid.style[self.anti.dim] = "100%"; 1719 | kidDimension = kid[self.anti.out] - subtract; 1720 | appendPixelValue(kid, self.anti.dim, NULL); 1721 | 1722 | kidDimension = targetDimension; 1723 | kidDimension -= getComputedStyle(kid, self.anti.pos, TRUE); 1724 | 1725 | for (k = 0, l = self.anti.pad.length; k < l; k++) { 1726 | pad = self.anti.pad[k]; 1727 | 1728 | kidDimension -= getComputedStyle(kid, pad, TRUE); 1729 | } 1730 | 1731 | kidDimension -= getComputedStyle(kid, self.anti.opp, TRUE); 1732 | kidDimension = Math.max(0, kidDimension); 1733 | 1734 | appendPixelValue(kid, self.anti.dim, kidDimension); 1735 | break; 1736 | } 1737 | } 1738 | break; 1739 | } 1740 | }, 1741 | 1742 | boxPack : function (target, children, params) { 1743 | var self = this, 1744 | groupDimension = 0, 1745 | firstComputedMargin = 0, 1746 | targetPadding = 0, 1747 | totalDimension, 1748 | fractionedDimension, 1749 | currentDimension, 1750 | remainder, 1751 | length = children.length - 1, 1752 | kid, i, j, value, pad; 1753 | 1754 | for (i = 0, j = children.length; i < j; i++) { 1755 | kid = children[i]; 1756 | 1757 | groupDimension += kid[self.props.out]; 1758 | groupDimension += getComputedStyle(kid, self.props.pos, TRUE); 1759 | groupDimension += getComputedStyle(kid, self.props.opp, TRUE); 1760 | } 1761 | 1762 | firstComputedMargin = getComputedStyle(children[0], self.props.pos, TRUE); 1763 | totalDimension = target[self.props.out] - groupDimension; 1764 | 1765 | // Remove padding / border from target dimension 1766 | for (i = 0, j = self.props.pad.length; i < j; i++) { 1767 | pad = self.props.pad[i]; 1768 | totalDimension -= getComputedStyle(target, pad, TRUE); 1769 | } 1770 | 1771 | // If totalDimension is less than 0, we have a problem... 1772 | if (totalDimension < 0) { 1773 | totalDimension = Math.max(0, totalDimension); 1774 | } 1775 | 1776 | switch (params.pack) { 1777 | case "end" : 1778 | appendPixelValue(children[0], self.props.pos, targetPadding + firstComputedMargin + totalDimension); 1779 | break; 1780 | 1781 | case "center" : 1782 | if (targetPadding) { 1783 | targetPadding /= 2; 1784 | } 1785 | 1786 | appendPixelValue(children[0], self.props.pos, targetPadding + firstComputedMargin + Math.floor(totalDimension / 2)); 1787 | break; 1788 | 1789 | case "justify" : 1790 | fractionedDimension = Math.floor((targetPadding + totalDimension) / length); 1791 | remainder = (fractionedDimension * length) - totalDimension; 1792 | 1793 | i = children.length - 1; 1794 | 1795 | while (i) { 1796 | kid = children[i]; 1797 | currentDimension = fractionedDimension; 1798 | 1799 | if (remainder) { 1800 | currentDimension++; 1801 | remainder++; 1802 | } 1803 | 1804 | value = getComputedStyle(kid, self.props.pos, TRUE) + currentDimension; 1805 | appendPixelValue(kid, self.props.pos, value); 1806 | 1807 | i--; 1808 | } 1809 | 1810 | break; 1811 | } 1812 | 1813 | target.style.overflow = ""; 1814 | } 1815 | }, 1816 | 1817 | setup : function (target, children, params) { 1818 | var self = this, matrix, flexCheck, 1819 | key, func; 1820 | 1821 | if (!target || !children || !params) { 1822 | return; 1823 | } 1824 | 1825 | if (SUPPORT && SUPPORT.partialSupport) { 1826 | matrix = createMatchMatrix(params.children, children, NULL); 1827 | flexCheck = parentFlex(target); 1828 | children = sanitizeChildren(target, target.childNodes); 1829 | 1830 | self.properties.boxOrient.call(self, target, children, params); 1831 | 1832 | if (!matrix.total || !LIBRARY(params.nested).length) { 1833 | if ((params.align === "stretch") && !SUPPORT.boxAlignStretch && (!flexCheck.nested || !flexCheck.flex)) { 1834 | self.properties.boxAlign.call(self, target, children, params); 1835 | } 1836 | 1837 | if ((params.pack === "justify") && !SUPPORT.boxPackJustify && !matrix.total) { 1838 | self.properties.boxPack.call(self, target, children, params); 1839 | } 1840 | } 1841 | } else if (!SUPPORT) { 1842 | for (key in self.properties) { 1843 | if (self.properties.hasOwnProperty(key)) { 1844 | func = self.properties[key]; 1845 | func.call(self, target, sanitizeChildren(target, target.childNodes), params); 1846 | } 1847 | } 1848 | } 1849 | }, 1850 | 1851 | trackDOM : function (params) { 1852 | attachResizeListener(this, params); 1853 | }, 1854 | 1855 | updateModel : function (params) { 1856 | var self = this, 1857 | target = params.target, 1858 | children = params.nodes; 1859 | 1860 | // Null properties 1861 | cleanPositioningProperties(children); 1862 | 1863 | if (params.flexMatrix || params.ordinalMatrix) { 1864 | params = updateChildValues(params); 1865 | } 1866 | 1867 | self.setup(target, children, params); 1868 | self.bubbleUp(target, params); 1869 | }, 1870 | 1871 | renderModel : function (params) { 1872 | var self = this, 1873 | target = params.target, 1874 | nodes = target.childNodes; 1875 | 1876 | // Sanity check. 1877 | if (!target.length && !nodes) { 1878 | return false; 1879 | } 1880 | 1881 | params = ensureStructuralIntegrity(params, this); 1882 | 1883 | // Setup properties 1884 | self.updateModel(params); 1885 | 1886 | // Resize / DOM Polling Events 1887 | // Delay for an instant because IE6 is insane. 1888 | win.setTimeout(function () { 1889 | self.trackDOM(params); 1890 | }, 0); 1891 | 1892 | return self; 1893 | }, 1894 | 1895 | bubbleUp : function (target, params) { 1896 | var self = this, flex, 1897 | parent = params.target.parentNode; 1898 | 1899 | while (parent) { 1900 | flex = FLEX_BOXES[parent.FLX_DOM_ID]; 1901 | 1902 | if (flex) { 1903 | cleanPositioningProperties(flex.nodes); 1904 | self.setup(flex.target, flex.nodes, flex); 1905 | } 1906 | 1907 | parent = parent.parentNode; 1908 | } 1909 | } 1910 | }; 1911 | 1912 | FLX.updateInstance = function (target, params) { 1913 | var box, key; 1914 | 1915 | if (target) { 1916 | box = FLEX_BOXES[target.FLX_DOM_ID]; 1917 | 1918 | if (box && box._instance) { 1919 | box._instance.updateModel(box); 1920 | } else if (!box) { 1921 | box = new FLX.box(params); 1922 | } 1923 | } else { 1924 | for (key in FLEX_BOXES) { 1925 | if (FLEX_BOXES.hasOwnProperty(key)) { 1926 | box = FLEX_BOXES[key]; 1927 | 1928 | if (box && box._instance) { 1929 | box._instance.updateModel(box); 1930 | } 1931 | } 1932 | } 1933 | } 1934 | }; 1935 | 1936 | FLX.getInstance = function (target) { 1937 | return FLEX_BOXES[target.FLX_DOM_ID]; 1938 | }; 1939 | 1940 | FLX.destroyInstance = function (target) { 1941 | var box, destroy, i, j, x, key; 1942 | 1943 | destroy = function (box) { 1944 | box.target.FLX_DOM_ID = NULL; 1945 | box.target.style.cssText = EMPTY_STRING; 1946 | 1947 | for (i = 0, j = box.children.length; i < j; i++) { 1948 | x = box.children[i]; 1949 | x.match.style.cssText = EMPTY_STRING; 1950 | } 1951 | }; 1952 | 1953 | if (target) { 1954 | box = FLEX_BOXES[target.FLX_DOM_ID]; 1955 | 1956 | if (box) { 1957 | destroy(box); 1958 | } 1959 | } else { 1960 | for (key in FLEX_BOXES) { 1961 | if (FLEX_BOXES.hasOwnProperty(key)) { 1962 | destroy(FLEX_BOXES[key]); 1963 | } 1964 | } 1965 | 1966 | FLEX_BOXES = []; 1967 | } 1968 | }; 1969 | 1970 | FLX.flexboxSupport = function () { 1971 | var partialSupportGrid = {}, 1972 | height = 100, 1973 | childHeight, 1974 | dummy = doc.createElement("flxbox"), 1975 | child = '', 1976 | tests, result, key, value; 1977 | 1978 | dummy.style.width = dummy.style.height = height + "px"; 1979 | dummy.innerHTML = (child + child + child); 1980 | 1981 | appendProperty(dummy, "display", "box", NULL); 1982 | appendProperty(dummy, "box-align", "stretch", TRUE); 1983 | appendProperty(dummy, "box-pack", "justify", TRUE); 1984 | 1985 | doc.body.appendChild(dummy); 1986 | childHeight = dummy.firstChild.offsetHeight; 1987 | 1988 | tests = { 1989 | boxAlignStretch : function () { 1990 | return (childHeight === 100); 1991 | }, 1992 | 1993 | boxPackJustify : function () { 1994 | var totalOffset = 0, 1995 | i, j; 1996 | 1997 | for (i = 0, j = dummy.childNodes.length; i < j; i++) { 1998 | totalOffset += dummy.childNodes[i].offsetLeft; 1999 | } 2000 | 2001 | return (totalOffset === 135); 2002 | } 2003 | }; 2004 | 2005 | for (key in tests) { 2006 | if (tests.hasOwnProperty(key)) { 2007 | value = tests[key]; 2008 | 2009 | result = value(); 2010 | 2011 | if (!result) { 2012 | partialSupportGrid.partialSupport = TRUE; 2013 | } 2014 | 2015 | partialSupportGrid[key] = result; 2016 | } 2017 | } 2018 | 2019 | doc.body.removeChild(dummy); 2020 | return ~ (dummy.style.display).indexOf("box") ? partialSupportGrid : FALSE; 2021 | }; 2022 | 2023 | FLX.init = function () { 2024 | FLX.flexboxSupported = SUPPORT = FLX.flexboxSupport(); 2025 | 2026 | if ((!SUPPORT || SUPPORT.partialSupport) && LIBRARY) { 2027 | selectivizrEngine(); 2028 | } 2029 | }; 2030 | 2031 | // Flexie Version 2032 | FLX.version = "1.0.3"; 2033 | 2034 | // Load when the DOM is ready 2035 | attachLoadMethod(FLX.init); 2036 | 2037 | return FLX; 2038 | }(this, document)); 2039 | -------------------------------------------------------------------------------- /demos/flexie/flexie.js: -------------------------------------------------------------------------------- 1 | /* 2 | File: flexie.js 3 | 4 | About: Version 5 | 1.0.3 6 | 7 | Project: Flexie 8 | 9 | Description: 10 | Legacy support for the CSS3 Flexible Box Model 11 | 12 | License: 13 | The MIT License 14 | 15 | Copyright (c) 2010 Richard Herrera 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in 25 | all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | */ 35 | 36 | /* 37 | Class: Flexie 38 | Scoped to the Flexie Global Namespace 39 | */ 40 | 41 | /*jslint evil: true, regexp: false, plusplus: false */ 42 | /*global window, document */ 43 | 44 | var Flexie = (function (win, doc) { 45 | 46 | // Scope public properties 47 | var FLX = {}, 48 | 49 | // Each Flexie-modified DOM node gets a unique identifier 50 | FLX_DOM_ID = 0, 51 | FLX_DOM_ATTR = "data-flexie-id", 52 | FLX_PARENT_ATTR = "data-flexie-parent", 53 | 54 | // Store support for flexbox 55 | SUPPORT, 56 | 57 | // Store reference to engine 58 | ENGINE, 59 | 60 | ENGINES = { 61 | "NW" : { 62 | s : "*.Dom.select" 63 | }, 64 | "DOMAssistant" : { 65 | s : "*.$", 66 | m : "*.DOMReady" 67 | }, 68 | "Prototype" : { 69 | s : "$$", 70 | m : "document.observe", 71 | p : "dom:loaded", 72 | c : "document" 73 | }, 74 | "YAHOO" : { 75 | s : "*.util.Selector.query", 76 | m : "*.util.Event.onDOMReady", 77 | c : "*.util.Event" 78 | }, 79 | "MooTools" : { 80 | s : "$$", 81 | m : "window.addEvent", 82 | p : "domready" 83 | }, 84 | "Sizzle" : { 85 | s : "*" 86 | }, 87 | "jQuery" : { 88 | s : "*", 89 | m : "*(document).ready" 90 | }, 91 | "dojo" : { 92 | s : "*.query", 93 | m : "*.addOnLoad" 94 | } 95 | }, 96 | 97 | // Store reference to library 98 | LIBRARY, 99 | 100 | // Regular Expressions 101 | PIXEL = /^-?\d+(?:px)?$/i, 102 | NUMBER = /^-?\d/, 103 | SIZES = /width|height|margin|padding|border/, 104 | MSIE = /(msie) ([\w.]+)/, 105 | WHITESPACE_CHARACTERS = /\t|\n|\r/g, 106 | RESTRICTIVE_PROPERTIES = /^max\-([a-z]+)/, 107 | PROTOCOL = /^https?:\/\//i, 108 | LEADINGTRIM = /^\s\s*/, 109 | TRAILINGTRIM = /\s\s*$/, 110 | ONLY_WHITESPACE = /^\s*$/, 111 | CSS_SELECTOR = /\s?(\#|\.|\[|\:(\:)?[^first\-(line|letter)|before|after]+)/g, 112 | 113 | // String constants 114 | EMPTY_STRING = "", 115 | SPACE_STRING = " ", 116 | PLACEHOLDER_STRING = "$1", 117 | PADDING_RIGHT = "paddingRight", 118 | PADDING_BOTTOM = "paddingBottom", 119 | PADDING_LEFT = "paddingLeft", 120 | PADDING_TOP = "paddingTop", 121 | BORDER_RIGHT = "borderRightWidth", 122 | BORDER_BOTTOM = "borderBottomWidth", 123 | BORDER_LEFT = "borderLeftWidth", 124 | BORDER_TOP = "borderTopWidth", 125 | HORIZONTAL = "horizontal", 126 | VERTICAL = "vertical", 127 | INLINE_AXIS = "inline-axis", 128 | BLOCK_AXIS = "block-axis", 129 | INHERIT = "inherit", 130 | LEFT = "left", 131 | 132 | END_MUSTACHE = "}", 133 | 134 | PREFIXES = " -o- -moz- -ms- -webkit- -khtml- ".split(SPACE_STRING), 135 | 136 | DEFAULTS = { 137 | orient : HORIZONTAL, 138 | align : "stretch", 139 | direction : INHERIT, 140 | pack : "start" 141 | }, 142 | 143 | // Global reference objects 144 | FLEX_BOXES = [], 145 | POSSIBLE_FLEX_CHILDREN = [], 146 | DOM_ORDERED, 147 | 148 | RESIZE_LISTENER, 149 | 150 | // Minification optimizations 151 | TRUE = true, 152 | FALSE = false, 153 | NULL = null, 154 | UNDEFINED, 155 | 156 | // If IE, which version? 157 | BROWSER = { 158 | IE : (function () { 159 | var ie, ua = win.navigator.userAgent, 160 | match = (MSIE).exec(ua.toLowerCase()); 161 | 162 | if (match) { 163 | ie = parseInt(match[2], 10); 164 | } 165 | 166 | return ie; 167 | }()) 168 | }, 169 | 170 | /* 171 | selectivizr v1.0.0 - (c) Keith Clark, freely distributable under the terms 172 | of the MIT license. 173 | 174 | selectivizr.com 175 | */ 176 | selectivizrEngine; 177 | 178 | function trim (string) { 179 | if (string) { 180 | string = string.replace(LEADINGTRIM, EMPTY_STRING).replace(TRAILINGTRIM, EMPTY_STRING); 181 | } 182 | 183 | return string; 184 | } 185 | 186 | // --[ determineSelectorMethod() ]-------------------------------------- 187 | // walks through the engines object testing for an suitable 188 | // selector engine. 189 | 190 | // Moving outside Selectivizr scope because detection is needed before running selectivizrEngine 191 | function determineSelectorMethod() { 192 | // compatiable selector engines in order of CSS3 support 193 | var engines = ENGINES, method, 194 | engine, obj; 195 | 196 | for (engine in engines) { 197 | if (engines.hasOwnProperty(engine)) { 198 | obj = engines[engine]; 199 | 200 | if (win[engine] && !method) { 201 | method = eval(obj.s.replace("*", engine)); 202 | 203 | if (method) { 204 | ENGINE = engine; 205 | break; 206 | } 207 | } 208 | } 209 | } 210 | 211 | return method; 212 | } 213 | 214 | // Event handler for onload/onresize events 215 | function addEvent(type, func) { 216 | type = "on" + type; 217 | var oldevent = win[type]; 218 | 219 | if (typeof win[type] !== "function") { 220 | win[type] = func; 221 | } else { 222 | win[type] = function () { 223 | if (oldevent) { 224 | oldevent(); 225 | } 226 | func(); 227 | }; 228 | } 229 | } 230 | 231 | function attachLoadMethod(handler) { 232 | if (!ENGINE) { 233 | LIBRARY = determineSelectorMethod(); 234 | } 235 | 236 | // compatiable selector engines in order of CSS3 support 237 | var engines = ENGINES, 238 | method, caller, args, 239 | engine, obj; 240 | 241 | for (engine in engines) { 242 | if (engines.hasOwnProperty(engine)) { 243 | obj = engines[engine]; 244 | 245 | if (win[engine] && !method && obj.m) { 246 | method = eval(obj.m.replace("*", engine)); 247 | caller = obj.c ? eval(obj.c.replace("*", engine)) : win; 248 | args = []; 249 | 250 | if (method && caller) { 251 | if (obj.p) { 252 | args.push(obj.p); 253 | } 254 | args.push(handler); 255 | method.apply(caller, args); 256 | break; 257 | } 258 | } 259 | } 260 | } 261 | 262 | if (!method) { 263 | addEvent("load", handler); 264 | } 265 | } 266 | 267 | function buildSelector (node) { 268 | var selector = node.nodeName.toLowerCase(); 269 | 270 | if (node.id) { 271 | selector += "#" + node.id; 272 | } else if (node.FLX_DOM_ID) { 273 | selector += "[" + FLX_DOM_ATTR + "='" + node.FLX_DOM_ID + "']"; 274 | } 275 | 276 | return selector; 277 | } 278 | 279 | function setFlexieId (node) { 280 | if (!node.FLX_DOM_ID) { 281 | FLX_DOM_ID = (FLX_DOM_ID + 1); 282 | 283 | node.FLX_DOM_ID = FLX_DOM_ID; 284 | node.setAttribute(FLX_DOM_ATTR, node.FLX_DOM_ID); 285 | } 286 | } 287 | 288 | function buildSelectorTree(text) { 289 | var rules = [], ruletext, rule, 290 | match, selector, proptext, splitprop, properties, 291 | i, j, x; 292 | 293 | // Tabs, Returns 294 | text = text.replace(WHITESPACE_CHARACTERS, EMPTY_STRING); 295 | 296 | // Leading / Trailing Whitespace 297 | text = text.replace(/\s?(\{|\:|\})\s?/g, PLACEHOLDER_STRING); 298 | 299 | ruletext = text.split(END_MUSTACHE); 300 | 301 | for (i in ruletext) { 302 | if (ruletext.hasOwnProperty(i)) { 303 | text = ruletext[i]; 304 | 305 | if (text) { 306 | rule = [text, END_MUSTACHE].join(EMPTY_STRING); 307 | 308 | match = (/(\@media[^\{]+\{)?(.*)\{(.*)\}/).exec(rule); 309 | 310 | if (match && match[3]) { 311 | selector = match[2]; 312 | proptext = match[3].split(";"); 313 | properties = []; 314 | 315 | for (j in proptext) { 316 | if (proptext.hasOwnProperty(j)) { 317 | x = proptext[j]; 318 | splitprop = x.split(":"); 319 | 320 | if (splitprop.length && splitprop[1]) { 321 | properties.push({ 322 | property : splitprop[0], 323 | value : splitprop[1] 324 | }); 325 | } 326 | } 327 | } 328 | 329 | if (selector && properties.length) { 330 | rules.push({ 331 | selector : selector, 332 | properties : properties 333 | }); 334 | } 335 | } 336 | } 337 | } 338 | } 339 | 340 | return rules; 341 | } 342 | 343 | function findFlexboxElements(rules) { 344 | var selectors, properties, 345 | property, value, shortProp, 346 | selectorSplit = /\s?,\s?/, 347 | createUniqueObject, addRules, key, 348 | uniqueChildren = {}, uniqueBoxes = {}, 349 | i, j, rule, k, l, selector, m, n, prop; 350 | 351 | createUniqueObject = function (selector, rules, prop, value) { 352 | var unique, i, j, rule; 353 | 354 | unique = { 355 | selector : trim(selector), 356 | properties : [] 357 | }; 358 | 359 | for (i = 0, j = rules.properties.length; i < j; i++) { 360 | rule = rules.properties[i]; 361 | 362 | unique.properties.push({ 363 | property : trim(rule.property), 364 | value : trim(rule.value) 365 | }); 366 | } 367 | 368 | if (prop && value) { 369 | unique[prop] = value; 370 | } 371 | 372 | return unique; 373 | }; 374 | 375 | addRules = function (selector, rules, prop, value) { 376 | var box = (prop && value) ? uniqueChildren[selector] : uniqueBoxes[selector], 377 | exists, x, i, j, rule, k, l; 378 | 379 | if (box) { 380 | for (i = 0, j = rules.properties.length; i < j; i++) { 381 | rule = rules.properties[i]; 382 | 383 | for (k = 0, l = box.properties.length; k < l; k++) { 384 | x = box.properties[k]; 385 | 386 | if (rule.property === x.property) { 387 | exists = k; 388 | return false; 389 | } 390 | } 391 | 392 | if (exists) { 393 | box.properties[exists] = rule; 394 | } else { 395 | box.properties.push(rule); 396 | } 397 | } 398 | 399 | if (prop && value) { 400 | box[prop] = value; 401 | } 402 | } else { 403 | if (prop && value) { 404 | uniqueChildren[selector] = createUniqueObject(selector, rules, prop, value); 405 | } else { 406 | uniqueBoxes[selector] = createUniqueObject(selector, rules, NULL, NULL); 407 | } 408 | } 409 | }; 410 | 411 | for (i = 0, j = rules.length; i < j; i++) { 412 | rule = rules[i]; 413 | 414 | selectors = trim(rule.selector).replace(selectorSplit, ",").split(selectorSplit); 415 | 416 | for (k = 0, l = selectors.length; k < l; k++) { 417 | selector = trim(selectors[k]); 418 | properties = rule.properties; 419 | 420 | for (m = 0, n = properties.length; m < n; m++) { 421 | prop = properties[m]; 422 | property = trim(prop.property); 423 | value = trim(prop.value); 424 | 425 | // if you use the new syntax along with the old 426 | if (property && property !== "flex") { 427 | 428 | shortProp = property.replace("box-", EMPTY_STRING); 429 | shortProp = property.replace("-webkit-box-", EMPTY_STRING); 430 | 431 | switch (shortProp) { 432 | case "display" : 433 | if (value === "box" || value === "-webkit-box") { 434 | addRules(selector, rule, NULL, NULL); 435 | } 436 | break; 437 | 438 | case "orient" : 439 | case "align" : 440 | case "direction" : 441 | case "pack" : 442 | addRules(selector, rule, NULL, NULL); 443 | break; 444 | 445 | case "flex" : 446 | case "flex-group" : 447 | case "ordinal-group" : 448 | addRules(selector, rule, shortProp, value); 449 | break; 450 | } 451 | } 452 | } 453 | } 454 | } 455 | 456 | for (key in uniqueBoxes) { 457 | if (uniqueBoxes.hasOwnProperty(key)) { 458 | FLEX_BOXES.push(uniqueBoxes[key]); 459 | } 460 | } 461 | 462 | for (key in uniqueChildren) { 463 | if (uniqueChildren.hasOwnProperty(key)) { 464 | POSSIBLE_FLEX_CHILDREN.push(uniqueChildren[key]); 465 | } 466 | } 467 | 468 | return { 469 | boxes : FLEX_BOXES, 470 | children : POSSIBLE_FLEX_CHILDREN 471 | }; 472 | } 473 | 474 | function matchFlexChildren(parent, lib, possibleChildren) { 475 | var caller, unique, matches = [], 476 | i, j, child, 477 | k, l, node, 478 | key; 479 | 480 | for (i = 0, j = possibleChildren.length; i < j; i++) { 481 | child = possibleChildren[i]; 482 | 483 | if (child.selector) { 484 | caller = lib(child.selector); 485 | caller = caller[0] ? caller : [caller]; 486 | 487 | if (caller[0]) { 488 | 489 | for (k = 0, l = caller.length; k < l; k++) { 490 | node = caller[k]; 491 | 492 | if (node.nodeName !== UNDEFINED) { 493 | switch (node.nodeName.toLowerCase()) { 494 | case "script" : 495 | case "style" : 496 | case "link" : 497 | break; 498 | 499 | default : 500 | if (node.parentNode === parent) { 501 | // Flag each unique node with FLX_DOM_ID 502 | setFlexieId(node); 503 | 504 | unique = {}; 505 | 506 | for (key in child) { 507 | if (child.hasOwnProperty(key)) { 508 | unique[key] = child[key]; 509 | } 510 | } 511 | 512 | unique.match = node; 513 | matches.push(unique); 514 | } 515 | break; 516 | } 517 | } 518 | } 519 | } 520 | } else { 521 | // Flag each unique node with FLX_DOM_ID 522 | setFlexieId(child); 523 | 524 | matches.push({ 525 | match : child, 526 | selector : buildSelector(child) 527 | }); 528 | } 529 | } 530 | 531 | return matches; 532 | } 533 | 534 | function getParams(params) { 535 | var key; 536 | 537 | for (key in params) { 538 | if (params.hasOwnProperty(key)) { 539 | params[key] = params[key] || DEFAULTS[key]; 540 | } 541 | } 542 | 543 | return params; 544 | } 545 | 546 | function buildFlexieCall(flexers) { 547 | var selector, properties, property, value, shortProp, 548 | display, orient, align, direction, pack, 549 | lib, caller, children, 550 | box, params, flexboxes = {}, 551 | match, childMatch, nestedFlexboxes, 552 | flexieParentSelector = "[" + FLX_PARENT_ATTR + "]", 553 | i, j, flex, k, l, prop, 554 | target, key, m, n, child, o, p, existing; 555 | 556 | // No boxflex? No dice. 557 | if (!flexers) { 558 | return; 559 | } 560 | 561 | for (i = 0, j = flexers.boxes.length; i < j; i++) { 562 | flex = flexers.boxes[i]; 563 | flex.selector = trim(flex.selector); 564 | 565 | selector = flex.selector; 566 | properties = flex.properties; 567 | 568 | display = orient = align = direction = pack = NULL; 569 | 570 | for (k = 0, l = properties.length; k < l; k++) { 571 | prop = properties[k]; 572 | 573 | property = trim(prop.property); 574 | value = trim(prop.value); 575 | 576 | if (property && property !== "flex") { 577 | shortProp = property.replace("box-", EMPTY_STRING); 578 | shortProp = property.replace("-webkit-box-", EMPTY_STRING); 579 | 580 | switch (shortProp) { 581 | case "display" : 582 | if (value === "box" || value === "-webkit-box") { 583 | display = "box"; 584 | } 585 | break; 586 | 587 | case "orient" : 588 | orient = value; 589 | break; 590 | 591 | case "align" : 592 | align = value; 593 | break; 594 | 595 | case "direction" : 596 | direction = value; 597 | break; 598 | 599 | case "pack" : 600 | pack = value; 601 | break; 602 | } 603 | } 604 | } 605 | 606 | // Determine library 607 | lib = LIBRARY; 608 | 609 | // Call it. 610 | caller = lib(flex.selector); 611 | 612 | // In an array? 613 | caller = caller[0] ? caller : [caller]; 614 | 615 | for (k = 0, l = caller.length; k < l; k++) { 616 | target = caller[k]; 617 | 618 | // If is DOM object 619 | if (target.nodeType) { 620 | // Flag each unique node with FLX_DOM_ID 621 | setFlexieId(target); 622 | 623 | // Find possible child node matches 624 | children = matchFlexChildren(target, lib, flexers.children); 625 | 626 | // Find any nested flexbox elements 627 | nestedFlexboxes = selector + " " + flexieParentSelector; 628 | 629 | // Make sure there is some value associated with box properties 630 | params = { 631 | target : target, 632 | selector : selector, 633 | properties : properties, 634 | children : children, 635 | display : display, 636 | orient : orient, 637 | align : align, 638 | direction: direction, 639 | pack : pack, 640 | nested : nestedFlexboxes 641 | }; 642 | 643 | match = flexboxes[target.FLX_DOM_ID]; 644 | 645 | if (match) { 646 | for (key in params) { 647 | if (params.hasOwnProperty(key)) { 648 | value = params[key]; 649 | 650 | switch (key) { 651 | case "selector" : 652 | if (value && !(new RegExp(value).test(match[key]))) { 653 | match[key] += ", " + value; 654 | } 655 | break; 656 | 657 | case "children" : 658 | for (m = 0, n = params[key].length; m < n; m++) { 659 | child = params[key][m]; 660 | childMatch = FALSE; 661 | 662 | for (o = 0, p = match[key].length; o < p; o++) { 663 | existing = match[key][o]; 664 | 665 | if (child.match.FLX_DOM_ID === existing.match.FLX_DOM_ID) { 666 | childMatch = TRUE; 667 | } 668 | } 669 | 670 | if (!childMatch) { 671 | match[key].push(child); 672 | } 673 | } 674 | break; 675 | 676 | default : 677 | if (value) { 678 | match[key] = value; 679 | } 680 | break; 681 | } 682 | } 683 | } 684 | } else { 685 | flexboxes[target.FLX_DOM_ID] = getParams(params); 686 | flexboxes[target.FLX_DOM_ID].target.setAttribute(FLX_PARENT_ATTR, TRUE); 687 | } 688 | } 689 | } 690 | } 691 | 692 | DOM_ORDERED = LIBRARY(flexieParentSelector); 693 | FLEX_BOXES = {}; 694 | 695 | for (i = 0, j = DOM_ORDERED.length; i < j; i++) { 696 | target = DOM_ORDERED[i]; 697 | 698 | FLEX_BOXES[target.FLX_DOM_ID] = flexboxes[target.FLX_DOM_ID]; 699 | } 700 | 701 | // Loop through each match, initialize constructor 702 | for (key in FLEX_BOXES) { 703 | if (FLEX_BOXES.hasOwnProperty(key)) { 704 | flex = FLEX_BOXES[key]; 705 | 706 | // One final check to ensure each flexbox has a display property 707 | if (flex.display === "box") { 708 | // Constructor 709 | box = new FLX.box(flex); 710 | } 711 | } 712 | } 713 | } 714 | 715 | function calcPx(element, props, dir) { 716 | var dim = dir.replace(dir.charAt(0), dir.charAt(0).toUpperCase()), 717 | value = element["offset" + dim] || 0, 718 | i, j, prop; 719 | 720 | if (value) { 721 | for (i = 0, j = props.length; i < j; i++) { 722 | prop = parseFloat(element.currentStyle[props[i]]); 723 | 724 | if (!isNaN(prop)) { 725 | value -= prop; 726 | } 727 | } 728 | } 729 | 730 | return value; 731 | } 732 | 733 | function getTrueValue(element, name) { 734 | var left, rsLeft, 735 | ret = element.currentStyle && element.currentStyle[name], 736 | style = element.style; 737 | 738 | if (!PIXEL.test(ret) && NUMBER.test(ret)) { 739 | 740 | // Remember the original values 741 | left = style.left; 742 | rsLeft = element.runtimeStyle.left; 743 | 744 | // Put in the new values to get a computed value out 745 | element.runtimeStyle.left = element.currentStyle.left; 746 | style.left = ret || 0; 747 | ret = style.pixelLeft + "px"; 748 | 749 | // Revert the changed values 750 | style.left = left || 0; 751 | element.runtimeStyle.left = rsLeft; 752 | } 753 | 754 | return ret; 755 | } 756 | 757 | function unAuto(element, prop, name) { 758 | var props; 759 | 760 | switch (name) { 761 | case "width" : 762 | props = [PADDING_LEFT, PADDING_RIGHT, BORDER_LEFT, BORDER_RIGHT]; 763 | prop = calcPx(element, props, name); 764 | break; 765 | 766 | case "height" : 767 | props = [PADDING_TOP, PADDING_BOTTOM, BORDER_TOP, BORDER_BOTTOM]; 768 | prop = calcPx(element, props, name); 769 | break; 770 | 771 | default : 772 | prop = getTrueValue(element, name); 773 | break; 774 | } 775 | 776 | return prop; 777 | } 778 | 779 | function getPixelValue(element, prop, name) { 780 | if (PIXEL.test(prop)) { 781 | return prop; 782 | } 783 | 784 | // if property is auto, do some messy appending 785 | if (prop === "auto" || prop === "medium") { 786 | prop = unAuto(element, prop, name); 787 | } else { 788 | prop = getTrueValue(element, name); 789 | } 790 | 791 | return prop; 792 | } 793 | 794 | function getComputedStyle(element, property, returnAsInt) { 795 | var value; 796 | 797 | if (element === UNDEFINED) { 798 | return; 799 | } 800 | 801 | if (win.getComputedStyle) { 802 | value = win.getComputedStyle(element, NULL)[property]; 803 | } else { 804 | if (SIZES.test(property)) { 805 | value = getPixelValue(element, (element && element.currentStyle) ? element.currentStyle[property] : 0, property); 806 | } else { 807 | value = element.currentStyle[property]; 808 | } 809 | } 810 | 811 | if (returnAsInt) { 812 | value = parseInt(value, 10); 813 | 814 | if (isNaN(value)) { 815 | value = 0; 816 | } 817 | } 818 | 819 | return value; 820 | } 821 | 822 | function clientWidth(element) { 823 | return element.innerWidth || element.clientWidth; 824 | } 825 | 826 | function clientHeight(element) { 827 | return element.innerHeight || element.clientHeight; 828 | } 829 | 830 | function appendProperty(target, prop, value, prefixName) { 831 | var cssText = [], 832 | i, j, prefix; 833 | 834 | for (i = 0, j = PREFIXES.length; i < j; i++) { 835 | prefix = PREFIXES[i]; 836 | cssText.push((prefixName ? prefix : EMPTY_STRING) + prop + ":" + (!prefixName ? prefix : EMPTY_STRING) + value); 837 | } 838 | 839 | target.style.cssText += cssText.join(";"); 840 | return target; 841 | } 842 | 843 | function appendPixelValue(target, prop, value) { 844 | var targets = target && target[0] ? target : [target], 845 | i, j; 846 | 847 | for (i = 0, j = targets.length; i < j; i++) { 848 | target = targets[i]; 849 | 850 | if (target && target.style) { 851 | target.style[prop] = (value ? (value + "px") : EMPTY_STRING); 852 | } 853 | } 854 | } 855 | 856 | function calculateSpecificity (selector) { 857 | var selectorGrid, matrix, total, 858 | i, j, chunk; 859 | 860 | selectorGrid = selector.replace(CSS_SELECTOR, function (e, f) { 861 | return "%" + f; 862 | }).replace(/\s|\>|\+|\~/g, "%").split(/%/g); 863 | 864 | matrix = { 865 | _id : 100, 866 | _class : 10, 867 | _tag : 1 868 | }; 869 | 870 | // Start with rule index position 871 | total = 0; 872 | 873 | // Add each selector value to total. 874 | for (i = 0, j = selectorGrid.length; i < j; i++) { 875 | chunk = selectorGrid[i]; 876 | 877 | if ((/#/).test(chunk)) { 878 | total += matrix._id; 879 | } else if ((/\.|\[|\:/).test(chunk)) { 880 | total += matrix._class; 881 | } else if ((/[a-zA-Z]+/).test(chunk)) { 882 | total += matrix._tag; 883 | } 884 | } 885 | 886 | return total; 887 | } 888 | 889 | function filterDuplicates (matches, children, type) { 890 | var filteredMatches = [], exists, 891 | spec = (type ? "ordinal" : "flex") + "Specificity", 892 | i, j, x, k, l, f; 893 | 894 | for (i = 0, j = matches.length; i < j; i++) { 895 | x = matches[i]; 896 | 897 | if ((!type && x.flex) || (type && x["ordinal-group"])) { 898 | x[spec] = x[spec] || calculateSpecificity(x.selector); 899 | 900 | exists = FALSE; 901 | 902 | for (k = 0, l = filteredMatches.length; k < l; k++) { 903 | f = filteredMatches[k]; 904 | 905 | if (f.match === x.match) { 906 | if (f[spec] < x[spec]) { 907 | filteredMatches[j] = x; 908 | } 909 | 910 | exists = TRUE; 911 | return FALSE; 912 | } 913 | } 914 | 915 | if (!exists) { 916 | filteredMatches.push(x); 917 | } 918 | } 919 | } 920 | 921 | return filteredMatches; 922 | } 923 | 924 | function createMatchMatrix(matches, children, type) { 925 | var groups = {}, keys = [], totalRatio = 0, 926 | group, order = "ordinal-group", 927 | BoxOrdinalAttr = "data-" + order, 928 | i, j, kid, k, l, x, key; 929 | 930 | // Filter dupes 931 | matches = filterDuplicates(matches, children, type); 932 | 933 | for (i = 0, j = children.length; i < j; i++) { 934 | kid = children[i]; 935 | 936 | for (k = 0, l = matches.length; k < l; k++) { 937 | x = matches[k]; 938 | 939 | if (type) { 940 | // If no value declared, it's the default. 941 | group = x[order] || "1"; 942 | 943 | if (x.match === kid) { 944 | x.match.setAttribute(BoxOrdinalAttr, group); 945 | 946 | groups[group] = groups[group] || []; 947 | groups[group].push(x); 948 | } 949 | } else { 950 | // If no value declared, it's the default. 951 | group = x.flex || "0"; 952 | 953 | if (x.match === kid && (!x[group] || (x[group] && parseInt(x[group], 10) <= 1))) { 954 | totalRatio += parseInt(group, 10); 955 | 956 | groups[group] = groups[group] || []; 957 | groups[group].push(x); 958 | } 959 | } 960 | } 961 | 962 | if (type && !kid.getAttribute(BoxOrdinalAttr)) { 963 | group = "1"; 964 | kid.setAttribute(BoxOrdinalAttr, group); 965 | 966 | groups[group] = groups[group] || []; 967 | groups[group].push({ 968 | match : kid 969 | }); 970 | } 971 | } 972 | 973 | for (key in groups) { 974 | if (groups.hasOwnProperty(key)) { 975 | keys.push(key); 976 | } 977 | } 978 | 979 | keys.sort(function (a, b) { 980 | return b - a; 981 | }); 982 | 983 | return { 984 | keys : keys, 985 | groups : groups, 986 | total : totalRatio 987 | }; 988 | } 989 | 990 | function attachResizeListener(construct, params) { 991 | if (!RESIZE_LISTENER) { 992 | var storedWidth, storedHeight, 993 | currentWidth, currentHeight, 994 | docBody = doc.body, 995 | docEl = doc.documentElement, 996 | resizeTimer, 997 | innerWidth = "innerWidth", innerHeight = "innerHeight", 998 | clientWidth = "clientWidth", clientHeight = "clientHeight"; 999 | 1000 | addEvent("resize", function () { 1001 | if (resizeTimer) { 1002 | window.clearTimeout(resizeTimer); 1003 | } 1004 | 1005 | resizeTimer = window.setTimeout(function () { 1006 | currentWidth = win[innerWidth] || docEl[innerWidth] || docEl[clientWidth] || docBody[clientWidth]; 1007 | currentHeight = win[innerHeight] || docEl[innerHeight] || docEl[clientHeight] || docBody[clientHeight]; 1008 | 1009 | if (storedWidth !== currentWidth || storedHeight !== currentHeight) { 1010 | FLX.updateInstance(NULL, NULL); 1011 | 1012 | storedWidth = currentWidth; 1013 | storedHeight = currentHeight; 1014 | } 1015 | }, 250); 1016 | }); 1017 | 1018 | RESIZE_LISTENER = TRUE; 1019 | } 1020 | } 1021 | 1022 | function cleanPositioningProperties (children) { 1023 | var i, j, kid, w, h; 1024 | 1025 | for (i = 0, j = children.length; i < j; i++) { 1026 | kid = children[i]; 1027 | 1028 | w = kid.style.width; 1029 | h = kid.style.height; 1030 | 1031 | kid.style.cssText = EMPTY_STRING; 1032 | 1033 | kid.style.width = w; 1034 | kid.style.height = h; 1035 | } 1036 | } 1037 | 1038 | function sanitizeChildren (target, nodes) { 1039 | var children = [], node, i, j; 1040 | 1041 | for (i = 0, j = nodes.length; i < j; i++) { 1042 | node = nodes[i]; 1043 | 1044 | if (node) { 1045 | switch (node.nodeName.toLowerCase()) { 1046 | case "script" : 1047 | case "style" : 1048 | case "link" : 1049 | break; 1050 | 1051 | default : 1052 | if (node.nodeType === 1) { 1053 | children.push(node); 1054 | } else if ((node.nodeType === 3) && (node.isElementContentWhitespace || (ONLY_WHITESPACE).test(node.data))) { 1055 | target.removeChild(node); 1056 | i--; 1057 | } 1058 | break; 1059 | } 1060 | } 1061 | } 1062 | 1063 | return children; 1064 | } 1065 | 1066 | function parentFlex (target) { 1067 | var totalFlex = 0, 1068 | parent = target.parentNode, 1069 | obj, 1070 | matrix, 1071 | isNested; 1072 | 1073 | while (parent.FLX_DOM_ID) { 1074 | obj = FLEX_BOXES[parent.FLX_DOM_ID]; 1075 | matrix = createMatchMatrix(obj.children, sanitizeChildren(parent, parent.childNodes), NULL); 1076 | 1077 | totalFlex += matrix.total; 1078 | isNested = TRUE; 1079 | 1080 | parent = parent.parentNode; 1081 | } 1082 | 1083 | return { 1084 | nested : isNested, 1085 | flex : totalFlex 1086 | }; 1087 | } 1088 | 1089 | function dimensionValues (target, prop) { 1090 | var parent = target.parentNode, 1091 | obj, dimension, i, j, rule; 1092 | 1093 | if (parent.FLX_DOM_ID) { 1094 | obj = FLEX_BOXES[parent.FLX_DOM_ID]; 1095 | 1096 | for (i = 0, j = obj.properties.length; i < j; i++) { 1097 | rule = obj.properties[i]; 1098 | 1099 | if ((new RegExp(prop)).test(rule.property)) { 1100 | dimension = TRUE; 1101 | return FALSE; 1102 | } 1103 | } 1104 | } 1105 | 1106 | return dimension; 1107 | } 1108 | 1109 | function updateChildValues (params) { 1110 | var i, j, x; 1111 | 1112 | if (params.flexMatrix) { 1113 | for (i = 0, j = params.children.length; i < j; i++) { 1114 | x = params.children[i]; 1115 | x.flex = params.flexMatrix[i]; 1116 | } 1117 | } 1118 | 1119 | if (params.ordinalMatrix) { 1120 | for (i = 0, j = params.children.length; i < j; i++) { 1121 | x = params.children[i]; 1122 | x["ordinal-group"] = params.ordinalMatrix[i]; 1123 | } 1124 | } 1125 | 1126 | return params; 1127 | } 1128 | 1129 | function ensureStructuralIntegrity (params, instance) { 1130 | var target = params.target; 1131 | 1132 | if (!target.FLX_DOM_ID) { 1133 | target.FLX_DOM_ID = target.FLX_DOM_ID || (++FLX_DOM_ID); 1134 | } 1135 | 1136 | if (!params.nodes) { 1137 | params.nodes = sanitizeChildren(target, target.childNodes); 1138 | } 1139 | 1140 | if (!params.selector) { 1141 | params.selector = buildSelector(target); 1142 | target.setAttribute(FLX_PARENT_ATTR, TRUE); 1143 | } 1144 | 1145 | if (!params.properties) { 1146 | params.properties = []; 1147 | } 1148 | 1149 | if (!params.children) { 1150 | params.children = matchFlexChildren(target, LIBRARY, sanitizeChildren(target, target.childNodes)); 1151 | } 1152 | 1153 | if (!params.nested) { 1154 | params.nested = params.selector + " [" + FLX_PARENT_ATTR + "]"; 1155 | } 1156 | 1157 | params.target = target; 1158 | params._instance = instance; 1159 | 1160 | return params; 1161 | } 1162 | 1163 | selectivizrEngine = (function () { 1164 | var RE_COMMENT = /(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)\s*?/g, 1165 | RE_IMPORT = /@import\s*(?:(?:(?:url\(\s*(['"]?)(.*)\1)\s*\))|(?:(['"])(.*)\3))\s*([^;]*);/g, 1166 | RE_ASSET_URL = /(behavior\s*?:\s*)?\burl\(\s*(["']?)(?!data:)([^"')]+)\2\s*\)/g, 1167 | RE_SELECTOR_GROUP = /((?:^|(?:\s*\})+)(?:\s*@media[^\{]+\{)?)\s*([^\{]*?[\[:][^{]+)/g, 1168 | 1169 | // Whitespace normalization regexp's 1170 | RE_TIDY_TRAILING_WHITESPACE = /([(\[+~])\s+/g, 1171 | RE_TIDY_LEADING_WHITESPACE = /\s+([)\]+~])/g, 1172 | RE_TIDY_CONSECUTIVE_WHITESPACE = /\s+/g, 1173 | RE_TIDY_TRIM_WHITESPACE = /^\s*((?:[\S\s]*\S)?)\s*$/; 1174 | 1175 | // --[ trim() ]--------------------------------------------------------- 1176 | // removes leading, trailing whitespace from a string 1177 | function trim(text) { 1178 | return text.replace(RE_TIDY_TRIM_WHITESPACE, PLACEHOLDER_STRING); 1179 | } 1180 | 1181 | // --[ normalizeWhitespace() ]------------------------------------------ 1182 | // removes leading, trailing and consecutive whitespace from a string 1183 | function normalizeWhitespace(text) { 1184 | return trim(text).replace(RE_TIDY_CONSECUTIVE_WHITESPACE, SPACE_STRING); 1185 | } 1186 | 1187 | // --[ normalizeSelectorWhitespace() ]---------------------------------- 1188 | // tidys whitespace around selector brackets and combinators 1189 | function normalizeSelectorWhitespace(selectorText) { 1190 | return normalizeWhitespace(selectorText.replace(RE_TIDY_TRAILING_WHITESPACE, PLACEHOLDER_STRING).replace(RE_TIDY_LEADING_WHITESPACE, PLACEHOLDER_STRING)); 1191 | } 1192 | 1193 | // --[ patchStyleSheet() ]---------------------------------------------- 1194 | // Scans the passed cssText for selectors that require emulation and 1195 | // creates one or more patches for each matched selector. 1196 | function patchStyleSheet(cssText) { 1197 | return cssText.replace(RE_SELECTOR_GROUP, function (m, prefix, selectorText) { 1198 | var selectorGroups, selector, 1199 | i, j, group; 1200 | 1201 | selectorGroups = selectorText.split(","); 1202 | 1203 | for (i = 0, j = selectorGroups.length; i < j; i++) { 1204 | group = selectorGroups[i]; 1205 | selector = normalizeSelectorWhitespace(group) + SPACE_STRING; 1206 | } 1207 | 1208 | return prefix + selectorGroups.join(","); 1209 | }); 1210 | } 1211 | 1212 | // --[ getXHRObject() ]------------------------------------------------- 1213 | function getXHRObject() { 1214 | if (win.XMLHttpRequest) { 1215 | return new win.XMLHttpRequest(); 1216 | } 1217 | 1218 | try { 1219 | return new win.ActiveXObject("Microsoft.XMLHTTP"); 1220 | } catch (e) { 1221 | return NULL; 1222 | } 1223 | } 1224 | 1225 | function parseInlineStyles ( text ) { 1226 | var reg = /]*>([^<>]*)<\/style[\s]?>/img, 1227 | match = reg.exec(text), 1228 | stylesheets = [], 1229 | rawCSSText; 1230 | 1231 | while (match) { 1232 | rawCSSText = match[1]; 1233 | 1234 | if (rawCSSText) { 1235 | stylesheets.push(rawCSSText); 1236 | } 1237 | 1238 | match = reg.exec(text); 1239 | } 1240 | 1241 | return stylesheets.join("\n\n"); 1242 | } 1243 | 1244 | // --[ loadStyleSheet() ]----------------------------------------------- 1245 | function loadStyleSheet(url) { 1246 | var xhr = getXHRObject(), 1247 | responseText; 1248 | 1249 | xhr.open("GET", url, FALSE); 1250 | xhr.send(); 1251 | 1252 | responseText = (xhr.status === 200) ? xhr.responseText : EMPTY_STRING; 1253 | 1254 | if (url === window.location.href) { 1255 | responseText = parseInlineStyles(responseText); 1256 | } 1257 | 1258 | return responseText; 1259 | } 1260 | 1261 | // --[ resolveUrl() ]--------------------------------------------------- 1262 | // Converts a URL fragment to a fully qualified URL using the specified 1263 | // context URL. Returns null if same-origin policy is broken 1264 | function resolveUrl(url, contextUrl) { 1265 | 1266 | // IE9 returns a false positive sometimes(?) 1267 | if (!url) { 1268 | return; 1269 | } 1270 | 1271 | function getProtocolAndHost(url) { 1272 | return url.substring(0, url.indexOf("/", 8)); 1273 | } 1274 | 1275 | // absolute path 1276 | if (PROTOCOL.test(url)) { 1277 | return getProtocolAndHost(contextUrl) === getProtocolAndHost(url) ? url : NULL; 1278 | } 1279 | 1280 | // root-relative path 1281 | if (url.charAt(0) === "/") { 1282 | return getProtocolAndHost(contextUrl) + url; 1283 | } 1284 | 1285 | // relative path 1286 | var contextUrlPath = contextUrl.split("?")[0]; // ignore query string in the contextUrl 1287 | if (url.charAt(0) !== "?" && contextUrlPath.charAt(contextUrlPath.length - 1) !== "/") { 1288 | contextUrlPath = contextUrlPath.substring(0, contextUrlPath.lastIndexOf("/") + 1); 1289 | } 1290 | 1291 | return contextUrlPath + url; 1292 | } 1293 | 1294 | // --[ parseStyleSheet() ]---------------------------------------------- 1295 | // Downloads the stylesheet specified by the URL, removes it's comments 1296 | // and recursivly replaces @import rules with their contents, ultimately 1297 | // returning the full cssText. 1298 | function parseStyleSheet( url ) { 1299 | if (url) { 1300 | return loadStyleSheet(url).replace(RE_COMMENT, EMPTY_STRING). 1301 | replace(RE_IMPORT, function( match, quoteChar, importUrl, quoteChar2, importUrl2, media ) { 1302 | var cssText = parseStyleSheet(resolveUrl(importUrl || importUrl2, url)); 1303 | return (media) ? "@media " + media + " {" + cssText + "}" : cssText; 1304 | }). 1305 | replace(RE_ASSET_URL, function( match, isBehavior, quoteChar, assetUrl ) { 1306 | quoteChar = quoteChar || EMPTY_STRING; 1307 | return isBehavior ? match : " url(" + quoteChar + resolveUrl(assetUrl, url, true) + quoteChar + ") "; 1308 | }); 1309 | } 1310 | return EMPTY_STRING; 1311 | } 1312 | 1313 | // --[ init() ]--------------------------------------------------------- 1314 | return function () { 1315 | // honour the tag 1316 | var url, stylesheets = [], stylesheet, i, j, 1317 | baseTags = doc.getElementsByTagName("BASE"), 1318 | baseUrl = (baseTags.length > 0) ? baseTags[0].href : doc.location.href, 1319 | externalStyles = doc.styleSheets, 1320 | cssText, tree, flexers; 1321 | 1322 | for (i = 0, j = externalStyles.length; i < j; i++) { 1323 | stylesheet = externalStyles[i]; 1324 | 1325 | if (stylesheet != NULL) { 1326 | stylesheets.push(stylesheet); 1327 | } 1328 | } 1329 | 1330 | // Add self to test for inline styles 1331 | stylesheets.push(window.location); 1332 | 1333 | for (i = 0, j = stylesheets.length; i < j; i++) { 1334 | stylesheet = stylesheets[i]; 1335 | 1336 | if (stylesheet) { 1337 | url = resolveUrl(stylesheet.href, baseUrl); 1338 | 1339 | if (url) { 1340 | cssText = patchStyleSheet(parseStyleSheet(url)); 1341 | } 1342 | 1343 | if (cssText) { 1344 | tree = buildSelectorTree(cssText); 1345 | flexers = findFlexboxElements(tree); 1346 | } 1347 | } 1348 | } 1349 | 1350 | buildFlexieCall(flexers); 1351 | }; 1352 | }()); 1353 | 1354 | // Flexie box constructor 1355 | FLX.box = function (params) { 1356 | return this.renderModel(params); 1357 | }; 1358 | 1359 | FLX.box.prototype = { 1360 | properties : { 1361 | boxModel : function (target, children, params) { 1362 | var selectors, stylesheet, paddingFix, generatedRules, 1363 | i, j, selector; 1364 | 1365 | target.style.display = "block"; 1366 | 1367 | if (BROWSER.IE === 8) { 1368 | target.style.overflow = "hidden"; 1369 | } 1370 | 1371 | // We'll be using floats, so the easiest way to retain layout 1372 | // is the dreaded clear fix: 1373 | if (!params.cleared) { 1374 | selectors = params.selector.split(/\s?,\s?/); 1375 | stylesheet = doc.styleSheets; 1376 | stylesheet = stylesheet[stylesheet.length - 1]; 1377 | paddingFix = "padding-top:" + (getComputedStyle(target, PADDING_TOP, NULL) || "0.1px;"); 1378 | 1379 | generatedRules = [ 1380 | "content: '.'", 1381 | "display: block", 1382 | "height: 0", 1383 | "overflow: hidden" 1384 | ].join(";"); 1385 | 1386 | for (i = 0, j = selectors.length; i < j; i++) { 1387 | selector = selectors[i]; 1388 | 1389 | if (stylesheet.addRule) { 1390 | if (BROWSER.IE < 8) { 1391 | target.style.zoom = "1"; 1392 | 1393 | if (BROWSER.IE === 6) { 1394 | stylesheet.addRule(selector.replace(/\>|\+|\~/g, ""), paddingFix + "zoom:1;", 0); 1395 | } else if (BROWSER.IE === 7) { 1396 | stylesheet.addRule(selector, paddingFix + "display:inline-block;", 0); 1397 | } 1398 | } else { 1399 | stylesheet.addRule(selector, paddingFix, 0); 1400 | stylesheet.addRule(selector + ":before", generatedRules, 0); 1401 | stylesheet.addRule(selector + ":after", generatedRules + ";clear:both;", 0); 1402 | } 1403 | } else if (stylesheet.insertRule) { 1404 | stylesheet.insertRule(selector + "{" + paddingFix + "}", 0); 1405 | stylesheet.insertRule(selector + ":after{" + generatedRules + ";clear:both;}", 0); 1406 | } 1407 | } 1408 | 1409 | params.cleared = TRUE; 1410 | } 1411 | }, 1412 | 1413 | boxDirection : function (target, children, params) { 1414 | var nestedSelector, nested, 1415 | i, j, kid, node; 1416 | 1417 | if ((params.direction === "reverse" && !params.reversed) || (params.direction === "normal" && params.reversed)) { 1418 | children = children.reverse(); 1419 | 1420 | for (i = 0, j = children.length; i < j; i++) { 1421 | kid = children[i]; 1422 | target.appendChild(kid); 1423 | } 1424 | 1425 | // box-direction is inheritable. 1426 | // We need to see if there are any nested flexbox elements 1427 | nestedSelector = LIBRARY(params.nested); 1428 | 1429 | for (i = 0, j = nestedSelector.length; i < j; i++) { 1430 | node = nestedSelector[i]; 1431 | 1432 | nested = FLEX_BOXES[node.FLX_DOM_ID]; 1433 | 1434 | if (nested && nested.direction === INHERIT) { 1435 | nested.direction = params.direction; 1436 | } 1437 | } 1438 | 1439 | params.reversed = !params.reversed; 1440 | } 1441 | }, 1442 | 1443 | boxOrient : function (target, children, params) { 1444 | var self = this, wide, high, 1445 | i, j, kid; 1446 | 1447 | wide = { 1448 | pos : "marginLeft", 1449 | opp : "marginRight", 1450 | dim : "width", 1451 | out : "offsetWidth", 1452 | func : clientWidth, 1453 | pad : [PADDING_LEFT, PADDING_RIGHT, BORDER_LEFT, BORDER_RIGHT] 1454 | }; 1455 | 1456 | high = { 1457 | pos : "marginTop", 1458 | opp : "marginBottom", 1459 | dim : "height", 1460 | out : "offsetHeight", 1461 | func : clientHeight, 1462 | pad : [PADDING_TOP, PADDING_BOTTOM, BORDER_TOP, BORDER_BOTTOM] 1463 | }; 1464 | 1465 | if (!SUPPORT) { 1466 | for (i = 0, j = children.length; i < j; i++) { 1467 | kid = children[i]; 1468 | 1469 | kid.style[(BROWSER.IE >= 9) ? "cssFloat" : "styleFloat"] = LEFT; 1470 | 1471 | if (params.orient === VERTICAL || params.orient === BLOCK_AXIS) { 1472 | kid.style.clear = LEFT; 1473 | } 1474 | 1475 | if (BROWSER.IE === 6) { 1476 | kid.style.display = "inline"; 1477 | } 1478 | } 1479 | } 1480 | 1481 | switch (params.orient) { 1482 | case VERTICAL : 1483 | case BLOCK_AXIS: 1484 | self.props = high; 1485 | self.anti = wide; 1486 | break; 1487 | 1488 | default : 1489 | self.props = wide; 1490 | self.anti = high; 1491 | break; 1492 | } 1493 | }, 1494 | 1495 | boxOrdinalGroup : function (target, children, params) { 1496 | var organizeChildren, 1497 | matrix; 1498 | 1499 | if (!children.length) { 1500 | return; 1501 | } 1502 | 1503 | organizeChildren = function (matrix) { 1504 | var keys = matrix.keys, 1505 | iterator = params.reversed ? keys : keys.reverse(), 1506 | i, j, key, k, l, kid; 1507 | 1508 | for (i = 0, j = iterator.length; i < j; i++) { 1509 | key = iterator[i]; 1510 | 1511 | for (k = 0, l = children.length; k < l; k++) { 1512 | kid = children[k]; 1513 | 1514 | if (key === kid.getAttribute("data-ordinal-group")) { 1515 | target.appendChild(kid); 1516 | } 1517 | } 1518 | } 1519 | }; 1520 | 1521 | matrix = createMatchMatrix(params.children, children, TRUE); 1522 | 1523 | if (matrix.keys.length > 1) { 1524 | organizeChildren(matrix); 1525 | } 1526 | }, 1527 | 1528 | boxFlex : function (target, children, params) { 1529 | var self = this, 1530 | testForRestrictiveProperties, 1531 | findTotalWhitespace, 1532 | distributeRatio, 1533 | matrix, 1534 | restrict, 1535 | whitespace, 1536 | distro; 1537 | 1538 | if (!children.length) { 1539 | return; 1540 | } 1541 | 1542 | testForRestrictiveProperties = function (matrix) { 1543 | var flexers = matrix.groups, 1544 | keys = matrix.keys, 1545 | max, i, j, key, 1546 | k, l, x, m, n, rule; 1547 | 1548 | for (i = 0, j = keys.length; i < j; i++) { 1549 | key = keys[i]; 1550 | 1551 | for (k = 0, l = flexers[key].length; k < l; k++) { 1552 | x = flexers[key][k]; 1553 | max = NULL; 1554 | 1555 | for (m = 0, n = x.properties.length; m < n; m++) { 1556 | rule = x.properties[m]; 1557 | 1558 | if ((RESTRICTIVE_PROPERTIES).test(rule.property)) { 1559 | max = parseFloat(rule.value); 1560 | } 1561 | } 1562 | 1563 | if (!max || x.match[self.props.out] > max) { 1564 | appendPixelValue(x.match, self.props.pos, NULL); 1565 | } 1566 | 1567 | } 1568 | } 1569 | }; 1570 | 1571 | findTotalWhitespace = function (matrix) { 1572 | var groupDimension = 0, 1573 | whitespace, 1574 | ration, 1575 | i, j, kid, 1576 | k, l, pad; 1577 | 1578 | for (i = 0, j = children.length; i < j; i++) { 1579 | kid = children[i]; 1580 | 1581 | groupDimension += getComputedStyle(kid, self.props.dim, TRUE); 1582 | 1583 | for (k = 0, l = self.props.pad.length; k < l; k++) { 1584 | pad = self.props.pad[k]; 1585 | 1586 | groupDimension += getComputedStyle(kid, pad, TRUE); 1587 | } 1588 | 1589 | groupDimension += getComputedStyle(kid, self.props.pos, TRUE); 1590 | groupDimension += getComputedStyle(kid, self.props.opp, TRUE); 1591 | } 1592 | 1593 | whitespace = target[self.props.out] - groupDimension; 1594 | 1595 | for (i = 0, j = self.props.pad.length; i < j; i++) { 1596 | pad = self.props.pad[i]; 1597 | whitespace -= getComputedStyle(target, pad, TRUE); 1598 | } 1599 | 1600 | ration = (whitespace / matrix.total); 1601 | 1602 | return { 1603 | whitespace : whitespace, 1604 | ration : ration 1605 | }; 1606 | }; 1607 | 1608 | distributeRatio = function (matrix, whitespace) { 1609 | var flexers = matrix.groups, 1610 | keys = matrix.keys, 1611 | flex, specificity, 1612 | ration = whitespace.ration, 1613 | widthRation, trueDim, newDimension, 1614 | i, j, key, k, l, x; 1615 | 1616 | for (i = 0, j = keys.length; i < j; i++) { 1617 | key = keys[i]; 1618 | widthRation = (ration * key); 1619 | 1620 | for (k = 0, l = flexers[key].length; k < l; k++) { 1621 | x = flexers[key][k]; 1622 | 1623 | if (x.match) { 1624 | flex = x.match.getAttribute("data-flex"); 1625 | specificity = x.match.getAttribute("data-specificity"); 1626 | 1627 | if (!flex || (specificity <= x.flexSpecificity)) { 1628 | x.match.setAttribute("data-flex", key); 1629 | x.match.setAttribute("data-specificity", x.flexSpecificity); 1630 | 1631 | trueDim = getComputedStyle(x.match, self.props.dim, TRUE); 1632 | newDimension = Math.max(0, (trueDim + widthRation)); 1633 | appendPixelValue(x.match, self.props.dim, newDimension); 1634 | } 1635 | } 1636 | } 1637 | } 1638 | }; 1639 | 1640 | matrix = createMatchMatrix(params.children, children, NULL); 1641 | 1642 | if (matrix.total) { 1643 | params.hasFlex = TRUE; 1644 | 1645 | restrict = testForRestrictiveProperties(matrix); 1646 | whitespace = findTotalWhitespace(matrix); 1647 | 1648 | // Distribute the calculated ratios among the children 1649 | distro = distributeRatio(matrix, whitespace); 1650 | } 1651 | }, 1652 | 1653 | boxAlign : function (target, children, params) { 1654 | var self = this, 1655 | targetDimension, 1656 | kidDimension, 1657 | flexCheck = parentFlex(target), 1658 | i, j, pad, k, l, kid; 1659 | 1660 | if (!SUPPORT && !flexCheck.flex && (params.orient === VERTICAL || params.orient === BLOCK_AXIS)) { 1661 | if (!dimensionValues(target, self.anti.dim)) { 1662 | appendPixelValue(target, self.anti.dim, NULL); 1663 | } 1664 | appendPixelValue(children, self.anti.dim, NULL); 1665 | } 1666 | 1667 | // Remove padding / border from target dimension 1668 | targetDimension = target[self.anti.out]; 1669 | 1670 | for (i = 0, j = self.anti.pad.length; i < j; i++) { 1671 | pad = self.anti.pad[i]; 1672 | targetDimension -= getComputedStyle(target, pad, TRUE); 1673 | } 1674 | 1675 | switch (params.align) { 1676 | case "start" : 1677 | break; 1678 | 1679 | case "end" : 1680 | for (i = 0, j = children.length; i < j; i++) { 1681 | kid = children[i]; 1682 | 1683 | kidDimension = targetDimension - kid[self.anti.out]; 1684 | kidDimension -= getComputedStyle(kid, self.anti.opp, TRUE); 1685 | appendPixelValue(kid, self.anti.pos, kidDimension); 1686 | } 1687 | break; 1688 | 1689 | case "center" : 1690 | for (i = 0, j = children.length; i < j; i++) { 1691 | kid = children[i]; 1692 | 1693 | kidDimension = (targetDimension - kid[self.anti.out]) / 2; 1694 | appendPixelValue(kid, self.anti.pos, kidDimension); 1695 | } 1696 | break; 1697 | 1698 | default : 1699 | for (i = 0, j = children.length; i < j; i++) { 1700 | kid = children[i]; 1701 | 1702 | switch (kid.nodeName.toLowerCase()) { 1703 | case "button" : 1704 | case "input" : 1705 | case "select" : 1706 | break; 1707 | 1708 | default : 1709 | var subtract = 0; 1710 | 1711 | for (k = 0, l = self.anti.pad.length; k < l; k++) { 1712 | pad = self.anti.pad[k]; 1713 | 1714 | subtract += getComputedStyle(kid, pad, TRUE); 1715 | subtract += getComputedStyle(target, pad, TRUE); 1716 | } 1717 | 1718 | kid.style[self.anti.dim] = "100%"; 1719 | kidDimension = kid[self.anti.out] - subtract; 1720 | appendPixelValue(kid, self.anti.dim, NULL); 1721 | 1722 | kidDimension = targetDimension; 1723 | kidDimension -= getComputedStyle(kid, self.anti.pos, TRUE); 1724 | 1725 | for (k = 0, l = self.anti.pad.length; k < l; k++) { 1726 | pad = self.anti.pad[k]; 1727 | 1728 | kidDimension -= getComputedStyle(kid, pad, TRUE); 1729 | } 1730 | 1731 | kidDimension -= getComputedStyle(kid, self.anti.opp, TRUE); 1732 | kidDimension = Math.max(0, kidDimension); 1733 | 1734 | appendPixelValue(kid, self.anti.dim, kidDimension); 1735 | break; 1736 | } 1737 | } 1738 | break; 1739 | } 1740 | }, 1741 | 1742 | boxPack : function (target, children, params) { 1743 | var self = this, 1744 | groupDimension = 0, 1745 | firstComputedMargin = 0, 1746 | targetPadding = 0, 1747 | totalDimension, 1748 | fractionedDimension, 1749 | currentDimension, 1750 | remainder, 1751 | length = children.length - 1, 1752 | kid, i, j, value, pad; 1753 | 1754 | for (i = 0, j = children.length; i < j; i++) { 1755 | kid = children[i]; 1756 | 1757 | groupDimension += kid[self.props.out]; 1758 | groupDimension += getComputedStyle(kid, self.props.pos, TRUE); 1759 | groupDimension += getComputedStyle(kid, self.props.opp, TRUE); 1760 | } 1761 | 1762 | firstComputedMargin = getComputedStyle(children[0], self.props.pos, TRUE); 1763 | totalDimension = target[self.props.out] - groupDimension; 1764 | 1765 | // Remove padding / border from target dimension 1766 | for (i = 0, j = self.props.pad.length; i < j; i++) { 1767 | pad = self.props.pad[i]; 1768 | totalDimension -= getComputedStyle(target, pad, TRUE); 1769 | } 1770 | 1771 | // If totalDimension is less than 0, we have a problem... 1772 | if (totalDimension < 0) { 1773 | totalDimension = Math.max(0, totalDimension); 1774 | } 1775 | 1776 | switch (params.pack) { 1777 | case "end" : 1778 | appendPixelValue(children[0], self.props.pos, targetPadding + firstComputedMargin + totalDimension); 1779 | break; 1780 | 1781 | case "center" : 1782 | if (targetPadding) { 1783 | targetPadding /= 2; 1784 | } 1785 | 1786 | appendPixelValue(children[0], self.props.pos, targetPadding + firstComputedMargin + Math.floor(totalDimension / 2)); 1787 | break; 1788 | 1789 | case "justify" : 1790 | fractionedDimension = Math.floor((targetPadding + totalDimension) / length); 1791 | remainder = (fractionedDimension * length) - totalDimension; 1792 | 1793 | i = children.length - 1; 1794 | 1795 | while (i) { 1796 | kid = children[i]; 1797 | currentDimension = fractionedDimension; 1798 | 1799 | if (remainder) { 1800 | currentDimension++; 1801 | remainder++; 1802 | } 1803 | 1804 | value = getComputedStyle(kid, self.props.pos, TRUE) + currentDimension; 1805 | appendPixelValue(kid, self.props.pos, value); 1806 | 1807 | i--; 1808 | } 1809 | 1810 | break; 1811 | } 1812 | 1813 | target.style.overflow = ""; 1814 | } 1815 | }, 1816 | 1817 | setup : function (target, children, params) { 1818 | var self = this, matrix, flexCheck, 1819 | key, func; 1820 | 1821 | if (!target || !children || !params) { 1822 | return; 1823 | } 1824 | 1825 | if (SUPPORT && SUPPORT.partialSupport) { 1826 | matrix = createMatchMatrix(params.children, children, NULL); 1827 | flexCheck = parentFlex(target); 1828 | children = sanitizeChildren(target, target.childNodes); 1829 | 1830 | self.properties.boxOrient.call(self, target, children, params); 1831 | 1832 | if (!matrix.total || !LIBRARY(params.nested).length) { 1833 | if ((params.align === "stretch") && !SUPPORT.boxAlignStretch && (!flexCheck.nested || !flexCheck.flex)) { 1834 | self.properties.boxAlign.call(self, target, children, params); 1835 | } 1836 | 1837 | if ((params.pack === "justify") && !SUPPORT.boxPackJustify && !matrix.total) { 1838 | self.properties.boxPack.call(self, target, children, params); 1839 | } 1840 | } 1841 | } else if (!SUPPORT) { 1842 | for (key in self.properties) { 1843 | if (self.properties.hasOwnProperty(key)) { 1844 | func = self.properties[key]; 1845 | func.call(self, target, sanitizeChildren(target, target.childNodes), params); 1846 | } 1847 | } 1848 | } 1849 | }, 1850 | 1851 | trackDOM : function (params) { 1852 | attachResizeListener(this, params); 1853 | }, 1854 | 1855 | updateModel : function (params) { 1856 | var self = this, 1857 | target = params.target, 1858 | children = params.nodes; 1859 | 1860 | // Null properties 1861 | cleanPositioningProperties(children); 1862 | 1863 | if (params.flexMatrix || params.ordinalMatrix) { 1864 | params = updateChildValues(params); 1865 | } 1866 | 1867 | self.setup(target, children, params); 1868 | self.bubbleUp(target, params); 1869 | }, 1870 | 1871 | renderModel : function (params) { 1872 | var self = this, 1873 | target = params.target, 1874 | nodes = target.childNodes; 1875 | 1876 | // Sanity check. 1877 | if (!target.length && !nodes) { 1878 | return false; 1879 | } 1880 | 1881 | params = ensureStructuralIntegrity(params, this); 1882 | 1883 | // Setup properties 1884 | self.updateModel(params); 1885 | 1886 | // Resize / DOM Polling Events 1887 | // Delay for an instant because IE6 is insane. 1888 | win.setTimeout(function () { 1889 | self.trackDOM(params); 1890 | }, 0); 1891 | 1892 | return self; 1893 | }, 1894 | 1895 | bubbleUp : function (target, params) { 1896 | var self = this, flex, 1897 | parent = params.target.parentNode; 1898 | 1899 | while (parent) { 1900 | flex = FLEX_BOXES[parent.FLX_DOM_ID]; 1901 | 1902 | if (flex) { 1903 | cleanPositioningProperties(flex.nodes); 1904 | self.setup(flex.target, flex.nodes, flex); 1905 | } 1906 | 1907 | parent = parent.parentNode; 1908 | } 1909 | } 1910 | }; 1911 | 1912 | FLX.updateInstance = function (target, params) { 1913 | var box, key; 1914 | 1915 | if (target) { 1916 | box = FLEX_BOXES[target.FLX_DOM_ID]; 1917 | 1918 | if (box && box._instance) { 1919 | box._instance.updateModel(box); 1920 | } else if (!box) { 1921 | box = new FLX.box(params); 1922 | } 1923 | } else { 1924 | for (key in FLEX_BOXES) { 1925 | if (FLEX_BOXES.hasOwnProperty(key)) { 1926 | box = FLEX_BOXES[key]; 1927 | 1928 | if (box && box._instance) { 1929 | box._instance.updateModel(box); 1930 | } 1931 | } 1932 | } 1933 | } 1934 | }; 1935 | 1936 | FLX.getInstance = function (target) { 1937 | return FLEX_BOXES[target.FLX_DOM_ID]; 1938 | }; 1939 | 1940 | FLX.destroyInstance = function (target) { 1941 | var box, destroy, i, j, x, key; 1942 | 1943 | destroy = function (box) { 1944 | box.target.FLX_DOM_ID = NULL; 1945 | box.target.style.cssText = EMPTY_STRING; 1946 | 1947 | for (i = 0, j = box.children.length; i < j; i++) { 1948 | x = box.children[i]; 1949 | x.match.style.cssText = EMPTY_STRING; 1950 | } 1951 | }; 1952 | 1953 | if (target) { 1954 | box = FLEX_BOXES[target.FLX_DOM_ID]; 1955 | 1956 | if (box) { 1957 | destroy(box); 1958 | } 1959 | } else { 1960 | for (key in FLEX_BOXES) { 1961 | if (FLEX_BOXES.hasOwnProperty(key)) { 1962 | destroy(FLEX_BOXES[key]); 1963 | } 1964 | } 1965 | 1966 | FLEX_BOXES = []; 1967 | } 1968 | }; 1969 | 1970 | FLX.flexboxSupport = function () { 1971 | var partialSupportGrid = {}, 1972 | height = 100, 1973 | childHeight, 1974 | dummy = doc.createElement("flxbox"), 1975 | child = '', 1976 | tests, result, key, value; 1977 | 1978 | dummy.style.width = dummy.style.height = height + "px"; 1979 | dummy.innerHTML = (child + child + child); 1980 | 1981 | appendProperty(dummy, "display", "box", NULL); 1982 | appendProperty(dummy, "box-align", "stretch", TRUE); 1983 | appendProperty(dummy, "box-pack", "justify", TRUE); 1984 | 1985 | doc.body.appendChild(dummy); 1986 | childHeight = dummy.firstChild.offsetHeight; 1987 | 1988 | tests = { 1989 | boxAlignStretch : function () { 1990 | return (childHeight === 100); 1991 | }, 1992 | 1993 | boxPackJustify : function () { 1994 | var totalOffset = 0, 1995 | i, j; 1996 | 1997 | for (i = 0, j = dummy.childNodes.length; i < j; i++) { 1998 | totalOffset += dummy.childNodes[i].offsetLeft; 1999 | } 2000 | 2001 | return (totalOffset === 135); 2002 | } 2003 | }; 2004 | 2005 | for (key in tests) { 2006 | if (tests.hasOwnProperty(key)) { 2007 | value = tests[key]; 2008 | 2009 | result = value(); 2010 | 2011 | if (!result) { 2012 | partialSupportGrid.partialSupport = TRUE; 2013 | } 2014 | 2015 | partialSupportGrid[key] = result; 2016 | } 2017 | } 2018 | 2019 | doc.body.removeChild(dummy); 2020 | return ~ (dummy.style.display).indexOf("box") ? partialSupportGrid : FALSE; 2021 | }; 2022 | 2023 | FLX.init = function () { 2024 | FLX.flexboxSupported = SUPPORT = FLX.flexboxSupport(); 2025 | 2026 | if ((!SUPPORT || SUPPORT.partialSupport) && LIBRARY) { 2027 | selectivizrEngine(); 2028 | } 2029 | }; 2030 | 2031 | // Flexie Version 2032 | FLX.version = "1.0.3"; 2033 | 2034 | // Load when the DOM is ready 2035 | attachLoadMethod(FLX.init); 2036 | 2037 | return FLX; 2038 | }(this, document)); 2039 | --------------------------------------------------------------------------------