├── .gitignore ├── Gruntfile.js ├── LICENSE.txt ├── README.md ├── animator ├── animator.js └── bin │ └── animator.min.js ├── gestureadapter ├── bin │ ├── gestureadapter-combined.min.js │ └── gestureadapter.min.js └── gestureadapter.js ├── listview ├── bin │ ├── listview-combined.min.js │ └── listview.min.js ├── example │ ├── assets │ │ ├── img_0.jpeg │ │ ├── img_1.jpeg │ │ ├── img_2.jpeg │ │ ├── img_3.jpeg │ │ ├── img_4.jpeg │ │ ├── img_5.jpeg │ │ ├── img_6.jpeg │ │ ├── img_7.jpeg │ │ ├── img_8.jpeg │ │ └── img_9.jpeg │ └── index.html └── listview.js ├── objectpool ├── bin │ └── objectpool.min.js └── objectpool.js ├── package.json ├── pubsub ├── bin │ └── pubsub.min.js └── pubsub.js ├── scrollbar └── scrollbar.js ├── scrollview ├── bin │ ├── scrollview-combined.min.js │ └── scrollview.min.js ├── examples │ ├── horizontal.html │ └── vertical.html └── scrollview.js ├── servicelocator ├── bin │ └── servicelocator.min.js └── servicelocator.js └── utils ├── bin └── utils.min.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.idea/* 3 | nbproject/ 4 | *nbproject/* 5 | .DS_Store 6 | .DS_STORE 7 | node_modules -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | var timer = require("grunt-timer"); 2 | 3 | module.exports = function (grunt) { 4 | timer.init(grunt); 5 | 6 | grunt.loadNpmTasks('grunt-contrib-concat'); 7 | grunt.loadNpmTasks('grunt-contrib-uglify'); 8 | grunt.loadNpmTasks('grunt-contrib-clean'); 9 | 10 | grunt.initConfig({ 11 | concat: { 12 | listview: { 13 | src: ['utils/utils.js', 14 | 'objectpool/objectpool.js', 15 | 'listview/listview.js', 16 | 'gestureadapter/gestureadapter.js', 17 | 'animator/animator.js', 18 | 'scrollview/scrollview.js'], 19 | dest: 'listview/bin/listview-combined.min.js' 20 | }, 21 | scrollview: { 22 | src: ['utils/utils.js', 23 | 'animator/animator.js', 24 | 'objectpool/objectpool.js', 25 | 'gestureadapter/gestureadapter.js', 26 | 'scrollview/scrollview.js'], 27 | dest: 'scrollview/bin/scrollview-combined.min.js' 28 | }, 29 | gestureadapter: { 30 | src: ['objectpool/objectpool.js', 31 | 'gestureadapter/gestureadapter.js'], 32 | dest: 'gestureadapter/bin/gestureadapter-combined.min.js' 33 | } 34 | }, 35 | 36 | uglify: { 37 | animator: { 38 | src: ['animator/animator.js'], 39 | dest: 'animator/bin/animator.min.js' 40 | }, 41 | gestureadapter: { 42 | src: ['gestureadapter/gestureadapter.js'], 43 | dest: 'gestureadapter/bin/gestureadapter.min.js' 44 | }, 45 | gestureadaptercombined: { 46 | src: ['gestureadapter/bin/gestureadapter-combined.min.js'], 47 | dest: 'gestureadapter/bin/gestureadapter-combined.min.js' 48 | }, 49 | listview: { 50 | src: ['listview/listview.js'], 51 | dest: 'listview/bin/listview.min.js' 52 | }, 53 | listviewcombined: { 54 | src: ['listview/bin/listview-combined.min.js'], 55 | dest: 'listview/bin/listview-combined.min.js' 56 | }, 57 | objectpool: { 58 | src: ['objectpool/objectpool.js'], 59 | dest: 'objectpool/bin/objectpool.min.js' 60 | }, 61 | scrollview: { 62 | src: ['scrollview/scrollview.js'], 63 | dest: 'scrollview/bin/scrollview.min.js' 64 | }, 65 | scrollviewcombined: { 66 | src: ['scrollview/bin/scrollview-combined.min.js'], 67 | dest: 'scrollview/bin/scrollview-combined.min.js' 68 | }, 69 | utils: { 70 | src: ['utils/utils.js'], 71 | dest: 'utils/bin/utils.min.js' 72 | }, 73 | servicelocator: { 74 | src: ['servicelocator/servicelocator.js'], 75 | dest: 'servicelocator/bin/servicelocator.min.js' 76 | }, 77 | pubsub: { 78 | src: ['pubsub/pubsub.js'], 79 | dest: 'pubsub/bin/pubsub.min.js' 80 | } 81 | }, 82 | 83 | clean: { 84 | animator: { 85 | src: ['animator/bin/animator.min.js'] 86 | }, 87 | gestureadapter: { 88 | src: ['gestureadapter/bin/gestureadapter.min.js', 'gestureadapter/bin/gestureadapter-combined.min.js'] 89 | }, 90 | listview: { 91 | src: ['listview/bin/listview.min.js', 'listview/bin/listview-combined.min.js'] 92 | }, 93 | objectpool: { 94 | src: ['objectpool/bin/objectpool.min.js'] 95 | }, 96 | scrollview: { 97 | scr: ['scrollview/bin/scrollview.min.js', 'scrollview/bin/scrollview-combined.min.js'] 98 | }, 99 | utils: { 100 | src: ['utils/bin/utils.min.js'] 101 | }, 102 | servicelocator: { 103 | src: ['servicelocator/bin/servicelocator.min.js'] 104 | }, 105 | pubsub: { 106 | src: ['pubsub/bin/pubsub.min.js'] 107 | } 108 | } 109 | }); 110 | 111 | 112 | grunt.registerTask('build-animator', ['clean:animator', 'uglify:animator']); 113 | grunt.registerTask('build-gestureadapter', ['clean:gestureadapter', 'concat:gestureadapter', 'uglify:gestureadapter']); 114 | grunt.registerTask('build-listview', ['clean:listview', 'uglify:listview', 'concat:listview', 'uglify:listviewcombined']); 115 | grunt.registerTask('build-objectpool', ['clean:objectpool', 'uglify:objectpool']); 116 | grunt.registerTask('build-scrollview', ['clean:scrollview', 'uglify:scrollview', 'concat:scrollview', 'uglify:scrollviewcombined']); 117 | grunt.registerTask('build-utils', ['clean:utils', 'uglify:utils']); 118 | grunt.registerTask('build-servicelocator', ['clean:servicelocator', 'uglify:servicelocator']); 119 | grunt.registerTask('build-pubsub', ['clean:pubsub', 'uglify:pubsub']); 120 | 121 | grunt.registerTask('build', [ 122 | 'build-animator', 123 | 'build-gestureadapter', 124 | 'build-listview', 125 | 'build-objectpool', 126 | 'build-scrollview', 127 | 'build-utils', 128 | 'build-servicelocator', 129 | 'build-pubsub' 130 | ]); 131 | }; -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Mobidev Corp. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software under the following conditions: 8 | Mobidev Corp. reserves the right to specify in any matter without any limitations 9 | - the Publishers/Distributors which use "Software" in their products; 10 | - products which contain "Software"; 11 | - sources containing "Software" 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RAD.JS-toolkit 2 | ============== 3 | 4 | Rapid Application Development javascript (RAD.js) Toolkit 5 | *** 6 | We reached the goal of creating a toolkit where each tool can be used separately for its specific tasks. 7 | We upgrade [RAD.js](http://rad-js.com/ "rad-js.com") and split its functionality into independent modules, in order to make a good start for development of a toolkit (including frequently used UI widgets) for the most common tasks in mobile, web, and cross-platform development. 8 | 9 | -------------------------------------------------------------------------------- /animator/animator.js: -------------------------------------------------------------------------------- 1 | window.performance = window.performance || {}; 2 | window.performance.now = (function () { 3 | return performance.now || 4 | performance.mozNow || 5 | performance.msNow || 6 | performance.oNow || 7 | performance.webkitNow || 8 | function () { 9 | return new Date().getTime(); 10 | }; 11 | }()); 12 | 13 | (function () { 14 | var lastTime = 0, x, currTime, timeToCall, id, vendors = ['ms', 'moz', 'webkit', 'o']; 15 | for (x = 0; x < vendors.length && !window.requestAnimationFrame; x += 1) { 16 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; 17 | window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] 18 | || window[vendors[x] + 'CancelRequestAnimationFrame']; 19 | } 20 | 21 | if (!window.requestAnimationFrame) { 22 | window.requestAnimationFrame = function (callback) { 23 | currTime = window.performance.now(); 24 | timeToCall = Math.max(0, 16 - (currTime - lastTime)); 25 | id = window.setTimeout(function () { 26 | callback(currTime + timeToCall); 27 | }, timeToCall); 28 | lastTime = currTime + timeToCall; 29 | return id; 30 | }; 31 | } 32 | 33 | if (!window.cancelAnimationFrame) { 34 | window.cancelAnimationFrame = function (id) { 35 | clearTimeout(id); 36 | }; 37 | } 38 | }()); 39 | 40 | function Animator(o) { 41 | var easing = (o && o.easing) ? o.easing : null, 42 | boundsEasing = (o && o.boundsEasing) ? o.boundsEasing : null; 43 | 44 | this.isTweaking = false; 45 | this.isAnimating = false; 46 | 47 | this._easing = (typeof easing === 'function') ? easing : this[easing]; 48 | this._bounds = (o && o.bounds) ? true : false; 49 | this._boundsEasing = (typeof boundsEasing === 'function') ? boundsEasing : this[boundsEasing]; 50 | this._keepAbsoluteMetrics = (o && o.keepAbsoluteMetrics) ? true : false; 51 | 52 | if (this._bounds) { 53 | this.checkBounds = function (position) { 54 | this._lastPosition = this._lastPosition || position; 55 | if (position < this.minPosition) { 56 | position = this._lastPosition + (position - this._lastPosition) / 3; 57 | } 58 | 59 | if (position > this.maxPosition) { 60 | position = this._lastPosition + (position - this._lastPosition) / 3; 61 | } 62 | 63 | this._lastPosition = position; 64 | return position; 65 | }; 66 | } else { 67 | this.checkBounds = function (position) { 68 | if (position < this.minPosition) { 69 | position = this.minPosition; 70 | } 71 | 72 | if (position > this.maxPosition) { 73 | position = this.maxPosition; 74 | } 75 | return position; 76 | }; 77 | } 78 | } 79 | 80 | Animator.prototype = (function () { 81 | var proto = {}, 82 | STRINGS = { 83 | animation: "animation", 84 | stop: "stop", 85 | tweak: "tweak" 86 | }; 87 | 88 | /* 89 | * Easing Functions - inspired from http://gizma.com/easing/ 90 | * only considering the t value for the range [0, 1] => [0, 1] 91 | */ 92 | 93 | // no easing, no acceleration 94 | proto.linear = function (t) { 95 | return t 96 | }; 97 | 98 | // accelerating from zero velocity 99 | proto.easeInQuad = function (t) { 100 | return t * t 101 | }; 102 | 103 | // decelerating to zero velocity 104 | proto.easeOutQuad = function (t) { 105 | return t * (2 - t) 106 | }; 107 | 108 | // decelerating to zero velocity 109 | proto.easeOutSin = function (t) { 110 | return Math.sin(t * Math.PI / 2); 111 | }; 112 | 113 | // acceleration until halfway, then deceleration 114 | proto.easeInOutQuad = function (t) { 115 | return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t 116 | }; 117 | 118 | // accelerating from zero velocity 119 | proto.easeInCubic = function (t) { 120 | return t * t * t 121 | }; 122 | 123 | // decelerating to zero velocity 124 | proto.easeOutCubic = function (t) { 125 | return (--t) * t * t + 1 126 | }; 127 | 128 | // acceleration until halfway, then deceleration 129 | proto.easeInOutCubic = function (t) { 130 | return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 131 | }; 132 | 133 | // accelerating from zero velocity 134 | proto.easeInQuart = function (t) { 135 | return t * t * t * t 136 | }; 137 | 138 | // decelerating to zero velocity 139 | proto.easeOutQuart = function (t) { 140 | return 1 - (--t) * t * t * t 141 | }; 142 | 143 | // acceleration until halfway, then deceleration 144 | proto.easeInOutQuart = function (t) { 145 | return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t 146 | }; 147 | 148 | // accelerating from zero velocity 149 | proto.easeInQuint = function (t) { 150 | return t * t * t * t * t 151 | }; 152 | 153 | // decelerating to zero velocity 154 | proto.easeOutQuint = function (t) { 155 | return 1 + (--t) * t * t * t * t 156 | }; 157 | 158 | // acceleration until halfway, then deceleration 159 | proto.easeInOutQuint = function (t) { 160 | return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t 161 | }; 162 | 163 | // key spline animation 164 | proto.KeySpline = function (mX1, mY1, mX2, mY2) { 165 | 166 | function a(aA1, aA2) { 167 | return 1.0 - 3.0 * aA2 + 3.0 * aA1; 168 | } 169 | 170 | function b(aA1, aA2) { 171 | return 3.0 * aA2 - 6.0 * aA1; 172 | } 173 | 174 | function c(aA1) { 175 | return 3.0 * aA1; 176 | } 177 | 178 | // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. 179 | function calculateBezier(aT, aA1, aA2) { 180 | return ((a(aA1, aA2) * aT + b(aA1, aA2)) * aT + c(aA1)) * aT; 181 | } 182 | 183 | // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. 184 | function getSlope(aT, aA1, aA2) { 185 | return 3.0 * a(aA1, aA2) * aT * aT + 2.0 * b(aA1, aA2) * aT + c(aA1); 186 | } 187 | 188 | function getTForX(aX) { 189 | // Newton raphson iteration 190 | var aGuessT = aX; 191 | for (var i = 0; i < 4; ++i) { 192 | var currentSlope = getSlope(aGuessT, mX1, mX2); 193 | if (currentSlope == 0.0) return aGuessT; 194 | var currentX = calculateBezier(aGuessT, mX1, mX2) - aX; 195 | aGuessT -= currentX / currentSlope; 196 | } 197 | return aGuessT; 198 | } 199 | 200 | return function (aX) { 201 | if (mX1 == mY1 && mX2 == mY2) return aX; // linear 202 | return calculateBezier(getTForX(aX), mY1, mY2); 203 | }; 204 | }; 205 | // ==================================================================================================== 206 | 207 | proto.animate = function (startPosition, endPosition, duration, callback, easing) { 208 | var startTimestamp, firstIteration = true, tmpVariable, tmpTime, self = this, easingFunction, 209 | lastIteraction = false, state = this.isTweaking ? STRINGS.tweak : STRINGS.animation, tmpPosition; 210 | 211 | /* Prevent scrolling to the Y point if already there */ 212 | if (startPosition === endPosition) { 213 | return; 214 | } 215 | easingFunction = (typeof easing === 'function') ? easing : ((typeof easing === 'string') ? this[easing] : this._easing); 216 | this.isAnimating = true; 217 | this._callback = callback; 218 | 219 | function animationStep(currentTimestamp) { 220 | tmpVariable = ((currentTimestamp - startTimestamp) / duration); 221 | tmpTime = (1 < tmpVariable) ? 1 : tmpVariable; 222 | 223 | if ((tmpTime < 1 || !startTimestamp) && self.isAnimating) { 224 | self._animationID = window.requestAnimationFrame(animationStep, null); 225 | } 226 | 227 | // if it is first iteration, save timestamp and return 228 | if (firstIteration) { 229 | startTimestamp = currentTimestamp; 230 | firstIteration = false; 231 | return; 232 | } 233 | 234 | // calculate new position 235 | self._currentPosition = (easingFunction(tmpTime) * (endPosition - startPosition)) + startPosition; 236 | 237 | // stop animation if time ends 238 | if (tmpTime >= 1) { 239 | lastIteraction = true; 240 | self.isTweaking = false; 241 | self.isAnimating = false; 242 | self._currentPosition = Math.round(self._currentPosition); 243 | 244 | state = STRINGS.stop; 245 | } 246 | 247 | // check bounds behavior 248 | if (self._bounds) { 249 | var delta = 0; 250 | if (self._currentPosition < self.minPosition) { 251 | delta = self._currentPosition - self.minPosition; 252 | } 253 | 254 | if (self._currentPosition > self.maxPosition) { 255 | delta = self._currentPosition - self.maxPosition; 256 | } 257 | 258 | if (delta) { 259 | if (!self.isTweaking) { 260 | if ((Math.abs(delta) > self.margin) || !self.isAnimating) { 261 | self.stop(); 262 | self.isTweaking = true; 263 | self.animate(self._currentPosition, self._currentPosition - delta, Math.min(Math.abs(delta) * 2, 350), self._callback, self._boundsEasing || 'easeOutQuad'); 264 | state = STRINGS.tweak; 265 | } 266 | } 267 | } 268 | } else { 269 | tmpPosition = self.checkBounds(self._currentPosition); 270 | if (tmpPosition !== self._currentPosition) { 271 | lastIteraction = true; 272 | self.isTweaking = false; 273 | self.isAnimating = false; 274 | tmpPosition = Math.round(tmpPosition); 275 | 276 | state = STRINGS.stop; 277 | } 278 | self._currentPosition = tmpPosition; 279 | } 280 | 281 | 282 | // setup new position 283 | callback(self._currentPosition, lastIteraction, state); 284 | } 285 | 286 | window.requestAnimationFrame(animationStep, null); 287 | }; 288 | 289 | proto.FRICTION = 0.000025; 290 | 291 | proto.startFling = function (startPosition, velocity, callback) { 292 | var duration, shift, newShift, flag = false, sign = velocity && velocity / Math.abs(velocity), friction = this.FRICTION; 293 | 294 | if (!this.DPI && !this._keepAbsoluteMetrics) { 295 | calculateScreenDPI(); 296 | } 297 | 298 | 299 | if (!this._keepAbsoluteMetrics) { 300 | friction = this.FRICTION * this.DPI; 301 | } 302 | 303 | duration = Math.abs(velocity) / friction; 304 | shift = sign * velocity * velocity / friction; 305 | if (this._bounds) { 306 | if (startPosition + shift < this.minPosition - this.margin) { 307 | newShift = this.minPosition - this.margin/2 - startPosition; 308 | flag = true; 309 | } 310 | 311 | if (startPosition + shift > this.maxPosition + this.margin) { 312 | newShift = this.maxPosition + this.margin/2 - startPosition; 313 | flag = true; 314 | } 315 | if (flag) { 316 | duration = duration * newShift / shift; 317 | shift = newShift; 318 | } 319 | } 320 | 321 | this.animate(startPosition, startPosition + shift, duration, callback); 322 | }; 323 | 324 | proto.tweakIfNeeded = function (position, callback) { 325 | var delta = 0; 326 | if (this.isAnimating) { 327 | return; 328 | } 329 | 330 | if (position < this.minPosition) { 331 | delta = position - this.minPosition; 332 | } 333 | if (position > this.maxPosition) { 334 | delta = position - this.maxPosition; 335 | } 336 | 337 | if (delta) { 338 | this.isTweaking = true; 339 | this.animate(position, position - delta, Math.min(Math.abs(delta) * 2, 350), callback, this._boundsEasing || 'easeOutQuad'); 340 | } 341 | }; 342 | 343 | proto.setBounds = function (min, max, margin) { 344 | this.minPosition = min; 345 | this.maxPosition = max; 346 | this.margin = margin || 0; 347 | }; 348 | 349 | proto.inBounds = function (position) { 350 | return (position >= this.minPosition) && (position <= this.maxPosition); 351 | }; 352 | 353 | proto.isStopped = function () { 354 | return !this.isAnimating; 355 | }; 356 | 357 | proto.stop = function () { 358 | if (this.isAnimating) { 359 | window.cancelAnimationFrame(this._animationID); 360 | this.isAnimating = false; 361 | 362 | if (typeof this._callback === "function") { 363 | this._currentPosition = Math.round(this._currentPosition); 364 | this._callback(this._currentPosition, true, STRINGS.stop); 365 | } 366 | } 367 | }; 368 | 369 | // =============================== prepare constants ====================================== 370 | function calculateScreenDPI() { 371 | var stub = document.createElement('div'); 372 | 373 | stub.style.position = 'absolute'; 374 | stub.style.height = '1in'; 375 | stub.style.width = '1in'; 376 | stub.style.left = '-100%'; 377 | stub.style.top = '-100%'; 378 | 379 | document.body.appendChild(stub); 380 | proto.DPI = stub.offsetHeight; 381 | document.body.removeChild(stub); 382 | 383 | window.removeEventListener('load', calculateScreenDPI); 384 | } 385 | 386 | window.addEventListener('load', calculateScreenDPI, false); 387 | // ======================================================================================== 388 | 389 | return proto; 390 | })(); -------------------------------------------------------------------------------- /animator/bin/animator.min.js: -------------------------------------------------------------------------------- 1 | function Animator(a){var b=a&&a.easing?a.easing:null,c=a&&a.boundsEasing?a.boundsEasing:null;this.isTweaking=!1,this.isAnimating=!1,this._easing="function"==typeof b?b:this[b],this._bounds=a&&a.bounds?!0:!1,this._boundsEasing="function"==typeof c?c:this[c],this._keepAbsoluteMetrics=a&&a.keepAbsoluteMetrics?!0:!1,this.checkBounds=this._bounds?function(a){return this._lastPosition=this._lastPosition||a,athis.maxPosition&&(a=this._lastPosition+(a-this._lastPosition)/3),this._lastPosition=a,a}:function(a){return athis.maxPosition&&(a=this.maxPosition),a}}window.performance=window.performance||{},window.performance.now=function(){return performance.now||performance.mozNow||performance.msNow||performance.oNow||performance.webkitNow||function(){return(new Date).getTime()}}(),function(){var a,b,c,d,e=0,f=["ms","moz","webkit","o"];for(a=0;aa?2*a*a:-1+(4-2*a)*a},b.easeInCubic=function(a){return a*a*a},b.easeOutCubic=function(a){return--a*a*a+1},b.easeInOutCubic=function(a){return.5>a?4*a*a*a:(a-1)*(2*a-2)*(2*a-2)+1},b.easeInQuart=function(a){return a*a*a*a},b.easeOutQuart=function(a){return 1- --a*a*a*a},b.easeInOutQuart=function(a){return.5>a?8*a*a*a*a:1-8*--a*a*a*a},b.easeInQuint=function(a){return a*a*a*a*a},b.easeOutQuint=function(a){return 1+--a*a*a*a*a},b.easeInOutQuint=function(a){return.5>a?16*a*a*a*a*a:1+16*--a*a*a*a*a},b.KeySpline=function(a,b,c,d){function e(a,b){return 1-3*b+3*a}function f(a,b){return 3*b-6*a}function g(a){return 3*a}function h(a,b,c){return((e(b,c)*a+f(b,c))*a+g(b))*a}function i(a,b,c){return 3*e(b,c)*a*a+2*f(b,c)*a+g(b)}function j(b){for(var d=b,e=0;4>e;++e){var f=i(d,a,c);if(0==f)return d;var g=h(d,a,c)-b;d-=g/f}return d}return function(e){return a==b&&c==d?e:h(j(e),b,d)}},b.animate=function(a,b,d,e,f){function g(f){if(i=(f-h)/d,j=i>1?1:i,(1>j||!h)&&n.isAnimating&&(n._animationID=window.requestAnimationFrame(g,null)),m)return h=f,void(m=!1);if(n._currentPosition=k(j)*(b-a)+a,j>=1&&(o=!0,n.isTweaking=!1,n.isAnimating=!1,n._currentPosition=Math.round(n._currentPosition),p=c.stop),n._bounds){var q=0;n._currentPositionn.maxPosition&&(q=n._currentPosition-n.maxPosition),q&&(n.isTweaking||(Math.abs(q)>n.margin||!n.isAnimating)&&(n.stop(),n.isTweaking=!0,n.animate(n._currentPosition,n._currentPosition-q,Math.min(2*Math.abs(q),350),n._callback,n._boundsEasing||"easeOutQuad"),p=c.tweak))}else l=n.checkBounds(n._currentPosition),l!==n._currentPosition&&(o=!0,n.isTweaking=!1,n.isAnimating=!1,l=Math.round(l),p=c.stop),n._currentPosition=l;e(n._currentPosition,o,p)}var h,i,j,k,l,m=!0,n=this,o=!1,p=this.isTweaking?c.tweak:c.animation;a!==b&&(k="function"==typeof f?f:"string"==typeof f?this[f]:this._easing,this.isAnimating=!0,this._callback=e,window.requestAnimationFrame(g,null))},b.FRICTION=25e-6,b.startFling=function(b,c,d){var e,f,g,h=!1,i=c&&c/Math.abs(c),j=this.FRICTION;this.DPI||this._keepAbsoluteMetrics||a(),this._keepAbsoluteMetrics||(j=this.FRICTION*this.DPI),e=Math.abs(c)/j,f=i*c*c/j,this._bounds&&(b+fthis.maxPosition+this.margin&&(g=this.maxPosition+this.margin/2-b,h=!0),h&&(e=e*g/f,f=g)),this.animate(b,b+f,e,d)},b.tweakIfNeeded=function(a,b){var c=0;this.isAnimating||(athis.maxPosition&&(c=a-this.maxPosition),c&&(this.isTweaking=!0,this.animate(a,a-c,Math.min(2*Math.abs(c),350),b,this._boundsEasing||"easeOutQuad")))},b.setBounds=function(a,b,c){this.minPosition=a,this.maxPosition=b,this.margin=c||0},b.inBounds=function(a){return a>=this.minPosition&&a<=this.maxPosition},b.isStopped=function(){return!this.isAnimating},b.stop=function(){this.isAnimating&&(window.cancelAnimationFrame(this._animationID),this.isAnimating=!1,"function"==typeof this._callback&&(this._currentPosition=Math.round(this._currentPosition),this._callback(this._currentPosition,!0,c.stop)))},window.addEventListener("load",a,!1),b}(); -------------------------------------------------------------------------------- /gestureadapter/bin/gestureadapter-combined.min.js: -------------------------------------------------------------------------------- 1 | function Pool(Constructor, count, releaseFnName) { 2 | var objects = {}, quantity = 0, freeObjects = [], usedObjects = [], 3 | fn = (typeof releaseFnName === 'string') ? releaseFnName : 'release'; 4 | 5 | function create(id) { 6 | var obj; 7 | obj = new Constructor(); 8 | obj[fn] = function () { 9 | var i; 10 | freeObjects.push(id); 11 | 12 | // remove id from used array 13 | i = usedObjects.indexOf(id); 14 | usedObjects[i] = usedObjects[usedObjects.length -1]; 15 | usedObjects.length -= 1; 16 | }; 17 | objects[id] = obj; 18 | return id; 19 | } 20 | 21 | function allocate(count) { 22 | var i, l; 23 | for (i = 0, l = count; i < l; i++) { 24 | create(i); 25 | quantity++; 26 | freeObjects.push(i); 27 | } 28 | } 29 | 30 | this.get = function () { 31 | var id; 32 | if (freeObjects.length > 0) { 33 | id = freeObjects.pop(); 34 | } else { 35 | id = create(quantity); 36 | quantity++; 37 | } 38 | usedObjects.push(id); 39 | 40 | return objects[id]; 41 | }; 42 | 43 | allocate(count); 44 | return this; 45 | } 46 | 47 | function GestureAdapter(element, listener) { 48 | var adapter = this; 49 | 50 | adapter.destroy = function () { 51 | if (!adapter.isTouched) { 52 | clearTimeout(adapter.mouseWheelTimeout); 53 | 54 | adapter._el.removeEventListener('mousedown', this); 55 | adapter._el.removeEventListener('mouseup', this); 56 | adapter._el.removeEventListener('mousemove', this); 57 | adapter._el.removeEventListener('mouseout', this); 58 | 59 | // mouse event 60 | // IE9, Chrome, Safari, Opera 61 | adapter._el.removeEventListener("mousewheel", adapter); 62 | // Firefox 63 | adapter._el.removeEventListener("DOMMouseScroll", adapter); 64 | } else { 65 | adapter._el.removeEventListener('touchstart', this); 66 | adapter._el.removeEventListener('touchend', this); 67 | adapter._el.removeEventListener('touchmove', this); 68 | adapter._el.removeEventListener('touchcancel', this); 69 | } 70 | delete adapter._el; 71 | delete adapter._listener; 72 | }; 73 | 74 | adapter._el = element; 75 | adapter._listener = listener; 76 | adapter._tmpCoords = {}; 77 | 78 | if (!adapter.isTouched) { 79 | adapter._el.addEventListener('mousedown', adapter, false); 80 | adapter._el.addEventListener('mouseup', adapter, false); 81 | adapter._el.addEventListener('mousemove', adapter, false); 82 | adapter._el.addEventListener('mouseout', adapter, false); 83 | adapter._el.addEventListener('mouseover', adapter, false); 84 | 85 | // mouse event 86 | // IE9, Chrome, Safari, Opera 87 | adapter._el.addEventListener("mousewheel", adapter, false); 88 | // Firefox 89 | adapter._el.addEventListener("DOMMouseScroll", adapter, false); 90 | } else { 91 | adapter._el.addEventListener('touchstart', adapter, false); 92 | adapter._el.addEventListener('touchend', adapter, false); 93 | adapter._el.addEventListener('touchmove', adapter, false); 94 | adapter._el.addEventListener('touchcancel', adapter, false); 95 | } 96 | 97 | return adapter; 98 | } 99 | 100 | GestureAdapter.prototype = (function () { 101 | var STRINGS = { 102 | touchstart: "touchstart", 103 | touchmove: "touchmove", 104 | touchend: "touchend", 105 | touchleave: "touchleave", 106 | touchcancel: ".touchcancel", 107 | mousedown: "mousedown", 108 | mousemove: "mousemove", 109 | mouseup: "mouseup", 110 | mouseover: "mouseover", 111 | mouseout: "mouseout", 112 | mousewheel: "mousewheel", 113 | wheel: "DOMMouseScroll", 114 | horizontal: "horizontal", 115 | vertical: "vertical", 116 | fling: "fling", 117 | tap: "tap", 118 | longtap: "longtap", 119 | pointerdown: "pointerdown", 120 | pointermove: "pointermove", 121 | pointerup: "pointerup" 122 | }, 123 | touch = ('ontouchstart' in window), 124 | eventPool = new Pool(function () { 125 | }, 100), 126 | flingPool = new Pool(function () { 127 | this.start = {}; 128 | this.end = {}; 129 | }, 10), 130 | extractCoord = (function () { 131 | if (touch) 132 | return function (e, cntx) { 133 | var touchEvent, i, l; 134 | 135 | if (e.type === STRINGS.touchstart) { 136 | if (e.touches.length > 1){ 137 | return; 138 | } 139 | touchEvent = e.touches[0]; 140 | cntx.touchID = e.touches[0].identifier; 141 | } else { 142 | for (i = 0, l = e.changedTouches.length; i < l; i ++) { 143 | touchEvent = e.changedTouches[i]; 144 | if (touchEvent.identifier === cntx.touchID) { 145 | break; 146 | } 147 | } 148 | if (touchEvent.identifier !== cntx.touchID){ 149 | return; 150 | } 151 | } 152 | 153 | cntx._tmpCoords.screenX = touchEvent.screenX; 154 | cntx._tmpCoords.screenY = touchEvent.screenY; 155 | cntx._tmpCoords.clientX = touchEvent.clientX; 156 | cntx._tmpCoords.clientY = touchEvent.clientY; 157 | return cntx._tmpCoords; 158 | }; 159 | 160 | return function (e, cntx) { 161 | cntx._tmpCoords.screenX = e.screenX; 162 | cntx._tmpCoords.screenY = e.screenY; 163 | cntx._tmpCoords.clientX = e.clientX; 164 | cntx._tmpCoords.clientY = e.clientY; 165 | return cntx._tmpCoords; 166 | }; 167 | })(); 168 | 169 | function saveLastPoint(e, cntx) { 170 | if (e.timeStamp - cntx.preLastMove.timeStamp > 10) { 171 | var coords = extractCoord(e, cntx); 172 | if (!coords) { 173 | return; 174 | } 175 | 176 | cntx.lastMove.screenX = cntx.preLastMove.screenX; 177 | cntx.lastMove.screenY = cntx.preLastMove.screenY; 178 | cntx.lastMove.timeStamp = cntx.preLastMove.timeStamp; 179 | 180 | cntx.preLastMove.screenX = coords.screenX; 181 | cntx.preLastMove.screenY = coords.screenY; 182 | cntx.preLastMove.timeStamp = e.timeStamp; 183 | } 184 | } 185 | 186 | function getDirection(startX, startY, endX, endY) { 187 | if (Math.abs(startX - endX) > Math.abs(startY - endY)) { 188 | return STRINGS.horizontal; 189 | } 190 | return STRINGS.vertical; 191 | } 192 | 193 | function fireEvent(type, e, cntx) { 194 | var coords = extractCoord(e, cntx), event = eventPool.get(); 195 | if (!coords) { 196 | return; 197 | } 198 | event.type = type; 199 | event.clientX = coords.clientX; 200 | event.clientY = coords.clientY; 201 | event.screenX = coords.screenX; 202 | event.screenY = coords.screenY; 203 | event.timeStamp = e.timeStamp; 204 | event.origin = e; 205 | 206 | cntx._listener.handleEvent(event); 207 | } 208 | 209 | function getDirectionVelocity(lastX, lastY, lastTime, endX, endY, endTime) { 210 | if (Math.abs(lastX - endX) > Math.abs(lastY - endY)) { 211 | return (endX - lastX) / (endTime - lastTime); 212 | } else { 213 | return (endY - lastY) / (endTime - lastTime); 214 | } 215 | } 216 | 217 | function distance(x1, y1, x2, y2) { 218 | return Math.pow(((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)), 0.5); 219 | } 220 | 221 | function checkFling(e, cntx) { 222 | var coord = extractCoord(e, cntx), 223 | flingEvent; 224 | 225 | if (!coord) { 226 | return; 227 | } 228 | if ((Math.abs(distance(cntx.lastMove.screenX, cntx.lastMove.screenY, coord.screenX, coord.screenY) / (e.timeStamp - cntx.lastMove.timeStamp)) * 100) >> 0 > 0) { 229 | flingEvent = flingPool.get(); 230 | flingEvent.type = STRINGS.fling; 231 | //velocity (px/ms) in end point without considering direction 232 | flingEvent.velocity = distance(cntx.startX, cntx.startY, coord.screenX, coord.screenY) / (e.timeStamp - cntx.timeStamp); 233 | //fling direction ("vertical", "horizontal") 234 | flingEvent.direction = getDirection(cntx.startX, cntx.startY, coord.screenX, coord.screenY); 235 | //fling speed (px/ms) in end point along direction 236 | flingEvent.speed = getDirectionVelocity(cntx.startX, cntx.startY, cntx.timeStamp, coord.screenX, coord.screenY, e.timeStamp); 237 | 238 | flingEvent.start.screenX = cntx.startX; 239 | flingEvent.start.screenY = cntx.startY; 240 | flingEvent.start.clientX = cntx.startClientX; 241 | flingEvent.start.clientY = cntx.startClientY; 242 | flingEvent.start.timeStamp = cntx.timeStamp; 243 | 244 | flingEvent.end.screenX = coord.screenX; 245 | flingEvent.end.screenY = coord.screenY; 246 | flingEvent.end.clientX = coord.clientX; 247 | flingEvent.end.clientY = coord.clientY; 248 | flingEvent.end.timeStamp = e.timeStamp; 249 | 250 | cntx._listener.handleEvent(flingEvent); 251 | } 252 | } 253 | 254 | function onTouchStart(e, cntx) { 255 | var coords = extractCoord(e, cntx); 256 | if (!coords) { 257 | return; 258 | } 259 | cntx.startX = coords.screenX; 260 | cntx.startY = coords.screenY; 261 | cntx.startClientX = coords.clientX; 262 | cntx.startClientY = coords.clientY; 263 | cntx.timeStamp = e.timeStamp; 264 | cntx.moved = false; 265 | cntx.isDown = true; 266 | cntx.touchStartTime = e.timeStamp; 267 | 268 | cntx.lastMove = cntx.lastMove || {}; 269 | cntx.preLastMove = cntx.preLastMove || {}; 270 | 271 | cntx.lastMove.screenX = cntx.preLastMove.screenX = 0; 272 | cntx.lastMove.screenY = cntx.preLastMove.screenY = 0; 273 | cntx.lastMove.timeStamp = cntx.preLastMove.timeStamp = e.timeStamp; 274 | 275 | fireEvent(STRINGS.pointerdown, e, cntx); 276 | } 277 | 278 | function onTouchMove(e, cntx) { 279 | var coords = extractCoord(e, cntx); 280 | if (!coords) { 281 | return; 282 | } 283 | 284 | if (cntx.isDown) { 285 | saveLastPoint(e, cntx); 286 | fireEvent(STRINGS.pointermove, e, cntx); 287 | // 10px is tremor distance 288 | if ((Math.abs(coords.screenY - cntx.startY) > 10) || (Math.abs(coords.screenX - cntx.startX) > 10)) { 289 | cntx.moved = true; 290 | } 291 | } 292 | } 293 | 294 | function onTouchUp(e, cntx) { 295 | var duration = e.timeStamp - cntx.touchStartTime; 296 | 297 | if (cntx.isDown) { 298 | cntx.isDown = false; 299 | if (!cntx.moved) { 300 | // if touch duration is more then 300 ms - then it is long tap event 301 | if (duration <= 300) { 302 | fireEvent(STRINGS.tap, e, cntx); 303 | } else { 304 | fireEvent(STRINGS.longtap, e, cntx); 305 | } 306 | } else { 307 | checkFling(e, cntx); 308 | } 309 | fireEvent(STRINGS.pointerup, e, cntx); 310 | } 311 | } 312 | 313 | function onMouseOver(e, cntx) { 314 | clearTimeout(cntx.mouseOutTimeout); 315 | } 316 | 317 | function onMouseOut(e, cntx) { 318 | cntx.mouseOutTimeout = setTimeout(function () { 319 | onTouchUp(e, cntx); 320 | }, 10); 321 | } 322 | 323 | function onMouseWheel(e, cntx) { 324 | var startDelta = 10 * ((e.wheelDelta || -e.detail) > 0 ? 1 : -1); 325 | 326 | clearTimeout(cntx.mouseWheelTimeout); 327 | 328 | e.preventDefault(); 329 | e.stopPropagation(); 330 | 331 | e = { 332 | clientX: e.clientX, 333 | clientY: e.clientY, 334 | screenX: e.screenX, 335 | screenY: 0, 336 | timeStamp: e.timeStamp, 337 | 338 | preventDefault: function () { 339 | }, 340 | stopPropagation: function () { 341 | } 342 | }; 343 | 344 | if (!cntx.isDown) { 345 | cntx.isDown = true; 346 | cntx.moved = true; 347 | 348 | //special parameters for wheel 349 | cntx.useMouseWheel = true; 350 | cntx.currentWheelPosition = 0; 351 | cntx.acceleration = startDelta; 352 | 353 | onTouchStart(e, cntx); 354 | } 355 | 356 | cntx.acceleration *=1.2; 357 | cntx.currentWheelPosition += cntx.acceleration; 358 | e.screenY = cntx.currentWheelPosition; 359 | onTouchMove(e, cntx); 360 | 361 | cntx.mouseWheelTimeout = setTimeout(function(){ 362 | fireEvent(STRINGS.pointerup, e, cntx); 363 | cntx.isDown = false; 364 | cntx.moved = false; 365 | 366 | //special parameters for wheel 367 | cntx.useMouseWheel = false; 368 | }, 200); 369 | } 370 | 371 | return { 372 | isTouched: touch, 373 | 374 | handleEvent: function (event) { 375 | switch (event.type) { 376 | case STRINGS.touchmove: 377 | case STRINGS.mousemove: 378 | if (!this.useMouseWheel) 379 | onTouchMove(event, this); 380 | break; 381 | case STRINGS.touchstart: 382 | case STRINGS.mousedown: 383 | onTouchStart(event, this); 384 | break; 385 | case STRINGS.touchend: 386 | case STRINGS.touchleave: 387 | case STRINGS.touchcancel: 388 | case STRINGS.mouseup: 389 | onTouchUp(event, this); 390 | break; 391 | case STRINGS.mouseover: 392 | onMouseOver(event, this); 393 | break; 394 | case STRINGS.mouseout: 395 | onMouseOut(event, this); 396 | break; 397 | case STRINGS.wheel: 398 | case STRINGS.mousewheel: 399 | onMouseWheel(event, this); 400 | break; 401 | } 402 | } 403 | }; 404 | }()); -------------------------------------------------------------------------------- /gestureadapter/bin/gestureadapter.min.js: -------------------------------------------------------------------------------- 1 | function GestureAdapter(a,b){var c=this;return c.destroy=function(){c.isTouched?(c._el.removeEventListener("touchstart",this),c._el.removeEventListener("touchend",this),c._el.removeEventListener("touchmove",this),c._el.removeEventListener("touchcancel",this)):(clearTimeout(c.mouseWheelTimeout),c._el.removeEventListener("mousedown",this),c._el.removeEventListener("mouseup",this),c._el.removeEventListener("mousemove",this),c._el.removeEventListener("mouseout",this),c._el.removeEventListener("mousewheel",c),c._el.removeEventListener("DOMMouseScroll",c)),delete c._el,delete c._listener},c._el=a,c._listener=b,c._tmpCoords={},c.isTouched?(c._el.addEventListener("touchstart",c,!1),c._el.addEventListener("touchend",c,!1),c._el.addEventListener("touchmove",c,!1),c._el.addEventListener("touchcancel",c,!1)):(c._el.addEventListener("mousedown",c,!1),c._el.addEventListener("mouseup",c,!1),c._el.addEventListener("mousemove",c,!1),c._el.addEventListener("mouseout",c,!1),c._el.addEventListener("mouseover",c,!1),c._el.addEventListener("mousewheel",c,!1),c._el.addEventListener("DOMMouseScroll",c,!1)),c}GestureAdapter.prototype=function(){function a(a,b){if(a.timeStamp-b.preLastMove.timeStamp>10){var c=q(a,b);if(!c)return;b.lastMove.screenX=b.preLastMove.screenX,b.lastMove.screenY=b.preLastMove.screenY,b.lastMove.timeStamp=b.preLastMove.timeStamp,b.preLastMove.screenX=c.screenX,b.preLastMove.screenY=c.screenY,b.preLastMove.timeStamp=a.timeStamp}}function b(a,b,c,d){return Math.abs(a-c)>Math.abs(b-d)?m.horizontal:m.vertical}function c(a,b,c){var d=q(b,c),e=o.get();d&&(e.type=a,e.clientX=d.clientX,e.clientY=d.clientY,e.screenX=d.screenX,e.screenY=d.screenY,e.timeStamp=b.timeStamp,e.origin=b,c._listener.handleEvent(e))}function d(a,b,c,d,e,f){return Math.abs(a-d)>Math.abs(b-e)?(d-a)/(f-c):(e-b)/(f-c)}function e(a,b,c,d){return Math.pow((c-a)*(c-a)+(d-b)*(d-b),.5)}function f(a,c){var f,g=q(a,c);g&&100*Math.abs(e(c.lastMove.screenX,c.lastMove.screenY,g.screenX,g.screenY)/(a.timeStamp-c.lastMove.timeStamp))>>0>0&&(f=p.get(),f.type=m.fling,f.velocity=e(c.startX,c.startY,g.screenX,g.screenY)/(a.timeStamp-c.timeStamp),f.direction=b(c.startX,c.startY,g.screenX,g.screenY),f.speed=d(c.startX,c.startY,c.timeStamp,g.screenX,g.screenY,a.timeStamp),f.start.screenX=c.startX,f.start.screenY=c.startY,f.start.clientX=c.startClientX,f.start.clientY=c.startClientY,f.start.timeStamp=c.timeStamp,f.end.screenX=g.screenX,f.end.screenY=g.screenY,f.end.clientX=g.clientX,f.end.clientY=g.clientY,f.end.timeStamp=a.timeStamp,c._listener.handleEvent(f))}function g(a,b){var d=q(a,b);d&&(b.startX=d.screenX,b.startY=d.screenY,b.startClientX=d.clientX,b.startClientY=d.clientY,b.timeStamp=a.timeStamp,b.moved=!1,b.isDown=!0,b.touchStartTime=a.timeStamp,b.lastMove=b.lastMove||{},b.preLastMove=b.preLastMove||{},b.lastMove.screenX=b.preLastMove.screenX=0,b.lastMove.screenY=b.preLastMove.screenY=0,b.lastMove.timeStamp=b.preLastMove.timeStamp=a.timeStamp,c(m.pointerdown,a,b))}function h(b,d){var e=q(b,d);e&&d.isDown&&(a(b,d),c(m.pointermove,b,d),(Math.abs(e.screenY-d.startY)>10||Math.abs(e.screenX-d.startX)>10)&&(d.moved=!0))}function i(a,b){var d=a.timeStamp-b.touchStartTime;b.isDown&&(b.isDown=!1,b.moved?f(a,b):300>=d?c(m.tap,a,b):c(m.longtap,a,b),c(m.pointerup,a,b))}function j(a,b){clearTimeout(b.mouseOutTimeout)}function k(a,b){b.mouseOutTimeout=setTimeout(function(){i(a,b)},10)}function l(a,b){var d=10*((a.wheelDelta||-a.detail)>0?1:-1);clearTimeout(b.mouseWheelTimeout),a.preventDefault(),a.stopPropagation(),a={clientX:a.clientX,clientY:a.clientY,screenX:a.screenX,screenY:0,timeStamp:a.timeStamp,preventDefault:function(){},stopPropagation:function(){}},b.isDown||(b.isDown=!0,b.moved=!0,b.useMouseWheel=!0,b.currentWheelPosition=0,b.acceleration=d,g(a,b)),b.acceleration*=1.2,b.currentWheelPosition+=b.acceleration,a.screenY=b.currentWheelPosition,h(a,b),b.mouseWheelTimeout=setTimeout(function(){c(m.pointerup,a,b),b.isDown=!1,b.moved=!1,b.useMouseWheel=!1},200)}var m={touchstart:"touchstart",touchmove:"touchmove",touchend:"touchend",touchleave:"touchleave",touchcancel:".touchcancel",mousedown:"mousedown",mousemove:"mousemove",mouseup:"mouseup",mouseover:"mouseover",mouseout:"mouseout",mousewheel:"mousewheel",wheel:"DOMMouseScroll",horizontal:"horizontal",vertical:"vertical",fling:"fling",tap:"tap",longtap:"longtap",pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"},n="ontouchstart"in window,o=new Pool(function(){},100),p=new Pool(function(){this.start={},this.end={}},10),q=function(){return n?function(a,b){var c,d,e;if(a.type===m.touchstart){if(a.touches.length>1)return;c=a.touches[0],b.touchID=a.touches[0].identifier}else{for(d=0,e=a.changedTouches.length;e>d&&(c=a.changedTouches[d],c.identifier!==b.touchID);d++);if(c.identifier!==b.touchID)return}return b._tmpCoords.screenX=c.screenX,b._tmpCoords.screenY=c.screenY,b._tmpCoords.clientX=c.clientX,b._tmpCoords.clientY=c.clientY,b._tmpCoords}:function(a,b){return b._tmpCoords.screenX=a.screenX,b._tmpCoords.screenY=a.screenY,b._tmpCoords.clientX=a.clientX,b._tmpCoords.clientY=a.clientY,b._tmpCoords}}();return{isTouched:n,handleEvent:function(a){switch(a.type){case m.touchmove:case m.mousemove:this.useMouseWheel||h(a,this);break;case m.touchstart:case m.mousedown:g(a,this);break;case m.touchend:case m.touchleave:case m.touchcancel:case m.mouseup:i(a,this);break;case m.mouseover:j(a,this);break;case m.mouseout:k(a,this);break;case m.wheel:case m.mousewheel:l(a,this)}}}}(); -------------------------------------------------------------------------------- /gestureadapter/gestureadapter.js: -------------------------------------------------------------------------------- 1 | function GestureAdapter(element, listener) { 2 | var adapter = this; 3 | 4 | adapter.destroy = function () { 5 | if (!adapter.isTouched) { 6 | clearTimeout(adapter.mouseWheelTimeout); 7 | 8 | adapter._el.removeEventListener('mousedown', this); 9 | adapter._el.removeEventListener('mouseup', this); 10 | adapter._el.removeEventListener('mousemove', this); 11 | adapter._el.removeEventListener('mouseout', this); 12 | 13 | // mouse event 14 | // IE9, Chrome, Safari, Opera 15 | adapter._el.removeEventListener("mousewheel", adapter); 16 | // Firefox 17 | adapter._el.removeEventListener("DOMMouseScroll", adapter); 18 | } else { 19 | adapter._el.removeEventListener('touchstart', this); 20 | adapter._el.removeEventListener('touchend', this); 21 | adapter._el.removeEventListener('touchmove', this); 22 | adapter._el.removeEventListener('touchcancel', this); 23 | } 24 | delete adapter._el; 25 | delete adapter._listener; 26 | }; 27 | 28 | adapter._el = element; 29 | adapter._listener = listener; 30 | adapter._tmpCoords = {}; 31 | 32 | if (!adapter.isTouched) { 33 | adapter._el.addEventListener('mousedown', adapter, false); 34 | adapter._el.addEventListener('mouseup', adapter, false); 35 | adapter._el.addEventListener('mousemove', adapter, false); 36 | adapter._el.addEventListener('mouseout', adapter, false); 37 | adapter._el.addEventListener('mouseover', adapter, false); 38 | 39 | // mouse event 40 | // IE9, Chrome, Safari, Opera 41 | adapter._el.addEventListener("mousewheel", adapter, false); 42 | // Firefox 43 | adapter._el.addEventListener("DOMMouseScroll", adapter, false); 44 | } else { 45 | adapter._el.addEventListener('touchstart', adapter, false); 46 | adapter._el.addEventListener('touchend', adapter, false); 47 | adapter._el.addEventListener('touchmove', adapter, false); 48 | adapter._el.addEventListener('touchcancel', adapter, false); 49 | } 50 | 51 | return adapter; 52 | } 53 | 54 | GestureAdapter.prototype = (function () { 55 | var STRINGS = { 56 | touchstart: "touchstart", 57 | touchmove: "touchmove", 58 | touchend: "touchend", 59 | touchleave: "touchleave", 60 | touchcancel: ".touchcancel", 61 | mousedown: "mousedown", 62 | mousemove: "mousemove", 63 | mouseup: "mouseup", 64 | mouseover: "mouseover", 65 | mouseout: "mouseout", 66 | mousewheel: "mousewheel", 67 | wheel: "DOMMouseScroll", 68 | horizontal: "horizontal", 69 | vertical: "vertical", 70 | fling: "fling", 71 | tap: "tap", 72 | longtap: "longtap", 73 | pointerdown: "pointerdown", 74 | pointermove: "pointermove", 75 | pointerup: "pointerup" 76 | }, 77 | touch = ('ontouchstart' in window), 78 | eventPool = new Pool(function () { 79 | }, 100), 80 | flingPool = new Pool(function () { 81 | this.start = {}; 82 | this.end = {}; 83 | }, 10), 84 | extractCoord = (function () { 85 | if (touch) 86 | return function (e, cntx) { 87 | var touchEvent, i, l; 88 | 89 | if (e.type === STRINGS.touchstart) { 90 | if (e.touches.length > 1){ 91 | return; 92 | } 93 | touchEvent = e.touches[0]; 94 | cntx.touchID = e.touches[0].identifier; 95 | } else { 96 | for (i = 0, l = e.changedTouches.length; i < l; i ++) { 97 | touchEvent = e.changedTouches[i]; 98 | if (touchEvent.identifier === cntx.touchID) { 99 | break; 100 | } 101 | } 102 | if (touchEvent.identifier !== cntx.touchID){ 103 | return; 104 | } 105 | } 106 | 107 | cntx._tmpCoords.screenX = touchEvent.screenX; 108 | cntx._tmpCoords.screenY = touchEvent.screenY; 109 | cntx._tmpCoords.clientX = touchEvent.clientX; 110 | cntx._tmpCoords.clientY = touchEvent.clientY; 111 | return cntx._tmpCoords; 112 | }; 113 | 114 | return function (e, cntx) { 115 | cntx._tmpCoords.screenX = e.screenX; 116 | cntx._tmpCoords.screenY = e.screenY; 117 | cntx._tmpCoords.clientX = e.clientX; 118 | cntx._tmpCoords.clientY = e.clientY; 119 | return cntx._tmpCoords; 120 | }; 121 | })(); 122 | 123 | function saveLastPoint(e, cntx) { 124 | if (e.timeStamp - cntx.preLastMove.timeStamp > 10) { 125 | var coords = extractCoord(e, cntx); 126 | if (!coords) { 127 | return; 128 | } 129 | 130 | cntx.lastMove.screenX = cntx.preLastMove.screenX; 131 | cntx.lastMove.screenY = cntx.preLastMove.screenY; 132 | cntx.lastMove.timeStamp = cntx.preLastMove.timeStamp; 133 | 134 | cntx.preLastMove.screenX = coords.screenX; 135 | cntx.preLastMove.screenY = coords.screenY; 136 | cntx.preLastMove.timeStamp = e.timeStamp; 137 | } 138 | } 139 | 140 | function getDirection(startX, startY, endX, endY) { 141 | if (Math.abs(startX - endX) > Math.abs(startY - endY)) { 142 | return STRINGS.horizontal; 143 | } 144 | return STRINGS.vertical; 145 | } 146 | 147 | function fireEvent(type, e, cntx) { 148 | var coords = extractCoord(e, cntx), event = eventPool.get(); 149 | if (!coords) { 150 | return; 151 | } 152 | event.type = type; 153 | event.clientX = coords.clientX; 154 | event.clientY = coords.clientY; 155 | event.screenX = coords.screenX; 156 | event.screenY = coords.screenY; 157 | event.timeStamp = e.timeStamp; 158 | event.origin = e; 159 | 160 | cntx._listener.handleEvent(event); 161 | } 162 | 163 | function getDirectionVelocity(lastX, lastY, lastTime, endX, endY, endTime) { 164 | if (Math.abs(lastX - endX) > Math.abs(lastY - endY)) { 165 | return (endX - lastX) / (endTime - lastTime); 166 | } else { 167 | return (endY - lastY) / (endTime - lastTime); 168 | } 169 | } 170 | 171 | function distance(x1, y1, x2, y2) { 172 | return Math.pow(((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)), 0.5); 173 | } 174 | 175 | function checkFling(e, cntx) { 176 | var coord = extractCoord(e, cntx), 177 | flingEvent; 178 | 179 | if (!coord) { 180 | return; 181 | } 182 | if ((Math.abs(distance(cntx.lastMove.screenX, cntx.lastMove.screenY, coord.screenX, coord.screenY) / (e.timeStamp - cntx.lastMove.timeStamp)) * 100) >> 0 > 0) { 183 | flingEvent = flingPool.get(); 184 | flingEvent.type = STRINGS.fling; 185 | //velocity (px/ms) in end point without considering direction 186 | flingEvent.velocity = distance(cntx.startX, cntx.startY, coord.screenX, coord.screenY) / (e.timeStamp - cntx.timeStamp); 187 | //fling direction ("vertical", "horizontal") 188 | flingEvent.direction = getDirection(cntx.startX, cntx.startY, coord.screenX, coord.screenY); 189 | //fling speed (px/ms) in end point along direction 190 | flingEvent.speed = getDirectionVelocity(cntx.startX, cntx.startY, cntx.timeStamp, coord.screenX, coord.screenY, e.timeStamp); 191 | 192 | flingEvent.start.screenX = cntx.startX; 193 | flingEvent.start.screenY = cntx.startY; 194 | flingEvent.start.clientX = cntx.startClientX; 195 | flingEvent.start.clientY = cntx.startClientY; 196 | flingEvent.start.timeStamp = cntx.timeStamp; 197 | 198 | flingEvent.end.screenX = coord.screenX; 199 | flingEvent.end.screenY = coord.screenY; 200 | flingEvent.end.clientX = coord.clientX; 201 | flingEvent.end.clientY = coord.clientY; 202 | flingEvent.end.timeStamp = e.timeStamp; 203 | 204 | cntx._listener.handleEvent(flingEvent); 205 | } 206 | } 207 | 208 | function onTouchStart(e, cntx) { 209 | var coords = extractCoord(e, cntx); 210 | if (!coords) { 211 | return; 212 | } 213 | cntx.startX = coords.screenX; 214 | cntx.startY = coords.screenY; 215 | cntx.startClientX = coords.clientX; 216 | cntx.startClientY = coords.clientY; 217 | cntx.timeStamp = e.timeStamp; 218 | cntx.moved = false; 219 | cntx.isDown = true; 220 | cntx.touchStartTime = e.timeStamp; 221 | 222 | cntx.lastMove = cntx.lastMove || {}; 223 | cntx.preLastMove = cntx.preLastMove || {}; 224 | 225 | cntx.lastMove.screenX = cntx.preLastMove.screenX = 0; 226 | cntx.lastMove.screenY = cntx.preLastMove.screenY = 0; 227 | cntx.lastMove.timeStamp = cntx.preLastMove.timeStamp = e.timeStamp; 228 | 229 | fireEvent(STRINGS.pointerdown, e, cntx); 230 | } 231 | 232 | function onTouchMove(e, cntx) { 233 | var coords = extractCoord(e, cntx); 234 | if (!coords) { 235 | return; 236 | } 237 | 238 | if (cntx.isDown) { 239 | saveLastPoint(e, cntx); 240 | fireEvent(STRINGS.pointermove, e, cntx); 241 | // 10px is tremor distance 242 | if ((Math.abs(coords.screenY - cntx.startY) > 10) || (Math.abs(coords.screenX - cntx.startX) > 10)) { 243 | cntx.moved = true; 244 | } 245 | } 246 | } 247 | 248 | function onTouchUp(e, cntx) { 249 | var duration = e.timeStamp - cntx.touchStartTime; 250 | 251 | if (cntx.isDown) { 252 | cntx.isDown = false; 253 | if (!cntx.moved) { 254 | // if touch duration is more then 300 ms - then it is long tap event 255 | if (duration <= 300) { 256 | fireEvent(STRINGS.tap, e, cntx); 257 | } else { 258 | fireEvent(STRINGS.longtap, e, cntx); 259 | } 260 | } else { 261 | checkFling(e, cntx); 262 | } 263 | fireEvent(STRINGS.pointerup, e, cntx); 264 | } 265 | } 266 | 267 | function onMouseOver(e, cntx) { 268 | clearTimeout(cntx.mouseOutTimeout); 269 | } 270 | 271 | function onMouseOut(e, cntx) { 272 | cntx.mouseOutTimeout = setTimeout(function () { 273 | onTouchUp(e, cntx); 274 | }, 10); 275 | } 276 | 277 | function onMouseWheel(e, cntx) { 278 | var startDelta = 10 * ((e.wheelDelta || -e.detail) > 0 ? 1 : -1); 279 | 280 | clearTimeout(cntx.mouseWheelTimeout); 281 | 282 | e.preventDefault(); 283 | e.stopPropagation(); 284 | 285 | e = { 286 | clientX: e.clientX, 287 | clientY: e.clientY, 288 | screenX: e.screenX, 289 | screenY: 0, 290 | timeStamp: e.timeStamp, 291 | 292 | preventDefault: function () { 293 | }, 294 | stopPropagation: function () { 295 | } 296 | }; 297 | 298 | if (!cntx.isDown) { 299 | cntx.isDown = true; 300 | cntx.moved = true; 301 | 302 | //special parameters for wheel 303 | cntx.useMouseWheel = true; 304 | cntx.currentWheelPosition = 0; 305 | cntx.acceleration = startDelta; 306 | 307 | onTouchStart(e, cntx); 308 | } 309 | 310 | cntx.acceleration *=1.2; 311 | cntx.currentWheelPosition += cntx.acceleration; 312 | e.screenY = cntx.currentWheelPosition; 313 | onTouchMove(e, cntx); 314 | 315 | cntx.mouseWheelTimeout = setTimeout(function(){ 316 | fireEvent(STRINGS.pointerup, e, cntx); 317 | cntx.isDown = false; 318 | cntx.moved = false; 319 | 320 | //special parameters for wheel 321 | cntx.useMouseWheel = false; 322 | }, 200); 323 | } 324 | 325 | return { 326 | isTouched: touch, 327 | 328 | handleEvent: function (event) { 329 | switch (event.type) { 330 | case STRINGS.touchmove: 331 | case STRINGS.mousemove: 332 | if (!this.useMouseWheel) 333 | onTouchMove(event, this); 334 | break; 335 | case STRINGS.touchstart: 336 | case STRINGS.mousedown: 337 | onTouchStart(event, this); 338 | break; 339 | case STRINGS.touchend: 340 | case STRINGS.touchleave: 341 | case STRINGS.touchcancel: 342 | case STRINGS.mouseup: 343 | onTouchUp(event, this); 344 | break; 345 | case STRINGS.mouseover: 346 | onMouseOver(event, this); 347 | break; 348 | case STRINGS.mouseout: 349 | onMouseOut(event, this); 350 | break; 351 | case STRINGS.wheel: 352 | case STRINGS.mousewheel: 353 | onMouseWheel(event, this); 354 | break; 355 | } 356 | } 357 | }; 358 | }()); -------------------------------------------------------------------------------- /listview/bin/listview-combined.min.js: -------------------------------------------------------------------------------- 1 | function addVendorPrefix(a){function b(a){return a.charAt(0).toUpperCase()+a.slice(1)}var c,d=["ms","Ms","moz","Moz","webkit","Webkit","o","O"],e=document.createElement("div"),f=null,g=[];for(c=0;cb;b++)d(b),g++,h.push(b)}var f={},g=0,h=[],i=[],j="string"==typeof c?c:"release";return this.get=function(){var a;return h.length>0?a=h.pop():(a=d(g),g++),i.push(a),f[a]},e(b),this}function ListView(a,b,c){function d(){var a,c,d,e=b.getElementsCount();return 0===e?0:(a=b.getElement(0,null,{width:0,height:0}),d=document.createElement("div"),d.style.position="absolute",d.className=A,d.appendChild(a),o.appendChild(d),c=d.getBoundingClientRect(),r=c.height,q=c.width,o.removeChild(d),"vertical"===z?r:q)}function e(){var a=document.createElement("div");a.style.position="absolute",a.style.height=r+"px",a.style.width=q+"px",a.style.webkitFontSmoothing="antialiased",a.className=A,w&&a.addEventListener(c.eventListener.type,w,c.eventListener.useCapture),this.wrapper=a,this.item=null,this.position=null,this.index=0,this.timeout=null,this.handler={width:0,height:0},this.taskTimestamp=0}function f(){if(G.length>1){var a,b=G.pop(),d=b.wrapper.parentNode;d.removeChild(b.wrapper),w&&b.wrapper.removeEventListener(c.eventListener.type,w);for(a in b)b.hasOwnProperty(a)&&(b[a]=null);v=setTimeout(f,150)}}function g(a){return setTimeout(function(){a.wrapper.style[s]="vertical"!==z?"translate3d(0, 999999px, 0)":"translate3d(999999px, 0, 0)"},100)}function h(a){var c,d,e=window.performance.now();for(c=F.length-1;c>=0;c--)if(d=F[c],0!==d.taskTimestamp&&(e-d.taskTimestamp>H||a)){if(d.index=0&&(d+1+C)*D>-a;)c=G.pop()||new e,c.handler.width=q,c.handler.height=r,c.position=d*D,c.index=d,b=c.wrapper,b.parentNode?clearTimeout(c.timeout):o.appendChild(b),c.timeout=i(c),d--,K=d,F.unshift(c)}function k(a){var c,d,f=b.getElementsCount(),g=J,h=J*D+a;for(g;f>g&&h=0;c--)b=F[c],d=b.position>p._ParentSize-a+C*D,e=b.position+D*(1+C)<-a,(e||d)&&(b.timeout=g(b),G.push(l(c)),d?J=b.index:KJ*D&&k(a),(K+1)*D>-a&&j(a)}var o,p,q,r,s,t,u,v,w,x,y={},z=c&&c.direction?c.direction:"vertical",A=c?c.itemClass:"",B=!!(c?c.useOpacity:!1),C=c&&"number"==typeof c.stealthCount?Math.abs(c.stealthCount):0,D=0,E=[],F=[],G=[],H=1e3/(c&&c.requiredFPS?c.requiredFPS:20),I=0,J=0,K=-1,L=!1,M={pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"};return s=addVendorPrefix("transform"),t=addVendorPrefix("transition"),"vertical"===z?(E[0]="translate3d(0, ",E[2]="px, 0) scale(1)"):(E[0]="translate3d(",E[2]="px, 0, 0) scale(1)"),o=document.createElement("div"),o.style.width="100%",o.style.height="100%",a.insertBefore(o,a.firstChild),p=new ScrollView(a,c),c&&c.eventListener&&(w="object"==typeof c.eventListener.listener?function(a){a.type!==c.eventListener.type||L||c.eventListener.listener.handleEvent(a)}:function(a){a.type!==c.eventListener.type||L||c.eventListener.listener(a)}),p._calculateMaxScroll=function(){var a,c,e=q,f=r,i=d(),j=b.getElementsCount();if(K>j-1||0>K){for(K=j>0&&0>K?-1:j-1,J=K+1,c=F.length-1;c>=0;c--)a=F[c],(a.index=J)&&(a.timeout=g(a),G.push(l(c)));p.scrollPosition=-Math.max(0,K)*i}if(e!==q||f!==r){var k,m;for(p.scrollPosition=-(K+1)*i,D=i,c=F.length-1;c>=0;c-=1)a=F[c],m=a.wrapper,k=a.index*D,E[1]=k,m.style.height=r+"px",m.style.width=q+"px",m.style[s]=E.join(""),a.position=k,a.handler.width=q,a.handler.height=r;for(c=G.length-1;c>=0;c-=1)a=G[c],a.handler.width=q,a.handler.height=r,m=a.wrapper,m.style.height=r+"px",m.style.width=q+"px"}for(c=F.length-1;c>=0;c-=1)a=F[c],b.getElement(a.index,a.item,a.handler);p._MaxScroll=D*b.getElementsCount()-p._ParentSize,p.setPosition(p.scrollPosition,!0),h(!0)},y.setPosition=p.setPosition,p.setPosition=function(a,b){clearTimeout(v),y.setPosition.apply(p,arguments),u=window.performance.now(),(u-I>H||b)&&(n(a),h(),I=u),v=setTimeout(f,1e3)},y.handleEvent=p.handleEvent,p.handleEvent=function(a){switch(y.handleEvent.apply(p,arguments),a.type){case M.pointerdown:n(p.scrollPosition),h(!0),L=!1,x=z===M.vertical?a.screenY:a.screenX;break;case M.pointermove:(z===M.vertical?a.screenY:a.screenX)-x>10&&(L=!0)}},p.refresh(),n(0),p}function GestureAdapter(a,b){var c=this;return c.destroy=function(){c.isTouched?(c._el.removeEventListener("touchstart",this),c._el.removeEventListener("touchend",this),c._el.removeEventListener("touchmove",this),c._el.removeEventListener("touchcancel",this)):(clearTimeout(c.mouseWheelTimeout),c._el.removeEventListener("mousedown",this),c._el.removeEventListener("mouseup",this),c._el.removeEventListener("mousemove",this),c._el.removeEventListener("mouseout",this),c._el.removeEventListener("mousewheel",c),c._el.removeEventListener("DOMMouseScroll",c)),delete c._el,delete c._listener},c._el=a,c._listener=b,c._tmpCoords={},c.isTouched?(c._el.addEventListener("touchstart",c,!1),c._el.addEventListener("touchend",c,!1),c._el.addEventListener("touchmove",c,!1),c._el.addEventListener("touchcancel",c,!1)):(c._el.addEventListener("mousedown",c,!1),c._el.addEventListener("mouseup",c,!1),c._el.addEventListener("mousemove",c,!1),c._el.addEventListener("mouseout",c,!1),c._el.addEventListener("mouseover",c,!1),c._el.addEventListener("mousewheel",c,!1),c._el.addEventListener("DOMMouseScroll",c,!1)),c}function Animator(a){var b=a&&a.easing?a.easing:null,c=a&&a.boundsEasing?a.boundsEasing:null;this.isTweaking=!1,this.isAnimating=!1,this._easing="function"==typeof b?b:this[b],this._bounds=a&&a.bounds?!0:!1,this._boundsEasing="function"==typeof c?c:this[c],this._keepAbsoluteMetrics=a&&a.keepAbsoluteMetrics?!0:!1,this.checkBounds=this._bounds?function(a){return this._lastPosition=this._lastPosition||a,athis.maxPosition&&(a=this._lastPosition+(a-this._lastPosition)/3),this._lastPosition=a,a}:function(a){return athis.maxPosition&&(a=this.maxPosition),a}}function ScrollView(a,b){function c(a){q.stop(),l=a[r]}function d(a){n.setPosition(n.scrollPosition-(l-a[r])),l=a[r]}function e(a){n.setPosition(n.scrollPosition-(l-a[r]),!0),q.tweakIfNeeded(n.scrollPosition,n.setPosition)}function f(){clearTimeout(n.resizeTimeout),n.resizeTimeout=setTimeout(n.reflow,150)}var g,h,i,j,k,l,m,n=this,o={vertical:"vertical",fling:"fling",move:"move",pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"},p=b&&b.direction?b.direction:o.vertical,q=new Animator({easing:b&&b.easing?b.easing:"easeOutQuad",bounds:b?!!b.bounds:!1}),r=p===o.vertical?"screenY":"screenX",s=p===o.vertical?"offsetHeight":"offsetWidth",t=[];n._calculateMaxScroll=function(){n._MaxScroll=g[s]-n._ParentSize},n.scroll=function(a,b){q.animate(n.scrollPosition,n.scrollPosition+a,b,n.setPosition)},n.refresh=function(){q.stop(),n._calculateMaxScroll(),q.setBounds(Math.min(0,-n._MaxScroll),0,n._ParentSize/2.5),g[s]?q.tweakIfNeeded(n.scrollPosition,n.setPosition):n.setPosition(0)},n.reflow=function(){var a=n.container,b=a.offsetHeight,c=a.offsetWidth;0===b||b===k&&c===j||(n._ParentSize=a[s],k=b,j=c,n.refresh())},n.getMaxPosition=function(){return n._MaxScroll},n.destroy=function(){window.removeEventListener("resize",f),clearTimeout(n.resizeTimeout)},n.handleEvent=function(a){switch(a.type){case o.fling:q.inBounds(n.scrollPosition)&&m(a);break;case o.pointerdown:c(a);break;case o.pointermove:a.origin.preventDefault(),d(a);break;case o.pointerup:e(a)}a.release()},n.container=a,n.scrollPosition=0,m=function(a){return a?function(a){a.direction===o.vertical&&q.startFling(n.scrollPosition,a.speed,n.setPosition)}:function(a){a.direction!==o.vertical&&q.startFling(n.scrollPosition,a.speed,n.setPosition)}}(p===o.vertical),n.setPosition=function(a){return a?function(a,c,d){n.scrollPosition=c?a:q.checkBounds(a),t[1]=n.scrollPosition,g.style[h]=t.join(""),b.onScroll(n.scrollPosition,d||o.move)}:function(a,b){n.scrollPosition=b?a:q.checkBounds(a),t[1]=n.scrollPosition,g.style[h]=t.join("")}}(b&&"function"==typeof b.onScroll),p===o.vertical?(t[0]="translate3d(0, ",t[2]="px, 0) scale(1)"):(t[0]="translate3d(",t[2]="px, 0, 0) scale(1)"),i=addVendorPrefix("transition"),h=addVendorPrefix("transform");var u=["fixed","relative","absolute"],v=u.indexOf(window.getComputedStyle(a,null).position);return a.style.position=-1===v?"relative":u[v],a.style.overflow="hidden",g=a.firstElementChild,g.style[p===o.vertical?"width":"height"]="100%",g.style.margin=0,g.style.position="absolute",g.style[i]="transform 0ms",n.reflow(),window.addEventListener("resize",f,!1),n}GestureAdapter.prototype=function(){function a(a,b){if(a.timeStamp-b.preLastMove.timeStamp>10){var c=q(a,b);if(!c)return;b.lastMove.screenX=b.preLastMove.screenX,b.lastMove.screenY=b.preLastMove.screenY,b.lastMove.timeStamp=b.preLastMove.timeStamp,b.preLastMove.screenX=c.screenX,b.preLastMove.screenY=c.screenY,b.preLastMove.timeStamp=a.timeStamp}}function b(a,b,c,d){return Math.abs(a-c)>Math.abs(b-d)?m.horizontal:m.vertical}function c(a,b,c){var d=q(b,c),e=o.get();d&&(e.type=a,e.clientX=d.clientX,e.clientY=d.clientY,e.screenX=d.screenX,e.screenY=d.screenY,e.timeStamp=b.timeStamp,e.origin=b,c._listener.handleEvent(e))}function d(a,b,c,d,e,f){return Math.abs(a-d)>Math.abs(b-e)?(d-a)/(f-c):(e-b)/(f-c)}function e(a,b,c,d){return Math.pow((c-a)*(c-a)+(d-b)*(d-b),.5)}function f(a,c){var f,g=q(a,c);g&&100*Math.abs(e(c.lastMove.screenX,c.lastMove.screenY,g.screenX,g.screenY)/(a.timeStamp-c.lastMove.timeStamp))>>0>0&&(f=p.get(),f.type=m.fling,f.velocity=e(c.startX,c.startY,g.screenX,g.screenY)/(a.timeStamp-c.timeStamp),f.direction=b(c.startX,c.startY,g.screenX,g.screenY),f.speed=d(c.startX,c.startY,c.timeStamp,g.screenX,g.screenY,a.timeStamp),f.start.screenX=c.startX,f.start.screenY=c.startY,f.start.clientX=c.startClientX,f.start.clientY=c.startClientY,f.start.timeStamp=c.timeStamp,f.end.screenX=g.screenX,f.end.screenY=g.screenY,f.end.clientX=g.clientX,f.end.clientY=g.clientY,f.end.timeStamp=a.timeStamp,c._listener.handleEvent(f))}function g(a,b){var d=q(a,b);d&&(b.startX=d.screenX,b.startY=d.screenY,b.startClientX=d.clientX,b.startClientY=d.clientY,b.timeStamp=a.timeStamp,b.moved=!1,b.isDown=!0,b.touchStartTime=a.timeStamp,b.lastMove=b.lastMove||{},b.preLastMove=b.preLastMove||{},b.lastMove.screenX=b.preLastMove.screenX=0,b.lastMove.screenY=b.preLastMove.screenY=0,b.lastMove.timeStamp=b.preLastMove.timeStamp=a.timeStamp,c(m.pointerdown,a,b))}function h(b,d){var e=q(b,d);e&&d.isDown&&(a(b,d),c(m.pointermove,b,d),(Math.abs(e.screenY-d.startY)>10||Math.abs(e.screenX-d.startX)>10)&&(d.moved=!0))}function i(a,b){var d=a.timeStamp-b.touchStartTime;b.isDown&&(b.isDown=!1,b.moved?f(a,b):300>=d?c(m.tap,a,b):c(m.longtap,a,b),c(m.pointerup,a,b))}function j(a,b){clearTimeout(b.mouseOutTimeout)}function k(a,b){b.mouseOutTimeout=setTimeout(function(){i(a,b)},10)}function l(a,b){var d=10*((a.wheelDelta||-a.detail)>0?1:-1);clearTimeout(b.mouseWheelTimeout),a.preventDefault(),a.stopPropagation(),a={clientX:a.clientX,clientY:a.clientY,screenX:a.screenX,screenY:0,timeStamp:a.timeStamp,preventDefault:function(){},stopPropagation:function(){}},b.isDown||(b.isDown=!0,b.moved=!0,b.useMouseWheel=!0,b.currentWheelPosition=0,b.acceleration=d,g(a,b)),b.acceleration*=1.2,b.currentWheelPosition+=b.acceleration,a.screenY=b.currentWheelPosition,h(a,b),b.mouseWheelTimeout=setTimeout(function(){c(m.pointerup,a,b),b.isDown=!1,b.moved=!1,b.useMouseWheel=!1},200)}var m={touchstart:"touchstart",touchmove:"touchmove",touchend:"touchend",touchleave:"touchleave",touchcancel:".touchcancel",mousedown:"mousedown",mousemove:"mousemove",mouseup:"mouseup",mouseover:"mouseover",mouseout:"mouseout",mousewheel:"mousewheel",wheel:"DOMMouseScroll",horizontal:"horizontal",vertical:"vertical",fling:"fling",tap:"tap",longtap:"longtap",pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"},n="ontouchstart"in window,o=new Pool(function(){},100),p=new Pool(function(){this.start={},this.end={}},10),q=function(){return n?function(a,b){var c,d,e;if(a.type===m.touchstart){if(a.touches.length>1)return;c=a.touches[0],b.touchID=a.touches[0].identifier}else{for(d=0,e=a.changedTouches.length;e>d&&(c=a.changedTouches[d],c.identifier!==b.touchID);d++);if(c.identifier!==b.touchID)return}return b._tmpCoords.screenX=c.screenX,b._tmpCoords.screenY=c.screenY,b._tmpCoords.clientX=c.clientX,b._tmpCoords.clientY=c.clientY,b._tmpCoords}:function(a,b){return b._tmpCoords.screenX=a.screenX,b._tmpCoords.screenY=a.screenY,b._tmpCoords.clientX=a.clientX,b._tmpCoords.clientY=a.clientY,b._tmpCoords}}();return{isTouched:n,handleEvent:function(a){switch(a.type){case m.touchmove:case m.mousemove:this.useMouseWheel||h(a,this);break;case m.touchstart:case m.mousedown:g(a,this);break;case m.touchend:case m.touchleave:case m.touchcancel:case m.mouseup:i(a,this);break;case m.mouseover:j(a,this);break;case m.mouseout:k(a,this);break;case m.wheel:case m.mousewheel:l(a,this)}}}}(),window.performance=window.performance||{},window.performance.now=function(){return performance.now||performance.mozNow||performance.msNow||performance.oNow||performance.webkitNow||function(){return(new Date).getTime()}}(),function(){var a,b,c,d,e=0,f=["ms","moz","webkit","o"];for(a=0;aa?2*a*a:-1+(4-2*a)*a},b.easeInCubic=function(a){return a*a*a},b.easeOutCubic=function(a){return--a*a*a+1},b.easeInOutCubic=function(a){return.5>a?4*a*a*a:(a-1)*(2*a-2)*(2*a-2)+1},b.easeInQuart=function(a){return a*a*a*a},b.easeOutQuart=function(a){return 1- --a*a*a*a},b.easeInOutQuart=function(a){return.5>a?8*a*a*a*a:1-8*--a*a*a*a},b.easeInQuint=function(a){return a*a*a*a*a},b.easeOutQuint=function(a){return 1+--a*a*a*a*a},b.easeInOutQuint=function(a){return.5>a?16*a*a*a*a*a:1+16*--a*a*a*a*a},b.KeySpline=function(a,b,c,d){function e(a,b){return 1-3*b+3*a}function f(a,b){return 3*b-6*a}function g(a){return 3*a}function h(a,b,c){return((e(b,c)*a+f(b,c))*a+g(b))*a}function i(a,b,c){return 3*e(b,c)*a*a+2*f(b,c)*a+g(b)}function j(b){for(var d=b,e=0;4>e;++e){var f=i(d,a,c);if(0==f)return d;var g=h(d,a,c)-b;d-=g/f}return d}return function(e){return a==b&&c==d?e:h(j(e),b,d)}},b.animate=function(a,b,d,e,f){function g(f){if(i=(f-h)/d,j=i>1?1:i,(1>j||!h)&&n.isAnimating&&(n._animationID=window.requestAnimationFrame(g,null)),m)return h=f,void(m=!1);if(n._currentPosition=k(j)*(b-a)+a,j>=1&&(o=!0,n.isTweaking=!1,n.isAnimating=!1,n._currentPosition=Math.round(n._currentPosition),p=c.stop),n._bounds){var q=0;n._currentPositionn.maxPosition&&(q=n._currentPosition-n.maxPosition),q&&(n.isTweaking||(Math.abs(q)>n.margin||!n.isAnimating)&&(n.stop(),n.isTweaking=!0,n.animate(n._currentPosition,n._currentPosition-q,Math.min(2*Math.abs(q),350),n._callback,n._boundsEasing||"easeOutQuad"),p=c.tweak))}else l=n.checkBounds(n._currentPosition),l!==n._currentPosition&&(o=!0,n.isTweaking=!1,n.isAnimating=!1,l=Math.round(l),p=c.stop),n._currentPosition=l;e(n._currentPosition,o,p)}var h,i,j,k,l,m=!0,n=this,o=!1,p=this.isTweaking?c.tweak:c.animation;a!==b&&(k="function"==typeof f?f:"string"==typeof f?this[f]:this._easing,this.isAnimating=!0,this._callback=e,window.requestAnimationFrame(g,null))},b.FRICTION=25e-6,b.startFling=function(b,c,d){var e,f,g,h=!1,i=c&&c/Math.abs(c),j=this.FRICTION;this.DPI||this._keepAbsoluteMetrics||a(),this._keepAbsoluteMetrics||(j=this.FRICTION*this.DPI),e=Math.abs(c)/j,f=i*c*c/j,this._bounds&&(b+fthis.maxPosition+this.margin&&(g=this.maxPosition+this.margin/2-b,h=!0),h&&(e=e*g/f,f=g)),this.animate(b,b+f,e,d)},b.tweakIfNeeded=function(a,b){var c=0;this.isAnimating||(athis.maxPosition&&(c=a-this.maxPosition),c&&(this.isTweaking=!0,this.animate(a,a-c,Math.min(2*Math.abs(c),350),b,this._boundsEasing||"easeOutQuad")))},b.setBounds=function(a,b,c){this.minPosition=a,this.maxPosition=b,this.margin=c||0},b.inBounds=function(a){return a>=this.minPosition&&a<=this.maxPosition},b.isStopped=function(){return!this.isAnimating},b.stop=function(){this.isAnimating&&(window.cancelAnimationFrame(this._animationID),this.isAnimating=!1,"function"==typeof this._callback&&(this._currentPosition=Math.round(this._currentPosition),this._callback(this._currentPosition,!0,c.stop)))},window.addEventListener("load",a,!1),b}(); -------------------------------------------------------------------------------- /listview/bin/listview.min.js: -------------------------------------------------------------------------------- 1 | function ListView(a,b,c){function d(){var a,c,d,e=b.getElementsCount();return 0===e?0:(a=b.getElement(0,null,{width:0,height:0}),d=document.createElement("div"),d.style.position="absolute",d.className=A,d.appendChild(a),o.appendChild(d),c=d.getBoundingClientRect(),r=c.height,q=c.width,o.removeChild(d),"vertical"===z?r:q)}function e(){var a=document.createElement("div");a.style.position="absolute",a.style.height=r+"px",a.style.width=q+"px",a.style.webkitFontSmoothing="antialiased",a.className=A,w&&a.addEventListener(c.eventListener.type,w,c.eventListener.useCapture),this.wrapper=a,this.item=null,this.position=null,this.index=0,this.timeout=null,this.handler={width:0,height:0},this.taskTimestamp=0}function f(){if(G.length>1){var a,b=G.pop(),d=b.wrapper.parentNode;d.removeChild(b.wrapper),w&&b.wrapper.removeEventListener(c.eventListener.type,w);for(a in b)b.hasOwnProperty(a)&&(b[a]=null);v=setTimeout(f,150)}}function g(a){return setTimeout(function(){a.wrapper.style[s]="vertical"!==z?"translate3d(0, 999999px, 0)":"translate3d(999999px, 0, 0)"},100)}function h(a){var c,d,e=window.performance.now();for(c=F.length-1;c>=0;c--)if(d=F[c],0!==d.taskTimestamp&&(e-d.taskTimestamp>H||a)){if(d.index=0&&(d+1+C)*D>-a;)c=G.pop()||new e,c.handler.width=q,c.handler.height=r,c.position=d*D,c.index=d,b=c.wrapper,b.parentNode?clearTimeout(c.timeout):o.appendChild(b),c.timeout=i(c),d--,K=d,F.unshift(c)}function k(a){var c,d,f=b.getElementsCount(),g=J,h=J*D+a;for(g;f>g&&h=0;c--)b=F[c],d=b.position>p._ParentSize-a+C*D,e=b.position+D*(1+C)<-a,(e||d)&&(b.timeout=g(b),G.push(l(c)),d?J=b.index:KJ*D&&k(a),(K+1)*D>-a&&j(a)}var o,p,q,r,s,t,u,v,w,x,y={},z=c&&c.direction?c.direction:"vertical",A=c?c.itemClass:"",B=!!(c?c.useOpacity:!1),C=c&&"number"==typeof c.stealthCount?Math.abs(c.stealthCount):0,D=0,E=[],F=[],G=[],H=1e3/(c&&c.requiredFPS?c.requiredFPS:20),I=0,J=0,K=-1,L=!1,M={pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"};return s=addVendorPrefix("transform"),t=addVendorPrefix("transition"),"vertical"===z?(E[0]="translate3d(0, ",E[2]="px, 0) scale(1)"):(E[0]="translate3d(",E[2]="px, 0, 0) scale(1)"),o=document.createElement("div"),o.style.width="100%",o.style.height="100%",a.insertBefore(o,a.firstChild),p=new ScrollView(a,c),c&&c.eventListener&&(w="object"==typeof c.eventListener.listener?function(a){a.type!==c.eventListener.type||L||c.eventListener.listener.handleEvent(a)}:function(a){a.type!==c.eventListener.type||L||c.eventListener.listener(a)}),p._calculateMaxScroll=function(){var a,c,e=q,f=r,i=d(),j=b.getElementsCount();if(K>j-1||0>K){for(K=j>0&&0>K?-1:j-1,J=K+1,c=F.length-1;c>=0;c--)a=F[c],(a.index=J)&&(a.timeout=g(a),G.push(l(c)));p.scrollPosition=-Math.max(0,K)*i}if(e!==q||f!==r){var k,m;for(p.scrollPosition=-(K+1)*i,D=i,c=F.length-1;c>=0;c-=1)a=F[c],m=a.wrapper,k=a.index*D,E[1]=k,m.style.height=r+"px",m.style.width=q+"px",m.style[s]=E.join(""),a.position=k,a.handler.width=q,a.handler.height=r;for(c=G.length-1;c>=0;c-=1)a=G[c],a.handler.width=q,a.handler.height=r,m=a.wrapper,m.style.height=r+"px",m.style.width=q+"px"}for(c=F.length-1;c>=0;c-=1)a=F[c],b.getElement(a.index,a.item,a.handler);p._MaxScroll=D*b.getElementsCount()-p._ParentSize,p.setPosition(p.scrollPosition,!0),h(!0)},y.setPosition=p.setPosition,p.setPosition=function(a,b){clearTimeout(v),y.setPosition.apply(p,arguments),u=window.performance.now(),(u-I>H||b)&&(n(a),h(),I=u),v=setTimeout(f,1e3)},y.handleEvent=p.handleEvent,p.handleEvent=function(a){switch(y.handleEvent.apply(p,arguments),a.type){case M.pointerdown:n(p.scrollPosition),h(!0),L=!1,x=z===M.vertical?a.screenY:a.screenX;break;case M.pointermove:(z===M.vertical?a.screenY:a.screenX)-x>10&&(L=!0)}},p.refresh(),n(0),p} -------------------------------------------------------------------------------- /listview/example/assets/img_0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_0.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_1.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_2.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_3.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_4.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_5.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_6.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_7.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_8.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_8.jpeg -------------------------------------------------------------------------------- /listview/example/assets/img_9.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MobiDevBiz/RAD.JS-toolkit/acd576da5349e2cd4bdf0b064f2e20c07831a113/listview/example/assets/img_9.jpeg -------------------------------------------------------------------------------- /listview/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | List View 10 | 11 | 12 | 13 | Dynamic 14 | 154 | 155 | 156 | 157 |
158 |
159 | 160 |
161 |
162 |
163 |
164 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /listview/listview.js: -------------------------------------------------------------------------------- 1 | function ListView(element, adapter, o) { 2 | var mContainer, // container for item wrappers 3 | mView, // current view 4 | mFnHandlers = {}, // helper object - storage for override functions 5 | 6 | mDirection = (o && o.direction) ? o.direction : "vertical", // scrolling direction 7 | mWrapperClass = o ? o.itemClass : '', // css class for item wrappers 8 | mUseOpacity = !!(o ? o.useOpacity : false), 9 | mStealthCount = (o && typeof o.stealthCount === 'number') ? Math.abs(o.stealthCount): 0, 10 | 11 | mItemSize = 0, // item size along scroll direction 12 | mItemWidth, // item width 13 | mItemHeight, // item height 14 | 15 | mTransformName, // css transformation name with vendor prefix 16 | mTransitionName, 17 | mTransitionArray = [], // tmp array for constructing transformation value 18 | 19 | mVisibleHelpers = [], // visible items 20 | mInvisibleHelpers = [], // recycle container 21 | 22 | UPDATE_DELAY = 1000 / ((o && o.requiredFPS) ? o.requiredFPS : 20), // min delay between items layout update 23 | mLastLayoutTimestamp = 0, // timestamp of last items layout 24 | mTmpVariable, 25 | 26 | mLastAdapterIndex = 0, // last visible item index in list 27 | mFirstAdapterIndex = -1, // first visible item index in list 28 | 29 | mInvisibleCollectorTimeout, 30 | 31 | mItemListener, 32 | mIsMoving = false, 33 | mStartPoint, 34 | 35 | STRINGS = { 36 | pointerdown: 'pointerdown', 37 | pointermove: 'pointermove', 38 | pointerup: 'pointerup' 39 | }; 40 | 41 | function calculateItemSize() { 42 | var item, counts = adapter.getElementsCount(), box, wrapper; 43 | 44 | if (counts === 0) 45 | return 0; 46 | 47 | item = adapter.getElement(0, null, {width: 0, height: 0}); 48 | wrapper = document.createElement('div'); 49 | wrapper.style.position = 'absolute'; 50 | wrapper.className = mWrapperClass; 51 | wrapper.appendChild(item); 52 | mContainer.appendChild(wrapper); 53 | 54 | box = wrapper.getBoundingClientRect(); 55 | mItemHeight = box.height; 56 | mItemWidth = box.width; 57 | mContainer.removeChild(wrapper); 58 | 59 | return (mDirection === "vertical") ? mItemHeight : mItemWidth; 60 | } 61 | 62 | function CreateHelper() { 63 | var element = document.createElement('div'); 64 | 65 | //setup layer 66 | element.style.position = 'absolute'; 67 | element.style.height = mItemHeight + 'px'; 68 | element.style.width = mItemWidth + 'px'; 69 | element.style.webkitFontSmoothing = 'antialiased'; 70 | element.className = mWrapperClass; 71 | 72 | //setup listener 73 | if (mItemListener) 74 | element.addEventListener(o.eventListener.type, mItemListener, o.eventListener.useCapture); 75 | 76 | this.wrapper = element; 77 | this.item = null; 78 | this.position = null; 79 | this.index = 0; 80 | this.timeout = null; 81 | this.handler = { 82 | width: 0, 83 | height: 0 84 | }; 85 | this.taskTimestamp = 0; 86 | } 87 | 88 | function collectInvisibleItems() { 89 | if (mInvisibleHelpers.length > 1) { 90 | var key, helper = mInvisibleHelpers.pop(), parent = helper.wrapper.parentNode; 91 | 92 | // remove from DOM 93 | parent.removeChild(helper.wrapper); 94 | 95 | //remove listener 96 | if (mItemListener) 97 | helper.wrapper.removeEventListener(o.eventListener.type, mItemListener); 98 | 99 | // release helper attributes 100 | for (key in helper) { 101 | if (helper.hasOwnProperty(key)) { 102 | helper[key] = null; 103 | } 104 | } 105 | 106 | // post task 107 | mInvisibleCollectorTimeout = setTimeout(collectInvisibleItems, 150); 108 | } 109 | } 110 | 111 | function setInvisible(helper) { 112 | // push into invisible area only after 100ms to avoid redundant work with DOM 113 | return setTimeout(function () { 114 | helper.wrapper.style[mTransformName] = (mDirection !== 'vertical') ? "translate3d(0, 999999px, 0)" : "translate3d(999999px, 0, 0)"; 115 | }, 100); 116 | } 117 | 118 | function checkHandlersTasks(force) { 119 | var i, helper, now = window.performance.now(); 120 | for (i = mVisibleHelpers.length - 1; i >= 0; i--) { 121 | helper = mVisibleHelpers[i]; 122 | if ((helper.taskTimestamp !== 0) && ((now - helper.taskTimestamp > UPDATE_DELAY) || force)) { 123 | if (helper.index < adapter.getElementsCount()) { 124 | var item = adapter.getElement(helper.index, helper.item, helper.handler); 125 | helper.wrapper.appendChild(item); 126 | helper.item = item; 127 | 128 | if (mUseOpacity) { 129 | helper.item.style[mTransitionName] = 'opacity 150ms ease-in'; 130 | helper.item.style.opacity = 1; 131 | } 132 | } 133 | helper.taskTimestamp = 0; 134 | } 135 | } 136 | } 137 | 138 | function prepareItemAndWrapper(helper) { 139 | // setup wrapper position 140 | mTransitionArray[1] = helper.position; 141 | helper.wrapper.style[mTransformName] = mTransitionArray.join(""); 142 | helper.wrapper.setAttribute('data-item', helper.index); 143 | 144 | if (mUseOpacity && helper.item) { 145 | helper.item.style[mTransitionName] = 'none'; 146 | helper.item.style.opacity = 0; 147 | } 148 | 149 | // setup task for insert item content 150 | helper.taskTimestamp = window.performance.now(); 151 | } 152 | 153 | // fill bottom list with items from adapter 154 | function fillFromTop(containerPosition) { 155 | var wrapper, helper, itemIndex = mFirstAdapterIndex; 156 | while (itemIndex >= 0 && (itemIndex + 1 + mStealthCount) * mItemSize > -containerPosition) { 157 | helper = mInvisibleHelpers.pop() || new CreateHelper(); 158 | helper.handler.width = mItemWidth; 159 | helper.handler.height = mItemHeight; 160 | 161 | helper.position = itemIndex * mItemSize; 162 | helper.index = itemIndex; 163 | 164 | wrapper = helper.wrapper; 165 | if (!wrapper.parentNode) { 166 | mContainer.appendChild(wrapper); 167 | } else { 168 | clearTimeout(helper.timeout); 169 | } 170 | helper.timeout = prepareItemAndWrapper(helper); 171 | 172 | itemIndex--; 173 | mFirstAdapterIndex = itemIndex; 174 | 175 | mVisibleHelpers.unshift(helper); 176 | } 177 | } 178 | 179 | // fill top list 180 | function fillToBottom(containerPosition) { 181 | var itemsCount = adapter.getElementsCount(), helper, wrapper, itemIndex = mLastAdapterIndex, 182 | lastBottom = mLastAdapterIndex * mItemSize + containerPosition; 183 | 184 | for (itemIndex; itemIndex < itemsCount && lastBottom < mView._ParentSize + mStealthCount * mItemSize; itemIndex++) { 185 | lastBottom += mItemSize; 186 | helper = mInvisibleHelpers.pop() || new CreateHelper(); 187 | helper.handler.width = mItemWidth; 188 | helper.handler.height = mItemHeight; 189 | 190 | helper.position = itemIndex * mItemSize; 191 | helper.index = itemIndex; 192 | 193 | wrapper = helper.wrapper; 194 | if (!wrapper.parentNode) { 195 | mContainer.appendChild(wrapper); 196 | } else { 197 | clearTimeout(helper.timeout); 198 | } 199 | helper.timeout = prepareItemAndWrapper(helper); 200 | mVisibleHelpers.push(helper); 201 | } 202 | mLastAdapterIndex = itemIndex; 203 | } 204 | 205 | // we don't use array "splice" method because it obstructs memory 206 | function removeVisibleHelper(index) { 207 | var i, j, result; 208 | for (i = 0; i < mVisibleHelpers.length; i++) { 209 | if (i === index) { 210 | result = mVisibleHelpers[i]; 211 | for (j = i; j < mVisibleHelpers.length - 1; j++) { 212 | mVisibleHelpers[j] = mVisibleHelpers[j + 1]; 213 | } 214 | mVisibleHelpers.length = mVisibleHelpers.length - 1; 215 | return result; 216 | } 217 | } 218 | } 219 | 220 | // check and remove list items which are outside of the bounds 221 | function removeInvisibleItems(containerPosition) { 222 | var helper, i, fromDown, fromUp; 223 | 224 | for (i = mVisibleHelpers.length - 1; i >= 0; i--) { 225 | helper = mVisibleHelpers[i]; 226 | fromDown = helper.position > mView._ParentSize - containerPosition + mStealthCount * mItemSize; 227 | fromUp = helper.position + mItemSize * (1 + mStealthCount) < -containerPosition; 228 | 229 | if (fromUp || fromDown) { 230 | helper.timeout = setInvisible(helper); 231 | mInvisibleHelpers.push(removeVisibleHelper(i)); 232 | 233 | if (fromDown) { 234 | mLastAdapterIndex = helper.index; 235 | } else if (mFirstAdapterIndex < helper.index) { 236 | mFirstAdapterIndex = helper.index; 237 | } 238 | } 239 | } 240 | } 241 | 242 | // complex function for layouting items on the list 243 | function layoutItems(position) { 244 | removeInvisibleItems(position); 245 | 246 | if (mView._ParentSize - position > mLastAdapterIndex * mItemSize) { 247 | fillToBottom(position); 248 | } 249 | if (-position < (mFirstAdapterIndex + 1) * mItemSize) { 250 | fillFromTop(position); 251 | } 252 | } 253 | 254 | //======================== construction part ======================== 255 | mTransformName = addVendorPrefix("transform"); 256 | mTransitionName = addVendorPrefix("transition"); 257 | if (mDirection === "vertical") { 258 | mTransitionArray[0] = "translate3d(0, "; 259 | mTransitionArray[2] = "px, 0) scale(1)"; 260 | } else { 261 | mTransitionArray[0] = "translate3d("; 262 | mTransitionArray[2] = "px, 0, 0) scale(1)"; 263 | } 264 | 265 | //create container for items 266 | mContainer = document.createElement('div'); 267 | mContainer.style.width = '100%'; 268 | mContainer.style.height = '100%'; 269 | element.insertBefore(mContainer, element.firstChild); 270 | 271 | mView = new ScrollView(element, o); 272 | 273 | if (o && o.eventListener) { 274 | if (typeof o.eventListener.listener === 'object') { 275 | mItemListener = function (e) { 276 | if ((e.type === o.eventListener.type) && !mIsMoving) { 277 | o.eventListener.listener.handleEvent(e); 278 | } 279 | }; 280 | } else { 281 | mItemListener = function (e) { 282 | if ((e.type === o.eventListener.type) && !mIsMoving){ 283 | o.eventListener.listener(e); 284 | } 285 | }; 286 | } 287 | } 288 | 289 | // ----------------- decorate scroll view methods ------------------- 290 | // override inner method for "refresh"/"reflow" 291 | mView._calculateMaxScroll = function () { 292 | var helper, i, tmpWidth = mItemWidth, tmpHeight = mItemHeight, newItemSize = calculateItemSize(), 293 | itemsCount = adapter.getElementsCount(); 294 | 295 | // refresh mLastAdapterIndex, mFirstAdapterIndex and mView.scrollPosition 296 | if ((mFirstAdapterIndex > itemsCount - 1) || (mFirstAdapterIndex < 0)) { 297 | if ((itemsCount > 0) && (mFirstAdapterIndex < 0)) { 298 | mFirstAdapterIndex = - 1; 299 | } else { 300 | mFirstAdapterIndex = itemsCount - 1; 301 | } 302 | mLastAdapterIndex = mFirstAdapterIndex + 1; 303 | 304 | //remove invisible items 305 | for (i = mVisibleHelpers.length - 1; i >= 0; i--) { 306 | helper = mVisibleHelpers[i]; 307 | if (helper.index < mFirstAdapterIndex || helper.index >= mLastAdapterIndex) { 308 | helper.timeout = setInvisible(helper); 309 | mInvisibleHelpers.push(removeVisibleHelper(i)); 310 | } 311 | } 312 | 313 | mView.scrollPosition = -Math.max(0, mFirstAdapterIndex) * newItemSize; 314 | } 315 | 316 | // reflow existing items if new size !== old item size 317 | if ((tmpWidth !== mItemWidth) || (tmpHeight !== mItemHeight)) { 318 | var position, wrapper; 319 | 320 | mView.scrollPosition = -(mFirstAdapterIndex + 1) * newItemSize; 321 | 322 | // refresh new items size 323 | mItemSize = newItemSize; 324 | 325 | // reflow mVisibleItems items 326 | for (i = mVisibleHelpers.length - 1; i >= 0; i -= 1) { 327 | helper = mVisibleHelpers[i]; 328 | 329 | wrapper = helper.wrapper; 330 | position = helper.index * mItemSize; 331 | mTransitionArray[1] = position; 332 | 333 | wrapper.style.height = mItemHeight + 'px'; 334 | wrapper.style.width = mItemWidth + 'px'; 335 | wrapper.style[mTransformName] = mTransitionArray.join(""); 336 | 337 | helper.position = position; 338 | helper.handler.width = mItemWidth; 339 | helper.handler.height = mItemHeight; 340 | } 341 | 342 | // reflow mInvisibleItems items 343 | for (i = mInvisibleHelpers.length - 1; i >= 0; i -= 1) { 344 | helper = mInvisibleHelpers[i]; 345 | helper.handler.width = mItemWidth; 346 | helper.handler.height = mItemHeight; 347 | 348 | wrapper = helper.wrapper; 349 | wrapper.style.height = mItemHeight + 'px'; 350 | wrapper.style.width = mItemWidth + 'px'; 351 | } 352 | } 353 | 354 | for (i = mVisibleHelpers.length - 1; i >= 0; i -= 1) { 355 | helper = mVisibleHelpers[i]; 356 | adapter.getElement(helper.index, helper.item, helper.handler); 357 | } 358 | 359 | // refresh max scroll position 360 | mView._MaxScroll = mItemSize * adapter.getElementsCount() - mView._ParentSize; 361 | 362 | // refresh scroll position 363 | mView.setPosition(mView.scrollPosition, true); 364 | checkHandlersTasks(true); 365 | }; 366 | 367 | // override "setPosition" method 368 | mFnHandlers.setPosition = mView.setPosition; 369 | mView.setPosition = function (position, force) { 370 | // stop collector of invisible items 371 | clearTimeout(mInvisibleCollectorTimeout); 372 | 373 | // scroll container 374 | mFnHandlers.setPosition.apply(mView, arguments); 375 | 376 | // layout items if delta time between last update and now more than 1000ms/needUpdateFPS 377 | mTmpVariable = window.performance.now(); 378 | if ((mTmpVariable - mLastLayoutTimestamp > UPDATE_DELAY) || force) { 379 | layoutItems(position); 380 | checkHandlersTasks(); 381 | mLastLayoutTimestamp = mTmpVariable; 382 | } 383 | 384 | // post task to collect unnecessary invisible items 385 | mInvisibleCollectorTimeout = setTimeout(collectInvisibleItems, 1000); 386 | }; 387 | 388 | // override "handleEvent" 389 | mFnHandlers.handleEvent = mView.handleEvent; 390 | mView.handleEvent = function (e) { 391 | mFnHandlers.handleEvent.apply(mView, arguments); 392 | 393 | switch (e.type) { 394 | case STRINGS.pointerdown: 395 | layoutItems(mView.scrollPosition); 396 | checkHandlersTasks(true); 397 | mIsMoving = false; 398 | mStartPoint = (mDirection === STRINGS.vertical) ? e.screenY : e.screenX; 399 | break; 400 | case STRINGS.pointermove: 401 | if (((mDirection === STRINGS.vertical) ? e.screenY : e.screenX) - mStartPoint > 10) { 402 | mIsMoving = true; 403 | } 404 | break; 405 | } 406 | }; 407 | // ----------------------------------------------------------------- 408 | 409 | // prepare first start 410 | mView.refresh(); 411 | layoutItems(0); 412 | 413 | return mView; 414 | //=================================================================== 415 | } -------------------------------------------------------------------------------- /objectpool/bin/objectpool.min.js: -------------------------------------------------------------------------------- 1 | function Pool(a,b,c){function d(b){var c;return c=new a,c[j]=function(){var a;h.push(b),a=i.indexOf(b),i[a]=i[i.length-1],i.length-=1},f[b]=c,b}function e(a){var b,c;for(b=0,c=a;c>b;b++)d(b),g++,h.push(b)}var f={},g=0,h=[],i=[],j="string"==typeof c?c:"release";return this.get=function(){var a;return h.length>0?a=h.pop():(a=d(g),g++),i.push(a),f[a]},e(b),this} -------------------------------------------------------------------------------- /objectpool/objectpool.js: -------------------------------------------------------------------------------- 1 | function Pool(Constructor, count, releaseFnName) { 2 | var objects = {}, quantity = 0, freeObjects = [], usedObjects = [], 3 | fn = (typeof releaseFnName === 'string') ? releaseFnName : 'release'; 4 | 5 | function create(id) { 6 | var obj; 7 | obj = new Constructor(); 8 | obj[fn] = function () { 9 | var i; 10 | freeObjects.push(id); 11 | 12 | // remove id from used array 13 | i = usedObjects.indexOf(id); 14 | usedObjects[i] = usedObjects[usedObjects.length -1]; 15 | usedObjects.length -= 1; 16 | }; 17 | objects[id] = obj; 18 | return id; 19 | } 20 | 21 | function allocate(count) { 22 | var i, l; 23 | for (i = 0, l = count; i < l; i++) { 24 | create(i); 25 | quantity++; 26 | freeObjects.push(i); 27 | } 28 | } 29 | 30 | this.get = function () { 31 | var id; 32 | if (freeObjects.length > 0) { 33 | id = freeObjects.pop(); 34 | } else { 35 | id = create(quantity); 36 | quantity++; 37 | } 38 | usedObjects.push(id); 39 | 40 | return objects[id]; 41 | }; 42 | 43 | allocate(count); 44 | return this; 45 | } 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RAD.JS-toolkit", 3 | "description": "Rapid Application Development javascript (RAD.js) Toolkit", 4 | "devDependencies": { 5 | "grunt": "~0.4.2", 6 | "grunt-contrib-clean": "~0.5.0", 7 | "grunt-contrib-concat": "~0.3.0", 8 | "grunt-contrib-uglify": "~0.2.7", 9 | "grunt-contrib-cssmin": "~0.7.0", 10 | "grunt-timer": "~0.2.0" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/mobidevpublisher/RAD.JS-toolkit" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pubsub/bin/pubsub.min.js: -------------------------------------------------------------------------------- 1 | function PubSub(){function a(){e&&console.log.apply(null,arguments)}function b(){return Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15)}var c={},d={},e=!1,f=".";return{printLog:function(a){return e=a,this},setSeparator:function(a){return f=a,this},publish:function(b,e,g){var h,i,j,k,l,m,n,o=b.split(f);for(a(this.radID+" publish:",arguments),"sticky"===g&&(d[b]=arguments),h=0,k=o.length;k>h;h+=1)if(n=o.slice(0,h+1).join(f),c[n])for(i=0,j=c[n].length;j>i;i+=1)l=c[n][i],l.callback.apply(l.context,arguments),m=l.context.options||l.context,a("receiver:"+m.radID+" channel:"+n,arguments);return this},subscribe:function(e,g,h){var i,j,k,l,m=h||this,n=e.split(f);for(i=m.radID=m.radID||b(),c[e]=c[e]||[],c[e].push({context:m,callback:g,ID:i}),a(i+" subscribe to channel:"+e,arguments),j=0,k=n.length;k>j;j+=1)l=n.slice(0,j+1).join(f),d[l]&&g.apply(m,d[l]);return this},unsubscribe:function(b,d){var e,f,g,h;if(b&&b.radID){h=b.radID;for(e in c)if(c.hasOwnProperty(e))for(f=c[e].length-1,g=0;f>=g;f-=1)if((null===d||d===e)&&c[e][f].ID===h&&(a(h+" unsubscribe from channel:"+e,arguments),c[e].splice(f,1),d))return this}return this}}} -------------------------------------------------------------------------------- /pubsub/pubsub.js: -------------------------------------------------------------------------------- 1 | function PubSub() { 2 | var channels = {}, sticky = {}, debug = false, separator = '.'; 3 | 4 | function log() { 5 | if (debug) { 6 | console.log.apply(null, arguments); 7 | } 8 | } 9 | 10 | function generateQuickGuid() { 11 | return Math.random().toString(36).substring(2, 15) + 12 | Math.random().toString(36).substring(2, 15); 13 | } 14 | 15 | return { 16 | 17 | printLog: function (flag) { 18 | debug = flag; 19 | return this; 20 | }, 21 | 22 | setSeparator: function (sprtr) { 23 | separator = sprtr; 24 | return this; 25 | }, 26 | 27 | publish: function (channel, data, type) { 28 | var index, i, l, length, subscription, receiver, parts = channel.split(separator), currentChannel; 29 | 30 | log(this.radID + " publish:", arguments); 31 | 32 | //attach sticky message 33 | if (type === "sticky") { 34 | sticky[channel] = arguments; 35 | } 36 | 37 | //post message 38 | for (index = 0, length = parts.length; index < length; index += 1) { 39 | currentChannel = parts.slice(0, index + 1).join(separator); 40 | if (channels[currentChannel]) { 41 | for (i = 0, l = channels[currentChannel].length; i < l; i += 1) { 42 | subscription = channels[currentChannel][i]; 43 | subscription.callback.apply(subscription.context, arguments); 44 | receiver = subscription.context.options || subscription.context; 45 | log("receiver:" + receiver.radID + " channel:" + currentChannel, arguments); 46 | } 47 | } 48 | } 49 | 50 | return this; 51 | }, 52 | 53 | subscribe: function (channel, fn, context) { 54 | var cntx = context || this, radID, parts = channel.split(separator), index, length, currentChannel; 55 | 56 | radID = cntx.radID = cntx.radID || generateQuickGuid(); 57 | 58 | channels[channel] = channels[channel] || []; 59 | channels[channel].push({ context: cntx, callback: fn, ID: radID}); 60 | 61 | log(radID + " subscribe to channel:" + channel, arguments); 62 | 63 | //post sticky messages 64 | for (index = 0, length = parts.length; index < length; index += 1) { 65 | currentChannel = parts.slice(0, index + 1).join(separator); 66 | if (sticky[currentChannel]) { 67 | fn.apply(cntx, sticky[currentChannel]); 68 | } 69 | } 70 | 71 | return this; 72 | }, 73 | 74 | unsubscribe: function (context, channel) { 75 | var m, i, length, id; 76 | 77 | if (context && context.radID) { 78 | id = context.radID; 79 | for (m in channels) { 80 | if (channels.hasOwnProperty(m)) { 81 | for (i = channels[m].length - 1, length = 0; i >= length; i -= 1) { 82 | if ((channel === null || channel === m) && channels[m][i].ID === id) { 83 | log(id + " unsubscribe from channel:" + m, arguments); 84 | channels[m].splice(i, 1); 85 | if (channel) { 86 | return this; 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | return this; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /scrollbar/scrollbar.js: -------------------------------------------------------------------------------- 1 | function ScrollBar(wrappable, className) { 2 | var mPrevFunc = wrappable.setPosition, 3 | mPrevRefresh = wrappable.refresh, 4 | mContainer = wrappable.container, 5 | mBar = document.createElement('div'), 6 | mLastPosition, 7 | mHeight, 8 | mTransformName, 9 | mTranslateArray = [], 10 | mPXStr = "px"; 11 | 12 | function updateBar() { 13 | if(Math.min(0, -wrappable.getMaxPosition()) === 0){ 14 | mBar.style.opacity = 0; 15 | } else { 16 | mBar.style.opacity = 1; 17 | } 18 | 19 | mBar.style.height = mContainer.offsetHeight * (mContainer.offsetHeight / (wrappable.getMaxPosition() + mContainer.offsetHeight)) + mPXStr; 20 | mHeight = mContainer.offsetHeight - mBar.offsetHeight; 21 | } 22 | 23 | wrappable.setPosition = function () { 24 | mPrevFunc.apply(this, arguments); 25 | 26 | mLastPosition = -wrappable.scrollPosition * mHeight / wrappable.getMaxPosition(); 27 | mTranslateArray[1] = mLastPosition; 28 | mBar.style[mTransformName] = mTranslateArray.join(""); 29 | }; 30 | 31 | wrappable.refresh = function () { 32 | mPrevRefresh.apply(this, arguments); 33 | updateBar(); 34 | }; 35 | 36 | mTransformName = addVendorPrefix("transform"); 37 | mTranslateArray[0] = "translate3d(0, "; 38 | mTranslateArray[2] = "px, 0) scale(1)"; 39 | 40 | mBar.style.position = "absolute"; 41 | mBar.style.marginRight = "3px"; 42 | mBar.className = className; 43 | mContainer.appendChild(mBar); 44 | 45 | updateBar(); 46 | 47 | return wrappable; 48 | } 49 | -------------------------------------------------------------------------------- /scrollview/bin/scrollview-combined.min.js: -------------------------------------------------------------------------------- 1 | function addVendorPrefix(a){function b(a){return a.charAt(0).toUpperCase()+a.slice(1)}var c,d=["ms","Ms","moz","Moz","webkit","Webkit","o","O"],e=document.createElement("div"),f=null,g=[];for(c=0;cthis.maxPosition&&(a=this._lastPosition+(a-this._lastPosition)/3),this._lastPosition=a,a}:function(a){return athis.maxPosition&&(a=this.maxPosition),a}}function Pool(a,b,c){function d(b){var c;return c=new a,c[j]=function(){var a;h.push(b),a=i.indexOf(b),i[a]=i[i.length-1],i.length-=1},f[b]=c,b}function e(a){var b,c;for(b=0,c=a;c>b;b++)d(b),g++,h.push(b)}var f={},g=0,h=[],i=[],j="string"==typeof c?c:"release";return this.get=function(){var a;return h.length>0?a=h.pop():(a=d(g),g++),i.push(a),f[a]},e(b),this}function GestureAdapter(a,b){var c=this;return c.destroy=function(){c.isTouched?(c._el.removeEventListener("touchstart",this),c._el.removeEventListener("touchend",this),c._el.removeEventListener("touchmove",this),c._el.removeEventListener("touchcancel",this)):(clearTimeout(c.mouseWheelTimeout),c._el.removeEventListener("mousedown",this),c._el.removeEventListener("mouseup",this),c._el.removeEventListener("mousemove",this),c._el.removeEventListener("mouseout",this),c._el.removeEventListener("mousewheel",c),c._el.removeEventListener("DOMMouseScroll",c)),delete c._el,delete c._listener},c._el=a,c._listener=b,c._tmpCoords={},c.isTouched?(c._el.addEventListener("touchstart",c,!1),c._el.addEventListener("touchend",c,!1),c._el.addEventListener("touchmove",c,!1),c._el.addEventListener("touchcancel",c,!1)):(c._el.addEventListener("mousedown",c,!1),c._el.addEventListener("mouseup",c,!1),c._el.addEventListener("mousemove",c,!1),c._el.addEventListener("mouseout",c,!1),c._el.addEventListener("mouseover",c,!1),c._el.addEventListener("mousewheel",c,!1),c._el.addEventListener("DOMMouseScroll",c,!1)),c}function ScrollView(a,b){function c(a){q.stop(),l=a[r]}function d(a){n.setPosition(n.scrollPosition-(l-a[r])),l=a[r]}function e(a){n.setPosition(n.scrollPosition-(l-a[r]),!0),q.tweakIfNeeded(n.scrollPosition,n.setPosition)}function f(){clearTimeout(n.resizeTimeout),n.resizeTimeout=setTimeout(n.reflow,150)}var g,h,i,j,k,l,m,n=this,o={vertical:"vertical",fling:"fling",move:"move",pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"},p=b&&b.direction?b.direction:o.vertical,q=new Animator({easing:b&&b.easing?b.easing:"easeOutQuad",bounds:b?!!b.bounds:!1}),r=p===o.vertical?"screenY":"screenX",s=p===o.vertical?"offsetHeight":"offsetWidth",t=[];n._calculateMaxScroll=function(){n._MaxScroll=g[s]-n._ParentSize},n.scroll=function(a,b){q.animate(n.scrollPosition,n.scrollPosition+a,b,n.setPosition)},n.refresh=function(){q.stop(),n._calculateMaxScroll(),q.setBounds(Math.min(0,-n._MaxScroll),0,n._ParentSize/2.5),g[s]?q.tweakIfNeeded(n.scrollPosition,n.setPosition):n.setPosition(0)},n.reflow=function(){var a=n.container,b=a.offsetHeight,c=a.offsetWidth;0===b||b===k&&c===j||(n._ParentSize=a[s],k=b,j=c,n.refresh())},n.getMaxPosition=function(){return n._MaxScroll},n.destroy=function(){window.removeEventListener("resize",f),clearTimeout(n.resizeTimeout)},n.handleEvent=function(a){switch(a.type){case o.fling:q.inBounds(n.scrollPosition)&&m(a);break;case o.pointerdown:c(a);break;case o.pointermove:a.origin.preventDefault(),d(a);break;case o.pointerup:e(a)}a.release()},n.container=a,n.scrollPosition=0,m=function(a){return a?function(a){a.direction===o.vertical&&q.startFling(n.scrollPosition,a.speed,n.setPosition)}:function(a){a.direction!==o.vertical&&q.startFling(n.scrollPosition,a.speed,n.setPosition)}}(p===o.vertical),n.setPosition=function(a){return a?function(a,c,d){n.scrollPosition=c?a:q.checkBounds(a),t[1]=n.scrollPosition,g.style[h]=t.join(""),b.onScroll(n.scrollPosition,d||o.move)}:function(a,b){n.scrollPosition=b?a:q.checkBounds(a),t[1]=n.scrollPosition,g.style[h]=t.join("")}}(b&&"function"==typeof b.onScroll),p===o.vertical?(t[0]="translate3d(0, ",t[2]="px, 0) scale(1)"):(t[0]="translate3d(",t[2]="px, 0, 0) scale(1)"),i=addVendorPrefix("transition"),h=addVendorPrefix("transform");var u=["fixed","relative","absolute"],v=u.indexOf(window.getComputedStyle(a,null).position);return a.style.position=-1===v?"relative":u[v],a.style.overflow="hidden",g=a.firstElementChild,g.style[p===o.vertical?"width":"height"]="100%",g.style.margin=0,g.style.position="absolute",g.style[i]="transform 0ms",n.reflow(),window.addEventListener("resize",f,!1),n}window.performance=window.performance||{},window.performance.now=function(){return performance.now||performance.mozNow||performance.msNow||performance.oNow||performance.webkitNow||function(){return(new Date).getTime()}}(),function(){var a,b,c,d,e=0,f=["ms","moz","webkit","o"];for(a=0;aa?2*a*a:-1+(4-2*a)*a},b.easeInCubic=function(a){return a*a*a},b.easeOutCubic=function(a){return--a*a*a+1},b.easeInOutCubic=function(a){return.5>a?4*a*a*a:(a-1)*(2*a-2)*(2*a-2)+1},b.easeInQuart=function(a){return a*a*a*a},b.easeOutQuart=function(a){return 1- --a*a*a*a},b.easeInOutQuart=function(a){return.5>a?8*a*a*a*a:1-8*--a*a*a*a},b.easeInQuint=function(a){return a*a*a*a*a},b.easeOutQuint=function(a){return 1+--a*a*a*a*a},b.easeInOutQuint=function(a){return.5>a?16*a*a*a*a*a:1+16*--a*a*a*a*a},b.KeySpline=function(a,b,c,d){function e(a,b){return 1-3*b+3*a}function f(a,b){return 3*b-6*a}function g(a){return 3*a}function h(a,b,c){return((e(b,c)*a+f(b,c))*a+g(b))*a}function i(a,b,c){return 3*e(b,c)*a*a+2*f(b,c)*a+g(b)}function j(b){for(var d=b,e=0;4>e;++e){var f=i(d,a,c);if(0==f)return d;var g=h(d,a,c)-b;d-=g/f}return d}return function(e){return a==b&&c==d?e:h(j(e),b,d)}},b.animate=function(a,b,d,e,f){function g(f){if(i=(f-h)/d,j=i>1?1:i,(1>j||!h)&&n.isAnimating&&(n._animationID=window.requestAnimationFrame(g,null)),m)return h=f,void(m=!1);if(n._currentPosition=k(j)*(b-a)+a,j>=1&&(o=!0,n.isTweaking=!1,n.isAnimating=!1,n._currentPosition=Math.round(n._currentPosition),p=c.stop),n._bounds){var q=0;n._currentPositionn.maxPosition&&(q=n._currentPosition-n.maxPosition),q&&(n.isTweaking||(Math.abs(q)>n.margin||!n.isAnimating)&&(n.stop(),n.isTweaking=!0,n.animate(n._currentPosition,n._currentPosition-q,Math.min(2*Math.abs(q),350),n._callback,n._boundsEasing||"easeOutQuad"),p=c.tweak))}else l=n.checkBounds(n._currentPosition),l!==n._currentPosition&&(o=!0,n.isTweaking=!1,n.isAnimating=!1,l=Math.round(l),p=c.stop),n._currentPosition=l;e(n._currentPosition,o,p)}var h,i,j,k,l,m=!0,n=this,o=!1,p=this.isTweaking?c.tweak:c.animation;a!==b&&(k="function"==typeof f?f:"string"==typeof f?this[f]:this._easing,this.isAnimating=!0,this._callback=e,window.requestAnimationFrame(g,null))},b.FRICTION=25e-6,b.startFling=function(b,c,d){var e,f,g,h=!1,i=c&&c/Math.abs(c),j=this.FRICTION;this.DPI||this._keepAbsoluteMetrics||a(),this._keepAbsoluteMetrics||(j=this.FRICTION*this.DPI),e=Math.abs(c)/j,f=i*c*c/j,this._bounds&&(b+fthis.maxPosition+this.margin&&(g=this.maxPosition+this.margin/2-b,h=!0),h&&(e=e*g/f,f=g)),this.animate(b,b+f,e,d)},b.tweakIfNeeded=function(a,b){var c=0;this.isAnimating||(athis.maxPosition&&(c=a-this.maxPosition),c&&(this.isTweaking=!0,this.animate(a,a-c,Math.min(2*Math.abs(c),350),b,this._boundsEasing||"easeOutQuad")))},b.setBounds=function(a,b,c){this.minPosition=a,this.maxPosition=b,this.margin=c||0},b.inBounds=function(a){return a>=this.minPosition&&a<=this.maxPosition},b.isStopped=function(){return!this.isAnimating},b.stop=function(){this.isAnimating&&(window.cancelAnimationFrame(this._animationID),this.isAnimating=!1,"function"==typeof this._callback&&(this._currentPosition=Math.round(this._currentPosition),this._callback(this._currentPosition,!0,c.stop)))},window.addEventListener("load",a,!1),b}(),GestureAdapter.prototype=function(){function a(a,b){if(a.timeStamp-b.preLastMove.timeStamp>10){var c=q(a,b);if(!c)return;b.lastMove.screenX=b.preLastMove.screenX,b.lastMove.screenY=b.preLastMove.screenY,b.lastMove.timeStamp=b.preLastMove.timeStamp,b.preLastMove.screenX=c.screenX,b.preLastMove.screenY=c.screenY,b.preLastMove.timeStamp=a.timeStamp}}function b(a,b,c,d){return Math.abs(a-c)>Math.abs(b-d)?m.horizontal:m.vertical}function c(a,b,c){var d=q(b,c),e=o.get();d&&(e.type=a,e.clientX=d.clientX,e.clientY=d.clientY,e.screenX=d.screenX,e.screenY=d.screenY,e.timeStamp=b.timeStamp,e.origin=b,c._listener.handleEvent(e))}function d(a,b,c,d,e,f){return Math.abs(a-d)>Math.abs(b-e)?(d-a)/(f-c):(e-b)/(f-c)}function e(a,b,c,d){return Math.pow((c-a)*(c-a)+(d-b)*(d-b),.5)}function f(a,c){var f,g=q(a,c);g&&100*Math.abs(e(c.lastMove.screenX,c.lastMove.screenY,g.screenX,g.screenY)/(a.timeStamp-c.lastMove.timeStamp))>>0>0&&(f=p.get(),f.type=m.fling,f.velocity=e(c.startX,c.startY,g.screenX,g.screenY)/(a.timeStamp-c.timeStamp),f.direction=b(c.startX,c.startY,g.screenX,g.screenY),f.speed=d(c.startX,c.startY,c.timeStamp,g.screenX,g.screenY,a.timeStamp),f.start.screenX=c.startX,f.start.screenY=c.startY,f.start.clientX=c.startClientX,f.start.clientY=c.startClientY,f.start.timeStamp=c.timeStamp,f.end.screenX=g.screenX,f.end.screenY=g.screenY,f.end.clientX=g.clientX,f.end.clientY=g.clientY,f.end.timeStamp=a.timeStamp,c._listener.handleEvent(f))}function g(a,b){var d=q(a,b);d&&(b.startX=d.screenX,b.startY=d.screenY,b.startClientX=d.clientX,b.startClientY=d.clientY,b.timeStamp=a.timeStamp,b.moved=!1,b.isDown=!0,b.touchStartTime=a.timeStamp,b.lastMove=b.lastMove||{},b.preLastMove=b.preLastMove||{},b.lastMove.screenX=b.preLastMove.screenX=0,b.lastMove.screenY=b.preLastMove.screenY=0,b.lastMove.timeStamp=b.preLastMove.timeStamp=a.timeStamp,c(m.pointerdown,a,b))}function h(b,d){var e=q(b,d);e&&d.isDown&&(a(b,d),c(m.pointermove,b,d),(Math.abs(e.screenY-d.startY)>10||Math.abs(e.screenX-d.startX)>10)&&(d.moved=!0))}function i(a,b){var d=a.timeStamp-b.touchStartTime;b.isDown&&(b.isDown=!1,b.moved?f(a,b):300>=d?c(m.tap,a,b):c(m.longtap,a,b),c(m.pointerup,a,b))}function j(a,b){clearTimeout(b.mouseOutTimeout)}function k(a,b){b.mouseOutTimeout=setTimeout(function(){i(a,b)},10)}function l(a,b){var d=10*((a.wheelDelta||-a.detail)>0?1:-1);clearTimeout(b.mouseWheelTimeout),a.preventDefault(),a.stopPropagation(),a={clientX:a.clientX,clientY:a.clientY,screenX:a.screenX,screenY:0,timeStamp:a.timeStamp,preventDefault:function(){},stopPropagation:function(){}},b.isDown||(b.isDown=!0,b.moved=!0,b.useMouseWheel=!0,b.currentWheelPosition=0,b.acceleration=d,g(a,b)),b.acceleration*=1.2,b.currentWheelPosition+=b.acceleration,a.screenY=b.currentWheelPosition,h(a,b),b.mouseWheelTimeout=setTimeout(function(){c(m.pointerup,a,b),b.isDown=!1,b.moved=!1,b.useMouseWheel=!1},200)}var m={touchstart:"touchstart",touchmove:"touchmove",touchend:"touchend",touchleave:"touchleave",touchcancel:".touchcancel",mousedown:"mousedown",mousemove:"mousemove",mouseup:"mouseup",mouseover:"mouseover",mouseout:"mouseout",mousewheel:"mousewheel",wheel:"DOMMouseScroll",horizontal:"horizontal",vertical:"vertical",fling:"fling",tap:"tap",longtap:"longtap",pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"},n="ontouchstart"in window,o=new Pool(function(){},100),p=new Pool(function(){this.start={},this.end={}},10),q=function(){return n?function(a,b){var c,d,e;if(a.type===m.touchstart){if(a.touches.length>1)return;c=a.touches[0],b.touchID=a.touches[0].identifier}else{for(d=0,e=a.changedTouches.length;e>d&&(c=a.changedTouches[d],c.identifier!==b.touchID);d++);if(c.identifier!==b.touchID)return}return b._tmpCoords.screenX=c.screenX,b._tmpCoords.screenY=c.screenY,b._tmpCoords.clientX=c.clientX,b._tmpCoords.clientY=c.clientY,b._tmpCoords}:function(a,b){return b._tmpCoords.screenX=a.screenX,b._tmpCoords.screenY=a.screenY,b._tmpCoords.clientX=a.clientX,b._tmpCoords.clientY=a.clientY,b._tmpCoords}}();return{isTouched:n,handleEvent:function(a){switch(a.type){case m.touchmove:case m.mousemove:this.useMouseWheel||h(a,this);break;case m.touchstart:case m.mousedown:g(a,this);break;case m.touchend:case m.touchleave:case m.touchcancel:case m.mouseup:i(a,this);break;case m.mouseover:j(a,this);break;case m.mouseout:k(a,this);break;case m.wheel:case m.mousewheel:l(a,this)}}}}(); -------------------------------------------------------------------------------- /scrollview/bin/scrollview.min.js: -------------------------------------------------------------------------------- 1 | function ScrollView(a,b){function c(a){q.stop(),l=a[r]}function d(a){n.setPosition(n.scrollPosition-(l-a[r])),l=a[r]}function e(a){n.setPosition(n.scrollPosition-(l-a[r]),!0),q.tweakIfNeeded(n.scrollPosition,n.setPosition)}function f(){clearTimeout(n.resizeTimeout),n.resizeTimeout=setTimeout(n.reflow,150)}var g,h,i,j,k,l,m,n=this,o={vertical:"vertical",fling:"fling",move:"move",pointerdown:"pointerdown",pointermove:"pointermove",pointerup:"pointerup"},p=b&&b.direction?b.direction:o.vertical,q=new Animator({easing:b&&b.easing?b.easing:"easeOutQuad",bounds:b?!!b.bounds:!1}),r=p===o.vertical?"screenY":"screenX",s=p===o.vertical?"offsetHeight":"offsetWidth",t=[];n._calculateMaxScroll=function(){n._MaxScroll=g[s]-n._ParentSize},n.scroll=function(a,b){q.animate(n.scrollPosition,n.scrollPosition+a,b,n.setPosition)},n.refresh=function(){q.stop(),n._calculateMaxScroll(),q.setBounds(Math.min(0,-n._MaxScroll),0,n._ParentSize/2.5),g[s]?q.tweakIfNeeded(n.scrollPosition,n.setPosition):n.setPosition(0)},n.reflow=function(){var a=n.container,b=a.offsetHeight,c=a.offsetWidth;0===b||b===k&&c===j||(n._ParentSize=a[s],k=b,j=c,n.refresh())},n.getMaxPosition=function(){return n._MaxScroll},n.destroy=function(){window.removeEventListener("resize",f),clearTimeout(n.resizeTimeout)},n.handleEvent=function(a){switch(a.type){case o.fling:q.inBounds(n.scrollPosition)&&m(a);break;case o.pointerdown:c(a);break;case o.pointermove:a.origin.preventDefault(),d(a);break;case o.pointerup:e(a)}a.release()},n.container=a,n.scrollPosition=0,m=function(a){return a?function(a){a.direction===o.vertical&&q.startFling(n.scrollPosition,a.speed,n.setPosition)}:function(a){a.direction!==o.vertical&&q.startFling(n.scrollPosition,a.speed,n.setPosition)}}(p===o.vertical),n.setPosition=function(a){return a?function(a,c,d){n.scrollPosition=c?a:q.checkBounds(a),t[1]=n.scrollPosition,g.style[h]=t.join(""),b.onScroll(n.scrollPosition,d||o.move)}:function(a,b){n.scrollPosition=b?a:q.checkBounds(a),t[1]=n.scrollPosition,g.style[h]=t.join("")}}(b&&"function"==typeof b.onScroll),p===o.vertical?(t[0]="translate3d(0, ",t[2]="px, 0) scale(1)"):(t[0]="translate3d(",t[2]="px, 0, 0) scale(1)"),i=addVendorPrefix("transition"),h=addVendorPrefix("transform");var u=["fixed","relative","absolute"],v=u.indexOf(window.getComputedStyle(a,null).position);return a.style.position=-1===v?"relative":u[v],a.style.overflow="hidden",g=a.firstElementChild,g.style[p===o.vertical?"width":"height"]="100%",g.style.margin=0,g.style.position="absolute",g.style[i]="transform 0ms",n.reflow(),window.addEventListener("resize",f,!1),n} -------------------------------------------------------------------------------- /scrollview/examples/horizontal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | Scroll View 10 | 11 | 42 | 43 | 44 |
45 |
    46 |
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • lkjhlds
  • 116 |
117 |
118 | 131 | 132 | -------------------------------------------------------------------------------- /scrollview/examples/vertical.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | Scroll View 10 | 11 | 36 | 37 | 38 |
39 |
    40 | 41 |
42 |
43 | 68 | 69 | -------------------------------------------------------------------------------- /scrollview/scrollview.js: -------------------------------------------------------------------------------- 1 | function ScrollView(element, o) { 2 | var mView = this, 3 | mScrollingWrapper, 4 | 5 | STRINGS = { 6 | vertical: 'vertical', 7 | fling: 'fling', 8 | move: 'move', 9 | pointerdown: 'pointerdown', 10 | pointermove: 'pointermove', 11 | pointerup: 'pointerup' 12 | }, 13 | 14 | mTransformName, 15 | mTransitionName, 16 | mDirection = (o && o.direction) ? o.direction : STRINGS.vertical, 17 | mAnimator = new Animator({ 18 | easing: (o && o.easing) ? o.easing : 'easeOutQuad', 19 | bounds: o ? !!o.bounds : false 20 | }), 21 | 22 | mCoordProp = (mDirection === STRINGS.vertical) ? 'screenY' : 'screenX', 23 | mParentProp = (mDirection === STRINGS.vertical) ? 'offsetHeight' : 'offsetWidth', 24 | 25 | mParentWidth, 26 | mParentHeight, 27 | 28 | mLastPointerCoordinate, 29 | 30 | mTransitionArray = [], 31 | eventFling; 32 | 33 | function eventPointerDown(e) { 34 | mAnimator.stop(); 35 | mLastPointerCoordinate = e[mCoordProp]; 36 | } 37 | 38 | function eventPointerMove(e) { 39 | mView.setPosition(mView.scrollPosition - (mLastPointerCoordinate - e[mCoordProp])); 40 | mLastPointerCoordinate = e[mCoordProp]; 41 | } 42 | 43 | function eventPointerUp(e) { 44 | mView.setPosition(mView.scrollPosition - (mLastPointerCoordinate - e[mCoordProp]), true); 45 | mAnimator.tweakIfNeeded(mView.scrollPosition, mView.setPosition); 46 | } 47 | 48 | function eventResize() { 49 | clearTimeout(mView.resizeTimeout); 50 | mView.resizeTimeout = setTimeout(mView.reflow, 150); 51 | } 52 | 53 | mView._calculateMaxScroll = function () { 54 | mView._MaxScroll = mScrollingWrapper[mParentProp] - mView._ParentSize; 55 | }; 56 | 57 | mView.scroll = function (shift, duration) { 58 | mAnimator.animate(mView.scrollPosition, mView.scrollPosition + shift, duration, mView.setPosition); 59 | }; 60 | 61 | mView.refresh = function () { 62 | mAnimator.stop(); 63 | 64 | mView._calculateMaxScroll(); 65 | mAnimator.setBounds(Math.min(0, -mView._MaxScroll), 0, mView._ParentSize / 2.5); 66 | if (mScrollingWrapper[mParentProp]) { 67 | mAnimator.tweakIfNeeded(mView.scrollPosition, mView.setPosition); 68 | } else { 69 | mView.setPosition(0); 70 | } 71 | }; 72 | 73 | mView.reflow = function () { 74 | var container = mView.container, tmpHeight = container.offsetHeight, tmpWidth = container.offsetWidth; 75 | 76 | if ((tmpHeight === 0) || (tmpHeight === mParentHeight && tmpWidth === mParentWidth)) { 77 | return; 78 | } 79 | 80 | mView._ParentSize = container[mParentProp]; 81 | mParentHeight = tmpHeight; 82 | mParentWidth = tmpWidth; 83 | mView.refresh(); 84 | }; 85 | 86 | mView.getMaxPosition = function () { 87 | return mView._MaxScroll; 88 | }; 89 | 90 | mView.destroy = function () { 91 | window.removeEventListener('resize', eventResize); 92 | clearTimeout(mView.resizeTimeout); 93 | }; 94 | 95 | mView.handleEvent = function (e) { 96 | switch (e.type) { 97 | case STRINGS.fling: 98 | if (mAnimator.inBounds(mView.scrollPosition)) 99 | eventFling(e); 100 | break; 101 | case STRINGS.pointerdown: 102 | eventPointerDown(e); 103 | break; 104 | case STRINGS.pointermove: 105 | e.origin.preventDefault(); 106 | eventPointerMove(e); 107 | break; 108 | case STRINGS.pointerup: 109 | eventPointerUp(e); 110 | break; 111 | } 112 | e.release(); 113 | }; 114 | 115 | //======================== construction part ======================== 116 | mView.container = element; 117 | mView.scrollPosition = 0; 118 | 119 | eventFling = (function (isVertical) { 120 | if (isVertical) 121 | return function (e) { 122 | if (e.direction === STRINGS.vertical) { 123 | mAnimator.startFling(mView.scrollPosition, e.speed, mView.setPosition); 124 | } 125 | }; 126 | 127 | return function (e) { 128 | if (e.direction !== STRINGS.vertical) { 129 | mAnimator.startFling(mView.scrollPosition, e.speed, mView.setPosition); 130 | } 131 | }; 132 | 133 | })(mDirection === STRINGS.vertical); 134 | 135 | mView.setPosition = (function (enableListener) { 136 | if (enableListener) { 137 | return function (position, force, typeOfMotion) { 138 | mView.scrollPosition = force ? position : mAnimator.checkBounds(position); 139 | mTransitionArray[1] = mView.scrollPosition; 140 | mScrollingWrapper.style[mTransformName] = mTransitionArray.join(""); 141 | o.onScroll(mView.scrollPosition, typeOfMotion || STRINGS.move); 142 | }; 143 | } 144 | return function (position, force) { 145 | mView.scrollPosition = force ? position : mAnimator.checkBounds(position); 146 | mTransitionArray[1] = mView.scrollPosition; 147 | mScrollingWrapper.style[mTransformName] = mTransitionArray.join(""); 148 | }; 149 | })(o && typeof o.onScroll === 'function'); 150 | 151 | if (mDirection === STRINGS.vertical) { 152 | mTransitionArray[0] = "translate3d(0, "; 153 | mTransitionArray[2] = "px, 0) scale(1)"; 154 | } else { 155 | mTransitionArray[0] = "translate3d("; 156 | mTransitionArray[2] = "px, 0, 0) scale(1)"; 157 | } 158 | 159 | mTransitionName = addVendorPrefix("transition"); 160 | mTransformName = addVendorPrefix("transform"); 161 | 162 | var validPosition = ['fixed', 'relative', 'absolute'], tmp = validPosition.indexOf(window.getComputedStyle(element, null).position); 163 | element.style.position = (tmp === -1) ? 'relative' : validPosition[tmp]; 164 | element.style.overflow = 'hidden'; 165 | 166 | mScrollingWrapper = element.firstElementChild; 167 | mScrollingWrapper.style[(mDirection === STRINGS.vertical) ? 'width' : 'height'] = '100%'; 168 | mScrollingWrapper.style.margin = 0; 169 | mScrollingWrapper.style.position = 'absolute'; 170 | mScrollingWrapper.style[mTransitionName] = 'transform 0ms'; 171 | 172 | mView.reflow(); 173 | window.addEventListener('resize', eventResize, false); 174 | //================================================================== 175 | 176 | return mView; 177 | } -------------------------------------------------------------------------------- /servicelocator/bin/servicelocator.min.js: -------------------------------------------------------------------------------- 1 | function ServiceLocator(){function a(){i&&console.log(arguments)}function b(a){var b,c,d=Array.prototype.slice.call(arguments,1);for(a.__mixins=[],c=0;c1e3))if(b.recursion+=1,a.hasOwnProperty("__mixins")){for(c=0;c-1;i--)f(c[i]);else f(c);return this},regiaterAll:function(a){var b,c,d,e;for(b=0;b-1;d--)c.push(b(a[d]));else c=b(a);return c},unregisterAll:function(){var a,b,c=[];for(a in h)h.hasOwnProperty(a)&&(b=this.unregister(a),b&&c.push(b));return c}}} -------------------------------------------------------------------------------- /servicelocator/servicelocator.js: -------------------------------------------------------------------------------- 1 | function ServiceLocator() { 2 | var servicesWrap = {}, 3 | serviceMixin, 4 | debug = false; 5 | 6 | function log() { 7 | if (debug) { 8 | console.log(arguments); 9 | } 10 | } 11 | 12 | function mix(object) { 13 | var mixins = Array.prototype.slice.call(arguments, 1), key, i; 14 | object.__mixins = []; 15 | for (i = 0; i < mixins.length; ++i) { 16 | for (key in mixins[i]) { 17 | if (typeof object[key] === "undefined") { 18 | object[key] = mixins[i][key]; 19 | object.__mixins.push(key); 20 | } 21 | } 22 | } 23 | } 24 | 25 | function invoke(Constr, mixin, args) { 26 | var instance; 27 | 28 | function Temp(mixins) { 29 | var i, key; 30 | if (!mixins) return this; 31 | this.__mixins = []; 32 | for (i = 0; i < mixins.length; ++i) { 33 | for (key in mixins[i]) { 34 | this[key] = mixin[i][key]; 35 | this.__mixins.push(key); 36 | } 37 | } 38 | } 39 | 40 | Temp.prototype = Constr.prototype; 41 | Constr.prototype = new Temp(mixin); 42 | instance = new Constr(args); 43 | Constr.prototype = Temp.prototype; 44 | 45 | return instance; 46 | } 47 | 48 | function deleteProp(object, propList) { 49 | var j; 50 | 51 | if (!object || propList.recursion > 1000) return; 52 | 53 | propList.recursion += 1; 54 | if (object.hasOwnProperty('__mixins')) { 55 | for (j = 0; j < propList.length; j++) { 56 | delete object[propList[j]]; 57 | } 58 | delete object.__mixins; 59 | } else { 60 | deleteProp(Object.getPrototypeOf(object), propList); 61 | } 62 | } 63 | 64 | function unmix(object) { 65 | object.__mixins.recursion = 0; 66 | deleteProp(object, object.__mixins); 67 | 68 | return object; 69 | } 70 | 71 | function createObj(id) { 72 | log("create: " + id); 73 | return servicesWrap[id].instance = invoke(servicesWrap[id].creator, [ 74 | {radID: id}, 75 | serviceMixin 76 | ]); 77 | } 78 | 79 | return { 80 | 81 | printLog: function (flag) { 82 | debug = flag; 83 | return this; 84 | }, 85 | 86 | setMixin: function (obj) { 87 | serviceMixin = obj; 88 | return this; 89 | }, 90 | 91 | register: function (value, obj, instantiate) { 92 | 93 | function track(id){ 94 | if (servicesWrap[id] === undefined) { 95 | if (typeof obj === "function" && (instantiate === true || instantiate === undefined)) { 96 | servicesWrap[id] = { 97 | creator: obj 98 | }; 99 | } else { 100 | mix(obj, {radID: id}, serviceMixin); 101 | servicesWrap[id] = { 102 | instance: obj 103 | }; 104 | } 105 | } else { 106 | log('You try register already registered module:' + id + '!'); 107 | } 108 | } 109 | 110 | if (Object.prototype.toString.call(value) === '[object Array]') { 111 | for(var i = value.length - 1; i > -1; i--){ 112 | track(value[i]); 113 | } 114 | } else { 115 | track(value); 116 | } 117 | return this; 118 | }, 119 | 120 | regiaterAll: function (arrayOfServices) { 121 | var i, service, radID, obj; 122 | 123 | for (i = 0; i < arrayOfServices.length; ++i) { 124 | service = arrayOfServices[i]; 125 | radID = service.radID || service.ID || service.id; 126 | obj = service.service || service.obj || service.object || service.creator; 127 | this.register(radID, obj, service.instantiate); 128 | } 129 | return this; 130 | }, 131 | 132 | get: function (id) { 133 | if (servicesWrap[id] === undefined) { 134 | log('Error - ' + id + ' is unregister!'); 135 | return null; 136 | } 137 | 138 | return servicesWrap[id].instance || createObj(id); 139 | }, 140 | 141 | instantiateAll: function () { 142 | var radID, result = []; 143 | for (radID in servicesWrap) { 144 | if (servicesWrap.hasOwnProperty(radID) && servicesWrap[radID].creator && !servicesWrap[radID].instance) { 145 | result.push(createObj(radID)); 146 | } 147 | } 148 | return result; 149 | }, 150 | 151 | getAllInstantiate: function (withConstructor) { 152 | var radID, result = [], flag; 153 | for (radID in servicesWrap) { 154 | flag = (withConstructor) ? !!servicesWrap[radID].creator : true; 155 | if (servicesWrap.hasOwnProperty(radID) && servicesWrap[radID].instance && servicesWrap[radID].creator) { 156 | result.push(radID); 157 | } 158 | } 159 | return result; 160 | }, 161 | 162 | unregister: function (value) { 163 | var result, i; 164 | 165 | function remove(id){ 166 | var serviceData, instance; 167 | serviceData = servicesWrap[id]; 168 | if (serviceData && serviceData.instance) { 169 | instance = serviceData.instance; 170 | unmix(instance); 171 | } 172 | delete servicesWrap[id]; 173 | return instance; 174 | } 175 | 176 | if (Object.prototype.toString.call(value) === '[object Array]') { 177 | result = []; 178 | for (i = value.length - 1; i > -1; i--) { 179 | result.push(remove(value[i])); 180 | } 181 | } else { 182 | result = remove(value); 183 | } 184 | return result; 185 | }, 186 | 187 | unregisterAll: function () { 188 | var id, result = [], instance; 189 | 190 | for (id in servicesWrap) { 191 | if ( servicesWrap.hasOwnProperty(id)) { 192 | instance = this.unregister(id); 193 | if (instance) result.push(instance); 194 | } 195 | } 196 | return result; 197 | } 198 | 199 | }; 200 | } -------------------------------------------------------------------------------- /utils/bin/utils.min.js: -------------------------------------------------------------------------------- 1 | function addVendorPrefix(a){function b(a){return a.charAt(0).toUpperCase()+a.slice(1)}var c,d=["ms","Ms","moz","Moz","webkit","Webkit","o","O"],e=document.createElement("div"),f=null,g=[];for(c=0;c