1 /*-------------------------------------------------------- 2 * Copyright (c) 2011, The Dojo Foundation 3 * This software is distributed under the "Simplified BSD license", 4 * the text of which is available at http://www.winktoolkit.org/licence.txt 5 * or see the "license.txt" file for more details. 6 *--------------------------------------------------------*/ 7 8 /** 9 * @fileOverview Wink main object and core methods 10 * 11 * @compatibility iOS2, iOS3, iOS4, iOS5, iOS6, Android 1.1, Android 1.5, Android 2.1, Android 2.2, Android 2.3, Android 3.0, Android 3.1, Android 4.0, BlackBerry 6, BlackBerry 7, Bada 1.0, Windows Phone 7.5, Windows Phone 8 12 * @author Jerome GIRAUD 13 */ 14 15 define(['../../_kernel/js/kernel'], function(wink) 16 { 17 /** 18 * The version of Wink currently in use 19 * 20 * @property 21 * @type string 22 */ 23 wink.version = '1.4.3'; 24 25 /** 26 * @namespace Gathers all the HTML5 APIs related components 27 */ 28 wink.api = {}; 29 30 /** 31 * @namespace Gathers all things related to CSS effects 32 * 33 * @compatibility 34 * 35 * <b>2D fx</b> iOS2, iOS3, iOS4, iOS5, iOS6, Android 1.5, Android 2.1, Android 2.2, Android 2.3, Android 3.0, Android 3.1, Android 4.0, Bada 1.0, Windows Phone 7.5, Windows Phone 8 36 * <br /> 37 * <b>3D fx</b> iOS2, iOS3, iOS4, iOS5, iOS6, Android 3.0, Android 3.1, Android 4.0, BlackBerry 7, Windows Phone 8 38 * 39 * @see <a href="WINK_ROOT_URL/fx/_xy/test/test_xy_1.html" target="_blank">Test page</a> 40 * @see <a href="WINK_ROOT_URL/fx/_xy/test/test_xy_2.html" target="_blank">Test page (transition)</a> 41 * @see <a href="WINK_ROOT_URL/fx/_xyz/test/test_xyz.html" target="_blank">Test page (3d)</a> 42 */ 43 wink.fx = {}; 44 45 /** 46 * @namespace A set a of mathematical libraries and methods 47 * 48 * @compatibility 49 * 50 * <b>basics</b> iOS2, iOS3, iOS4, iOS5, iOS6, Android 1.1, Android 1.5, Android 2.1, Android 2.2, Android 2.3, Android 3.0, Android 3.1, Android 4.0, BlackBerry 6, BlackBerry 7, Bada 1.0, Windows Phone 7.5, Windows Phone 8 51 * <br /> 52 * <b>geometrics</b> iOS2, iOS3, iOS4, iOS5, iOS6, Android 1.1, Android 1.5, Android 2.1, Android 2.2, Android 2.3, Android 3.0, Android 3.1, Android 4.0, BlackBerry 6, BlackBerry 7, Bada 1.0, Windows Phone 7.5, Windows Phone 8 53 * <br /> 54 * <b>matrix</b> iOS2, iOS3, iOS4, iOS5, iOS6, Android 2.1, Android 2.2, Android 2.3, Android 3.0, Android 3.1, Android 4.0, BlackBerry 6, BlackBerry 7, Bada 1.0, Windows Phone 8 55 * 56 * @see <a href="WINK_ROOT_URL/math/_basics/test/test_basics.html" target="_blank">Test page (basics)</a> 57 * @see <a href="WINK_ROOT_URL/math/_geometric/test/test_geometric.html" target="_blank">Test page (geometric)</a> 58 * @see <a href="WINK_ROOT_URL/math/_matrix/test/test_matrix.html" target="_blank">Test page (matrix)</a> 59 */ 60 wink.math = {}; 61 62 /** 63 * @namespace Gathers all the multimedia components 64 */ 65 wink.mm = {}; 66 67 /** 68 * @namespace Gathers all the network related components 69 */ 70 wink.net = {}; 71 72 /** 73 * @namespace Gathers all the wink plugins 74 */ 75 wink.plugins = {}; 76 77 /** 78 * @namespace Gathers all the UI components 79 */ 80 wink.ui = 81 { 82 /** 83 * @namespace Gathers all the form components 84 */ 85 form: {}, 86 /** 87 * @namespace Gathers all the layout components 88 */ 89 layout: {}, 90 /** 91 * @namespace Gathers all the 2D components 92 */ 93 xy: {}, 94 /** 95 * @namespace Gathers all the 3D components 96 */ 97 xyz: {} 98 }; 99 100 /** 101 * @namespace Gathers all the interactions components 102 */ 103 wink.ux = {}; 104 105 var slice = Array.prototype.slice; 106 var wd = window; 107 108 /** 109 * Returns a DOM element 110 * 111 * @param {string} id The identifier of the DOM element to return 112 * @returns {HTMLElement} Returns the DOM ellement if it has been found or the id otherwise 113 * 114 * @example 115 * 116 * var test = wink.byId('myComponent'); 117 * 118 */ 119 wink.byId = function(id) 120 { 121 if (wink.isString(id)) 122 { 123 return document.getElementById(id); 124 } else 125 { 126 return id; 127 } 128 }; 129 130 /** 131 * Execute a query and returns the corresponding DOM elements 132 * 133 * @param {string} selector The query selector you want to use 134 * @param {HTMLElement} [element] The element where you want to search 135 * 136 * @returns {object} Returns a wrapper containing an array of the DOM elements corresponding to the query 137 * 138 * @example 139 * 140 * var test = wink.query('.MyClass'); 141 * var test2 = $$('input[type=radio]'); 142 * 143 * $$(".MyClass").removeClass("hidden").addClass("active"); 144 145 * $$(".MyClass").translate(20, 20).rotate(2); 146 * var positions = $$(".MyClass").getPosition(); 147 * 148 * if ($$("#box").hasClass("visible")) { 149 * $$("#box").applyTransition("background-color", "1s", "1ms", "linear").apply({ "background-color": "blue" }); 150 * $$("#box").listenTo("rotation", function(gestureInfos) { 151 * console.log("rotation [" + gestureInfos.rotation + "deg]"); 152 * }); 153 * } 154 * 155 */ 156 wink.query = function(selector, element) 157 { 158 return new QueryWrapper(selector, element); 159 }; 160 161 /** 162 * The QueryWrapper wraps the result of a query selection, allowing to chain some wink calls for each element 163 */ 164 var QueryWrapper = (function() { 165 var wrapper = function(selector, element) { 166 if (wink.isUndefined(wrapper.prototype.initialized)) { 167 this.init(); 168 } 169 170 var r; 171 try { 172 r = slice.call((element||document).querySelectorAll(selector)); 173 } catch (e) { 174 r = []; 175 } 176 var l = this.length = r.length; 177 178 for (var i = 0; i < l; i++) { 179 this[i] = r[i]; 180 } 181 this.selector = selector; 182 183 return this; 184 }; 185 186 var wp = wrapper.prototype = { 187 /** 188 * Initialize the wrapper prototype's methods 189 * @ignore 190 */ 191 init: function() { 192 wp.each([ 193 "pop", "push", "reverse", "shift", "sort", "splice", "unshift", "slice", "indexOf", "lastIndexOf", "forEach" 194 ], function(i, name) { 195 wp[name] = [][name]; 196 }); 197 198 wink.query.extend(wink, [ "getPosition", "getTopPosition", "getLeftPosition" ], true); 199 wink.query.extend(wink.fx, [ "getTransformPosition", "hasClass" ], true); 200 wink.query.extend(wink.fx, [ "translate", "rotate", "scale", "addClass", "removeClass", 201 "apply", "applyTransition", "applyTransformTransition", "onTransitionEnd" ], false); 202 wink.query.extend(wink.ux.gesture, [ "listenTo", "unlistenTo" ], false); 203 204 wp.each([ 205 "start", "move", "end" 206 ], function(i, name) { 207 wp[name] = function() { 208 var l = this.size(); 209 if (l == 0) { 210 return; 211 } 212 var i, nodes = this.toArray(), argus = this.splice.call(arguments, 0), t = wink.ux.touch; 213 for (i = 0; i < l; i++) { 214 t.addListener.apply(t, [ nodes[i], name ].concat(argus)); 215 } 216 } 217 }); 218 219 wp.initialized = true; 220 }, 221 /** 222 * Extends the wrapper. The user can extend another wrapper by giving it as a parameter. 223 * @ignore 224 */ 225 extend: function(context, methods, withResult, wrapper) { 226 var thewp = wrapper || wp, 227 map = {}; 228 229 var l = methods.length; 230 for (var i = 0; i < l; i++) { 231 var mi = methods[i], 232 f = context ? context[mi] : null; 233 if (wink.isFunction(f)) { 234 map[mi] = { c: context, f: f, r: withResult }; 235 } 236 } 237 238 wp.each(map, function(method, props) { 239 var f = props.f, 240 ctx = props.c, 241 withResult = props.r; 242 thewp[method] = function() { 243 var l = this.size(); 244 if (l == 0) { 245 return; 246 } 247 var i, nodes = this.toArray(), res = [], argus = this.splice.call(arguments, 0); 248 for (i = 0; i < l; i++) { 249 res.push(f.apply(ctx, [ nodes[i] ].concat(argus))); 250 } 251 if (!withResult) { 252 return this; 253 } 254 if (res.length == 1) { 255 return res[0]; 256 } 257 return res; 258 }; 259 }); 260 }, 261 /** 262 * @ignore 263 */ 264 size: function() { 265 return this.length; 266 }, 267 /** 268 * Gets an array of selected elements 269 * @ignore 270 */ 271 toArray: function() { 272 return slice.call(this, 0); 273 }, 274 /** 275 * Call the callback for each element of the list 276 * @ignore 277 */ 278 each: function(list, callback) { 279 for (var i in list) { 280 var li = list[i]; 281 callback.call(li, i, li); 282 } 283 } 284 }; 285 286 return wrapper; 287 })(); 288 289 /** 290 * Extends the wrapper 291 */ 292 wink.query.extend = QueryWrapper.prototype.extend; 293 294 295 var _winklocale = "en_EN"; 296 /** 297 * Set wink locale used for translation 298 * 299 * @param {string} locale The lang you want to set 300 */ 301 wink.setLocale = function(locale) 302 { 303 _winklocale = locale; 304 }; 305 306 /** 307 * Returns the translated value of a key 308 * 309 * @param {String} key The key identifying a ressource 310 * @param {Object} [object] The component that holds the resource list (within an i18n object) 311 * 312 * @returns {string} The translated value of the key 313 * 314 * @example 315 * 316 * var test = wink.translate('myText') 317 * var test2 = _('myText'); 318 * 319 */ 320 wink.translate = function(key, object) 321 { 322 var result = key; 323 var i18n = window.i18n || {}; 324 if (wink.isSet(object) && wink.isSet(object.i18n)) 325 { 326 i18n = object.i18n; 327 } 328 var resourceList = i18n[_winklocale]; 329 if (wink.isUndefined(resourceList)) { 330 resourceList = i18n; 331 } 332 var value = resourceList[key]; 333 if (!wink.isUndefined(value)) 334 { 335 result = value; 336 } 337 return result; 338 }; 339 340 /** 341 * Returns true if the given parameter is undefined, false otherwise. 342 * 343 * @param {object} object The object to test 344 * 345 * @returns {boolean} True if the object is undefined false otherwise 346 */ 347 wink.isUndefined = function(object) 348 { 349 return (object === undefined); 350 }; 351 352 /** 353 * Returns true if the given parameter is null, false otherwise. 354 * 355 * @param {object} object The object to test 356 * 357 * @returns {boolean} True if the object is null false otherwise 358 */ 359 wink.isNull = function(object) 360 { 361 return (object === null); 362 }; 363 364 /** 365 * Returns true if the given parameter is set, false otherwise. 366 * 367 * @param {object} object The object to test 368 * 369 * @returns {boolean} True if the object is set false otherwise 370 */ 371 wink.isSet = function(object) 372 { 373 return ((!wink.isUndefined(object)) && (!wink.isNull(object))); 374 }; 375 376 /** 377 * Returns true if the given callback object is valid (contains at least a method. It can also contain a context) 378 * A callback can be also a function. 379 * 380 * @param {object|function} callback The object to test 381 * 382 * @returns {boolean} True if the object is a valid callback false otherwise 383 */ 384 wink.isCallback = function(callback) 385 { 386 return !!((callback && callback.method) || wink.isFunction(callback)); 387 }; 388 389 /** 390 * Returns true if the given parameter is a string, false otherwise. 391 * 392 * @param {object} object The object to test 393 * 394 * @returns {boolean} True if the object is a string false otherwise 395 */ 396 wink.isString = function(object) 397 { 398 return (typeof object == "string" || object instanceof String); 399 }; 400 401 /** 402 * Returns true if the given parameter is an integer 403 * 404 * @param {object} object The object to test 405 * 406 * @returns {boolean} True if the object is an integer false otherwise 407 */ 408 wink.isInteger = function(object) 409 { 410 return (parseInt(object)===object); 411 }; 412 413 /** 414 * Returns true if the given parameter is a number 415 * 416 * @param {object} object The object to test 417 * 418 * @returns {boolean} True if the object is a number false otherwise 419 */ 420 wink.isNumber = function(object) 421 { 422 return (typeof object == "number" || object instanceof Number); 423 }; 424 425 /** 426 * Returns true if the given parameter is an array 427 * 428 * @param {object} object The object to test 429 * 430 * @returns {boolean} True if the object is an array false otherwise 431 */ 432 wink.isArray = function(object) 433 { 434 return (typeof object == "array" || object instanceof Array); 435 }; 436 437 /** 438 * Returns true if the given parameter is a boolean 439 * 440 * @param {object} object The object to test 441 * 442 * @returns {boolean} True if the object is a boolean false otherwise 443 */ 444 wink.isBoolean = function(object) 445 { 446 return (typeof object == "boolean" || object instanceof Boolean); 447 }; 448 449 /** 450 * Returns true if the given parameter is a function 451 * 452 * @param {object} object The object to test 453 * 454 * @returns {boolean} True if the object is a function false otherwise 455 */ 456 wink.isFunction = function(object) 457 { 458 return Object.prototype.toString.call(object) === "[object Function]"; 459 }; 460 461 /** 462 * Returns the given string parameter trimed. 463 * 464 * @param {string} str The string to trim 465 * 466 * @returns {string} The trimmed string 467 */ 468 wink.trim = function(str) 469 { 470 return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); 471 }; 472 473 /** 474 * Binds a method to a given context 475 * 476 * @param {string} method The method to bind 477 * @param {object} context The scope with which the method will be executed 478 * @param {object} [arguments] Arguments to pass to the binded function 479 * 480 * @returns {function} The binded function 481 */ 482 wink.bind = function(method, context /*[, arg1 [, arg2 ... ] ]*/) 483 { 484 var args = slice.call(arguments, 2); 485 return function() 486 { 487 var finalArgs = args.concat(slice.call(arguments, 0)); 488 return method.apply(context, finalArgs); 489 }; 490 }; 491 492 /** 493 * Invokes the given callback 494 * 495 * @param {object|function} callback The callback to invoke 496 * @param {object} [parameters] Parameters to pass to the callback 497 * 498 * @returns {function} The called function 499 * 500 * @example 501 * 502 * var ctx = { 503 * fn: function(params, message) { 504 * console.log("fn: ", params.property, message); 505 * } 506 * }; 507 * var fn2 = function(message, params) { 508 * console.log("fn2: ", params.property, message); 509 * }; 510 * wink.call({ context: ctx, method: 'fn', arguments: "message" }, { property: "value" }); 511 * wink.call(wink.bind(fn2, this, "message"), { property: "value" }); 512 * 513 */ 514 wink.call = function(callback, parameters) 515 { 516 if (wink.isFunction(callback)) 517 { 518 return callback.apply(wd, wink.isArray(parameters) ? parameters : [parameters]); 519 } 520 521 var context = wd; 522 var method = callback.method; 523 var args = []; 524 525 if (wink.isSet(callback.context)) 526 { 527 context = callback.context; 528 } 529 530 if (arguments.length == 2) 531 { 532 args = [parameters]; 533 } 534 if (wink.isSet(callback.arguments)) 535 { 536 var additional = callback.arguments; 537 if (!wink.isArray(additional)) { 538 additional = [callback.arguments]; 539 } 540 args = args.concat(additional); 541 } 542 return context[method].apply(context, args); 543 }; 544 545 /** 546 * Connect a method to another method 547 * 548 * @param {object} source The source context 549 * @param {string} method The source method 550 * @param {object|function} callback A callback that will be called once the source method will be invoked 551 */ 552 wink.connect = function(source, method, callback) 553 { 554 var isFn = wink.isFunction(callback); 555 if (!isFn && !wink.isSet(callback.context)) 556 { 557 callback.context = wd; 558 } 559 560 var f = source[method]; 561 562 if ( wink.isNull(f) || wink.isUndefined(f.cbs) ) 563 { 564 var _source = function() 565 { 566 var target = _source.target, 567 args = [].splice.call(arguments, 0); 568 569 var result = target && target.apply(source, args); 570 571 var i, cbs = _source.cbs.slice(0), l = cbs.length; 572 for (i = 0; i < l; i++) 573 { 574 var cb = cbs[i]; 575 if (wink.isFunction(cb)) 576 { 577 wink.call(cb, args); 578 } 579 else 580 { 581 wink.call({ context: cb.context, method: cb.method, arguments: args.concat(cb.arguments) }); 582 } 583 } 584 585 return result; 586 }; 587 588 _source.target = f; 589 _source.cbs = []; 590 591 f = source[method] = _source; 592 } 593 594 var i, cbs = f.cbs, l = cbs.length; 595 for (i = 0; i < l; i++) 596 { 597 var cb = cbs[i]; 598 if ((isFn && callback == cb) || (!isFn && cb.context == callback.context && cb.method == callback.method)) 599 { 600 return 601 } 602 } 603 604 cbs.push(callback); 605 }; 606 607 /** 608 * Disconnect two methods 609 * 610 * @param {object} source The source context that was previously connected 611 * @param {string} method The source method that was previously connected 612 * @param {object|function} callback The callback that was previously connected 613 */ 614 wink.disconnect = function(source, method, callback) 615 { 616 var isFn = wink.isFunction(callback); 617 if (!isFn && !wink.isSet(callback.context)) 618 { 619 callback.context = wd; 620 } 621 622 var f = source[method]; 623 624 if ( !wink.isUndefined(f.cbs) ) 625 { 626 var i, cbs = f.cbs, l = cbs.length; 627 for (i = 0; i < l; i++) 628 { 629 var cb = cbs[i]; 630 if ((isFn && callback == cb) || (!isFn && cb.context == callback.context && cb.method == callback.method)) 631 { 632 cbs.splice(i, 1); 633 break; 634 } 635 } 636 } 637 }; 638 639 /** 640 * Calls a deferred method. 641 * 642 * @param {object} context The execution context of the method to call 643 * @param {string} method The method to call 644 * @param {integer} delay Time (in milliseconds) to wait before calling method 645 * @param {object} [arguments] A list of caller arguments 646 * 647 * @returns {object} The timeout object 648 */ 649 wink.setTimeout = function(context, method, delay /*[, arg1 [, arg2 ... ] ]*/) 650 { 651 var args = slice.call(arguments, 3); 652 var toExecute = function() 653 { 654 context[method].apply(context, args); 655 }; 656 return setTimeout(toExecute, delay); 657 }; 658 659 /** 660 * Calls a method periodically at the provided frequency 661 * 662 * @param {object} context The execution context of the method to call 663 * @param {string} method The method to call 664 * @param {integer} delay Time (in milliseconds) to wait before calling method again 665 * @param {object} [arguments] A list of caller arguments 666 * 667 * @returns {object} The interval object 668 */ 669 wink.setInterval = function(context, method, delay /*[, arg1 [, arg2 ... ] ]*/) 670 { 671 var args = slice.call(arguments, 3); 672 var toExecute = function() 673 { 674 context[method].apply(context, args); 675 }; 676 return setInterval(toExecute, delay); 677 }; 678 679 /** 680 * Retrieve the position of a node (top, left and transform if specified) 681 * 682 * @param {HTMLElement} node The node 683 * @param {HTMLElement} [parentNode] If specified, the returned value is relative to the parentNode node. If parentNode is not a parent node of the current HTML element or if not specified, the returned value will be an absolute position 684 * @param {boolean} [transform] Take CSS transforms into account while calculating the position 685 * 686 * @returns {object} the x and y position of the element 687 */ 688 wink.getPosition = function(node, parentNode, transform) 689 { 690 var position = {x: 0, y: 0}; 691 var obj = node; 692 693 while (obj && obj != parentNode) 694 { 695 position.x += obj.offsetLeft; 696 position.y += obj.offsetTop; 697 698 if ( transform ) 699 { 700 position.x += wink.fx.getTransformPosition(obj).x; 701 position.y += wink.fx.getTransformPosition(obj).y; 702 } 703 704 obj = obj.offsetParent; 705 } 706 707 return position; 708 }; 709 710 /** 711 * Retrieve the top position of a node (top and transform if specified) 712 * 713 * @param {HTMLElement} node The node 714 * @param {HTMLElement} [parentNode] If specified, the returned value is relative to the parentNode node. If parentNode is not a parent node of the current HTML element or if not specified, the returned value will be an absolute top position 715 * @param {boolean} [transform] Take CSS transforms into account while calculating the position 716 * 717 * @returns {integer} the y position of the element 718 */ 719 wink.getTopPosition = function(node, parentNode, transform) 720 { 721 return (wink.getPosition(node, parentNode, transform).y); 722 }; 723 724 /** 725 * Retrieve the top position of a node (left and transform if specified) 726 * 727 * @param {HTMLElement} node The node 728 * @param {HTMLElement} [parentNode] If specified, the returned value is relative to the parentNode node. If parentNode is not a parent node of the current HTML element or if not specified, the returned value will be an absolute left position 729 * @param {boolean} [transform] Take CSS transforms into account while calculating the position 730 * 731 * @returns {integer} The x position of the element 732 */ 733 wink.getLeftPosition = function(node, parentNode, transform) 734 { 735 return (wink.getPosition(node, parentNode, transform).x); 736 }; 737 738 var _uidSequence = 100; 739 /** 740 * Generates a unique identifier 741 * 742 * @returns {integer} The unique id 743 */ 744 wink.getUId = function() 745 { 746 return (_uidSequence += 1); 747 }; 748 749 750 if (wink.isUndefined(wd._)) 751 { 752 /** 753 * @function 754 * @see wink.translate 755 */ 756 _ = wink.bind(wink.translate, wink); 757 } 758 759 if (wink.isUndefined(wd.$)) 760 { 761 /** 762 * @function 763 * @see wink.query 764 */ 765 $ = function() { 766 if ( console ) 767 { 768 console.log("$ is deprecated: the use of wink.query or $$ methods is recommanded"); 769 } 770 return wink.query.apply(wink, arguments); 771 }; 772 } 773 774 if (wink.isUndefined(wd.$$)) 775 { 776 /** 777 * @function 778 * @see wink.query 779 */ 780 $$ = wink.bind(wink.query, wink); 781 } 782 783 return wink; 784 }); 785