├── .gitignore ├── README.md ├── bower.json ├── build ├── build.js ├── docs-legacy ├── docs.css ├── docs.less ├── index.html └── tutorial.html ├── docs.sh ├── docs ├── Application.html ├── Application.js.html ├── DomExtend.html ├── FrameImpulse.html ├── FrameImpulse.js.html ├── Gesture.html ├── Gesture.js.html ├── HistoryRouter.html ├── HistoryRouter.js.html ├── Loader.html ├── Loader.js.html ├── Simplrz.html ├── Simplrz.js.html ├── Timer.html ├── Timer.js.html ├── Trigger.html ├── Trigger.js.html ├── Util.html ├── Util.js.html ├── Value.html ├── Value.js.html ├── Version.js.html ├── VirtualScroll.html ├── VirtualScroll.js.html ├── domExtend_DomExtend.js.html ├── domExtend_State.js.html ├── domExtend_Transform.js.html ├── domExtend_Transition.js.html ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ └── OpenSans-Regular-webfont.woff ├── global.html ├── index.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js ├── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css ├── tutorial-home.html └── tutorial-website.html ├── extras └── ScrollStep.js ├── home ├── background.jpg ├── docs.svg ├── github.svg ├── home.css └── home.less ├── index.html ├── lib └── Stats.js ├── malibu.js ├── malibu.min.js ├── package-lock.json ├── package.json ├── qit.sh ├── src ├── Application.js ├── FrameImpulse.js ├── Gesture.js ├── HistoryRouter.js ├── Keyframes.js ├── Loader.js ├── Simplrz.js ├── Template.js ├── Template2.js ├── Timer.js ├── Trigger.js ├── Util.js ├── Value.js ├── Version.js ├── VirtualScroll.js └── domExtend │ ├── Animation.js │ ├── DomExtend.js │ ├── State.js │ ├── Transform.js │ └── Transition.js ├── test ├── css-animation.html ├── css │ ├── animation-api.css │ ├── css-animation.css │ └── extend.css ├── events.html ├── ext-animation.html ├── extend.html ├── frame-impulse.html ├── gesture.html ├── history.html ├── iecon.html ├── less │ ├── animation-api.less │ ├── css-flip.less │ ├── extend.less │ └── lesshat.less ├── nthchild-test.html ├── orientation.html ├── scroll-step.html ├── simplrz.html ├── state.html ├── styl │ └── css-animation.styl ├── tap.html ├── template2.html ├── threshold.html ├── timer-test.html ├── transition.html ├── wheel-ie.html ├── wheel-multi.html ├── wheel-simple.html └── wheel.html ├── tutorials ├── home.md └── website.md ├── version.json ├── wirekit ├── assets │ ├── icons │ │ ├── demo-files │ │ │ └── demo.css │ │ ├── demo.html │ │ ├── png │ │ │ ├── back.png │ │ │ ├── camera.png │ │ │ ├── cross.png │ │ │ ├── forward.png │ │ │ ├── list.png │ │ │ ├── location.png │ │ │ └── search.png │ │ ├── style.css │ │ ├── svg │ │ │ ├── back.svg │ │ │ ├── camera.svg │ │ │ ├── cross.svg │ │ │ ├── forward.svg │ │ │ ├── list-white.svg │ │ │ ├── list.svg │ │ │ ├── location.svg │ │ │ ├── search-white.svg │ │ │ └── search.svg │ │ └── svgdefs.svg │ ├── image.png │ ├── play.png │ └── profile.png ├── css │ ├── grid.css │ ├── sample.css │ └── ui.css ├── grid.html ├── styl │ ├── config.styl │ ├── grid.styl │ ├── sample.styl │ ├── ui.styl │ └── wirekit.styl └── ui.html └── ~quarantine ├── Anm.js ├── OldHistoryRouter.js └── Pointer.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | */.DS_Store 3 | node_modules 4 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Malibu 2 | 3 | A JS framework for interactive development. 4 | 5 | More info, can be found here [here](http://work.bartekdrozdz.com/malibu) 6 | 7 | [Reference docs](http://work.bartekdrozdz.com/malibu/docs/index.html) 8 | 9 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "malibu", 3 | "version": "3.4", 4 | "main": "malibu.min.js", 5 | "ignore": [ 6 | 7 | "**/.*", 8 | "*.md", 9 | 10 | "docs", 11 | "test", 12 | "src", 13 | "lib", 14 | "~quarantine", 15 | "wirekit", 16 | 17 | "version.json", 18 | "package.json", 19 | "index.html", 20 | "build", 21 | "build.js" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | node build.js 3 | 4 | ls -lh malibu*.js 5 | ls -l malibu*.js 6 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var UglifyJS = require("uglify-js"); 3 | 4 | var version = require("./version.json"); 5 | 6 | var frameworkOut = "malibu.js"; 7 | var frameworkOutMin = "malibu.min.js"; 8 | 9 | var baseUrl = "src/"; 10 | 11 | var frameworkFiles = { 12 | include: [ 13 | "Version", 14 | "Simplrz", 15 | "Trigger", 16 | "Timer", 17 | "Value", 18 | "Application", 19 | "Keyframes", 20 | 21 | "domExtend/DomExtend", 22 | "domExtend/State", 23 | "domExtend/Transform", 24 | "domExtend/Transition", 25 | "domExtend/Animation", 26 | 27 | "FrameImpulse", 28 | "HistoryRouter", 29 | "Loader", 30 | "VirtualScroll", 31 | "Gesture", 32 | "Template", 33 | "Util" 34 | ] 35 | }; 36 | 37 | var updateVersion = function() { 38 | version.build++; 39 | version.date = new Date(); 40 | 41 | var jsHeader = "/**\n"; 42 | jsHeader += " * @const Framework\n"; 43 | jsHeader += " * @description autogenerated with build script, holds current verison info\n"; 44 | jsHeader += " * @property {string} version - the version \n"; 45 | jsHeader += " * @property {string} build - the build number\n"; 46 | jsHeader += " * @property {string} date - the date of the build\n"; 47 | jsHeader += " */\n" 48 | jsHeader += "// DO NOT EDIT. Updated from version.json\nvar Framework = "; 49 | 50 | fs.writeFileSync("./version.json", JSON.stringify(version)); 51 | fs.writeFileSync(baseUrl + "Version.js", jsHeader + JSON.stringify(version)); 52 | 53 | 54 | } 55 | 56 | var minify = function(set) { 57 | var includes = []; 58 | 59 | for(var i = 0; i < set.include.length; i++) { 60 | includes.push(baseUrl + set.include[i] + ".js"); 61 | } 62 | 63 | var result = UglifyJS.minify(includes); 64 | 65 | return result.code; 66 | } 67 | 68 | var concat = function(set) { 69 | var concatFile = ""; 70 | 71 | for(var i = 0; i < set.include.length; i++) { 72 | var f = baseUrl + set.include[i] + ".js"; 73 | 74 | concatFile += "/* --- --- [" + set.include[i] + "] --- --- */\n\n"; 75 | concatFile += fs.readFileSync(f); 76 | concatFile += "\n\n"; 77 | } 78 | 79 | return concatFile; 80 | } 81 | 82 | updateVersion(); 83 | 84 | console.log("[ Framework " + version.version + " build " + version.build + " ]"); 85 | 86 | var minifiedFramework = minify(frameworkFiles, false); 87 | var concatenatedFramework = concat(frameworkFiles, false); 88 | 89 | fs.writeFileSync(frameworkOut, concatenatedFramework); 90 | fs.writeFileSync(frameworkOutMin, minifiedFramework); 91 | 92 | console.log("...done!"); 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /docs-legacy/docs.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #dddddd; 3 | margin: 0; 4 | padding: 0; 5 | border: 0; 6 | font-family: Helvetica, Arial, sans-serif; 7 | color: #444444; 8 | font-size: 0.8em; 9 | } 10 | @media screen and (min-width: 600px) { 11 | body { 12 | font-size: 1em; 13 | } 14 | } 15 | * { 16 | -webkit-box-sizing: border-box; 17 | -moz-box-sizing: border-box; 18 | -ms-box-sizing: border-box; 19 | box-sizing: border-box; 20 | } 21 | ul.class-list { 22 | background-color: rgba(0, 0, 0, 0.25); 23 | list-style-type: none; 24 | overflow: auto; 25 | padding: 10px; 26 | margin: 0; 27 | } 28 | @media screen and (min-width: 1140px) { 29 | ul.class-list { 30 | position: fixed; 31 | top: 0; 32 | left: 0; 33 | width: 180px; 34 | } 35 | } 36 | ul.class-list li { 37 | background-color: #000; 38 | color: #fff; 39 | padding: 10px; 40 | margin-right: 5px; 41 | margin-bottom: 5px; 42 | border-radius: 4px; 43 | float: left; 44 | } 45 | @media screen and (min-width: 1140px) { 46 | ul.class-list li { 47 | float: none; 48 | } 49 | } 50 | ul.class-list li:hover { 51 | background-color: #ff8000; 52 | } 53 | ul.class-list li:hover a { 54 | text-decoration: underline; 55 | } 56 | ul.class-list li a { 57 | text-decoration: none; 58 | } 59 | h1 { 60 | font-size: 2em; 61 | margin-left: 0px; 62 | } 63 | h1 a { 64 | font-size: 0.4em; 65 | text-decoration: none; 66 | font-weight: normal; 67 | background-color: #c1d0d5; 68 | padding: 4px; 69 | border-radius: 3px; 70 | position: relative; 71 | top: -5px; 72 | display: inline-block; 73 | } 74 | h2 { 75 | font-size: 1.4em; 76 | margin-left: 10px; 77 | } 78 | @media screen and (min-width: 600px) { 79 | h2 { 80 | margin-left: 40px; 81 | } 82 | } 83 | p, 84 | em, 85 | blockquote { 86 | line-height: 1.6em; 87 | margin-left: 20px; 88 | } 89 | @media screen and (min-width: 600px) { 90 | p, 91 | em, 92 | blockquote { 93 | margin-left: 80px; 94 | } 95 | } 96 | code { 97 | font-size: 1.2em; 98 | } 99 | blockquote { 100 | margin-right: 10px; 101 | padding: 5px; 102 | background-color: #f8ec85; 103 | border-radius: 4px; 104 | font-size: 1.2em; 105 | font-family: monospace; 106 | white-space: pre-line; 107 | } 108 | @media screen and (min-width: 600px) { 109 | blockquote { 110 | white-space: pre; 111 | } 112 | } 113 | p code { 114 | background-color: #f8ec85; 115 | padding: 2px 4px 2px 4px; 116 | border-radius: 4px; 117 | } 118 | a { 119 | color: inherit; 120 | } 121 | .red { 122 | background-color: #ffcece; 123 | } 124 | .blue { 125 | background-color: #5fd4e5; 126 | } 127 | em { 128 | padding: 10px; 129 | border-radius: 4px; 130 | display: block; 131 | overflow: auto; 132 | margin-right: 10px; 133 | } 134 | em ul { 135 | list-style-type: none; 136 | padding: 0; 137 | } 138 | em ul li { 139 | float: left; 140 | } 141 | em ul li:not(:last-child):after { 142 | content: ','; 143 | margin-right: 10px; 144 | } 145 | em ul li a { 146 | font-family: monospace; 147 | font-style: normal; 148 | font-size: 1.2em; 149 | text-decoration: none; 150 | color: black; 151 | } 152 | em ul li a:hover { 153 | text-decoration: underline; 154 | } 155 | h2 i { 156 | font-weight: normal; 157 | } 158 | section { 159 | padding: 10px; 160 | } 161 | @media screen and (min-width: 600px) { 162 | section { 163 | padding: 20px; 164 | } 165 | } 166 | #main { 167 | position: relative; 168 | width: 100%; 169 | background-color: #ffffff; 170 | } 171 | @media screen and (min-width: 960px) { 172 | #main { 173 | left: 50%; 174 | margin-left: -480px; 175 | width: 960px; 176 | } 177 | } 178 | @media screen and (min-width: 1140px) { 179 | #main { 180 | left: 180px; 181 | margin-left: 0; 182 | width: 960px; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /docs-legacy/docs.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #dddddd; 3 | margin: 0; 4 | padding: 0; 5 | border: 0; 6 | 7 | font-family: Helvetica, Arial, sans-serif; 8 | color: #444444; 9 | 10 | font-size: 0.8em; 11 | 12 | @media screen and (min-width: 600px) { 13 | font-size: 1em; 14 | } 15 | } 16 | 17 | * { 18 | -webkit-box-sizing: border-box; 19 | -moz-box-sizing: border-box; 20 | -ms-box-sizing: border-box; 21 | box-sizing: border-box; 22 | } 23 | 24 | @menu-margin: 180px; 25 | @min-side-menu-width: (960px + @menu-margin); 26 | @main-width: 960px; 27 | 28 | ul.class-list { 29 | 30 | @media screen and (min-width: @min-side-menu-width) { 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | width: @menu-margin; 35 | } 36 | 37 | background-color: rgba(0, 0, 0, 0.25); 38 | 39 | list-style-type: none; 40 | overflow: auto; 41 | padding: 10px; 42 | margin: 0; 43 | 44 | li { 45 | background-color: #000; 46 | color: #fff; 47 | padding: 10px; 48 | margin-right: 5px; 49 | margin-bottom: 5px; 50 | border-radius: 4px; 51 | float: left; 52 | 53 | @media screen and (min-width: @min-side-menu-width) { 54 | float: none; 55 | } 56 | 57 | &:hover { 58 | background-color: #ff8000; 59 | 60 | a { 61 | text-decoration: underline; 62 | } 63 | } 64 | 65 | a { 66 | text-decoration: none; 67 | } 68 | } 69 | } 70 | 71 | h1 { 72 | font-size: 2em; 73 | margin-left: 0px; 74 | 75 | a { 76 | font-size: 0.4em; 77 | text-decoration: none; 78 | font-weight: normal; 79 | background-color: #c1d0d5; 80 | padding: 4px; 81 | border-radius: 3px; 82 | position: relative; 83 | top: -5px; 84 | display: inline-block; 85 | } 86 | } 87 | 88 | h2 { 89 | font-size: 1.4em; 90 | margin-left: 10px; 91 | 92 | @media screen and (min-width: 600px) { 93 | margin-left: 40px; 94 | } 95 | } 96 | 97 | p, em, blockquote { 98 | line-height: 1.6em; 99 | margin-left: 20px; 100 | 101 | @media screen and (min-width: 600px) { 102 | margin-left: 80px; 103 | } 104 | } 105 | 106 | code { 107 | font-size: 1.2em; 108 | } 109 | 110 | blockquote { 111 | margin-right: 10px; 112 | padding: 5px; 113 | background-color: #f8ec85; 114 | border-radius: 4px; 115 | font-size: 1.2em; 116 | font-family: monospace; 117 | white-space: pre-line; 118 | 119 | @media screen and (min-width: 600px) { 120 | white-space: pre; 121 | } 122 | } 123 | 124 | p code { 125 | background-color: #f8ec85; 126 | padding: 2px 4px 2px 4px; 127 | border-radius: 4px; 128 | } 129 | 130 | a { 131 | color: inherit; 132 | } 133 | 134 | .red { 135 | background-color: #ffcece; 136 | } 137 | 138 | .blue { 139 | background-color: #5fd4e5; 140 | } 141 | 142 | em { 143 | padding: 10px; 144 | border-radius: 4px; 145 | display: block; 146 | overflow: auto; 147 | margin-right: 10px; 148 | 149 | ul { 150 | list-style-type: none; 151 | padding: 0; 152 | 153 | li { 154 | float: left; 155 | 156 | &:not(:last-child):after { 157 | content: ','; 158 | margin-right: 10px; 159 | } 160 | 161 | a { 162 | font-family: monospace; 163 | font-style: normal; 164 | font-size: 1.2em; 165 | text-decoration: none; 166 | color: black; 167 | 168 | &:hover { 169 | text-decoration: underline; 170 | } 171 | } 172 | } 173 | } 174 | } 175 | 176 | h2 i { 177 | font-weight: normal; 178 | } 179 | 180 | section { 181 | padding: 10px; 182 | 183 | @media screen and (min-width: 600px) { 184 | padding: 20px; 185 | } 186 | } 187 | 188 | #main { 189 | position: relative; 190 | width: 100%; 191 | 192 | @media screen and (min-width: @main-width) { 193 | left: 50%; 194 | margin-left: @main-width * -0.5; 195 | width: @main-width; 196 | } 197 | 198 | @media screen and (min-width: @min-side-menu-width) { 199 | left: 180px; 200 | margin-left: 0; 201 | width: @main-width; 202 | } 203 | 204 | background-color: #ffffff; 205 | } 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -Rf docs/* 4 | jsdoc -d docs -R tutorials/home.md -u tutorials/ src/* -------------------------------------------------------------------------------- /docs/Application.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: Application.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: Application.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
 30 |  *	@namespace Application
 31 |  */
 32 | var Application = (function() {
 33 | 
 34 | 	var app = {};
 35 | 	var router;
 36 | 
 37 | 	/**
 38 | 	 *	@member {Object} flags
 39 | 	 *	@memberof Application
 40 | 	 *	@static
 41 | 	 */	
 42 | 	app.flags = {};
 43 | 
 44 | 	var fs = document.location.search.substring(1).split('&');
 45 | 	fs.forEach(function(f) {
 46 | 		var ff = f.split('=');
 47 | 		app.flags[ff[0]] = parseFloat(ff[1]);
 48 | 	});
 49 | 
 50 | 	/**
 51 | 	 *	@member {Trigger} resize
 52 | 	 *	@memberof Application
 53 | 	 *	@static
 54 | 	 */
 55 | 	app.resize = new Trigger();
 56 | 
 57 | 	/**
 58 | 	 *	@member {Value} route
 59 | 	 *	@memberof Application
 60 | 	 *	@static
 61 | 	 */
 62 | 	app.route = new Value({
 63 | 		parts: []
 64 | 	}, true);
 65 | 	
 66 | 	/**
 67 | 	 *	@function init
 68 | 	 *	@memberof Application
 69 | 	 *	@static
 70 | 	 */
 71 | 	app.init = function(params) {
 72 | 
 73 | 		params = params || {};
 74 | 
 75 | 		console.log('%cMalibu v' + 
 76 | 			Framework.version + 
 77 | 			' b' + Framework.build + 
 78 | 			' (history:' + !params.disableHistoryAPI + ')'
 79 | 			, 'background: #ff3600; color: #ffdede; padding: 4px 10px 4px 10px');
 80 | 
 81 | 		window.addEventListener('resize', function(e) {
 82 | 			app.resize.trigger(e);
 83 | 		});
 84 | 
 85 | 		window.addEventListener('orientationchange', function(e) {
 86 | 			app.resize.trigger(e);
 87 | 		});	
 88 | 
 89 | 		router = HistoryRouter(app, params);
 90 | 		router.init();	
 91 | 	}
 92 | 	
 93 | 	return app;
 94 | 
 95 | })();
 96 | 
 97 | 
 98 | 
99 |
100 |
101 | 102 | 103 | 104 | 105 |
106 | 107 | 110 | 111 |
112 | 113 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /docs/HistoryRouter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Class: HistoryRouter 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Class: HistoryRouter

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |

32 | HistoryRouter 33 |

34 | 35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | 44 |

Constructor

45 | 46 | 47 |

new HistoryRouter()

48 | 49 | 50 | 51 | 52 | 53 |
54 |

A router that handles browser/app history. 55 | Works with either the History API or just internally within the app.

56 |

In most cases - NOT TO BE used directly, it is used internally by Application instead.

57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
Source:
99 |
102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |
128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 |
147 | 148 |
149 | 150 | 151 | 152 | 153 |
154 | 155 | 158 | 159 |
160 | 161 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /docs/Loader.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: Loader.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: Loader.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  *	@namespace Loader
31 |  *
32 |  *	@description A very (very) simple AJAX loader.
33 |  */
34 | var Loader = {
35 | 
36 | 	/**
37 | 	 *	@method loadText
38 | 	 *	@memberof Loader
39 | 	 *	@static
40 | 	 *
41 | 	 *	@description Loads a text file through AJAX
42 | 	 *
43 | 	 *	@param {string} path - the path to the file, absolute or relative
44 | 	 *	@param {Function} onLoadedFunc - callback for when the file is loaded. The contents of the file in string format will be passed to this callback as argument.
45 | 	 */
46 | 	loadText: function(path, onLoadedFunc){
47 | 
48 | 		var request = new XMLHttpRequest();
49 | 		request.open("GET", path);
50 | 
51 | 		request.onreadystatechange = function(){
52 | 			if (request.readyState == 4) {
53 | 				onLoadedFunc(request.responseText);
54 | 			}
55 | 		};
56 | 
57 | 		request.send();
58 | 	},
59 | 
60 | 	/**
61 | 	 *	@method loadJSON
62 | 	 *	@memberof Loader
63 | 	 *	@static
64 | 	 *
65 | 	 *	@description Loads a JSON file through AJAX
66 | 	 *
67 | 	 *	@param {string} path - the path to the file, absolute or relative
68 | 	 *	@param {Function} onLoadedFunc - callback for when the file is loaded. The contents of the file in JS object format will be passed to this callback as argument.
69 | 	 */
70 | 	loadJSON: function(path, onLoadedFunc){
71 | 		Loader.loadText(path, function(text) {
72 | 			onLoadedFunc(JSON.parse(text));
73 | 		});
74 | 	}
75 | };
76 |
77 |
78 | 79 | 80 | 81 | 82 |
83 | 84 | 87 | 88 |
89 | 90 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/Version.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: Version.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: Version.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
30 |  *	@const Framework
31 |  *	@description autogenerated with build script, holds current verison info
32 |  *	@property {string} version - the version 
33 |  *	@property {string} build - the  build number
34 |  *	@property {string} date - the date of the build
35 |  */
36 | // DO NOT EDIT. Updated from version.json
37 | var Framework = {"version":"4","build":79,"date":"2015-11-03T00:22:52.407Z"}
38 |
39 |
40 | 41 | 42 | 43 | 44 |
45 | 46 | 49 | 50 |
51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Home

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
46 |

Malibu

An easy to use not-at-all-over-engineered Javascript framework.

47 |

Most important links

51 |

Tutorials

    52 |
  • Building a single page app website
  • 53 |
54 |

Guide:

Core WebGL rendering classes.

55 |
    56 |
  • DomExtend - an class that extends DOM elements with added functionality
  • 57 |
  • Application - the central gloabl Application instance
  • 58 |
  • FrameImpulse - utility to control RAF loops
  • 59 |
  • VirtualScroll - a scroll controller for all your paralax and other 60 | fancy scrolling needs
  • 61 |
  • Value - it's like a property, but with added event listener, so that you can listen to when the value changes
  • 62 |
  • Trigger - an event dispatcher
  • 63 |
  • Timer - a timer utility which is a more elegent and more managable version of setTimeout and setInterval
  • 64 |
  • Simplrz - a utility that performs feature detection tests (and some browser sniffing too, we're not ashamed to admit that)
  • 65 |
66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 | 75 | 78 | 79 |
80 | 81 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /docs/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/tutorial-home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Tutorial: home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Tutorial: home

21 | 22 |
23 | 24 |
25 | 26 | 27 |

home

28 |
29 | 30 |
31 |

Malibu

An easy to use not-at-all-over-engineered Javascript framework.

32 |

Most important links

36 |

Tutorials

    37 |
  • Building a single page app website
  • 38 |
39 |

Guide:

Core WebGL rendering classes.

40 |
    41 |
  • DomExtend - an class that extends DOM elements with added functionality
  • 42 |
  • Application - the central gloabl Application instance
  • 43 |
  • FrameImpulse - utility to control RAF loops
  • 44 |
  • VirtualScroll - a scroll controller for all your paralax and other 45 | fancy scrolling needs
  • 46 |
  • Value - it's like a property, but with added event listener, so that you can listen to when the value changes
  • 47 |
  • Trigger - an event dispatcher
  • 48 |
  • Timer - a timer utility which is a more elegent and more managable version of setTimeout and setInterval
  • 49 |
  • Simplrz - a utility that performs feature detection tests (and some browser sniffing too, we're not ashamed to admit that)
  • 50 |
51 |
52 | 53 |
54 | 55 |
56 | 57 | 60 | 61 |
62 | 63 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /extras/ScrollStep.js: -------------------------------------------------------------------------------- 1 | var ScrollStep = function(minForce, threshold) { 2 | 3 | threshold = threshold || 0.9; 4 | 5 | var easeDown = 0.92; 6 | var easeUp = 0.20; 7 | var touchMult = 64; 8 | 9 | if(Simplrz.touch) minForce /= touchMult; 10 | 11 | var forceMult = 1 / minForce; 12 | 13 | var locked = false; 14 | var overDown = false; 15 | 16 | var st = { 17 | threshold: threshold, 18 | jump: new Trigger(), 19 | } 20 | 21 | var targetLevel = 0; 22 | st.level = 0; 23 | 24 | FrameImpulse.on(function() { 25 | st.level += (targetLevel - st.level) * easeUp; 26 | if(!locked) targetLevel *= easeDown; 27 | }); 28 | 29 | VirtualScroll.on(function(e) { 30 | var d = -e.deltaY; 31 | var f = Math.abs(e.deltaY); 32 | 33 | if(d > 0) targetLevel = Math.max(d * forceMult, targetLevel); 34 | if(d < 0) targetLevel = Math.min(d * forceMult, targetLevel); 35 | 36 | targetLevel = Math.min(1, targetLevel); 37 | targetLevel = Math.max(-1, targetLevel); 38 | 39 | if(f > minForce && !locked && Math.abs(st.level) >= threshold) { 40 | locked = true; 41 | st.jump.trigger(d > 0); 42 | } 43 | }); 44 | 45 | st.reset = function() { 46 | locked = false; 47 | } 48 | 49 | return st; 50 | } -------------------------------------------------------------------------------- /home/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drojdjou/malibu/0471f108ef454fdbfd32a1922c17315e0df0f97c/home/background.jpg -------------------------------------------------------------------------------- /home/docs.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /home/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /home/home.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: #000; 4 | color: #ffffff; 5 | font-family: "proxima-nova", sans-serif; 6 | font-weight: 400; 7 | } 8 | a { 9 | color: inherit; 10 | text-decoration: none; 11 | } 12 | ol { 13 | list-style-type: none; 14 | padding: 0; 15 | margin: 0; 16 | } 17 | ol li { 18 | margin-top: 1px; 19 | } 20 | .splash { 21 | position: absolute; 22 | width: 100%; 23 | height: 100%; 24 | top: 0; 25 | left: 0; 26 | position: fixed; 27 | background-image: url(background.jpg); 28 | background-repeat: no-repeat; 29 | background-size: cover; 30 | -webkit-filter: blur(6px); 31 | transform: scaleX(1.1) scaleY(1.1); 32 | } 33 | .overlay { 34 | position: absolute; 35 | width: 100%; 36 | height: 100%; 37 | top: 0; 38 | left: 0; 39 | background-color: rgba(0, 0, 0, 0.1); 40 | } 41 | #content { 42 | position: relative; 43 | margin: 15px; 44 | } 45 | #content h1, 46 | #content h2, 47 | #content p, 48 | #content a { 49 | margin: 0; 50 | } 51 | #content a { 52 | padding: 2px 8px 4px 0px; 53 | } 54 | #content h1, 55 | #content h2 { 56 | color: #000; 57 | display: inline-block; 58 | } 59 | #content h2 { 60 | font-family: "proxima-nova", sans-serif; 61 | font-weight: 700; 62 | } 63 | #content h1 { 64 | font-family: "proxima-nova", sans-serif; 65 | font-weight: 900; 66 | font-size: 50px; 67 | letter-spacing: 0.01em; 68 | } 69 | #content p { 70 | color: #000; 71 | padding: 2px 0px 10px 3px; 72 | display: inline-block; 73 | } 74 | #content .left { 75 | display: block; 76 | } 77 | #content .left a { 78 | display: inline-block; 79 | color: #fff; 80 | background-color: rgba(0, 0, 0, 0.75); 81 | padding: 8px 12px 4px 12px; 82 | margin-bottom: 2px; 83 | } 84 | #content .left a:hover { 85 | color: #fff; 86 | } 87 | #content .left img { 88 | display: inline-block; 89 | vertical-align: middle; 90 | margin: 0px 6px 8px 0px; 91 | } 92 | #content .right a { 93 | background-color: rgba(0, 0, 0, 0.75); 94 | display: inline-block; 95 | padding: 2px 8px 4px 8px; 96 | } 97 | #content .right a:hover { 98 | background-color: #fff; 99 | color: #000; 100 | } 101 | #content .right { 102 | margin-top: 20px; 103 | } 104 | @media (min-width: 768px) { 105 | #content .right { 106 | position: absolute; 107 | top: 0; 108 | right: 0; 109 | text-align: right; 110 | margin-top: 0px; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /home/home.less: -------------------------------------------------------------------------------- 1 | .black() { 2 | font-family: "proxima-nova", sans-serif; 3 | font-weight: 900; 4 | } 5 | 6 | .bold() { 7 | font-family: "proxima-nova", sans-serif; 8 | font-weight: 700; 9 | } 10 | 11 | .regular() { 12 | font-family: "proxima-nova", sans-serif; 13 | font-weight: 400; 14 | } 15 | 16 | .full() { 17 | position: absolute; 18 | width: 100%; 19 | height: 100%; 20 | top: 0; 21 | left: 0; 22 | } 23 | 24 | body { 25 | margin: 0; 26 | background-color: #000; 27 | color: #ffffff; 28 | .regular(); 29 | } 30 | 31 | a { 32 | color: inherit; 33 | text-decoration: none; 34 | } 35 | 36 | ol { 37 | list-style-type: none; 38 | padding: 0; 39 | margin: 0; 40 | 41 | li { 42 | margin-top: 1px; 43 | } 44 | } 45 | 46 | .splash { 47 | .full(); 48 | position: fixed; 49 | background-image: url(background.jpg); 50 | background-repeat: no-repeat; 51 | background-size: cover; 52 | -webkit-filter: blur(6px); 53 | transform: scaleX(1.1) scaleY(1.1); 54 | } 55 | 56 | .overlay { 57 | .full(); 58 | background-color: rgba(0, 0, 0, 0.1); 59 | } 60 | 61 | #content { 62 | position: relative; 63 | margin: 15px; 64 | 65 | h1, h2, p, a { 66 | margin: 0; 67 | } 68 | 69 | a { 70 | padding: 2px 8px 4px 0px; 71 | } 72 | 73 | h1, h2 { 74 | color: #000; 75 | display: inline-block; 76 | } 77 | 78 | h2 { 79 | .bold(); 80 | } 81 | 82 | h1 { 83 | .black(); 84 | font-size: 50px; 85 | letter-spacing: 0.01em; 86 | } 87 | 88 | p { 89 | color: #000; 90 | padding: 2px 0px 10px 3px; 91 | display: inline-block; 92 | } 93 | 94 | .left { 95 | 96 | display: block; 97 | 98 | a { 99 | display: inline-block; 100 | color: #fff; 101 | background-color: rgba(0, 0, 0, 0.75); 102 | padding: 8px 12px 4px 12px; 103 | // border-radius: 8px; 104 | margin-bottom: 2px; 105 | 106 | 107 | &:hover { 108 | color: #fff; 109 | } 110 | } 111 | 112 | img { 113 | display: inline-block; 114 | vertical-align: middle; 115 | margin: 0px 6px 8px 0px; 116 | } 117 | 118 | } 119 | 120 | .right a { 121 | background-color: rgba(0, 0, 0, 0.75); 122 | display: inline-block; 123 | padding: 2px 8px 4px 8px; 124 | 125 | &:hover { 126 | background-color: #fff; 127 | color: #000; 128 | } 129 | } 130 | 131 | .right { 132 | margin-top: 20px; 133 | } 134 | 135 | @media (min-width: 768px) { 136 | 137 | .right { 138 | position: absolute; 139 | top: 0; 140 | right: 0; 141 | text-align: right; 142 | margin-top: 0px; 143 | } 144 | 145 | } 146 | } 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Malibu | A not-over-engineered Javascript framework 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | 19 |
20 | 21 |
    22 |
  1. MALIBU

  2. 23 |
  3. A Javascript framework that is not over engineered.

  4. 24 | 25 |
  5. Github Repository
  6. 26 |
  7. API docs
  8. 27 |
28 | 29 |
    30 |
  1. EXAMPLES

  2. 31 |
  3. Virtual scroll
  4. 32 |
  5. Virtual scroll simple
  6. 33 |
  7. Virtual scroll paralax
  8. 34 |
  9. Simplrz feature detection
  10. 35 | 36 |
  11. Tap
  12. 37 | 38 |
  13. DOM Extend
  14. 39 | 40 |
  15. History Router
  16. 41 |
  17. State
  18. 42 | 43 |
  19. Triggers
  20. 44 |
  21. Value.threshold
  22. 45 | 46 |
  23. EXT CSS Transitions
  24. 47 |
  25. EXT CSS Animations
  26. 48 |
  27. Frame Impulse
  28. 49 | 50 |
  29. Screen orientation
  30. 51 |
  31. Scroll step
  32. 52 |
53 | 54 |
55 | 56 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /lib/Stats.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var Stats = function () { 6 | 7 | var startTime = Date.now(), prevTime = startTime; 8 | var ms = 0, msMin = Infinity, msMax = 0; 9 | var fps = 0, fpsMin = Infinity, fpsMax = 0; 10 | var frames = 0, mode = 0; 11 | 12 | var container = document.createElement( 'div' ); 13 | container.id = 'stats'; 14 | container.addEventListener( 'mousedown', function ( event ) { event.preventDefault(); setMode( ++ mode % 2 ) }, false ); 15 | container.style.cssText = 'width:80px;opacity:0.9;cursor:pointer'; 16 | 17 | var fpsDiv = document.createElement( 'div' ); 18 | fpsDiv.id = 'fps'; 19 | fpsDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#002'; 20 | container.appendChild( fpsDiv ); 21 | 22 | var fpsText = document.createElement( 'div' ); 23 | fpsText.id = 'fpsText'; 24 | fpsText.style.cssText = 'color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 25 | fpsText.innerHTML = 'FPS'; 26 | fpsDiv.appendChild( fpsText ); 27 | 28 | var fpsGraph = document.createElement( 'div' ); 29 | fpsGraph.id = 'fpsGraph'; 30 | fpsGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0ff'; 31 | fpsDiv.appendChild( fpsGraph ); 32 | 33 | while ( fpsGraph.children.length < 74 ) { 34 | 35 | var bar = document.createElement( 'span' ); 36 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#113'; 37 | fpsGraph.appendChild( bar ); 38 | 39 | } 40 | 41 | var msDiv = document.createElement( 'div' ); 42 | msDiv.id = 'ms'; 43 | msDiv.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:#020;display:none'; 44 | container.appendChild( msDiv ); 45 | 46 | var msText = document.createElement( 'div' ); 47 | msText.id = 'msText'; 48 | msText.style.cssText = 'color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px'; 49 | msText.innerHTML = 'MS'; 50 | msDiv.appendChild( msText ); 51 | 52 | var msGraph = document.createElement( 'div' ); 53 | msGraph.id = 'msGraph'; 54 | msGraph.style.cssText = 'position:relative;width:74px;height:30px;background-color:#0f0'; 55 | msDiv.appendChild( msGraph ); 56 | 57 | while ( msGraph.children.length < 74 ) { 58 | 59 | var bar = document.createElement( 'span' ); 60 | bar.style.cssText = 'width:1px;height:30px;float:left;background-color:#131'; 61 | msGraph.appendChild( bar ); 62 | 63 | } 64 | 65 | var setMode = function ( value ) { 66 | 67 | mode = value; 68 | 69 | switch ( mode ) { 70 | 71 | case 0: 72 | fpsDiv.style.display = 'block'; 73 | msDiv.style.display = 'none'; 74 | break; 75 | case 1: 76 | fpsDiv.style.display = 'none'; 77 | msDiv.style.display = 'block'; 78 | break; 79 | } 80 | 81 | } 82 | 83 | var updateGraph = function ( dom, value ) { 84 | 85 | var child = dom.appendChild( dom.firstChild ); 86 | child.style.height = value + 'px'; 87 | 88 | } 89 | 90 | return { 91 | 92 | REVISION: 11, 93 | 94 | domElement: container, 95 | 96 | setMode: setMode, 97 | 98 | begin: function () { 99 | 100 | startTime = Date.now(); 101 | 102 | }, 103 | 104 | end: function () { 105 | 106 | var time = Date.now(); 107 | 108 | ms = time - startTime; 109 | msMin = Math.min( msMin, ms ); 110 | msMax = Math.max( msMax, ms ); 111 | 112 | msText.textContent = ms + ' MS (' + msMin + '-' + msMax + ')'; 113 | updateGraph( msGraph, Math.min( 30, 30 - ( ms / 200 ) * 30 ) ); 114 | 115 | frames ++; 116 | 117 | if ( time > prevTime + 1000 ) { 118 | 119 | fps = Math.round( ( frames * 1000 ) / ( time - prevTime ) ); 120 | fpsMin = Math.min( fpsMin, fps ); 121 | fpsMax = Math.max( fpsMax, fps ); 122 | 123 | fpsText.textContent = fps + ' FPS (' + fpsMin + '-' + fpsMax + ')'; 124 | updateGraph( fpsGraph, Math.min( 30, 30 - ( fps / 100 ) * 30 ) ); 125 | 126 | prevTime = time; 127 | frames = 0; 128 | 129 | } 130 | 131 | return time; 132 | 133 | }, 134 | 135 | update: function () { 136 | 137 | startTime = this.end(); 138 | 139 | } 140 | } 141 | }; -------------------------------------------------------------------------------- /malibu.min.js: -------------------------------------------------------------------------------- 1 | src,Version.js,src,Simplrz.js,src,Trigger.js,src,Timer.js,src,Value.js,src,Application.js,src,Keyframes.js,src,domExtend,DomExtend.js,src,domExtend,State.js,src,domExtend,Transform.js,src,domExtend,Transition.js,src,domExtend,Animation.js,src,FrameImpulse.js,src,HistoryRouter.js,src,Loader.js,src,VirtualScroll.js,src,Gesture.js,src,Template.js,src,Util.js; -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "malibu", 3 | "version": "0.0.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "commander": { 8 | "version": "2.20.0", 9 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", 10 | "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", 11 | "dev": true 12 | }, 13 | "source-map": { 14 | "version": "0.6.1", 15 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 16 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 17 | "dev": true 18 | }, 19 | "uglify-js": { 20 | "version": "3.5.12", 21 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.12.tgz", 22 | "integrity": "sha512-KeQesOpPiZNgVwJj8Ge3P4JYbQHUdZzpx6Fahy6eKAYRSV4zhVmLXoC+JtOeYxcHCHTve8RG1ZGdTvpeOUM26Q==", 23 | "dev": true, 24 | "requires": { 25 | "commander": "~2.20.0", 26 | "source-map": "~0.6.1" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "malibu", 3 | "description": "A simple JS framework", 4 | "version": "0.0.2", 5 | "devDependencies": { 6 | "uglify-js": "*" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /qit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BRANCH=$(git rev-parse --abbrev-ref HEAD) 4 | 5 | ./build 6 | git add -u . 7 | git add . 8 | git status 9 | git commit -m "$1" 10 | git push origin $BRANCH -------------------------------------------------------------------------------- /src/Application.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace Application 3 | */ 4 | var Application = (function() { 5 | 6 | var app = {}; 7 | var router; 8 | 9 | /** 10 | * @member {Object} flags 11 | * @memberof Application 12 | * @static 13 | */ 14 | app.flags = {}; 15 | 16 | var fs = document.location.search.substring(1).split('&'); 17 | fs.forEach(function(f) { 18 | var ff = f.split('='); 19 | app.flags[ff[0]] = parseFloat(ff[1]); 20 | }); 21 | 22 | /** 23 | * @member {Trigger} start 24 | * @memberof Application 25 | * @static 26 | */ 27 | app.start = new Trigger(); 28 | 29 | /** 30 | * @member {Trigger} resize 31 | * @memberof Application 32 | * @static 33 | */ 34 | app.resize = new Trigger(); 35 | 36 | /** 37 | * @member {Value} route 38 | * @memberof Application 39 | * @static 40 | */ 41 | app.route = new Value({ 42 | parts: [] 43 | }, true); 44 | 45 | /** 46 | * @function init 47 | * @memberof Application 48 | * @static 49 | */ 50 | app.init = function(params) { 51 | 52 | params = params || {}; 53 | 54 | if(!params.dontPrintVersion) { 55 | console.log('%cMalibu v' + 56 | Framework.version + 57 | ' b' + Framework.build + 58 | ' (history:' + !params.disableHistoryAPI + ')' 59 | , 'background: #ff3600; color: #ffdede; padding: 4px 10px 4px 10px'); 60 | } 61 | 62 | var r = { 63 | width: 0, 64 | height: 0, 65 | aspect: 0, 66 | orientation: -1, 67 | event: null 68 | } 69 | 70 | var triggerResize = function(e) { 71 | var f = function() { 72 | r.width = window.innerWidth; 73 | r.height = window.innerHeight; 74 | r.aspect = r.width / r.height; 75 | r.orientation = window.orientation; 76 | r.event = e; 77 | app.resize.trigger(r); 78 | } 79 | 80 | f(); 81 | 82 | if(Simplrz.iOS) { 83 | // window.scroll(0, 0); // This was causing some weird behavior on iPhones, of course! 84 | setTimeout(f, 400); 85 | setTimeout(f, 1000); 86 | } 87 | } 88 | 89 | window.addEventListener('resize', triggerResize); 90 | 91 | router = HistoryRouter(app, params); 92 | router.init(); 93 | 94 | app.start.trigger(); 95 | } 96 | 97 | return app; 98 | 99 | })(); 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/FrameImpulse.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace FrameImpulse 3 | * 4 | * @description

A utility to handle requestAnimationFrame loops. It really only exists to eliminate a common but hard debug problem: 5 | * since RaF is sort of a recurent function, sometimes the code can accidentally start the loop twice (or even more times). This has diastrous 6 | * conseuences for perofrmance, but it is not easy to spot at all.

7 | * 8 |

With FrameImpulse you will not get into this kind of trouble easily.

9 | * 10 | * @example 11 | var render = function() { 12 | // Do some rendering logic in here 13 | } 14 | 15 | // When the loop needs to be activated 16 | FrameImpulse.on(render); 17 | 18 | // ...and when it needs to stop 19 | FrameImpulse.off(render); 20 | */ 21 | var FrameImpulse = (function() { 22 | 23 | var vendors = ['webkit', 'moz']; 24 | 25 | var listeners = [], numListeners = 0, toRemove = [], numToRemove; 26 | var lastTime = 0; 27 | 28 | var provider = window; 29 | 30 | var r = {}; 31 | 32 | // for(var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { 33 | // window.requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame']; 34 | // } 35 | 36 | // if (!window.requestAnimationFrame) { 37 | // window.requestAnimationFrame = function(callback) { 38 | // var currTime = new Date().getTime(); 39 | // var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 40 | // var id = window.setTimeout(function() { 41 | // callback(currTime + timeToCall); 42 | // }, timeToCall); 43 | // lastTime = currTime + timeToCall; 44 | // return id; 45 | // }; 46 | // } 47 | 48 | var run = function(time, frame) { 49 | provider.requestAnimationFrame(run); 50 | 51 | if(numListeners == 0) return; 52 | 53 | for(var i = 0; i < numListeners; i++) { 54 | listeners[i].apply(null, arguments); 55 | } 56 | 57 | if(numToRemove > 0) { 58 | var indexToRemove = []; 59 | for (var i = listeners.length - 1; i >= 0; i--) { 60 | for (var j = 0; j < toRemove.length; j++) { 61 | if (listeners[i] === toRemove[j]) 62 | indexToRemove.push(i); 63 | }; 64 | }; 65 | 66 | for (var i = 0; i < indexToRemove.length; i++) { 67 | listeners.splice(indexToRemove[i], 1); 68 | }; 69 | 70 | numListeners = listeners.length; 71 | toRemove = []; 72 | numToRemove = 0; 73 | } 74 | } 75 | 76 | /** 77 | * @method on 78 | * @memberof FrameImpulse 79 | * @static 80 | * 81 | * @param {Function} callback - the function used as callback for the listener 82 | * @description Adds a listener to be called on every frame. The cool thing about this function, 83 | * is that the same function is added twice, it will not be called twice later on. However, this 84 | * does not work with anonymous functions, so we suggest to never use anonnymous functions with this. 85 | */ 86 | r.on = function(f) { 87 | if(listeners.indexOf(f) > -1) { return; } 88 | listeners.push(f); 89 | numListeners = listeners.length; 90 | // console.log("FrameImpulse > new listener > total :", numListeners); 91 | } 92 | 93 | /** 94 | * @method off 95 | * @memberof FrameImpulse 96 | * @static 97 | * 98 | * @param {Function} callback - the function used as callback for the listener. 99 | * Needs to be the same function as passed to the on() when it was being registered. 100 | * @description Removes a listener to be called on every frame 101 | */ 102 | r.off = function(f) { 103 | 104 | 105 | // At this point we think the "late" removal patttern was more harmful than helpful, so it's gone. 106 | 107 | // if(listeners.indexOf(f) == -1) { return; } 108 | // toRemove.push(f); 109 | // numToRemove = toRemove.length; 110 | 111 | var i = listeners.indexOf(f); 112 | if(i == -1) return; 113 | listeners.splice(i, 1); 114 | numListeners = listeners.length; 115 | } 116 | 117 | /** 118 | * @method getListeners 119 | * @memberof FrameImpulse 120 | * @static 121 | * 122 | * @description Returns a list of all currently registered functions. Useful for debugging. 123 | */ 124 | r.getListeners = function() { 125 | return listeners; 126 | } 127 | 128 | r.setProvider = function(p) { 129 | var newprov = p && p != provider; 130 | provider = p || window; 131 | if(newprov) provider.requestAnimationFrame(run); 132 | } 133 | 134 | run(); 135 | return r; 136 | 137 | })(); -------------------------------------------------------------------------------- /src/Gesture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Gesture 3 | * 4 | * @param {Object=} options - object holding settings (see above) 5 | * 6 | * @description 7 | * 8 | *

A simple touch (or click/drag) gesture recognition class.

9 | * 10 | *

Works with touch gesture, mouse clik/drag gestures and key press (cursor keys), detects swipes in 4 directions.

11 | * 12 | *

For advanced scenarios Hammer.js can be used instead.

13 | * 14 | *

Options include: 15 | *

23 | *

24 | * 25 | * @example 26 | var g = new Gesture(); 27 | g.swipeUp.on(function() { 28 | console.log("User swiped up!"); 29 | }); 30 | */ 31 | var Gesture = function(options) { 32 | 33 | options = options || {}; 34 | 35 | var that = this; 36 | var cl; 37 | 38 | var isTouch = 'ontouchstart' in document; 39 | var downEvent = isTouch ? 'touchstart' : 'mousedown'; 40 | var moveEvent = isTouch ? 'touchmove' : 'mousemove'; 41 | var upEvent = isTouch ? 'touchend' : 'mouseup'; 42 | 43 | /** 44 | * @member {Trigger} swipeUp 45 | * @memberof Gesture.prototype 46 | * 47 | * @description Triggered when a "swipe up" gesture is detected 48 | */ 49 | this.swipeUp = new Trigger(); 50 | 51 | /** 52 | * @member {Trigger} swipeDown 53 | * @memberof Gesture.prototype 54 | * 55 | * @description Triggered when a "swipe down" gesture is detected 56 | */ 57 | this.swipeDown = new Trigger(); 58 | 59 | /** 60 | * @member {Trigger} swipeLeft 61 | * @memberof Gesture.prototype 62 | * 63 | * @description Triggered when a "swipe left" gesture is detected 64 | */ 65 | this.swipeLeft = new Trigger(); 66 | 67 | /** 68 | * @member {Trigger} swipeRight 69 | * @memberof Gesture.prototype 70 | * 71 | * @description Triggered when a "swipe right" gesture is detected 72 | */ 73 | this.swipeRight = new Trigger(); 74 | 75 | var tolerance = options.tolerance || 0.1; 76 | 77 | var start = { x:0, y:0 }, 78 | delta = { x: 0, y: 0 }, 79 | startTime = 0, 80 | maxTime = options.maxTime || 300, minDistance = options.minDistance || 30; 81 | minDistance = minDistance * minDistance; // square it for faster math 82 | 83 | var onStart = function(e) { 84 | e = isTouch ? e.targetTouches[0] : e; 85 | start.x = e.pageX; 86 | start.y = e.pageY; 87 | delta.x = 0; 88 | delta.y = 0; 89 | startTime = new Date().getTime(); 90 | } 91 | 92 | var onMove = function(e) { 93 | e = isTouch ? e.targetTouches[0] : e; 94 | delta.x = e.pageX - start.x; 95 | delta.y = e.pageY - start.y; 96 | } 97 | 98 | var onStop = function(e) { 99 | var ds = delta.x * delta.x + delta.y * delta.y; 100 | var dt = new Date().getTime() - startTime; 101 | var t = tolerance; 102 | 103 | if(dt > maxTime) return; 104 | if(ds < minDistance) return; 105 | 106 | var a = Math.atan2(delta.y, delta.x) / Math.PI; 107 | // up = -0.5, down = 0.5, left = 1, right = 0 108 | if(a > -0.5 - t && a < -0.5 + t) that.swipeUp.trigger(); 109 | if(a > 0.5 - t && a < 0.5 + t) that.swipeDown.trigger(); 110 | if(a > 0.0 - t && a < 0.0 + t) that.swipeRight.trigger(); 111 | if(a < -1.0 + t || a > 1.0 - t) that.swipeLeft.trigger(); 112 | } 113 | 114 | var onKeyDown = function(e) { 115 | // 37 left arrow, 38 up arrow, 39 right arrow, 40 down arrow 116 | delta.x = delta.y = 0; 117 | switch(e.keyCode) { 118 | case 39: 119 | that.swipeLeft.trigger(); 120 | break; 121 | case 37: 122 | that.swipeRight.trigger(); 123 | break; 124 | case 40: 125 | that.swipeUp.trigger(); 126 | break; 127 | case 38: 128 | that.swipeDown.trigger(); 129 | break; 130 | } 131 | } 132 | 133 | /** 134 | * @method create 135 | * @memberof Gesture.prototype 136 | * 137 | * @description registers all necessary listeners. 138 | * This is done automatically in the constructor, 139 | * so it doesn't need to be called, unless destroy() 140 | * was called before and we want to reuse the object. 141 | */ 142 | this.create = function() { 143 | (options.element || document).addEventListener(downEvent, onStart); 144 | document.addEventListener(moveEvent, onMove); 145 | document.addEventListener(upEvent, onStop); 146 | if(!options.noKeyboard) document.addEventListener("keydown", onKeyDown); 147 | } 148 | 149 | /** 150 | * @method destroy 151 | * @memberof Gesture.prototype 152 | * 153 | * @description deregisters all listeners 154 | */ 155 | this.destroy = function() { 156 | (options.element || document).removeEventListener(downEvent, onStart); 157 | document.removeEventListener(moveEvent, onMove); 158 | document.removeEventListener(upEvent, onStop); 159 | if(!options.noKeyboard) document.removeEventListener("keydown", onKeyDown); 160 | } 161 | 162 | this.create(); 163 | } -------------------------------------------------------------------------------- /src/HistoryRouter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class HistoryRouter 3 | * 4 | * @description

A router that handles browser/app history. 5 | * Works with either the History API or just internally within the app.

6 | *

In most cases - NOT TO BE used directly, it is used internally by {@link Application} instead.

7 | */ 8 | var HistoryRouter = function (app, params) { 9 | 10 | var disableHistoryAPI = (params && params.disableHistoryAPI) || !Simplrz.history; 11 | 12 | var rootUrl = document.location.protocol + '//' + (document.location.hostname || document.location.host); 13 | if(document.location.port) rootUrl += ":" + document.location.port; 14 | app.navigate = new Trigger(); 15 | app.hijackLinks = new Trigger(); 16 | 17 | Application.history = []; 18 | 19 | var setBase = function() { 20 | var base = document.querySelector('base'); 21 | base = (base && base.getAttribute('href')) ? base.getAttribute('href') : '/'; 22 | 23 | // In case base href is a full URL with protocol & domain 24 | // - this gets just the part we need 25 | var prs = document.createElement('a'); 26 | prs.href = base; 27 | base = prs.pathname; 28 | 29 | if(base == '/') base = ''; 30 | if(base[base.length-1] == '/') base = base.substring(0, base.length - 1); 31 | app.baseUrl = base; 32 | } 33 | 34 | var hijackLinks = function (element) { 35 | var allLinksSelector = 'a[href]'; 36 | var allLinks = (element || document).querySelectorAll(allLinksSelector); 37 | 38 | allLinks = Array.prototype.slice.call(allLinks); 39 | 40 | if(element && element.nodeName.toLowerCase() == "a") { 41 | allLinks.unshift(element); 42 | } 43 | 44 | for (var i = 0; i < allLinks.length; i++) { 45 | var link = allLinks[i]; 46 | 47 | var url = link.getAttribute('href'); 48 | var target = link.getAttribute('target'); 49 | var hj = link.getAttribute('data-hj'); 50 | 51 | if(url == null || url.indexOf(':') > -1 || target == '_blank' || hj == "no") { 52 | // Skip absolute URLs, those that have no URL, a _blank target 53 | // and those that are explicitely set to not be hijacked 54 | // (this is done by adding an attribute like this: data-hj='no') 55 | continue; 56 | } 57 | 58 | if (!link.hijacked) { 59 | link.hijacked = true; 60 | 61 | link.originalHref = link.getAttribute('href') || ""; 62 | link.hijackedHref = app.baseUrl + "/" + link.originalHref; 63 | 64 | if(link.hijackedHref.indexOf('//') == 0) link.hijackedHref = link.hijackedHref.substring(1); 65 | // normalize the URL, so it doesn't start with double slashes 66 | 67 | var cb = function (e) { 68 | if(e) e.preventDefault(); 69 | app.navigate.trigger(this.hijackedHref); 70 | } 71 | 72 | link.removeHijack = (function() { 73 | var l = link; 74 | return function() { 75 | l.removeEventListener('click', cb); 76 | l.hijacked = false; 77 | } 78 | })(); 79 | 80 | link.hijackCallback = cb; 81 | link.addEventListener('click', cb); 82 | } 83 | } 84 | }; 85 | 86 | var notify = function(href) { 87 | 88 | var r = {}; 89 | var h; 90 | 91 | if(disableHistoryAPI && href) { 92 | h = href; 93 | } else { 94 | h = document.location.href.replace(rootUrl + app.baseUrl, ""); 95 | } 96 | 97 | h = h.replace(/(^\/)|(\/$)/, ''); 98 | 99 | var qs = h.indexOf('?'); 100 | var hs = h.indexOf('#'); 101 | if(qs > -1) h = h.substring(0, qs); 102 | if(hs > -1) h = h.substring(0, hs); 103 | 104 | r.route = h; 105 | r.parts = h.split('/'); 106 | r.lastPart = r.parts[r.parts.length - 1]; 107 | 108 | if(r.route == app.route.value.route) return; 109 | Application.history.push(r); 110 | app.route.value = r; 111 | } 112 | 113 | if(!disableHistoryAPI) { 114 | window.addEventListener('popstate', function(e) { 115 | notify(); 116 | }); 117 | } 118 | 119 | app.hijackLinks.on(hijackLinks); 120 | 121 | var navCond; 122 | 123 | // https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload 124 | var bu = function(e) { 125 | var m = navCond(); 126 | e.returnValue = m; 127 | return m; 128 | } 129 | 130 | app.setNavigateCondition = function(c) { 131 | navCond = c; 132 | window.addEventListener('beforeunload', bu); 133 | } 134 | 135 | app.clearNavigateCondition = function() { 136 | window.removeEventListener('beforeunload', bu); 137 | navCond = null; 138 | } 139 | 140 | window.addEventListener('popstate', function(e) { 141 | if(navCond) { 142 | window.removeEventListener('beforeunload', bu); 143 | navCond = null; 144 | } 145 | }, false); 146 | 147 | app.navigate.on(function(href) { 148 | 149 | var n = function() { 150 | if(!disableHistoryAPI) history.pushState(null, null, href); 151 | notify(href); 152 | } 153 | 154 | if(navCond) navCond(n, href); 155 | else n(); 156 | }); 157 | 158 | return { 159 | 160 | init: function () { 161 | setBase(); 162 | notify(); 163 | } 164 | } 165 | }; -------------------------------------------------------------------------------- /src/Keyframes.js: -------------------------------------------------------------------------------- 1 | var Keyframes = (function() { 2 | 3 | var r = {}, style; 4 | 5 | var lazyInit = function() { 6 | style = document.createElement("style"); 7 | document.head.appendChild(style); 8 | } 9 | 10 | r.add = function(name, selectors) { 11 | 12 | if(!style) lazyInit(); 13 | 14 | var r = ''; 15 | 16 | for(var s in selectors) { 17 | r += s + '% { ' + selectors[s] + ' } '; 18 | } 19 | 20 | var rp = '@-' + Simplrz.prefix.lowercase + '-keyframes ' + name + ' {' + r + '}';; 21 | style.appendChild(document.createTextNode(rp)); 22 | 23 | var rn = '@keyframes ' + name + ' {' + r + '}';; 24 | style.appendChild(document.createTextNode(rn)); 25 | 26 | return name; 27 | } 28 | 29 | return r; 30 | 31 | })(); -------------------------------------------------------------------------------- /src/Loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace Loader 3 | * 4 | * @description A very (very) simple AJAX loader. 5 | */ 6 | var Loader = { 7 | 8 | error: new Trigger(), 9 | 10 | /** 11 | * @method loadText 12 | * @memberof Loader 13 | * @static 14 | * 15 | * @description Loads a text file through AJAX 16 | * 17 | * @param {string} path - the path to the file, absolute or relative 18 | * @param {Function} onLoadedFunc - callback for when the file is loaded. The contents of the file in JS object format will be passed to this callback as argument. 19 | * @param {FormData} formData - data to be sent via POST 20 | * @param {Function} progressCallback - callback for loading progress 21 | * @param {boolean} withCredentials - defaults to true 22 | */ 23 | loadText: function(path, onLoadedFunc, formData, progressCallback, withCredentials){ 24 | 25 | var request = new XMLHttpRequest(); 26 | request.open(formData ? "POST" : "GET", path, true); 27 | request.withCredentials = withCredentials === null ? true : false; 28 | 29 | request.addEventListener('readystatechange', function(e) { 30 | if (this.readyState == 4) { 31 | 32 | if(!this.responseText) { 33 | console.error("Empty response from " + path); 34 | return; 35 | } 36 | 37 | if(this.status >= 400) { 38 | // console.error("Loader error " + this.status); 39 | Loader.error.trigger({ path: path, error: e }); 40 | return; 41 | } 42 | 43 | onLoadedFunc(request.responseText); 44 | } 45 | }); 46 | 47 | request.addEventListener("error", function(e) { 48 | Loader.error.trigger({ path: path, error: e }); 49 | }) 50 | 51 | if(progressCallback) { 52 | request.addEventListener('progress', function(e) { 53 | if(e.lengthComputable) { 54 | var t = e.loaded / e.total; 55 | progressCallback(t, e.loaded, e.total); 56 | } 57 | }); 58 | } 59 | 60 | request.send(formData); 61 | }, 62 | 63 | /** 64 | * @method loadJSON 65 | * @memberof Loader 66 | * @static 67 | * 68 | * @description Loads a JSON file through AJAX 69 | * 70 | * @param {string} path - the path to the file, absolute or relative 71 | * @param {Function} onLoadedFunc - callback for when the file is loaded. The contents of the file in JS object format will be passed to this callback as argument. 72 | * @param {FormData} formData - data to be sent via POST 73 | * @param {Function} progressCallback - callback for loading progress 74 | * @param {boolean} withCredentials - defaults to true 75 | */ 76 | loadJSON: function(path, onLoadedFunc, formData, progressCallback, withCredentials){ 77 | Loader.loadText(path, function(text) { 78 | // try { 79 | onLoadedFunc(JSON.parse(text)); 80 | // } catch(e) { 81 | // if(Loader.onError) Loader.onError(e); 82 | // else console.error(e); 83 | // } 84 | }, formData, progressCallback, withCredentials); 85 | } 86 | }; 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/Template.js: -------------------------------------------------------------------------------- 1 | var Template = function() { 2 | 3 | var that = this; 4 | var selectorCache; 5 | 6 | this.set = function(content) { 7 | if(content instanceof HTMLElement) { 8 | that.content = EXT.extend(content.cloneNode(true)); 9 | } else { 10 | var df = document.createElement('div'); 11 | df.innerHTML = content ? content.trim() : ""; 12 | that.content = EXT.extend(df.firstChild); 13 | } 14 | 15 | selectorCache = {}; 16 | 17 | return that; 18 | } 19 | 20 | this.wrap = function(element) { 21 | that.content = EXT.extend(element); 22 | selectorCache = {}; 23 | return that; 24 | } 25 | 26 | this.select = function(sel) { 27 | if(!selectorCache) selectorCache = {}; 28 | 29 | if(selectorCache[sel]) { 30 | return selectorCache[sel]; 31 | } else if(that.content) { 32 | var e = that.content.ext.select(sel); 33 | if(!e) console.warn("Template: selector not found: " + sel); 34 | else selectorCache[sel] = e; 35 | return e; 36 | } 37 | } 38 | 39 | this.selectAll = function(sel) { 40 | return this.content ? this.content.ext.selectAll(sel) : null; 41 | } 42 | 43 | this.clearCache = function() { 44 | selectorCache = {}; 45 | } 46 | 47 | this.hide = function(sel) { 48 | that.select(sel).style.display = 'none'; 49 | } 50 | 51 | this.attachTo = function(parent, onAdded) { 52 | 53 | if(!that.content) return; 54 | 55 | that.content.ext.attachTo(parent); 56 | if(onAdded) { 57 | // http://jsfiddle.net/CAewW/2/ 58 | requestAnimationFrame(function() { 59 | requestAnimationFrame(onAdded); 60 | }); 61 | } 62 | } 63 | 64 | this.detach = function(onBeforeRemove) { 65 | 66 | if(!that.content) return; 67 | 68 | if(onBeforeRemove) { 69 | onBeforeRemove(function() { 70 | that.content.ext.detach(); 71 | }); 72 | } else { 73 | that.content.ext.detach(); 74 | } 75 | } 76 | 77 | this.updateText = function(sel, text) { 78 | console.warn('Template.updateText is deprecated, use Template.text instead'); 79 | that.select(sel).innerHTML = text; 80 | } 81 | 82 | this.text = function(sel, text) { 83 | that.select(sel).innerHTML = text; 84 | } 85 | 86 | this.appendText = function(sel, text) { 87 | that.select(sel).innerHTML += text; 88 | } 89 | 90 | this.append = function(sel, elem) { 91 | that.select(sel).appendChild(elem); 92 | } 93 | 94 | this.clone = function() { 95 | 96 | } 97 | 98 | this.insertList = function(sel, list, template) { 99 | list.forEach(function(e) { 100 | 101 | if(template) { 102 | var t = template.content.cloneNode(true); 103 | t.innerHTML = e; 104 | that.append(sel, t); 105 | } else { 106 | that.appendText(sel, e); 107 | } 108 | 109 | }); 110 | } 111 | } -------------------------------------------------------------------------------- /src/Template2.js: -------------------------------------------------------------------------------- 1 | var Template2 = function(content, isLive, defaultValues) { 2 | 3 | var selectorCache; 4 | var that = {}; 5 | var TEXT = "#text"; 6 | 7 | var reactiveNodes; 8 | var __dirty = false; 9 | var vars; 10 | that.vars; 11 | 12 | that.set = function(content, isLive) { 13 | if(content instanceof HTMLElement) { 14 | that.content = EXT.extend(isLive ? content : content.cloneNode(true)); 15 | } else { 16 | var df = document.createElement('div'); 17 | df.innerHTML = content ? content.trim() : ""; 18 | that.content = EXT.extend(df.firstChild); 19 | } 20 | 21 | reactiveNodes = []; 22 | vars = {}; 23 | that.vars = {}; 24 | 25 | var walker = document.createTreeWalker(that.content); 26 | while(walker.nextNode()) { 27 | var n = walker.currentNode; 28 | var v = n.nodeValue; 29 | if(n.nodeName == TEXT && v.trim() != "" && v.indexOf("{{") > -1) { 30 | reactiveNodes.push({ 31 | node: n, text: v, vars: {} 32 | }); 33 | } 34 | } 35 | 36 | reactiveNodes.forEach(function(r) { 37 | 38 | var re = /{{(.*?)}}/g; 39 | var m = r.text.match(re); 40 | m.forEach(function(p) { 41 | p = p.replace(/{|}/g, "").trim(); 42 | 43 | r.vars.p = ""; 44 | 45 | if(vars[p]) { 46 | vars[p].push(r); 47 | } else { 48 | vars[p] = [r]; 49 | (function() { 50 | var _v = "", _p = p; 51 | Object.defineProperty(that.vars, p, { 52 | get: function() { 53 | return _v; 54 | }, 55 | set: function(v) { 56 | _v = v; 57 | update(_p, _v); 58 | } 59 | }); 60 | })(); 61 | } 62 | 63 | var d = defaultValues[p]; 64 | if(d !== undefined) that.vars[p] = d; 65 | 66 | }); 67 | }); 68 | 69 | 70 | selectorCache = {}; 71 | 72 | return that; 73 | } 74 | 75 | that.render = function() { 76 | console.log(vars); 77 | for(var k in vars) { 78 | update(k, vars[k]); 79 | } 80 | } 81 | 82 | var update = function(key, value) { 83 | if(vars[key]) { 84 | vars[key].forEach(function(r) { 85 | if(value !== undefined && value !== null) r.vars[key] = value; 86 | if(!r._text) r._text = r.text; 87 | for(var k in r.vars) r._text = r._text.replace("{{" + k + "}}", r.vars[k]); 88 | }); 89 | if(!__dirty) window.requestAnimationFrame(redraw); 90 | __dirty = true; 91 | } else { 92 | throw "key: " + key + " not found on template"; 93 | } 94 | } 95 | 96 | var redraw = function() { 97 | reactiveNodes.forEach(function(r) { 98 | if(r._text) { 99 | r.node.textContent = r._text; 100 | r._text = null; 101 | } 102 | }); 103 | __dirty = false; 104 | } 105 | 106 | that.select = function(sel) { 107 | if(selectorCache[sel]) { 108 | return selectorCache[sel]; 109 | } else { 110 | var e = that.content.ext.select(sel); 111 | if(!e) throw "Selector not found: " + sel; 112 | selectorCache[sel] = e; 113 | return e; 114 | } 115 | } 116 | 117 | that.clearCache = function() { 118 | selectorCache = {}; 119 | } 120 | 121 | that.attachTo = function(parent, onAdded) { 122 | 123 | if(!that.content) return; 124 | 125 | that.content.ext.attachTo(parent); 126 | if(onAdded) { 127 | // http://jsfiddle.net/CAewW/2/ 128 | requestAnimationFrame(function() { 129 | requestAnimationFrame(onAdded); 130 | }); 131 | } 132 | } 133 | 134 | that.detach = function(onBeforeRemove) { 135 | 136 | if(!that.content) return; 137 | 138 | if(onBeforeRemove) { 139 | onBeforeRemove(function() { 140 | that.content.ext.detach(); 141 | }); 142 | } else { 143 | that.content.ext.detach(); 144 | } 145 | } 146 | 147 | if(content) that.set(content, isLive) 148 | 149 | return that; 150 | } 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/Trigger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class Trigger 3 | * 4 | * @description Trigger is a simple utility used to create events. 5 | *

A Trigger can only send one type of event and it will always notify all of its listeners. 6 | *

In order to build a more robust event system, use multiple 7 | * Trigger objects as properties. 8 | * 9 | * @example 10 | // Simple usage for a single type of event 11 | var menuPress = new Trigger(); 12 | 13 | var menuPressListener = function(params) { 14 | console.log("menuPress trigger fired"); 15 | // params = whatever was passed to the trigger method (see below) 16 | console.log(params); 17 | } 18 | 19 | menuPress.on(menuPressListener); 20 | 21 | // ... then somewhere in the code: 22 | menuPress.trigger({ id: 5 }); 23 | 24 | // ... and eventually 25 | menuPress.off(menuPressListener); 26 | * 27 | * @example 28 | // If there are multiple events to handle, 29 | // simply create multiple triggers 30 | var car = { 31 | engineStarted: new Trigger(), 32 | brakeApplied: new Trigger(), 33 | gearChanged: new Trigger() 34 | } 35 | */ 36 | var Trigger = function() { 37 | 38 | var t = {}; 39 | 40 | var listeners = []; 41 | var lock = false; 42 | 43 | var lateTriggers = []; 44 | var lateRemovals = []; 45 | 46 | /** 47 | * @method on 48 | * @memberof Trigger.prototype 49 | * @param {Function} callback - the function used as callback for the listener 50 | * @param {Object=} context - the context in which to invoke the function 51 | * @description Adds a listener to this trigger 52 | */ 53 | t.on = function (callback, context, callOnInit) { 54 | if(listeners.indexOf(callback) > -1) { return; } 55 | callback.context = context; 56 | listeners.push(callback); 57 | if(callOnInit) callback(); 58 | }; 59 | 60 | /** 61 | * @method off 62 | * @memberof Trigger.prototype 63 | * @param {Function} callback - the function used as callback for the listener. 64 | * Needs to be the same function as passed to the on() when it was being registered. 65 | * @description Removes a listener from this trigger. 66 | *

If the passed callback is not a listener of this trigger, 67 | * this function will not throw any warnings, it will just return. 68 | *

If this function is called from within a function that is a listener for that trigger, 69 | * the callback will not be removed until all other listeners are called. 70 | */ 71 | t.off = function (callback) { 72 | var i = listeners.indexOf(callback); 73 | 74 | if(i == -1) return; 75 | 76 | if(lock) { 77 | lateRemovals.push({ callback: callback }); 78 | return; 79 | } 80 | 81 | listeners.splice(i, 1); 82 | }; 83 | 84 | /** 85 | * @method trigger 86 | * @memberof Trigger.prototype 87 | * @param {Object=} data - An object specifying the events parameters. All listeners will receive this object as argument. 88 | * @description Fires this trigger passing data as srgument to all listeners. 89 | *

If this function is called from within a function that is a listener for that trigger, 90 | * the trigger will not be fired until all other listeners 91 | * are called for the previous one. 92 | */ 93 | t.trigger = function (data) { 94 | 95 | if(lock) { 96 | lateTriggers.push({ data: data }); 97 | return; 98 | } 99 | 100 | lock = true; 101 | 102 | var i = 0, nl = listeners.length; 103 | while(i < nl) { 104 | var f = listeners[i]; 105 | f.call(f.context, data); 106 | i++; 107 | } 108 | 109 | lock = false; 110 | 111 | var d; 112 | while(d = lateTriggers.shift()) t.trigger(d.data); 113 | while(d = lateRemovals.shift()) t.off(d.callback); 114 | }; 115 | 116 | return t; 117 | 118 | }; -------------------------------------------------------------------------------- /src/Version.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @const Framework 3 | * @description autogenerated with build script, holds current verison info 4 | * @property {string} version - the version 5 | * @property {string} build - the build number 6 | * @property {string} date - the date of the build 7 | */ 8 | // DO NOT EDIT. Updated from version.json 9 | var Framework = {"version":"4","build":224,"date":"2022-06-27T21:09:39.716Z"} -------------------------------------------------------------------------------- /src/domExtend/Animation.js: -------------------------------------------------------------------------------- 1 | var ExtAnimation = function(ext, element, globalExt) { 2 | 3 | var events = { 4 | 'animation': 'animationend', 5 | 'Moz': 'animationend', 6 | 'O': 'oanimationend', 7 | 'Webkit': 'webkitAnimationEnd', 8 | 'Ms': 'MSAnimationEnd' 9 | }; 10 | 11 | var animStrigify = function(anim) { 12 | return [ 13 | anim.name, 14 | anim.duration + 's', 15 | anim.ease, 16 | anim.delay + 's', 17 | anim.count, 18 | anim.direction, 19 | anim.fillMode//, 20 | // anim.playState // doesn't work on Safari 8.0, but it's not very useful anyway 21 | ].join(' '); 22 | } 23 | 24 | // animation: name duration timing-function delay iteration-count direction fill-mode (play-state - not-inplemented); 25 | var createAnimation = function(name, duration, ease, delay) { 26 | var a = { 27 | name: name, 28 | duration: duration || 1, 29 | ease: ease || 'ease', 30 | delay: delay || 0, 31 | count: 1, 32 | direction: 'normal', 33 | fillMode: 'backwards'//, 34 | // playState: 'running' 35 | }; 36 | 37 | a.setTime = function(t) { 38 | a.time = t; 39 | return a; 40 | } 41 | 42 | a.setDelay = function(t) { 43 | a.delay = t; 44 | return a; 45 | } 46 | 47 | return a; 48 | } 49 | 50 | globalExt.createAnimation = createAnimation; 51 | ext.createAnimation = createAnimation; 52 | 53 | ext.animate = function(anim, callback, dontClear) { 54 | 55 | var a; 56 | 57 | if(anim instanceof Array) { 58 | var aa = []; 59 | anim.forEach(function(e) { aa.push(animStrigify(e)); }); 60 | a = aa.join(', '); 61 | } else { 62 | a = animStrigify(anim); 63 | } 64 | 65 | var eventName = events[Simplrz.prefix.js]; 66 | 67 | if(element._onEnded) element.removeEventListener(eventName, element._onEnded); 68 | 69 | element._onEnded = function() { 70 | element.removeEventListener(eventName, element._onEnded); 71 | 72 | if(dontClear == null) { 73 | element.style[Simplrz.prefix.js + "Animation"] = ''; 74 | element.style["animation"] = ''; 75 | } 76 | 77 | if(callback) callback(); 78 | } 79 | 80 | 81 | element.style[Simplrz.prefix.js + "Animation"] = ""; 82 | element.style["animation"] = ""; 83 | 84 | setTimeout(function() { 85 | if(ext.show) ext.show(); 86 | element.addEventListener(eventName, element._onEnded); 87 | element.style[Simplrz.prefix.js + "Animation"] = a; 88 | element.style["animation"] = a; 89 | }, 0); 90 | } 91 | }; -------------------------------------------------------------------------------- /src/domExtend/DomExtend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace DomExtend 3 | */ 4 | var DomExtend = (function() { 5 | 6 | var that = {}; 7 | 8 | /** 9 | * @method create 10 | * @memberof DomExtend 11 | * @static 12 | * @param {string} tag - the name of the tag to create 13 | * @description Created a HTMLElement of type defined by the tag. It first calls document.createElement(tag) 14 | * and the extends this element with DomExtend functionality. 15 | */ 16 | that.create = function(tag, cssclass) { 17 | var e = document.createElement(tag); 18 | if(cssclass) e.classList.add(cssclass); 19 | that.extend(e); 20 | return e; 21 | }; 22 | 23 | /** 24 | * The equivalent of document.querySelector. It extends the object 25 | * with DomExtend functionality before returning the result. 26 | * 27 | * @method select 28 | * @memberof DomExtend 29 | * @static 30 | * @param {string} sel - the CSS selector to query 31 | * @param {HTMLElement=} element - the HTML element to query on, defaults to document 32 | */ 33 | that.select = function(sel, element) { 34 | var e = (element || document).querySelector(sel); 35 | if(e && !e.ext) that.extend(e); 36 | return e; 37 | }; 38 | 39 | /** 40 | * The equivalent of document.querySelectorAll. It extends the objects 41 | * with DomExtend functionality before returning the result and it returns them as regular Array (yay!) 42 | * 43 | * @method select 44 | * @memberof DomExtend 45 | * @static 46 | * @param {string} sel - the CSS selector to query 47 | * @param {HTMLElement=} element - the HTML element to query on, defaults to document 48 | */ 49 | that.selectAll = function(sel, element) { 50 | var es = (element || document).querySelectorAll(sel); 51 | var nes = es.length, r = []; 52 | for(var i = 0; i < nes; i++) { 53 | var e = es[i] 54 | if(!e.ext) e = that.extend(e); 55 | r.push(e); 56 | } 57 | return r; 58 | }; 59 | 60 | /** 61 | * @method extend 62 | * @memberof DomExtend 63 | * @static 64 | * @param {HTMLElement} element - the tag to extend 65 | * @description adds the .ext property to the element, with all the DomExtend functionality. This method should be rarely used and if you 66 | * find yourself using it a lot, you need to rethink the code. All element selected with EXT.select or element.ext.select 67 | * or created with EXT.create will be already extended. 68 | */ 69 | that.extend = function(element) { 70 | 71 | if(element.ext) return element; 72 | 73 | var ext = {}; 74 | 75 | /** 76 | * The equivalent of element.querySelector. It extends the object 77 | * with DomExtend functionality before returning the result. 78 | * 79 | * @method select 80 | * @memberof DomExtend.prototype 81 | * @param {string} sel - the CSS selector to query 82 | */ 83 | ext.select = function(sel) { 84 | return that.select(sel, element); 85 | }; 86 | 87 | /** 88 | * The equivalent of element.querySelectorAll. It extends the objects 89 | * with DomExtend functionality before returning the result and it returns them as regular Array (yay!) 90 | * 91 | * @method select 92 | * @memberof DomExtend.prototype 93 | * @param {string} sel - the CSS selector to query 94 | */ 95 | ext.selectAll = function(sel) { 96 | return that.selectAll(sel, element); 97 | }; 98 | 99 | /** 100 | * @method detach 101 | * @memberof DomExtend.prototype 102 | * @description Safely removes the element from it's parent node. It is the same as saying 103 | * element.parentNode.removeChild(element) but will not throw an error if parentNode is null. 104 | */ 105 | ext.detach = function() { 106 | var p = element.parentNode; 107 | if(!p) return; 108 | p.removeChild(element); 109 | }; 110 | 111 | /** 112 | * @method attachTo 113 | * @memberof DomExtend.prototype 114 | * @description Safely attaches the element to a parent node. It is the same as saying 115 | * parent.appednChild(element) but will not throw an error if child is already added to parent. 116 | */ 117 | ext.attachTo = function(parent) { 118 | if(element.parentNode == parent) return; 119 | else parent.appendChild(element); 120 | } 121 | 122 | // Add State related functions (see State.js for details) 123 | if(window.ExtState) ExtState(ext, element); 124 | 125 | // Add Transform related functions (see Transform.js for details) 126 | if(window.ExtTransform) ExtTransform(ext, element); 127 | 128 | // Add Transition related functions (see Transition.js for details) 129 | if(window.ExtTransition) ExtTransition(ext, element); 130 | 131 | // Add Animation related functions (see Transition.js for details) 132 | if(window.ExtAnimation) ExtAnimation(ext, element, that); 133 | 134 | ext.element = element; 135 | element.ext = ext; 136 | return element; 137 | }; 138 | 139 | window.EXT = that; 140 | 141 | return that; 142 | 143 | })(); -------------------------------------------------------------------------------- /src/domExtend/State.js: -------------------------------------------------------------------------------- 1 | var ExtState = function(ext, element) { 2 | 3 | var cc = function(p) { 4 | return p.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); 5 | } 6 | 7 | ext.data = {}; 8 | 9 | /** 10 | * @method show 11 | * @memberof DomExtend.prototype 12 | * @param {string} [display=block] the CSS property value to use. 13 | * @description Sets the display CSS property of the object to the display type specified in the argument. Defaults to "block". 14 | */ 15 | ext.show = function(display) { 16 | element.style.display = display || element.ext.__defaultDisplay || "block"; 17 | }; 18 | 19 | /** 20 | * @method hide 21 | * @memberof DomExtend.prototype 22 | * @description Sets the display CSS property of the object to "none". 23 | */ 24 | ext.hide = function() { 25 | if(!element.ext.__defaultDisplay) { 26 | var d = ext.readCss('display'); 27 | element.ext.__defaultDisplay = d == 'none' ? 'block' : d; 28 | } 29 | element.style.display = "none"; 30 | }; 31 | 32 | /** 33 | * @method toggle 34 | * @memberof DomExtend.prototype 35 | * @description Toggle the display CSS between "none" and "block". 36 | */ 37 | ext.toggle = function(show, display) { 38 | if(show) ext.show(display); 39 | else ext.hide(); 40 | }; 41 | 42 | /** 43 | * @method visible 44 | * @memberof DomExtend.prototype 45 | * @description Returns true if the CSS display property is set to none on this element. 46 | */ 47 | ext.visible = function() { 48 | return ext.readCss('display') != "none"; 49 | }; 50 | 51 | /** 52 | * @method on 53 | * @memberof DomExtend.prototype 54 | * @description Equivalent of element.addEventListener but shorter and has a special touch handler for 'click' events. 55 | */ 56 | ext.on = function(event, callback, options) { 57 | // if(Simplrz.touch && event == 'click') { 58 | // callback.___thProxy = Util.handleTap(element, callback); 59 | // return callback.___thProxy; 60 | // } else 61 | if(event == 'doubleclick') { 62 | callback.___dcProxy = Util.handleDC(element, callback); 63 | return callback.___dcProxy; 64 | } else { 65 | // if(!options) options = { passive: true }; 66 | if(!options) options = { }; 67 | return element.addEventListener(event, callback, options); 68 | } 69 | } 70 | 71 | /** 72 | * @method off 73 | * @memberof DomExtend.prototype 74 | * @description Equivalent of element.removeEventListener but shorter and works witht the special touch handler for 'click' events. 75 | */ 76 | ext.off = function(event, callback, useCapture) { 77 | // if(callback.___thProxy) { 78 | // Util.clearTapHandler(element, callback.___thProxy); 79 | // callback.___thProxy = null; 80 | // } else 81 | if(callback.___dcProxy) { 82 | // callback.___dcProxy.clear = null; 83 | Util.clearDCHandler(element, callback.___dcProxy); 84 | } else { 85 | return element.removeEventListener(event, callback, useCapture); 86 | } 87 | 88 | }; 89 | 90 | /** 91 | * @method readCss 92 | * @memberof DomExtend.prototype 93 | * 94 | * @param {string} property - the name of the CSS property 95 | * @param {Boolean} notCalculated - if true, grabs the value directly from the style property of the object. 96 | * 97 | * @description

Returns true if the value of a CSS property, fetched using computed styles. 98 | *

The CSS values of the object can be defined in multiple stylesheets, so it's not straightforward 99 | * to read them - i.e. in most cases just saying ex. var d = element.style.display will not return 100 | * expected results. 101 | *

This method uses computed styles to fetch the actual CSS value of a property. 102 | */ 103 | ext.readCss = function(property, notCalculated) { 104 | if(notCalculated) { 105 | return element.style[property]; 106 | } else { 107 | var s = getComputedStyle(element); 108 | if(!s) element.style[property]; // Bug in Firefox - this will be null if in iframe and it's set to display:none 109 | else return s.getPropertyValue(property); 110 | } 111 | } 112 | 113 | /** 114 | * @method bg 115 | * @memberof DomExtend.prototype 116 | * @description Loads and sets a backgroung image for the element. Passing the onLoad function allows to make 117 | * animated transitions (ex. fade in) when the background images are loaded. 118 | * 119 | * @param {string} path - the path to the image 120 | * @param {Function} onLoad - the load callback to be exectued. It is called after the image was loaded but before 121 | * it has been set as background image. 122 | */ 123 | ext.bg = function(path, onLoad) { 124 | 125 | if(onLoad) { 126 | var i = new Image(); 127 | i.addEventListener('load', function() { 128 | onLoad(element, i); 129 | element.style.backgroundImage = 'url(' + path + ')'; 130 | }); 131 | i.src = path; 132 | } else { 133 | element.style.backgroundImage = 'url(' + path + ')'; 134 | } 135 | } 136 | }; 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /src/domExtend/Transition.js: -------------------------------------------------------------------------------- 1 | var ExtTransition = function(ext, element) { 2 | 3 | var events = { 4 | 'transition': 'transitionEnd', 5 | 'Moz': 'transitionend', 6 | 'O': 'oTransitionEnd', 7 | 'Webkit': 'webkitTransitionEnd', 8 | 'Ms': 'MSTransitionEnd' 9 | }; 10 | 11 | var trEvent = events[Simplrz.prefix.js]; 12 | var TR = "transform"; 13 | 14 | var now = function() { 15 | return new Date().getTime(); 16 | } 17 | 18 | ext.createTransition = function() { 19 | 20 | var transition = {}; 21 | var tr = [], ts = []; 22 | var cb, numTrans; 23 | var startTime, maxTime = 0, finalized; 24 | 25 | var onEnded = function(e) { 26 | numTrans--; 27 | if(numTrans <= 0) { 28 | var t = now() - startTime; 29 | if(t >= maxTime) { 30 | finalize(); 31 | } else if(!finalized) { 32 | // console.log("Transition early end > ", t, maxTime); 33 | setTimeout(finalize, t); 34 | finalized = true; 35 | } 36 | } 37 | }; 38 | 39 | var finalize = function() { 40 | transition.clear(); 41 | if(cb) cb(); 42 | } 43 | 44 | var setValues = function(vals) { 45 | var nv = vals.length; 46 | 47 | for(var i = 0; i < nv; i++) { 48 | var p = vals[i][0], v = vals[i][1]; 49 | if(p == TR) ext.transform(v); 50 | else element.style[p] = v; 51 | } 52 | 53 | return transition; 54 | }; 55 | 56 | function propToCss(str) { 57 | return str.replace(/([A-Z])/g, function(letter) { return '-' + letter.toLowerCase(); }); 58 | } 59 | 60 | transition.add = function(property, to, time, ease, delay) { 61 | maxTime = Math.max(maxTime, time); 62 | ease = ease || Util.cssEase.ease; 63 | delay = delay || 0; 64 | tr.push([propToCss(property), time+'ms', ease, delay+'ms'].join(' ')); 65 | ts.push([property, to]); 66 | 67 | return transition; 68 | } 69 | 70 | transition.trs = function(values, time, ease, delay) { 71 | maxTime = Math.max(maxTime, time); 72 | ease = ease || Util.cssEase.ease; 73 | delay = delay || 0; 74 | tr.push([Simplrz.prefix.css + "transform", time+'ms', ease, delay+'ms'].join(' ')); 75 | ts.push([TR, values]); 76 | 77 | return transition; 78 | } 79 | 80 | transition.clear = function() { 81 | element.removeEventListener(trEvent, onEnded); 82 | tr = []; 83 | ts = []; 84 | element.style[Simplrz.prefix.js + "Transition"] = ""; 85 | element.style["transition"] = ""; 86 | } 87 | 88 | transition.start = function(callback) { 89 | cb = callback; 90 | numTrans = ts.length; 91 | 92 | // force repaint 93 | var w = element.offsetWidth; 94 | 95 | element.addEventListener(trEvent, onEnded); 96 | startTime = now(); 97 | finalized = false; 98 | element.style[Simplrz.prefix.js + "Transition"] = tr; 99 | element.style["transition"] = tr; 100 | setValues(ts); 101 | 102 | return transition; 103 | }; 104 | 105 | transition.then = function(callback) { 106 | var t = ext.createTransition(); 107 | 108 | var c = function() { 109 | callback(); 110 | t.start(); 111 | } 112 | 113 | transition.start(c); 114 | 115 | return t; 116 | } 117 | 118 | return transition; 119 | 120 | }; 121 | 122 | /** 123 | * @method transition 124 | * @memberof DomExtend.prototype 125 | * @description Creates and starts a CSS transition animation on the element. 126 | * 127 | * @param {Object} properties - the properties to animate, See examples below. 128 | * @param {Number} time - the duration of the animation in milliseconds 129 | * @param {string} ease - the ease. See Util.cssEase for list of easing functions available. 130 | * @param {Number=} delay - the delay before the animation starts in milliseconds, defaults to 0 131 | * @param {Function=} callback - the function to be invoked when the animation is finished 132 | * 133 | * @example 134 | // Animate the opacity property 135 | element.style.opacity = 0; 136 | element.ext.transtion({ opacity: 1 }, 1000, 'ease'); 137 | 138 | // Animate the opacity with custom easing and listen for when the animation is over 139 | element.style.opacity = 0; 140 | element.ext.transtion({ opacity: 1 }, 1000, Util.cssEase.quadIn, 0, function() { 141 | console.log('Animation is over!'); 142 | }); 143 | 144 | // Animate the x, y position and z rotation 145 | 146 | // 1. Define start values 147 | // If this is omitted the transtions will start 148 | // from the current state of the object. 149 | element.ext.x = 0; 150 | element.ext.y = 0; 151 | element.ext.rotZ = 0; 152 | element.ext.transform(); 153 | 154 | // 2. Start the animation 155 | // Note that the transform values are passed as object, 156 | // not as properties of the "properties" argument 157 | element.ext.transition({ 158 | transform: { 159 | x: 100, y: 100, rotZ: 20 160 | } 161 | }, 1000, 'ease'); 162 | */ 163 | ext.transition = function(properties, time, ease, delay, callback) { 164 | var t = ext.createTransition(); 165 | 166 | for(var p in properties) { 167 | var v = properties[p]; 168 | if(p == TR) t.trs(v, time, ease, delay); 169 | else t.add(p, v, time, ease, delay); 170 | } 171 | 172 | t.start(callback); 173 | return t; 174 | } 175 | }; 176 | 177 | 178 | -------------------------------------------------------------------------------- /test/css-animation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CSS Animations test | v0.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 |
#1
17 |
#2
0
18 |
#3
19 |
#4
20 |
#5
21 |
22 | 23 |
24 |
    25 |
  1. #1 fades-in continously
  2. 26 |
  3. #2 dissapears and fades-in 1s after click + counter increases
  4. 27 |
  5. #3 rotates 90deg on 1st click and back on 2nd
  6. 28 |
  7. #4 dissapears then rotates/fades back in on click
  8. 29 |
  9. #5 turns to blue and back to red on click
  10. 30 |
31 |
32 | 33 |
34 | 35 | 41 | 42 |
43 | 44 | 130 | 131 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /test/css/animation-api.css: -------------------------------------------------------------------------------- 1 | body { 2 | position: absolute; 3 | width: 100%; 4 | height: 100%; 5 | margin: 0; 6 | font-family: Arial, sans-serif; 7 | font-size: 1.3em; 8 | background-color: #000; 9 | color: #fff; 10 | } 11 | 12 | body * { 13 | -webkit-box-sizing: border-box; 14 | -moz-box-sizing: border-box; 15 | user-select: none; 16 | } 17 | 18 | body ul { 19 | list-style-type: none; 20 | margin: 0; 21 | padding: 0; 22 | 23 | -webkit-transform: translateZ(0px); 24 | } 25 | 26 | body ul li { 27 | float: left; 28 | width: 10%; 29 | height: 200px; 30 | padding-top: 128px; 31 | text-align: center; 32 | background-color: red; 33 | border-right: 1px solid black; 34 | overflow: hidden; 35 | 36 | -webkit-transform: matrix(1, 0, 0, 1, 0, -20); 37 | opacity: 0.5; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /test/css/extend.css: -------------------------------------------------------------------------------- 1 | body { 2 | position: absolute; 3 | width: 100%; 4 | margin: 0; 5 | font-family: Arial, sans-serif; 6 | font-size: 1.3em; 7 | background-color: #000; 8 | color: #fff; 9 | } 10 | #square { 11 | background-color: #550000; 12 | width: 200px; 13 | height: 200px; 14 | } 15 | #square:active { 16 | background-color: #aa0000; 17 | } 18 | -------------------------------------------------------------------------------- /test/events.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Events - Framework Tests 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 145 | 146 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /test/ext-animation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CSS Animations test | v0.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
#1
20 |
#2
0
21 |
#3
22 |
#4
23 |
#5
24 |
25 | 26 |
27 |
    28 |
  1. #1 fades-in continously
  2. 29 |
  3. #2 dissapears and fades-in 1s after click + counter increases
  4. 30 |
  5. #3 rotates 90deg on 1st click and back on 2nd
  6. 31 |
  7. #4 dissapears then rotates/fades back in on click
  8. 32 |
  9. #5 turns to blue and back to red on click
  10. 33 |
34 |
35 | 36 |
37 | 38 | 44 | 45 |
46 | 47 | 100 | 101 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /test/extend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DomExtend - Framework Tests 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 44 | 45 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /test/frame-impulse.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FrameImpulse 5 | 6 | 7 | 8 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 53 | 54 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /test/gesture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0.1 Virtual scroll demo - simple 5 | 6 | 7 | 8 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 58 | 59 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /test/history.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Framework - History Router 5 | 6 | 7 | 8 | 46 | 47 | 48 | 49 | 50 |
51 | 66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /test/iecon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tap handling on mobile 5 | 6 | 7 | 8 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 57 | 58 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/less/animation-api.less: -------------------------------------------------------------------------------- 1 | body { 2 | position: absolute; 3 | width: 100%; 4 | height: 100%; 5 | 6 | margin: 0; 7 | 8 | font-family: Arial, sans-serif; 9 | font-size: 1.3em; 10 | background-color: #000; 11 | color: #fff; 12 | 13 | * { 14 | -webkit-box-sizing: border-box; 15 | -moz-box-sizing: border-box; 16 | user-select: none; 17 | } 18 | 19 | #stats { 20 | position: absolute; 21 | bottom: 0; 22 | left: 0; 23 | } 24 | 25 | ul { 26 | list-style-type: none; 27 | margin: 0; 28 | padding: 0; 29 | 30 | li { 31 | float: left; 32 | width: 10%; 33 | height: 200px; 34 | padding-top: 128px; 35 | text-align: center; 36 | background-color: red; 37 | border-right: 1px solid black; 38 | } 39 | } 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/less/css-flip.less: -------------------------------------------------------------------------------- 1 | .row { 2 | 3 | width: 100%; 4 | 5 | .outer { 6 | 7 | position: relative; 8 | display: inline-block; 9 | float: left; 10 | -webkit-perspective: 600; 11 | perspective: 600; 12 | 13 | .holder { 14 | position: relative; 15 | width: 200px; 16 | height: 200px; 17 | 18 | .content { 19 | opacity: 0; 20 | transform-origin: 30% 50%; 21 | -webkit-transform-origin: 30% 50%; 22 | position: absolute; 23 | width: 200px; 24 | height: 200px; 25 | background: black; 26 | } 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/less/extend.less: -------------------------------------------------------------------------------- 1 | //@import "lesshat"; 2 | //@opera: false; 3 | 4 | body { 5 | position: absolute; 6 | width: 100%; 7 | margin: 0; 8 | 9 | font-family: Arial, sans-serif; 10 | font-size: 1.3em; 11 | background-color: #000; 12 | color: #fff; 13 | } 14 | 15 | #square { 16 | background-color: #550000; 17 | width: 200px; 18 | height: 200px; 19 | //.transition(~"transform 0.3s ease"); 20 | } 21 | 22 | #square:active { 23 | background-color: #aa0000; 24 | } -------------------------------------------------------------------------------- /test/nthchild-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CSS Animations test | v0.2 5 | 6 | 7 | 8 | 43 | 44 | 45 | 46 | 47 |