1/* jshint ignore:start */ 2 3window.EmberENV = {"FEATURES":{}}; 4var runningTests = false; 5 6 7 8/* jshint ignore:end */ 9 10;var loader, define, requireModule, require, requirejs; 11 12(function(global) { 13 'use strict'; 14 15 var stats; 16 17 // Save off the original values of these globals, so we can restore them if someone asks us to 18 var oldGlobals = { 19 loader: loader, 20 define: define, 21 requireModule: requireModule, 22 require: require, 23 requirejs: requirejs 24 }; 25 26 requirejs = require = requireModule = function(name) { 27 stats.require++; 28 var pending = []; 29 var mod = findModule(name, '(require)', pending); 30 31 for (var i = pending.length - 1; i >= 0; i--) { 32 pending[i].exports(); 33 } 34 35 return mod.module.exports; 36 }; 37 38 function resetStats() { 39 stats = { 40 define: 0, 41 require: 0, 42 reify: 0, 43 findDeps: 0, 44 modules: 0, 45 exports: 0, 46 resolve: 0, 47 resolveRelative: 0, 48 findModule: 0, 49 pendingQueueLength: 0 50 }; 51 requirejs._stats = stats; 52 } 53 54 55 resetStats(); 56 57 loader = { 58 noConflict: function(aliases) { 59 var oldName, newName; 60 61 for (oldName in aliases) { 62 if (aliases.hasOwnProperty(oldName)) { 63 if (oldGlobals.hasOwnProperty(oldName)) { 64 newName = aliases[oldName]; 65 66 global[newName] = global[oldName]; 67 global[oldName] = oldGlobals[oldName]; 68 } 69 } 70 } 71 } 72 }; 73 74 var _isArray; 75 if (!Array.isArray) { 76 _isArray = function (x) { 77 return Object.prototype.toString.call(x) === '[object Array]'; 78 }; 79 } else { 80 _isArray = Array.isArray; 81 } 82 83 var registry = {}; 84 var seen = {}; 85 86 var uuid = 0; 87 88 function unsupportedModule(length) { 89 throw new Error('an unsupported module was defined, expected `define(name, deps, module)` instead got: `' + 90 length + '` arguments to define`'); 91 } 92 93 var defaultDeps = ['require', 'exports', 'module']; 94 95 function Module(name, deps, callback, alias) { 96 stats.modules++; 97 this.id = uuid++; 98 this.name = name; 99 this.deps = !deps.length && callback.length ? defaultDeps : deps; 100 this.module = { exports: {} }; 101 this.callback = callback; 102 this.finalized = false; 103 this.hasExportsAsDep = false; 104 this.isAlias = alias; 105 this.reified = new Array(deps.length); 106 this._foundDeps = false; 107 this.isPending = false; 108 } 109 110 Module.prototype.makeDefaultExport = function() { 111 var exports = this.module.exports; 112 if (exports !== null && 113 (typeof exports === 'object' || typeof exports === 'function') && 114 exports['default'] === undefined) { 115 exports['default'] = exports; 116 } 117 }; 118 119 Module.prototype.exports = function() { 120 if (this.finalized) { return this.module.exports; } 121 stats.exports++; 122 123 this.finalized = true; 124 this.isPending = false; 125 126 if (loader.wrapModules) { 127 this.callback = loader.wrapModules(this.name, this.callback); 128 } 129 130 this.reify(); 131 132 var result = this.callback.apply(this, this.reified); 133 134 if (!(this.hasExportsAsDep && result === undefined)) { 135 this.module.exports = result; 136 } 137 this.makeDefaultExport(); 138 return this.module.exports; 139 }; 140 141 Module.prototype.unsee = function() { 142 this.finalized = false; 143 this._foundDeps = false; 144 this.isPending = false; 145 this.module = { exports: {} }; 146 }; 147 148 Module.prototype.reify = function() { 149 stats.reify++; 150 var reified = this.reified; 151 for (var i = 0; i < reified.length; i++) { 152 var mod = reified[i]; 153 reified[i] = mod.exports ? mod.exports : mod.module.exports(); 154 } 155 }; 156 157 Module.prototype.findDeps = function(pending) { 158 if (this._foundDeps) { 159 return; 160 } 161 162 stats.findDeps++; 163 this._foundDeps = true; 164 this.isPending = true; 165 166 var deps = this.deps; 167 168 for (var i = 0; i < deps.length; i++) { 169 var dep = deps[i]; 170 var entry = this.reified[i] = { exports: undefined, module: undefined }; 171 if (dep === 'exports') { 172 this.hasExportsAsDep = true; 173 entry.exports = this.module.exports; 174 } else if (dep === 'require') { 175 entry.exports = this.makeRequire(); 176 } else if (dep === 'module') { 177 entry.exports = this.module; 178 } else { 179 entry.module = findModule(resolve(dep, this.name), this.name, pending); 180 } 181 } 182 }; 183 184 Module.prototype.makeRequire = function() { 185 var name = this.name; 186 var r = function(dep) { 187 return require(resolve(dep, name)); 188 }; 189 r['default'] = r; 190 r.has = function(dep) { 191 return has(resolve(dep, name)); 192 }; 193 return r; 194 }; 195 196 define = function(name, deps, callback) { 197 stats.define++; 198 if (arguments.length < 2) { 199 unsupportedModule(arguments.length); 200 } 201 202 if (!_isArray(deps)) { 203 callback = deps; 204 deps = []; 205 } 206 207 if (callback instanceof Alias) { 208 registry[name] = new Module(callback.name, deps, callback, true); 209 } else { 210 registry[name] = new Module(name, deps, callback, false); 211 } 212 }; 213 214 // we don't support all of AMD 215 // define.amd = {}; 216 // we will support petals... 217 define.petal = { }; 218 219 function Alias(path) { 220 this.name = path; 221 } 222 223 define.alias = function(path) { 224 return new Alias(path); 225 }; 226 227 function missingModule(name, referrer) { 228 throw new Error('Could not find module `' + name + '` imported from `' + referrer + '`'); 229 } 230 231 function findModule(name, referrer, pending) { 232 stats.findModule++; 233 var mod = registry[name] || registry[name + '/index']; 234 235 while (mod && mod.isAlias) { 236 mod = registry[mod.name]; 237 } 238 239 if (!mod) { missingModule(name, referrer); } 240 241 if (pending && !mod.finalized && !mod.isPending) { 242 mod.findDeps(pending); 243 pending.push(mod); 244 stats.pendingQueueLength++; 245 } 246 return mod; 247 } 248 249 function resolve(child, name) { 250 stats.resolve++; 251 if (child.charAt(0) !== '.') { return child; } 252 stats.resolveRelative++; 253 254 var parts = child.split('/');
255 var nameParts = name.split('/'); 256 var parentBase = nameParts.slice(0, -1); 257 258 for (var i = 0, l = parts.length; i < l; i++) { 259 var part = parts[i]; 260 261 if (part === '..') { 262 if (parentBase.length === 0) { 263 throw new Error('Cannot access parent module of root'); 264 } 265 parentBase.pop(); 266 } else if (part === '.') { 267 continue; 268 } else { parentBase.push(part); } 269 } 270 271 return parentBase.join('/'); 272 } 273 274 function has(name) { 275 return !!(registry[name] || registry[name + '/index']); 276 } 277 278 requirejs.entries = requirejs._eak_seen = registry; 279 requirejs.has = has; 280 requirejs.unsee = function(moduleName) { 281 findModule(moduleName, '(unsee)', false).unsee(); 282 }; 283 284 requirejs.clear = function() { 285 resetStats(); 286 requirejs.entries = requirejs._eak_seen = registry = {}; 287 seen = {}; 288 }; 289 290 // prime 291 define('foo', function() {}); 292 define('foo/bar', [], function() {}); 293 define('foo/asdf', ['module', 'exports', 'require'], function(module, exports, require) { 294 if (require.has('foo/bar')) { 295 require('foo/bar'); 296 } 297 }); 298 define('foo/baz', [], define.alias('foo')); 299 define('foo/quz', define.alias('foo')); 300 define('foo/bar', ['foo', './quz', './baz', './asdf', './bar', '../foo'], function() {}); 301 define('foo/main', ['foo/bar'], function() {}); 302 303 require('foo/main'); 304 require.unsee('foo/bar'); 305 306 requirejs.clear(); 307 308 if (typeof exports === 'object' && typeof module === 'object' && module.exports) { 309 module.exports = { require: require, define: define }; 310 } 311})(this); 312 313;self.EmberENV.EXTEND_PROTOTYPES = false; 314 315;
vendor: 257,552 bytes, lines 315-10129
315/*! 316 * jQuery JavaScript Library v2.2.4 317 * http://jquery.com/ 318 * 319 * Includes Sizzle.js 320 * http://sizzlejs.com/ 321 * 322 * Copyright jQuery Foundation and other contributors 323 * Released under the MIT license 324 * http://jquery.org/license 325 * 326 * Date: 2016-05-20T17:23Z 327 */ 328 329(function( global, factory ) { 330 331 if ( typeof module === "object" && typeof module.exports === "object" ) { 332 // For CommonJS and CommonJS-like environments where a proper `window` 333 // is present, execute the factory and get jQuery. 334 // For environments that do not have a `window` with a `document` 335 // (such as Node.js), expose a factory as module.exports. 336 // This accentuates the need for the creation of a real `window`. 337 // e.g. var jQuery = require("jquery")(window); 338 // See ticket #14549 for more info. 339 module.exports = global.document ? 340 factory( global, true ) : 341 function( w ) { 342 if ( !w.document ) { 343 throw new Error( "jQuery requires a window with a document" ); 344 } 345 return factory( w ); 346 }; 347 } else { 348 factory( global ); 349 } 350 351// Pass this if window is not defined yet 352}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { 353 354// Support: Firefox 18+ 355// Can't be in strict mode, several libs including ASP.NET trace 356// the stack via arguments.caller.callee and Firefox dies if 357// you try to trace through "use strict" call chains. (#13335) 358//"use strict"; 359var arr = []; 360 361var document = window.document; 362 363var slice = arr.slice; 364 365var concat = arr.concat; 366 367var push = arr.push; 368 369var indexOf = arr.indexOf; 370 371var class2type = {}; 372 373var toString = class2type.toString; 374 375var hasOwn = class2type.hasOwnProperty; 376 377var support = {}; 378 379 380 381var 382 version = "2.2.4", 383 384 // Define a local copy of jQuery 385 jQuery = function( selector, context ) { 386 387 // The jQuery object is actually just the init constructor 'enhanced' 388 // Need init if jQuery is called (just allow error to be thrown if not included) 389 return new jQuery.fn.init( selector, context ); 390 }, 391 392 // Support: Android<4.1 393 // Make sure we trim BOM and NBSP 394 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, 395 396 // Matches dashed string for camelizing 397 rmsPrefix = /^-ms-/, 398 rdashAlpha = /-([\da-z])/gi, 399 400 // Used by jQuery.camelCase as callback to replace() 401 fcamelCase = function( all, letter ) { 402 return letter.toUpperCase(); 403 }; 404 405jQuery.fn = jQuery.prototype = { 406 407 // The current version of jQuery being used 408 jquery: version, 409 410 constructor: jQuery, 411 412 // Start with an empty selector 413 selector: "", 414 415 // The default length of a jQuery object is 0 416 length: 0, 417 418 toArray: function() { 419 return slice.call( this ); 420 }, 421 422 // Get the Nth element in the matched element set OR 423 // Get the whole matched element set as a clean array 424 get: function( num ) { 425 return num != null ? 426 427 // Return just the one element from the set 428 ( num < 0 ? this[ num + this.length ] : this[ num ] ) : 429 430 // Return all the elements in a clean array 431 slice.call( this ); 432 }, 433 434 // Take an array of elements and push it onto the stack 435 // (returning the new matched element set) 436 pushStack: function( elems ) { 437 438 // Build a new jQuery matched element set 439 var ret = jQuery.merge( this.constructor(), elems ); 440 441 // Add the old object onto the stack (as a reference) 442 ret.prevObject = this; 443 ret.context = this.context; 444 445 // Return the newly-formed element set 446 return ret; 447 }, 448 449 // Execute a callback for every element in the matched set. 450 each: function( callback ) { 451 return jQuery.each( this, callback ); 452 }, 453 454 map: function( callback ) { 455 return this.pushStack( jQuery.map( this, function( elem, i ) { 456 return callback.call( elem, i, elem ); 457 } ) ); 458 }, 459 460 slice: function() { 461 return this.pushStack( slice.apply( this, arguments ) ); 462 }, 463 464 first: function() { 465 return this.eq( 0 ); 466 }, 467 468 last: function() { 469 return this.eq( -1 ); 470 }, 471 472 eq: function( i ) { 473 var len = this.length, 474 j = +i + ( i < 0 ? len : 0 ); 475 return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); 476 }, 477 478 end: function() { 479 return this.prevObject || this.constructor(); 480 }, 481 482 // For internal use only. 483 // Behaves like an Array's method, not like a jQuery method. 484 push: push, 485 sort: arr.sort, 486 splice: arr.splice 487}; 488 489jQuery.extend = jQuery.fn.extend = function() { 490 var options, name, src, copy, copyIsArray, clone, 491 target = arguments[ 0 ] || {}, 492 i = 1, 493 length = arguments.length, 494 deep = false; 495 496 // Handle a deep copy situation 497 if ( typeof target === "boolean" ) { 498 deep = target; 499 500 // Skip the boolean and the target 501 target = arguments[ i ] || {}; 502 i++; 503 } 504 505 // Handle case when target is a string or something (possible in deep copy) 506 if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { 507 target = {}; 508 } 509 510 // Extend jQuery itself if only one argument is passed 511 if ( i === length ) { 512 target = this; 513 i--; 514 } 515 516 for ( ; i < length; i++ ) { 517 518 // Only deal with non-null/undefined values 519 if ( ( options = arguments[ i ] ) != null ) { 520 521 // Extend the base object 522 for ( name in options ) { 523 src = target[ name ]; 524 copy = options[ name ]; 525 526 // Prevent never-ending loop 527 if ( target === copy ) { 528 continue; 529 } 530 531 // Recurse if we're merging plain objects or arrays 532 if ( deep && copy && ( jQuery.isPlainObject( copy ) || 533 ( copyIsArray = jQuery.isArray( copy ) ) ) ) { 534 535 if ( copyIsArray ) { 536 copyIsArray = false; 537 clone = src && jQuery.isArray( src ) ? src : []; 538 539 } else { 540 clone = src && jQuery.isPlainObject( src ) ? src : {}; 541 } 542 543 // Never move original objects, clone them 544 target[ name ] = jQuery.extend( deep, clone, copy ); 545 546 // Don't bring in undefined values 547 } else if ( copy !== undefined ) { 548 target[ name ] = copy; 549 } 550 } 551 } 552 } 553 554 // Return the modified object 555 return target; 556}; 557 558jQuery.extend( { 559 560 // Unique for each copy of jQuery on the page 561 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 562 563 // Assume jQuery is ready without the ready module 564 isReady: true, 565 566 error: function( msg ) { 567 throw new Error( msg ); 568 }, 569 570 noop: function() {}, 571 572 isFunction: function( obj ) { 573 return jQuery.type( obj ) === "function"; 574 }, 575 576 isArray: Array.isArray, 577 578 isWindow: function( obj ) { 579 return obj != null && obj === obj.window; 580 }, 581 582 isNumeric: function( obj ) { 583 584 // parseFloat NaNs numeric-cast false positives (null|true|false|"") 585 // ...but misinterprets leading-number strings, particularly hex literals ("0x...") 586 // subtraction forces infinities to NaN 587 // adding 1 corrects loss of precision from parseFloat (#15100) 588 var realStringObj = obj && obj.toString(); 589 return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; 590 }, 591 592 isPlainObject: function( obj ) { 593 var key; 594 595 // Not plain objects: 596 // - Any object or value whose internal [[Class]] property is not "[object Object]" 597 // - DOM nodes 598 // - window 599 if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { 600 return false; 601 } 602 603 // Not own constructor property must be Object 604 if ( obj.constructor && 605 !hasOwn.call( obj, "constructor" ) && 606 !hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) { 607 return false; 608 } 609 610 // Own properties are enumerated firstly, so to speed up, 611 // if last one is own, then all properties are own 612 for ( key in obj ) {} 613 614 return key === undefined || hasOwn.call( obj, key ); 615 }, 616 617 isEmptyObject: function( obj ) { 618 var name; 619 for ( name in obj ) { 620 return false; 621 } 622 return true; 623 }, 624 625 type: function( obj ) { 626 if ( obj == null ) { 627 return obj + ""; 628 } 629 630 // Support: Android<4.0, iOS<6 (functionish RegExp) 631 return typeof obj === "object" || typeof obj === "function" ? 632 class2type[ toString.call( obj ) ] || "object" : 633 typeof obj; 634 }, 635 636 // Evaluates a script in a global context 637 globalEval: function( code ) { 638 var script, 639 indirect = eval; 640 641 code = jQuery.trim( code ); 642 643 if ( code ) { 644 645 // If the code includes a valid, prologue position 646 // strict mode pragma, execute code by injecting a 647 // script tag into the document. 648 if ( code.indexOf( "use strict" ) === 1 ) { 649 script = document.createElement( "script" ); 650 script.text = code; 651 document.head.appendChild( script ).parentNode.removeChild( script ); 652 } else { 653 654 // Otherwise, avoid the DOM node creation, insertion 655 // and removal by using an indirect global eval 656 657 indirect( code ); 658 } 659 } 660 }, 661 662 // Convert dashed to camelCase; used by the css and data modules 663 // Support: IE9-11+ 664 // Microsoft forgot to hump their vendor prefix (#9572) 665 camelCase: function( string ) { 666 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 667 }, 668 669 nodeName: function( elem, name ) { 670 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 671 }, 672 673 each: function( obj, callback ) { 674 var length, i = 0; 675 676 if ( isArrayLike( obj ) ) { 677 length = obj.length; 678 for ( ; i < length; i++ ) { 679 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 680 break; 681 } 682 } 683 } else { 684 for ( i in obj ) { 685 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 686 break; 687 } 688 } 689 } 690 691 return obj; 692 }, 693 694 // Support: Android<4.1 695 trim: function( text ) { 696 return text == null ? 697 "" : 698 ( text + "" ).replace( rtrim, "" ); 699 }, 700 701 // results is for internal usage only 702 makeArray: function( arr, results ) { 703 var ret = results || []; 704 705 if ( arr != null ) { 706 if ( isArrayLike( Object( arr ) ) ) { 707 jQuery.merge( ret, 708 typeof arr === "string" ? 709 [ arr ] : arr 710 ); 711 } else { 712 push.call( ret, arr ); 713 } 714 } 715 716 return ret; 717 }, 718 719 inArray: function( elem, arr, i ) { 720 return arr == null ? -1 : indexOf.call( arr, elem, i ); 721 }, 722 723 merge: function( first, second ) { 724 var len = +second.length, 725 j = 0, 726 i = first.length; 727 728 for ( ; j < len; j++ ) { 729 first[ i++ ] = second[ j ]; 730 } 731 732 first.length = i; 733 734 return first; 735 }, 736 737 grep: function( elems, callback, invert ) { 738 var callbackInverse, 739 matches = [], 740 i = 0, 741 length = elems.length, 742 callbackExpect = !invert; 743 744 // Go through the array, only saving the items 745 // that pass the validator function 746 for ( ; i < length; i++ ) { 747 callbackInverse = !callback( elems[ i ], i ); 748 if ( callbackInverse !== callbackExpect ) { 749 matches.push( elems[ i ] ); 750 } 751 } 752 753 return matches; 754 }, 755 756 // arg is for internal usage only 757 map: function( elems, callback, arg ) { 758 var length, value, 759 i = 0, 760 ret = []; 761 762 // Go through the array, translating each of the items to their new values 763 if ( isArrayLike( elems ) ) { 764 length = elems.length; 765 for ( ; i < length; i++ ) { 766 value = callback( elems[ i ], i, arg ); 767 768 if ( value != null ) { 769 ret.push( value ); 770 } 771 } 772 773 // Go through every key on the object, 774 } else { 775 for ( i in elems ) { 776 value = callback( elems[ i ], i, arg ); 777 778 if ( value != null ) { 779 ret.push( value ); 780 } 781 } 782 } 783 784 // Flatten any nested arrays 785 return concat.apply( [], ret ); 786 }, 787 788 // A global GUID counter for objects 789 guid: 1, 790 791 // Bind a function to a context, optionally partially applying any 792 // arguments. 793 proxy: function( fn, context ) { 794 var tmp, args, proxy; 795 796 if ( typeof context === "string" ) { 797 tmp = fn[ context ]; 798 context = fn; 799 fn = tmp; 800 } 801 802 // Quick check to determine if target is callable, in the spec 803 // this throws a TypeError, but we will just return undefined. 804 if ( !jQuery.isFunction( fn ) ) { 805 return undefined; 806 } 807 808 // Simulated bind 809 args = slice.call( arguments, 2 ); 810 proxy = function() { 811 return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); 812 }; 813 814 // Set the guid of unique handler to the same of original handler, so it can be removed 815 proxy.guid = fn.guid = fn.guid || jQuery.guid++; 816 817 return proxy; 818 }, 819 820 now: Date.now, 821 822 // jQuery.support is not used in Core but other projects attach their 823 // properties to it so it needs to exist. 824 support: support 825} ); 826 827// JSHint would error on this code due to the Symbol not being defined in ES5. 828// Defining this global in .jshintrc would create a danger of using the global 829// unguarded in another place, it seems safer to just disable JSHint for these 830// three lines. 831/* jshint ignore: start */ 832if ( typeof Symbol === "function" ) { 833 jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; 834} 835/* jshint ignore: end */ 836 837// Populate the class2type map 838jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), 839function( i, name ) { 840 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 841} ); 842 843function isArrayLike( obj ) { 844 845 // Support: iOS 8.2 (not reproducible in simulator) 846 // `in` check used to prevent JIT error (gh-2145) 847 // hasOwn isn't used here due to false negatives 848 // regarding Nodelist length in IE 849 var length = !!obj && "length" in obj && obj.length, 850 type = jQuery.type( obj ); 851 852 if ( type === "function" || jQuery.isWindow( obj ) ) { 853 return false; 854 } 855 856 return type === "array" || length === 0 || 857 typeof length === "number" && length > 0 && ( length - 1 ) in obj; 858} 859var Sizzle = 860/*! 861 * Sizzle CSS Selector Engine v2.2.1 862 * http://sizzlejs.com/ 863 * 864 * Copyright jQuery Foundation and other contributors 865 * Released under the MIT license 866 * http://jquery.org/license 867 * 868 * Date: 2015-10-17 869 */ 870(function( window ) { 871 872var i, 873 support, 874 Expr, 875 getText, 876 isXML, 877 tokenize, 878 compile, 879 select, 880 outermostContext, 881 sortInput, 882 hasDuplicate, 883 884 // Local document vars 885 setDocument, 886 document, 887 docElem, 888 documentIsHTML, 889 rbuggyQSA, 890 rbuggyMatches, 891 matches, 892 contains, 893 894 // Instance-specific data 895 expando = "sizzle" + 1 * new Date(), 896 preferredDoc = window.document, 897 dirruns = 0, 898 done = 0, 899 classCache = createCache(), 900 tokenCache = createCache(), 901 compilerCache = createCache(), 902 sortOrder = function( a, b ) { 903 if ( a === b ) { 904 hasDuplicate = true; 905 } 906 return 0; 907 }, 908 909 // General-purpose constants 910 MAX_NEGATIVE = 1 << 31, 911 912 // Instance methods 913 hasOwn = ({}).hasOwnProperty, 914 arr = [], 915 pop = arr.pop, 916 push_native = arr.push, 917 push = arr.push, 918 slice = arr.slice, 919 // Use a stripped-down indexOf as it's faster than native 920 // http://jsperf.com/thor-indexof-vs-for/5 921 indexOf = function( list, elem ) { 922 var i = 0, 923 len = list.length; 924 for ( ; i < len; i++ ) { 925 if ( list[i] === elem ) { 926 return i; 927 } 928 } 929 return -1; 930 }, 931 932 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", 933 934 // Regular expressions 935 936 // http://www.w3.org/TR/css3-selectors/#whitespace 937 whitespace = "[\\x20\\t\\r\\n\\f]", 938 939 // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier 940 identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", 941 942 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors 943 attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + 944 // Operator (capture 2) 945 "*([*^$|!~]?=)" + whitespace + 946 // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" 947 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + 948 "*\\]", 949 950 pseudos = ":(" + identifier + ")(?:\\((" + 951 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: 952 // 1. quoted (capture 3; capture 4 or capture 5) 953 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + 954 // 2. simple (capture 6) 955 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + 956 // 3. anything else (capture 2) 957 ".*" + 958 ")\\)|)", 959 960 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter 961 rwhitespace = new RegExp( whitespace + "+", "g" ), 962 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), 963 964 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), 965 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), 966 967 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), 968 969 rpseudo = new RegExp( pseudos ), 970 ridentifier = new RegExp( "^" + identifier + "$" ), 971 972 matchExpr = { 973 "ID": new RegExp( "^#(" + identifier + ")" ), 974 "CLASS": new RegExp( "^\\.(" + identifier + ")" ), 975 "TAG": new RegExp( "^(" + identifier + "|[*])" ), 976 "ATTR": new RegExp( "^" + attributes ), 977 "PSEUDO": new RegExp( "^" + pseudos ), 978 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + 979 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + 980 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), 981 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), 982 // For use in libraries implementing .is() 983 // We use this for POS matching in `select` 984 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + 985 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) 986 }, 987 988 rinputs = /^(?:input|select|textarea|button)$/i, 989 rheader = /^h\d$/i, 990 991 rnative = /^[^{]+\{\s*\[native \w/, 992 993 // Easily-parseable/retrievable ID or TAG or CLASS selectors 994 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, 995 996 rsibling = /[+~]/, 997 rescape = /'|\\/g, 998 999 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters 1000 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), 1001 funescape = function( _, escaped, escapedWhitespace ) { 1002 var high = "0x" + escaped - 0x10000; 1003 // NaN means non-codepoint 1004 // Support: Firefox<24 1005 // Workaround erroneous numeric interpretation of +"0x" 1006 return high !== high || escapedWhitespace ? 1007 escaped : 1008 high < 0 ? 1009 // BMP codepoint 1010 String.fromCharCode( high + 0x10000 ) : 1011 // Supplemental Plane codepoint (surrogate pair) 1012 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); 1013 }, 1014 1015 // Used for iframes 1016 // See setDocument() 1017 // Removing the function wrapper causes a "Permission Denied" 1018 // error in IE 1019 unloadHandler = function() { 1020 setDocument(); 1021 }; 1022 1023// Optimize for push.apply( _, NodeList ) 1024try { 1025 push.apply( 1026 (arr = slice.call( preferredDoc.childNodes )), 1027 preferredDoc.childNodes 1028 ); 1029 // Support: Android<4.0 1030 // Detect silently failing push.apply 1031 arr[ preferredDoc.childNodes.length ].nodeType; 1032} catch ( e ) { 1033 push = { apply: arr.length ? 1034 1035 // Leverage slice if possible 1036 function( target, els ) { 1037 push_native.apply( target, slice.call(els) ); 1038 } : 1039 1040 // Support: IE<9 1041 // Otherwise append directly 1042 function( target, els ) { 1043 var j = target.length, 1044 i = 0; 1045 // Can't trust NodeList.length 1046 while ( (target[j++] = els[i++]) ) {} 1047 target.length = j - 1; 1048 } 1049 }; 1050} 1051 1052function Sizzle( selector, context, results, seed ) { 1053 var m, i, elem, nid, nidselect, match, groups, newSelector, 1054 newContext = context && context.ownerDocument, 1055 1056 // nodeType defaults to 9, since context defaults to document 1057 nodeType = context ? context.nodeType : 9; 1058 1059 results = results || []; 1060 1061 // Return early from calls with invalid selector or context 1062 if ( typeof selector !== "string" || !selector || 1063 nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { 1064 1065 return results; 1066 } 1067 1068 // Try to shortcut find operations (as opposed to filters) in HTML documents 1069 if ( !seed ) { 1070 1071 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { 1072 setDocument( context ); 1073 } 1074 context = context || document; 1075 1076 if ( documentIsHTML ) { 1077 1078 // If the selector is sufficiently simple, try using a "get*By*" DOM method 1079 // (excepting DocumentFragment context, where the methods don't exist) 1080 if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { 1081 1082 // ID selector 1083 if ( (m = match[1]) ) { 1084 1085 // Document context 1086 if ( nodeType === 9 ) { 1087 if ( (elem = context.getElementById( m )) ) { 1088 1089 // Support: IE, Opera, Webkit 1090 // TODO: identify versions 1091 // getElementById can match elements by name instead of ID 1092 if ( elem.id === m ) { 1093 results.push( elem ); 1094 return results; 1095 } 1096 } else { 1097 return results; 1098 } 1099 1100 // Element context 1101 } else { 1102 1103 // Support: IE, Opera, Webkit 1104 // TODO: identify versions 1105 // getElementById can match elements by name instead of ID 1106 if ( newContext && (elem = newContext.getElementById( m )) && 1107 contains( context, elem ) && 1108 elem.id === m ) { 1109 1110 results.push( elem ); 1111 return results; 1112 } 1113 } 1114 1115 // Type selector 1116 } else if ( match[2] ) { 1117 push.apply( results, context.getElementsByTagName( selector ) ); 1118 return results; 1119 1120 // Class selector 1121 } else if ( (m = match[3]) && support.getElementsByClassName && 1122 context.getElementsByClassName ) { 1123 1124 push.apply( results, context.getElementsByClassName( m ) ); 1125 return results; 1126 } 1127 } 1128 1129 // Take advantage of querySelectorAll 1130 if ( support.qsa && 1131 !compilerCache[ selector + " " ] && 1132 (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { 1133 1134 if ( nodeType !== 1 ) { 1135 newContext = context; 1136 newSelector = selector; 1137 1138 // qSA looks outside Element context, which is not what we want 1139 // Thanks to Andrew Dupont for this workaround technique 1140 // Support: IE <=8 1141 // Exclude object elements 1142 } else if ( context.nodeName.toLowerCase() !== "object" ) { 1143 1144 // Capture the context ID, setting it first if necessary 1145 if ( (nid = context.getAttribute( "id" )) ) { 1146 nid = nid.replace( rescape, "\\$&" ); 1147 } else { 1148 context.setAttribute( "id", (nid = expando) ); 1149 } 1150 1151 // Prefix every selector in the list 1152 groups = tokenize( selector ); 1153 i = groups.length; 1154 nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; 1155 while ( i-- ) { 1156 groups[i] = nidselect + " " + toSelector( groups[i] ); 1157 } 1158 newSelector = groups.join( "," ); 1159 1160 // Expand context for sibling selectors 1161 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || 1162 context; 1163 } 1164 1165 if ( newSelector ) { 1166 try { 1167 push.apply( results, 1168 newContext.querySelectorAll( newSelector ) 1169 ); 1170 return results; 1171 } catch ( qsaError ) { 1172 } finally { 1173 if ( nid === expando ) { 1174 context.removeAttribute( "id" ); 1175 } 1176 } 1177 } 1178 } 1179 } 1180 } 1181 1182 // All others 1183 return select( selector.replace( rtrim, "$1" ), context, results, seed ); 1184} 1185 1186/** 1187 * Create key-value caches of limited size 1188 * @returns {function(string, object)} Returns the Object data after storing it on itself with 1189 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) 1190 * deleting the oldest entry 1191 */ 1192function createCache() { 1193 var keys = []; 1194 1195 function cache( key, value ) { 1196 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) 1197 if ( keys.push( key + " " ) > Expr.cacheLength ) { 1198 // Only keep the most recent entries 1199 delete cache[ keys.shift() ]; 1200 } 1201 return (cache[ key + " " ] = value); 1202 } 1203 return cache; 1204} 1205 1206/** 1207 * Mark a function for special use by Sizzle 1208 * @param {Function} fn The function to mark 1209 */ 1210function markFunction( fn ) { 1211 fn[ expando ] = true; 1212 return fn; 1213} 1214 1215/** 1216 * Support testing using an element 1217 * @param {Function} fn Passed the created div and expects a boolean result 1218 */ 1219function assert( fn ) { 1220 var div = document.createElement("div"); 1221 1222 try { 1223 return !!fn( div ); 1224 } catch (e) { 1225 return false; 1226 } finally { 1227 // Remove from its parent by default 1228 if ( div.parentNode ) { 1229 div.parentNode.removeChild( div ); 1230 } 1231 // release memory in IE 1232 div = null; 1233 } 1234} 1235 1236/** 1237 * Adds the same handler for all of the specified attrs 1238 * @param {String} attrs Pipe-separated list of attributes 1239 * @param {Function} handler The method that will be applied 1240 */ 1241function addHandle( attrs, handler ) { 1242 var arr = attrs.split("|"), 1243 i = arr.length; 1244 1245 while ( i-- ) { 1246 Expr.attrHandle[ arr[i] ] = handler; 1247 } 1248} 1249 1250/** 1251 * Checks document order of two siblings 1252 * @param {Element} a 1253 * @param {Element} b 1254 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b 1255 */ 1256function siblingCheck( a, b ) { 1257 var cur = b && a, 1258 diff = cur && a.nodeType === 1 && b.nodeType === 1 && 1259 ( ~b.sourceIndex || MAX_NEGATIVE ) - 1260 ( ~a.sourceIndex || MAX_NEGATIVE ); 1261 1262 // Use IE sourceIndex if available on both nodes 1263 if ( diff ) { 1264 return diff; 1265 } 1266 1267 // Check if b follows a 1268 if ( cur ) { 1269 while ( (cur = cur.nextSibling) ) { 1270 if ( cur === b ) { 1271 return -1; 1272 } 1273 } 1274 } 1275 1276 return a ? 1 : -1; 1277} 1278 1279/** 1280 * Returns a function to use in pseudos for input types 1281 * @param {String} type 1282 */ 1283function createInputPseudo( type ) { 1284 return function( elem ) { 1285 var name = elem.nodeName.toLowerCase(); 1286 return name === "input" && elem.type === type; 1287 }; 1288} 1289 1290/** 1291 * Returns a function to use in pseudos for buttons 1292 * @param {String} type 1293 */ 1294function createButtonPseudo( type ) { 1295 return function( elem ) { 1296 var name = elem.nodeName.toLowerCase(); 1297 return (name === "input" || name === "button") && elem.type === type; 1298 }; 1299} 1300 1301/** 1302 * Returns a function to use in pseudos for positionals 1303 * @param {Function} fn 1304 */ 1305function createPositionalPseudo( fn ) { 1306 return markFunction(function( argument ) { 1307 argument = +argument; 1308 return markFunction(function( seed, matches ) { 1309 var j, 1310 matchIndexes = fn( [], seed.length, argument ), 1311 i = matchIndexes.length; 1312 1313 // Match elements found at the specified indexes 1314 while ( i-- ) { 1315 if ( seed[ (j = matchIndexes[i]) ] ) { 1316 seed[j] = !(matches[j] = seed[j]); 1317 } 1318 } 1319 }); 1320 }); 1321} 1322 1323/** 1324 * Checks a node for validity as a Sizzle context 1325 * @param {Element|Object=} context 1326 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value 1327 */ 1328function testContext( context ) { 1329 return context && typeof context.getElementsByTagName !== "undefined" && context; 1330} 1331 1332// Expose support vars for convenience 1333support = Sizzle.support = {}; 1334 1335/** 1336 * Detects XML nodes 1337 * @param {Element|Object} elem An element or a document 1338 * @returns {Boolean} True iff elem is a non-HTML XML node 1339 */ 1340isXML = Sizzle.isXML = function( elem ) { 1341 // documentElement is verified for cases where it doesn't yet exist 1342 // (such as loading iframes in IE - #4833) 1343 var documentElement = elem && (elem.ownerDocument || elem).documentElement; 1344 return documentElement ? documentElement.nodeName !== "HTML" : false; 1345}; 1346 1347/** 1348 * Sets document-related variables once based on the current document 1349 * @param {Element|Object} [doc] An element or document object to use to set the document 1350 * @returns {Object} Returns the current document 1351 */ 1352setDocument = Sizzle.setDocument = function( node ) { 1353 var hasCompare, parent, 1354 doc = node ? node.ownerDocument || node : preferredDoc; 1355 1356 // Return early if doc is invalid or already selected 1357 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { 1358 return document; 1359 } 1360 1361 // Update global variables 1362 document = doc; 1363 docElem = document.documentElement; 1364 documentIsHTML = !isXML( document ); 1365 1366 // Support: IE 9-11, Edge 1367 // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) 1368 if ( (parent = document.defaultView) && parent.top !== parent ) { 1369 // Support: IE 11 1370 if ( parent.addEventListener ) { 1371 parent.addEventListener( "unload", unloadHandler, false ); 1372 1373 // Support: IE 9 - 10 only 1374 } else if ( parent.attachEvent ) { 1375 parent.attachEvent( "onunload", unloadHandler ); 1376 } 1377 } 1378 1379 /* Attributes 1380 ---------------------------------------------------------------------- */ 1381 1382 // Support: IE<8 1383 // Verify that getAttribute really returns attributes and not properties 1384 // (excepting IE8 booleans) 1385 support.attributes = assert(function( div ) { 1386 div.className = "i"; 1387 return !div.getAttribute("className"); 1388 }); 1389 1390 /* getElement(s)By* 1391 ---------------------------------------------------------------------- */ 1392 1393 // Check if getElementsByTagName("*") returns only elements 1394 support.getElementsByTagName = assert(function( div ) { 1395 div.appendChild( document.createComment("") ); 1396 return !div.getElementsByTagName("*").length; 1397 }); 1398 1399 // Support: IE<9 1400 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); 1401 1402 // Support: IE<10 1403 // Check if getElementById returns elements by name 1404 // The broken getElementById methods don't pick up programatically-set names, 1405 // so use a roundabout getElementsByName test 1406 support.getById = assert(function( div ) { 1407 docElem.appendChild( div ).id = expando; 1408 return !document.getElementsByName || !document.getElementsByName( expando ).length; 1409 }); 1410 1411 // ID find and filter 1412 if ( support.getById ) { 1413 Expr.find["ID"] = function( id, context ) { 1414 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { 1415 var m = context.getElementById( id ); 1416 return m ? [ m ] : []; 1417 } 1418 }; 1419 Expr.filter["ID"] = function( id ) { 1420 var attrId = id.replace( runescape, funescape ); 1421 return function( elem ) { 1422 return elem.getAttribute("id") === attrId; 1423 }; 1424 }; 1425 } else { 1426 // Support: IE6/7 1427 // getElementById is not reliable as a find shortcut 1428 delete Expr.find["ID"]; 1429 1430 Expr.filter["ID"] = function( id ) { 1431 var attrId = id.replace( runescape, funescape ); 1432 return function( elem ) { 1433 var node = typeof elem.getAttributeNode !== "undefined" && 1434 elem.getAttributeNode("id"); 1435 return node && node.value === attrId; 1436 }; 1437 }; 1438 } 1439 1440 // Tag 1441 Expr.find["TAG"] = support.getElementsByTagName ? 1442 function( tag, context ) { 1443 if ( typeof context.getElementsByTagName !== "undefined" ) { 1444 return context.getElementsByTagName( tag ); 1445 1446 // DocumentFragment nodes don't have gEBTN 1447 } else if ( support.qsa ) { 1448 return context.querySelectorAll( tag ); 1449 } 1450 } : 1451 1452 function( tag, context ) { 1453 var elem, 1454 tmp = [], 1455 i = 0, 1456 // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too 1457 results = context.getElementsByTagName( tag ); 1458 1459 // Filter out possible comments 1460 if ( tag === "*" ) { 1461 while ( (elem = results[i++]) ) { 1462 if ( elem.nodeType === 1 ) { 1463 tmp.push( elem ); 1464 } 1465 } 1466 1467 return tmp; 1468 } 1469 return results; 1470 }; 1471 1472 // Class 1473 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { 1474 if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { 1475 return context.getElementsByClassName( className ); 1476 } 1477 }; 1478 1479 /* QSA/matchesSelector 1480 ---------------------------------------------------------------------- */ 1481 1482 // QSA and matchesSelector support 1483 1484 // matchesSelector(:active) reports false when true (IE9/Opera 11.5) 1485 rbuggyMatches = []; 1486 1487 // qSa(:focus) reports false when true (Chrome 21) 1488 // We allow this because of a bug in IE8/9 that throws an error 1489 // whenever `document.activeElement` is accessed on an iframe 1490 // So, we allow :focus to pass through QSA all the time to avoid the IE error 1491 // See http://bugs.jquery.com/ticket/13378 1492 rbuggyQSA = []; 1493 1494 if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { 1495 // Build QSA regex 1496 // Regex strategy adopted from Diego Perini 1497 assert(function( div ) { 1498 // Select is set to empty string on purpose 1499 // This is to test IE's treatment of not explicitly 1500 // setting a boolean content attribute, 1501 // since its presence should be enough 1502 // http://bugs.jquery.com/ticket/12359 1503 docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" + 1504 "<select id='" + expando + "-\r\\' msallowcapture=''>" + 1505 "<option selected=''></option></select>"; 1506 1507 // Support: IE8, Opera 11-12.16 1508 // Nothing should be selected when empty strings follow ^= or $= or *= 1509 // The test attribute must be unknown in Opera but "safe" for WinRT 1510 // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section 1511 if ( div.querySelectorAll("[msallowcapture^='']").length ) { 1512 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); 1513 } 1514 1515 // Support: IE8 1516 // Boolean attributes and "value" are not treated correctly 1517 if ( !div.querySelectorAll("[selected]").length ) { 1518 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); 1519 } 1520 1521 // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ 1522 if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { 1523 rbuggyQSA.push("~="); 1524 } 1525 1526 // Webkit/Opera - :checked should return selected option elements 1527 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 1528 // IE8 throws error here and will not see later tests 1529 if ( !div.querySelectorAll(":checked").length ) { 1530 rbuggyQSA.push(":checked"); 1531 } 1532 1533 // Support: Safari 8+, iOS 8+ 1534 // https://bugs.webkit.org/show_bug.cgi?id=136851 1535 // In-page `selector#id sibing-combinator selector` fails 1536 if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { 1537 rbuggyQSA.push(".#.+[+~]"); 1538 } 1539 }); 1540 1541 assert(function( div ) { 1542 // Support: Windows 8 Native Apps 1543 // The type and name attributes are restricted during .innerHTML assignment 1544 var input = document.createElement("input"); 1545 input.setAttribute( "type", "hidden" ); 1546 div.appendChild( input ).setAttribute( "name", "D" ); 1547 1548 // Support: IE8 1549 // Enforce case-sensitivity of name attribute 1550 if ( div.querySelectorAll("[name=d]").length ) { 1551 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); 1552 } 1553 1554 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) 1555 // IE8 throws error here and will not see later tests 1556 if ( !div.querySelectorAll(":enabled").length ) { 1557 rbuggyQSA.push( ":enabled", ":disabled" ); 1558 } 1559 1560 // Opera 10-11 does not throw on post-comma invalid pseudos 1561 div.querySelectorAll("*,:x"); 1562 rbuggyQSA.push(",.*:"); 1563 }); 1564 } 1565 1566 if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || 1567 docElem.webkitMatchesSelector || 1568 docElem.mozMatchesSelector || 1569 docElem.oMatchesSelector || 1570 docElem.msMatchesSelector) )) ) { 1571 1572 assert(function( div ) { 1573 // Check to see if it's possible to do matchesSelector 1574 // on a disconnected node (IE 9) 1575 support.disconnectedMatch = matches.call( div, "div" ); 1576 1577 // This should fail with an exception 1578 // Gecko does not error, returns false instead 1579 matches.call( div, "[s!='']:x" ); 1580 rbuggyMatches.push( "!=", pseudos ); 1581 }); 1582 } 1583 1584 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); 1585 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); 1586 1587 /* Contains 1588 ---------------------------------------------------------------------- */ 1589 hasCompare = rnative.test( docElem.compareDocumentPosition ); 1590 1591 // Element contains another 1592 // Purposefully self-exclusive 1593 // As in, an element does not contain itself 1594 contains = hasCompare || rnative.test( docElem.contains ) ? 1595 function( a, b ) { 1596 var adown = a.nodeType === 9 ? a.documentElement : a, 1597 bup = b && b.parentNode; 1598 return a === bup || !!( bup && bup.nodeType === 1 && ( 1599 adown.contains ? 1600 adown.contains( bup ) : 1601 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 1602 )); 1603 } : 1604 function( a, b ) { 1605 if ( b ) { 1606 while ( (b = b.parentNode) ) { 1607 if ( b === a ) { 1608 return true; 1609 } 1610 } 1611 } 1612 return false; 1613 }; 1614 1615 /* Sorting 1616 ---------------------------------------------------------------------- */ 1617 1618 // Document order sorting 1619 sortOrder = hasCompare ? 1620 function( a, b ) { 1621 1622 // Flag for duplicate removal 1623 if ( a === b ) { 1624 hasDuplicate = true; 1625 return 0; 1626 } 1627 1628 // Sort on method existence if only one input has compareDocumentPosition 1629 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; 1630 if ( compare ) { 1631 return compare; 1632 } 1633 1634 // Calculate position if both inputs belong to the same document 1635 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? 1636 a.compareDocumentPosition( b ) : 1637 1638 // Otherwise we know they are disconnected 1639 1; 1640 1641 // Disconnected nodes 1642 if ( compare & 1 || 1643 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { 1644 1645 // Choose the first element that is related to our preferred document 1646 if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { 1647 return -1; 1648 } 1649 if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { 1650 return 1; 1651 } 1652 1653 // Maintain original order 1654 return sortInput ? 1655 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 1656 0; 1657 } 1658 1659 return compare & 4 ? -1 : 1; 1660 } : 1661 function( a, b ) { 1662 // Exit early if the nodes are identical 1663 if ( a === b ) { 1664 hasDuplicate = true; 1665 return 0; 1666 } 1667 1668 var cur, 1669 i = 0, 1670 aup = a.parentNode, 1671 bup = b.parentNode, 1672 ap = [ a ], 1673 bp = [ b ]; 1674 1675 // Parentless nodes are either documents or disconnected 1676 if ( !aup || !bup ) { 1677 return a === document ? -1 : 1678 b === document ? 1 : 1679 aup ? -1 : 1680 bup ? 1 : 1681 sortInput ? 1682 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 1683 0; 1684 1685 // If the nodes are siblings, we can do a quick check 1686 } else if ( aup === bup ) { 1687 return siblingCheck( a, b ); 1688 } 1689 1690 // Otherwise we need full lists of their ancestors for comparison 1691 cur = a; 1692 while ( (cur = cur.parentNode) ) { 1693 ap.unshift( cur ); 1694 } 1695 cur = b; 1696 while ( (cur = cur.parentNode) ) { 1697 bp.unshift( cur ); 1698 } 1699 1700 // Walk down the tree looking for a discrepancy 1701 while ( ap[i] === bp[i] ) { 1702 i++; 1703 } 1704 1705 return i ? 1706 // Do a sibling check if the nodes have a common ancestor 1707 siblingCheck( ap[i], bp[i] ) : 1708 1709 // Otherwise nodes in our document sort first 1710 ap[i] === preferredDoc ? -1 : 1711 bp[i] === preferredDoc ? 1 : 1712 0; 1713 }; 1714 1715 return document; 1716}; 1717 1718Sizzle.matches = function( expr, elements ) { 1719 return Sizzle( expr, null, null, elements ); 1720}; 1721 1722Sizzle.matchesSelector = function( elem, expr ) { 1723 // Set document vars if needed 1724 if ( ( elem.ownerDocument || elem ) !== document ) { 1725 setDocument( elem ); 1726 } 1727 1728 // Make sure that attribute selectors are quoted 1729 expr = expr.replace( rattributeQuotes, "='$1']" ); 1730 1731 if ( support.matchesSelector && documentIsHTML && 1732 !compilerCache[ expr + " " ] && 1733 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && 1734 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { 1735 1736 try { 1737 var ret = matches.call( elem, expr ); 1738 1739 // IE 9's matchesSelector returns false on disconnected nodes 1740 if ( ret || support.disconnectedMatch || 1741 // As well, disconnected nodes are said to be in a document 1742 // fragment in IE 9 1743 elem.document && elem.document.nodeType !== 11 ) { 1744 return ret; 1745 } 1746 } catch (e) {} 1747 } 1748 1749 return Sizzle( expr, document, null, [ elem ] ).length > 0; 1750}; 1751 1752Sizzle.contains = function( context, elem ) { 1753 // Set document vars if needed 1754 if ( ( context.ownerDocument || context ) !== document ) { 1755 setDocument( context ); 1756 } 1757 return contains( context, elem ); 1758}; 1759 1760Sizzle.attr = function( elem, name ) { 1761 // Set document vars if needed 1762 if ( ( elem.ownerDocument || elem ) !== document ) { 1763 setDocument( elem ); 1764 } 1765 1766 var fn = Expr.attrHandle[ name.toLowerCase() ], 1767 // Don't get fooled by Object.prototype properties (jQuery #13807) 1768 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? 1769 fn( elem, name, !documentIsHTML ) : 1770 undefined; 1771 1772 return val !== undefined ? 1773 val : 1774 support.attributes || !documentIsHTML ? 1775 elem.getAttribute( name ) : 1776 (val = elem.getAttributeNode(name)) && val.specified ? 1777 val.value : 1778 null; 1779}; 1780 1781Sizzle.error = function( msg ) { 1782 throw new Error( "Syntax error, unrecognized expression: " + msg ); 1783}; 1784 1785/** 1786 * Document sorting and removing duplicates 1787 * @param {ArrayLike} results 1788 */ 1789Sizzle.uniqueSort = function( results ) { 1790 var elem, 1791 duplicates = [], 1792 j = 0, 1793 i = 0; 1794 1795 // Unless we *know* we can detect duplicates, assume their presence 1796 hasDuplicate = !support.detectDuplicates; 1797 sortInput = !support.sortStable && results.slice( 0 ); 1798 results.sort( sortOrder ); 1799 1800 if ( hasDuplicate ) { 1801 while ( (elem = results[i++]) ) { 1802 if ( elem === results[ i ] ) { 1803 j = duplicates.push( i ); 1804 } 1805 } 1806 while ( j-- ) { 1807 results.splice( duplicates[ j ], 1 ); 1808 } 1809 } 1810 1811 // Clear input after sorting to release objects 1812 // See https://github.com/jquery/sizzle/pull/225 1813 sortInput = null; 1814 1815 return results; 1816}; 1817 1818/** 1819 * Utility function for retrieving the text value of an array of DOM nodes 1820 * @param {Array|Element} elem 1821 */ 1822getText = Sizzle.getText = function( elem ) { 1823 var node, 1824 ret = "", 1825 i = 0, 1826 nodeType = elem.nodeType; 1827 1828 if ( !nodeType ) { 1829 // If no nodeType, this is expected to be an array 1830 while ( (node = elem[i++]) ) { 1831 // Do not traverse comment nodes 1832 ret += getText( node ); 1833 } 1834 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { 1835 // Use textContent for elements 1836 // innerText usage removed for consistency of new lines (jQuery #11153) 1837 if ( typeof elem.textContent === "string" ) { 1838 return elem.textContent; 1839 } else { 1840 // Traverse its children 1841 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 1842 ret += getText( elem ); 1843 } 1844 } 1845 } else if ( nodeType === 3 || nodeType === 4 ) { 1846 return elem.nodeValue; 1847 } 1848 // Do not include comment or processing instruction nodes 1849 1850 return ret; 1851}; 1852 1853Expr = Sizzle.selectors = { 1854 1855 // Can be adjusted by the user 1856 cacheLength: 50, 1857 1858 createPseudo: markFunction, 1859 1860 match: matchExpr, 1861 1862 attrHandle: {}, 1863 1864 find: {}, 1865 1866 relative: { 1867 ">": { dir: "parentNode", first: true }, 1868 " ": { dir: "parentNode" }, 1869 "+": { dir: "previousSibling", first: true }, 1870 "~": { dir: "previousSibling" } 1871 }, 1872 1873 preFilter: { 1874 "ATTR": function( match ) { 1875 match[1] = match[1].replace( runescape, funescape ); 1876 1877 // Move the given value to match[3] whether quoted or unquoted 1878 match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); 1879 1880 if ( match[2] === "~=" ) { 1881 match[3] = " " + match[3] + " "; 1882 } 1883 1884 return match.slice( 0, 4 ); 1885 }, 1886 1887 "CHILD": function( match ) { 1888 /* matches from matchExpr["CHILD"] 1889 1 type (only|nth|...) 1890 2 what (child|of-type) 1891 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 1892 4 xn-component of xn+y argument ([+-]?\d*n|) 1893 5 sign of xn-component 1894 6 x of xn-component 1895 7 sign of y-component 1896 8 y of y-component 1897 */ 1898 match[1] = match[1].toLowerCase(); 1899 1900 if ( match[1].slice( 0, 3 ) === "nth" ) { 1901 // nth-* requires argument 1902 if ( !match[3] ) { 1903 Sizzle.error( match[0] ); 1904 } 1905 1906 // numeric x and y parameters for Expr.filter.CHILD 1907 // remember that false/true cast respectively to 0/1 1908 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); 1909 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); 1910 1911 // other types prohibit arguments 1912 } else if ( match[3] ) { 1913 Sizzle.error( match[0] ); 1914 } 1915 1916 return match; 1917 }, 1918 1919 "PSEUDO": function( match ) { 1920 var excess, 1921 unquoted = !match[6] && match[2]; 1922 1923 if ( matchExpr["CHILD"].test( match[0] ) ) { 1924 return null; 1925 } 1926 1927 // Accept quoted arguments as-is 1928 if ( match[3] ) { 1929 match[2] = match[4] || match[5] || ""; 1930 1931 // Strip excess characters from unquoted arguments 1932 } else if ( unquoted && rpseudo.test( unquoted ) && 1933 // Get excess from tokenize (recursively) 1934 (excess = tokenize( unquoted, true )) && 1935 // advance to the next closing parenthesis 1936 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { 1937 1938 // excess is a negative index 1939 match[0] = match[0].slice( 0, excess ); 1940 match[2] = unquoted.slice( 0, excess ); 1941 } 1942 1943 // Return only captures needed by the pseudo filter method (type and argument) 1944 return match.slice( 0, 3 ); 1945 } 1946 }, 1947 1948 filter: { 1949 1950 "TAG": function( nodeNameSelector ) { 1951 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); 1952 return nodeNameSelector === "*" ? 1953 function() { return true; } : 1954 function( elem ) { 1955 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; 1956 }; 1957 }, 1958 1959 "CLASS": function( className ) { 1960 var pattern = classCache[ className + " " ]; 1961 1962 return pattern || 1963 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && 1964 classCache( className, function( elem ) { 1965 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); 1966 }); 1967 }, 1968 1969 "ATTR": function( name, operator, check ) { 1970 return function( elem ) { 1971 var result = Sizzle.attr( elem, name ); 1972 1973 if ( result == null ) { 1974 return operator === "!="; 1975 } 1976 if ( !operator ) { 1977 return true; 1978 } 1979 1980 result += ""; 1981 1982 return operator === "=" ? result === check : 1983 operator === "!=" ? result !== check : 1984 operator === "^=" ? check && result.indexOf( check ) === 0 : 1985 operator === "*=" ? check && result.indexOf( check ) > -1 : 1986 operator === "$=" ? check && result.slice( -check.length ) === check : 1987 operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : 1988 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : 1989 false; 1990 }; 1991 }, 1992 1993 "CHILD": function( type, what, argument, first, last ) { 1994 var simple = type.slice( 0, 3 ) !== "nth", 1995 forward = type.slice( -4 ) !== "last", 1996 ofType = what === "of-type"; 1997 1998 return first === 1 && last === 0 ? 1999 2000 // Shortcut for :nth-*(n) 2001 function( elem ) { 2002 return !!elem.parentNode; 2003 } : 2004 2005 function( elem, context, xml ) { 2006 var cache, uniqueCache, outerCache, node, nodeIndex, start, 2007 dir = simple !== forward ? "nextSibling" : "previousSibling", 2008 parent = elem.parentNode, 2009 name = ofType && elem.nodeName.toLowerCase(), 2010 useCache = !xml && !ofType, 2011 diff = false; 2012 2013 if ( parent ) { 2014 2015 // :(first|last|only)-(child|of-type) 2016 if ( simple ) { 2017 while ( dir ) { 2018 node = elem; 2019 while ( (node = node[ dir ]) ) { 2020 if ( ofType ? 2021 node.nodeName.toLowerCase() === name : 2022 node.nodeType === 1 ) { 2023 2024 return false; 2025 } 2026 } 2027 // Reverse direction for :only-* (if we haven't yet done so) 2028 start = dir = type === "only" && !start && "nextSibling"; 2029 } 2030 return true; 2031 } 2032 2033 start = [ forward ? parent.firstChild : parent.lastChild ]; 2034 2035 // non-xml :nth-child(...) stores cache data on `parent` 2036 if ( forward && useCache ) { 2037 2038 // Seek `elem` from a previously-cached index 2039 2040 // ...in a gzip-friendly way 2041 node = parent; 2042 outerCache = node[ expando ] || (node[ expando ] = {}); 2043 2044 // Support: IE <9 only 2045 // Defend against cloned attroperties (jQuery gh-1709) 2046 uniqueCache = outerCache[ node.uniqueID ] || 2047 (outerCache[ node.uniqueID ] = {}); 2048 2049 cache = uniqueCache[ type ] || []; 2050 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 2051 diff = nodeIndex && cache[ 2 ]; 2052 node = nodeIndex && parent.childNodes[ nodeIndex ]; 2053 2054 while ( (node = ++nodeIndex && node && node[ dir ] || 2055 2056 // Fallback to seeking `elem` from the start 2057 (diff = nodeIndex = 0) || start.pop()) ) { 2058 2059 // When found, cache indexes on `parent` and break 2060 if ( node.nodeType === 1 && ++diff && node === elem ) { 2061 uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; 2062 break; 2063 } 2064 } 2065 2066 } else { 2067 // Use previously-cached element index if available 2068 if ( useCache ) { 2069 // ...in a gzip-friendly way 2070 node = elem; 2071 outerCache = node[ expando ] || (node[ expando ] = {}); 2072 2073 // Support: IE <9 only 2074 // Defend against cloned attroperties (jQuery gh-1709) 2075 uniqueCache = outerCache[ node.uniqueID ] || 2076 (outerCache[ node.uniqueID ] = {}); 2077 2078 cache = uniqueCache[ type ] || []; 2079 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 2080 diff = nodeIndex; 2081 } 2082 2083 // xml :nth-child(...) 2084 // or :nth-last-child(...) or :nth(-last)?-of-type(...) 2085 if ( diff === false ) { 2086 // Use the same loop as above to seek `elem` from the start 2087 while ( (node = ++nodeIndex && node && node[ dir ] || 2088 (diff = nodeIndex = 0) || start.pop()) ) { 2089 2090 if ( ( ofType ? 2091 node.nodeName.toLowerCase() === name : 2092 node.nodeType === 1 ) && 2093 ++diff ) { 2094 2095 // Cache the index of each encountered element 2096 if ( useCache ) { 2097 outerCache = node[ expando ] || (node[ expando ] = {}); 2098 2099 // Support: IE <9 only 2100 // Defend against cloned attroperties (jQuery gh-1709) 2101 uniqueCache = outerCache[ node.uniqueID ] || 2102 (outerCache[ node.uniqueID ] = {}); 2103 2104 uniqueCache[ type ] = [ dirruns, diff ]; 2105 } 2106 2107 if ( node === elem ) { 2108 break; 2109 } 2110 } 2111 } 2112 } 2113 } 2114 2115 // Incorporate the offset, then check against cycle size 2116 diff -= last; 2117 return diff === first || ( diff % first === 0 && diff / first >= 0 ); 2118 } 2119 }; 2120 }, 2121 2122 "PSEUDO": function( pseudo, argument ) { 2123 // pseudo-class names are case-insensitive 2124 // http://www.w3.org/TR/selectors/#pseudo-classes 2125 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters 2126 // Remember that setFilters inherits from pseudos 2127 var args, 2128 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || 2129 Sizzle.error( "unsupported pseudo: " + pseudo ); 2130 2131 // The user may use createPseudo to indicate that 2132 // arguments are needed to create the filter function 2133 // just as Sizzle does 2134 if ( fn[ expando ] ) { 2135 return fn( argument ); 2136 } 2137 2138 // But maintain support for old signatures 2139 if ( fn.length > 1 ) { 2140 args = [ pseudo, pseudo, "", argument ]; 2141 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? 2142 markFunction(function( seed, matches ) { 2143 var idx, 2144 matched = fn( seed, argument ), 2145 i = matched.length; 2146 while ( i-- ) { 2147 idx = indexOf( seed, matched[i] ); 2148 seed[ idx ] = !( matches[ idx ] = matched[i] ); 2149 } 2150 }) : 2151 function( elem ) { 2152 return fn( elem, 0, args ); 2153 }; 2154 } 2155 2156 return fn; 2157 } 2158 }, 2159 2160 pseudos: { 2161 // Potentially complex pseudos 2162 "not": markFunction(function( selector ) { 2163 // Trim the selector passed to compile 2164 // to avoid treating leading and trailing 2165 // spaces as combinators 2166 var input = [], 2167 results = [], 2168 matcher = compile( selector.replace( rtrim, "$1" ) ); 2169 2170 return matcher[ expando ] ? 2171 markFunction(function( seed, matches, context, xml ) { 2172 var elem, 2173 unmatched = matcher( seed, null, xml, [] ), 2174 i = seed.length; 2175 2176 // Match elements unmatched by `matcher` 2177 while ( i-- ) { 2178 if ( (elem = unmatched[i]) ) { 2179 seed[i] = !(matches[i] = elem); 2180 } 2181 } 2182 }) : 2183 function( elem, context, xml ) { 2184 input[0] = elem; 2185 matcher( input, null, xml, results ); 2186 // Don't keep the element (issue #299) 2187 input[0] = null; 2188 return !results.pop(); 2189 }; 2190 }), 2191 2192 "has": markFunction(function( selector ) { 2193 return function( elem ) { 2194 return Sizzle( selector, elem ).length > 0; 2195 }; 2196 }), 2197 2198 "contains": markFunction(function( text ) { 2199 text = text.replace( runescape, funescape ); 2200 return function( elem ) { 2201 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; 2202 }; 2203 }), 2204 2205 // "Whether an element is represented by a :lang() selector 2206 // is based solely on the element's language value 2207 // being equal to the identifier C, 2208 // or beginning with the identifier C immediately followed by "-". 2209 // The matching of C against the element's language value is performed case-insensitively. 2210 // The identifier C does not have to be a valid language name." 2211 // http://www.w3.org/TR/selectors/#lang-pseudo 2212 "lang": markFunction( function( lang ) { 2213 // lang value must be a valid identifier 2214 if ( !ridentifier.test(lang || "") ) { 2215 Sizzle.error( "unsupported lang: " + lang ); 2216 } 2217 lang = lang.replace( runescape, funescape ).toLowerCase(); 2218 return function( elem ) { 2219 var elemLang; 2220 do { 2221 if ( (elemLang = documentIsHTML ? 2222 elem.lang : 2223 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { 2224 2225 elemLang = elemLang.toLowerCase(); 2226 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; 2227 } 2228 } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); 2229 return false; 2230 }; 2231 }), 2232 2233 // Miscellaneous 2234 "target": function( elem ) { 2235 var hash = window.location && window.location.hash; 2236 return hash && hash.slice( 1 ) === elem.id; 2237 }, 2238 2239 "root": function( elem ) { 2240 return elem === docElem; 2241 }, 2242 2243 "focus": function( elem ) { 2244 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); 2245 }, 2246 2247 // Boolean properties 2248 "enabled": function( elem ) { 2249 return elem.disabled === false; 2250 }, 2251 2252 "disabled": function( elem ) { 2253 return elem.disabled === true; 2254 }, 2255 2256 "checked": function( elem ) { 2257 // In CSS3, :checked should return both checked and selected elements 2258 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 2259 var nodeName = elem.nodeName.toLowerCase(); 2260 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); 2261 }, 2262 2263 "selected": function( elem ) { 2264 // Accessing this property makes selected-by-default 2265 // options in Safari work properly 2266 if ( elem.parentNode ) { 2267 elem.parentNode.selectedIndex; 2268 } 2269 2270 return elem.selected === true; 2271 }, 2272 2273 // Contents 2274 "empty": function( elem ) { 2275 // http://www.w3.org/TR/selectors/#empty-pseudo 2276 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), 2277 // but not by others (comment: 8; processing instruction: 7; etc.) 2278 // nodeType < 6 works because attributes (2) do not appear as children 2279 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 2280 if ( elem.nodeType < 6 ) { 2281 return false; 2282 } 2283 } 2284 return true; 2285 }, 2286 2287 "parent": function( elem ) { 2288 return !Expr.pseudos["empty"]( elem ); 2289 }, 2290 2291 // Element/input types 2292 "header": function( elem ) { 2293 return rheader.test( elem.nodeName ); 2294 }, 2295 2296 "input": function( elem ) { 2297 return rinputs.test( elem.nodeName ); 2298 }, 2299 2300 "button": function( elem ) { 2301 var name = elem.nodeName.toLowerCase(); 2302 return name === "input" && elem.type === "button" || name === "button"; 2303 }, 2304 2305 "text": function( elem ) { 2306 var attr; 2307 return elem.nodeName.toLowerCase() === "input" && 2308 elem.type === "text" && 2309 2310 // Support: IE<8 2311 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" 2312 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); 2313 }, 2314 2315 // Position-in-collection 2316 "first": createPositionalPseudo(function() { 2317 return [ 0 ]; 2318 }), 2319 2320 "last": createPositionalPseudo(function( matchIndexes, length ) { 2321 return [ length - 1 ]; 2322 }), 2323 2324 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { 2325 return [ argument < 0 ? argument + length : argument ]; 2326 }), 2327 2328 "even": createPositionalPseudo(function( matchIndexes, length ) { 2329 var i = 0; 2330 for ( ; i < length; i += 2 ) { 2331 matchIndexes.push( i ); 2332 } 2333 return matchIndexes; 2334 }), 2335 2336 "odd": createPositionalPseudo(function( matchIndexes, length ) { 2337 var i = 1; 2338 for ( ; i < length; i += 2 ) { 2339 matchIndexes.push( i ); 2340 } 2341 return matchIndexes; 2342 }), 2343 2344 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { 2345 var i = argument < 0 ? argument + length : argument; 2346 for ( ; --i >= 0; ) { 2347 matchIndexes.push( i ); 2348 } 2349 return matchIndexes; 2350 }), 2351 2352 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { 2353 var i = argument < 0 ? argument + length : argument; 2354 for ( ; ++i < length; ) { 2355 matchIndexes.push( i ); 2356 } 2357 return matchIndexes; 2358 }) 2359 } 2360}; 2361 2362Expr.pseudos["nth"] = Expr.pseudos["eq"]; 2363 2364// Add button/input type pseudos 2365for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { 2366 Expr.pseudos[ i ] = createInputPseudo( i ); 2367} 2368for ( i in { submit: true, reset: true } ) { 2369 Expr.pseudos[ i ] = createButtonPseudo( i ); 2370} 2371 2372// Easy API for creating new setFilters 2373function setFilters() {} 2374setFilters.prototype = Expr.filters = Expr.pseudos; 2375Expr.setFilters = new setFilters(); 2376 2377tokenize = Sizzle.tokenize = function( selector, parseOnly ) { 2378 var matched, match, tokens, type, 2379 soFar, groups, preFilters, 2380 cached = tokenCache[ selector + " " ]; 2381 2382 if ( cached ) { 2383 return parseOnly ? 0 : cached.slice( 0 ); 2384 } 2385 2386 soFar = selector; 2387 groups = []; 2388 preFilters = Expr.preFilter; 2389 2390 while ( soFar ) { 2391 2392 // Comma and first run 2393 if ( !matched || (match = rcomma.exec( soFar )) ) { 2394 if ( match ) { 2395 // Don't consume trailing commas as valid 2396 soFar = soFar.slice( match[0].length ) || soFar; 2397 } 2398 groups.push( (tokens = []) ); 2399 } 2400 2401 matched = false; 2402 2403 // Combinators 2404 if ( (match = rcombinators.exec( soFar )) ) { 2405 matched = match.shift(); 2406 tokens.push({ 2407 value: matched, 2408 // Cast descendant combinators to space 2409 type: match[0].replace( rtrim, " " ) 2410 }); 2411 soFar = soFar.slice( matched.length ); 2412 } 2413 2414 // Filters 2415 for ( type in Expr.filter ) { 2416 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || 2417 (match = preFilters[ type ]( match ))) ) { 2418 matched = match.shift(); 2419 tokens.push({ 2420 value: matched, 2421 type: type, 2422 matches: match 2423 }); 2424 soFar = soFar.slice( matched.length ); 2425 } 2426 } 2427 2428 if ( !matched ) { 2429 break; 2430 } 2431 } 2432 2433 // Return the length of the invalid excess 2434 // if we're just parsing 2435 // Otherwise, throw an error or return tokens 2436 return parseOnly ? 2437 soFar.length : 2438 soFar ? 2439 Sizzle.error( selector ) : 2440 // Cache the tokens 2441 tokenCache( selector, groups ).slice( 0 ); 2442}; 2443 2444function toSelector( tokens ) { 2445 var i = 0, 2446 len = tokens.length, 2447 selector = ""; 2448 for ( ; i < len; i++ ) { 2449 selector += tokens[i].value; 2450 } 2451 return selector; 2452} 2453 2454function addCombinator( matcher, combinator, base ) { 2455 var dir = combinator.dir, 2456 checkNonElements = base && dir === "parentNode", 2457 doneName = done++; 2458 2459 return combinator.first ? 2460 // Check against closest ancestor/preceding element 2461 function( elem, context, xml ) { 2462 while ( (elem = elem[ dir ]) ) { 2463 if ( elem.nodeType === 1 || checkNonElements ) { 2464 return matcher( elem, context, xml ); 2465 } 2466 } 2467 } : 2468 2469 // Check against all ancestor/preceding elements 2470 function( elem, context, xml ) { 2471 var oldCache, uniqueCache, outerCache, 2472 newCache = [ dirruns, doneName ]; 2473 2474 // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching 2475 if ( xml ) { 2476 while ( (elem = elem[ dir ]) ) { 2477 if ( elem.nodeType === 1 || checkNonElements ) { 2478 if ( matcher( elem, context, xml ) ) { 2479 return true; 2480 } 2481 } 2482 } 2483 } else { 2484 while ( (elem = elem[ dir ]) ) { 2485 if ( elem.nodeType === 1 || checkNonElements ) { 2486 outerCache = elem[ expando ] || (elem[ expando ] = {}); 2487 2488 // Support: IE <9 only 2489 // Defend against cloned attroperties (jQuery gh-1709) 2490 uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); 2491 2492 if ( (oldCache = uniqueCache[ dir ]) && 2493 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { 2494 2495 // Assign to newCache so results back-propagate to previous elements 2496 return (newCache[ 2 ] = oldCache[ 2 ]); 2497 } else { 2498 // Reuse newcache so results back-propagate to previous elements 2499 uniqueCache[ dir ] = newCache; 2500 2501 // A match means we're done; a fail means we have to keep checking 2502 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { 2503 return true; 2504 } 2505 } 2506 } 2507 } 2508 } 2509 }; 2510} 2511 2512function elementMatcher( matchers ) { 2513 return matchers.length > 1 ? 2514 function( elem, context, xml ) { 2515 var i = matchers.length; 2516 while ( i-- ) { 2517 if ( !matchers[i]( elem, context, xml ) ) { 2518 return false; 2519 } 2520 } 2521 return true; 2522 } : 2523 matchers[0]; 2524} 2525 2526function multipleContexts( selector, contexts, results ) { 2527 var i = 0, 2528 len = contexts.length; 2529 for ( ; i < len; i++ ) { 2530 Sizzle( selector, contexts[i], results ); 2531 } 2532 return results; 2533} 2534 2535function condense( unmatched, map, filter, context, xml ) { 2536 var elem, 2537 newUnmatched = [], 2538 i = 0, 2539 len = unmatched.length, 2540 mapped = map != null; 2541 2542 for ( ; i < len; i++ ) { 2543 if ( (elem = unmatched[i]) ) { 2544 if ( !filter || filter( elem, context, xml ) ) { 2545 newUnmatched.push( elem ); 2546 if ( mapped ) { 2547 map.push( i ); 2548 } 2549 } 2550 } 2551 } 2552 2553 return newUnmatched; 2554} 2555 2556function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { 2557 if ( postFilter && !postFilter[ expando ] ) { 2558 postFilter = setMatcher( postFilter ); 2559 } 2560 if ( postFinder && !postFinder[ expando ] ) { 2561 postFinder = setMatcher( postFinder, postSelector ); 2562 } 2563 return markFunction(function( seed, results, context, xml ) { 2564 var temp, i, elem, 2565 preMap = [], 2566 postMap = [], 2567 preexisting = results.length, 2568 2569 // Get initial elements from seed or context 2570 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), 2571 2572 // Prefilter to get matcher input, preserving a map for seed-results synchronization 2573 matcherIn = preFilter && ( seed || !selector ) ? 2574 condense( elems, preMap, preFilter, context, xml ) : 2575 elems, 2576 2577 matcherOut = matcher ? 2578 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, 2579 postFinder || ( seed ? preFilter : preexisting || postFilter ) ? 2580 2581 // ...intermediate processing is necessary 2582 [] : 2583 2584 // ...otherwise use results directly 2585 results : 2586 matcherIn; 2587 2588 // Find primary matches 2589 if ( matcher ) { 2590 matcher( matcherIn, matcherOut, context, xml ); 2591 } 2592 2593 // Apply postFilter 2594 if ( postFilter ) { 2595 temp = condense( matcherOut, postMap ); 2596 postFilter( temp, [], context, xml ); 2597 2598 // Un-match failing elements by moving them back to matcherIn 2599 i = temp.length; 2600 while ( i-- ) { 2601 if ( (elem = temp[i]) ) { 2602 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); 2603 } 2604 } 2605 } 2606 2607 if ( seed ) { 2608 if ( postFinder || preFilter ) { 2609 if ( postFinder ) { 2610 // Get the final matcherOut by condensing this intermediate into postFinder contexts 2611 temp = []; 2612 i = matcherOut.length; 2613 while ( i-- ) { 2614 if ( (elem = matcherOut[i]) ) { 2615 // Restore matcherIn since elem is not yet a final match 2616 temp.push( (matcherIn[i] = elem) ); 2617 } 2618 } 2619 postFinder( null, (matcherOut = []), temp, xml ); 2620 } 2621 2622 // Move matched elements from seed to results to keep them synchronized 2623 i = matcherOut.length; 2624 while ( i-- ) { 2625 if ( (elem = matcherOut[i]) && 2626 (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { 2627 2628 seed[temp] = !(results[temp] = elem); 2629 } 2630 } 2631 } 2632 2633 // Add elements to results, through postFinder if defined 2634 } else { 2635 matcherOut = condense( 2636 matcherOut === results ? 2637 matcherOut.splice( preexisting, matcherOut.length ) : 2638 matcherOut 2639 ); 2640 if ( postFinder ) { 2641 postFinder( null, results, matcherOut, xml ); 2642 } else { 2643 push.apply( results, matcherOut ); 2644 } 2645 } 2646 }); 2647} 2648 2649function matcherFromTokens( tokens ) { 2650 var checkContext, matcher, j, 2651 len = tokens.length, 2652 leadingRelative = Expr.relative[ tokens[0].type ], 2653 implicitRelative = leadingRelative || Expr.relative[" "], 2654 i = leadingRelative ? 1 : 0, 2655 2656 // The foundational matcher ensures that elements are reachable from top-level context(s) 2657 matchContext = addCombinator( function( elem ) { 2658 return elem === checkContext; 2659 }, implicitRelative, true ), 2660 matchAnyContext = addCombinator( function( elem ) { 2661 return indexOf( checkContext, elem ) > -1; 2662 }, implicitRelative, true ), 2663 matchers = [ function( elem, context, xml ) { 2664 var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( 2665 (checkContext = context).nodeType ? 2666 matchContext( elem, context, xml ) : 2667 matchAnyContext( elem, context, xml ) ); 2668 // Avoid hanging onto element (issue #299) 2669 checkContext = null; 2670 return ret; 2671 } ]; 2672 2673 for ( ; i < len; i++ ) { 2674 if ( (matcher = Expr.relative[ tokens[i].type ]) ) { 2675 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; 2676 } else { 2677 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); 2678 2679 // Return special upon seeing a positional matcher 2680 if ( matcher[ expando ] ) { 2681 // Find the next relative operator (if any) for proper handling 2682 j = ++i; 2683 for ( ; j < len; j++ ) { 2684 if ( Expr.relative[ tokens[j].type ] ) { 2685 break; 2686 } 2687 } 2688 return setMatcher( 2689 i > 1 && elementMatcher( matchers ), 2690 i > 1 && toSelector( 2691 // If the preceding token was a descendant combinator, insert an implicit any-element `*` 2692 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) 2693 ).replace( rtrim, "$1" ), 2694 matcher, 2695 i < j && matcherFromTokens( tokens.slice( i, j ) ), 2696 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), 2697 j < len && toSelector( tokens ) 2698 ); 2699 } 2700 matchers.push( matcher ); 2701 } 2702 } 2703 2704 return elementMatcher( matchers ); 2705} 2706 2707function matcherFromGroupMatchers( elementMatchers, setMatchers ) { 2708 var bySet = setMatchers.length > 0, 2709 byElement = elementMatchers.length > 0, 2710 superMatcher = function( seed, context, xml, results, outermost ) { 2711 var elem, j, matcher, 2712 matchedCount = 0, 2713 i = "0", 2714 unmatched = seed && [], 2715 setMatched = [], 2716 contextBackup = outermostContext, 2717 // We must always have either seed elements or outermost context 2718 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), 2719 // Use integer dirruns iff this is the outermost matcher 2720 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), 2721 len = elems.length; 2722 2723 if ( outermost ) { 2724 outermostContext = context === document || context || outermost; 2725 } 2726 2727 // Add elements passing elementMatchers directly to results 2728 // Support: IE<9, Safari 2729 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id 2730 for ( ; i !== len && (elem = elems[i]) != null; i++ ) { 2731 if ( byElement && elem ) { 2732 j = 0; 2733 if ( !context && elem.ownerDocument !== document ) { 2734 setDocument( elem ); 2735 xml = !documentIsHTML; 2736 } 2737 while ( (matcher = elementMatchers[j++]) ) { 2738 if ( matcher( elem, context || document, xml) ) { 2739 results.push( elem ); 2740 break; 2741 } 2742 } 2743 if ( outermost ) { 2744 dirruns = dirrunsUnique; 2745 } 2746 } 2747 2748 // Track unmatched elements for set filters 2749 if ( bySet ) { 2750 // They will have gone through all possible matchers 2751 if ( (elem = !matcher && elem) ) { 2752 matchedCount--; 2753 } 2754 2755 // Lengthen the array for every element, matched or not 2756 if ( seed ) { 2757 unmatched.push( elem ); 2758 } 2759 } 2760 } 2761 2762 // `i` is now the count of elements visited above, and adding it to `matchedCount` 2763 // makes the latter nonnegative. 2764 matchedCount += i; 2765 2766 // Apply set filters to unmatched elements 2767 // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` 2768 // equals `i`), unless we didn't visit _any_ elements in the above loop because we have 2769 // no element matchers and no seed. 2770 // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that 2771 // case, which will result in a "00" `matchedCount` that differs from `i` but is also 2772 // numerically zero. 2773 if ( bySet && i !== matchedCount ) { 2774 j = 0; 2775 while ( (matcher = setMatchers[j++]) ) { 2776 matcher( unmatched, setMatched, context, xml ); 2777 } 2778 2779 if ( seed ) { 2780 // Reintegrate element matches to eliminate the need for sorting 2781 if ( matchedCount > 0 ) { 2782 while ( i-- ) { 2783 if ( !(unmatched[i] || setMatched[i]) ) { 2784 setMatched[i] = pop.call( results ); 2785 } 2786 } 2787 } 2788 2789 // Discard index placeholder values to get only actual matches 2790 setMatched = condense( setMatched ); 2791 } 2792 2793 // Add matches to results 2794 push.apply( results, setMatched ); 2795 2796 // Seedless set matches succeeding multiple successful matchers stipulate sorting 2797 if ( outermost && !seed && setMatched.length > 0 && 2798 ( matchedCount + setMatchers.length ) > 1 ) { 2799 2800 Sizzle.uniqueSort( results ); 2801 } 2802 } 2803 2804 // Override manipulation of globals by nested matchers 2805 if ( outermost ) { 2806 dirruns = dirrunsUnique; 2807 outermostContext = contextBackup; 2808 } 2809 2810 return unmatched; 2811 }; 2812 2813 return bySet ? 2814 markFunction( superMatcher ) : 2815 superMatcher; 2816} 2817 2818compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { 2819 var i, 2820 setMatchers = [], 2821 elementMatchers = [], 2822 cached = compilerCache[ selector + " " ]; 2823 2824 if ( !cached ) { 2825 // Generate a function of recursive functions that can be used to check each element 2826 if ( !match ) { 2827 match = tokenize( selector ); 2828 } 2829 i = match.length; 2830 while ( i-- ) { 2831 cached = matcherFromTokens( match[i] ); 2832 if ( cached[ expando ] ) { 2833 setMatchers.push( cached ); 2834 } else { 2835 elementMatchers.push( cached ); 2836 } 2837 } 2838 2839 // Cache the compiled function 2840 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); 2841 2842 // Save selector and tokenization 2843 cached.selector = selector; 2844 } 2845 return cached; 2846}; 2847 2848/** 2849 * A low-level selection function that works with Sizzle's compiled 2850 * selector functions 2851 * @param {String|Function} selector A selector or a pre-compiled 2852 * selector function built with Sizzle.compile 2853 * @param {Element} context 2854 * @param {Array} [results] 2855 * @param {Array} [seed] A set of elements to match against 2856 */ 2857select = Sizzle.select = function( selector, context, results, seed ) { 2858 var i, tokens, token, type, find, 2859 compiled = typeof selector === "function" && selector, 2860 match = !seed && tokenize( (selector = compiled.selector || selector) ); 2861 2862 results = results || []; 2863 2864 // Try to minimize operations if there is only one selector in the list and no seed 2865 // (the latter of which guarantees us context) 2866 if ( match.length === 1 ) { 2867 2868 // Reduce context if the leading compound selector is an ID 2869 tokens = match[0] = match[0].slice( 0 ); 2870 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && 2871 support.getById && context.nodeType === 9 && documentIsHTML && 2872 Expr.relative[ tokens[1].type ] ) { 2873 2874 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; 2875 if ( !context ) { 2876 return results; 2877 2878 // Precompiled matchers will still verify ancestry, so step up a level 2879 } else if ( compiled ) { 2880 context = context.parentNode; 2881 } 2882 2883 selector = selector.slice( tokens.shift().value.length ); 2884 } 2885 2886 // Fetch a seed set for right-to-left matching 2887 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; 2888 while ( i-- ) { 2889 token = tokens[i]; 2890 2891 // Abort if we hit a combinator 2892 if ( Expr.relative[ (type = token.type) ] ) { 2893 break; 2894 } 2895 if ( (find = Expr.find[ type ]) ) { 2896 // Search, expanding context for leading sibling combinators 2897 if ( (seed = find( 2898 token.matches[0].replace( runescape, funescape ), 2899 rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context 2900 )) ) { 2901 2902 // If seed is empty or no tokens remain, we can return early 2903 tokens.splice( i, 1 ); 2904 selector = seed.length && toSelector( tokens ); 2905 if ( !selector ) { 2906 push.apply( results, seed ); 2907 return results; 2908 } 2909 2910 break; 2911 } 2912 } 2913 } 2914 } 2915 2916 // Compile and execute a filtering function if one is not provided 2917 // Provide `match` to avoid retokenization if we modified the selector above 2918 ( compiled || compile( selector, match ) )( 2919 seed, 2920 context, 2921 !documentIsHTML, 2922 results, 2923 !context || rsibling.test( selector ) && testContext( context.parentNode ) || context 2924 ); 2925 return results; 2926}; 2927 2928// One-time assignments 2929 2930// Sort stability 2931support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; 2932 2933// Support: Chrome 14-35+ 2934// Always assume duplicates if they aren't passed to the comparison function 2935support.detectDuplicates = !!hasDuplicate; 2936 2937// Initialize against the default document 2938setDocument(); 2939 2940// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) 2941// Detached nodes confoundingly follow *each other* 2942support.sortDetached = assert(function( div1 ) { 2943 // Should return 1, but returns 4 (following) 2944 return div1.compareDocumentPosition( document.createElement("div") ) & 1; 2945}); 2946 2947// Support: IE<8 2948// Prevent attribute/property "interpolation" 2949// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 2950if ( !assert(function( div ) { 2951 div.innerHTML = "<a href='#'></a>"; 2952 return div.firstChild.getAttribute("href") === "#" ; 2953}) ) { 2954 addHandle( "type|href|height|width", function( elem, name, isXML ) { 2955 if ( !isXML ) { 2956 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); 2957 } 2958 }); 2959} 2960 2961// Support: IE<9 2962// Use defaultValue in place of getAttribute("value") 2963if ( !support.attributes || !assert(function( div ) { 2964 div.innerHTML = "<input/>"; 2965 div.firstChild.setAttribute( "value", "" ); 2966 return div.firstChild.getAttribute( "value" ) === ""; 2967}) ) { 2968 addHandle( "value", function( elem, name, isXML ) { 2969 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { 2970 return elem.defaultValue; 2971 } 2972 }); 2973} 2974 2975// Support: IE<9 2976// Use getAttributeNode to fetch booleans when getAttribute lies 2977if ( !assert(function( div ) { 2978 return div.getAttribute("disabled") == null; 2979}) ) { 2980 addHandle( booleans, function( elem, name, isXML ) { 2981 var val; 2982 if ( !isXML ) { 2983 return elem[ name ] === true ? name.toLowerCase() : 2984 (val = elem.getAttributeNode( name )) && val.specified ? 2985 val.value : 2986 null; 2987 } 2988 }); 2989} 2990 2991return Sizzle; 2992 2993})( window ); 2994 2995 2996 2997jQuery.find = Sizzle; 2998jQuery.expr = Sizzle.selectors; 2999jQuery.expr[ ":" ] = jQuery.expr.pseudos; 3000jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; 3001jQuery.text = Sizzle.getText; 3002jQuery.isXMLDoc = Sizzle.isXML; 3003jQuery.contains = Sizzle.contains; 3004 3005 3006 3007var dir = function( elem, dir, until ) { 3008 var matched = [], 3009 truncate = until !== undefined; 3010 3011 while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { 3012 if ( elem.nodeType === 1 ) { 3013 if ( truncate && jQuery( elem ).is( until ) ) { 3014 break; 3015 } 3016 matched.push( elem ); 3017 } 3018 } 3019 return matched; 3020}; 3021 3022 3023var siblings = function( n, elem ) { 3024 var matched = []; 3025 3026 for ( ; n; n = n.nextSibling ) { 3027 if ( n.nodeType === 1 && n !== elem ) { 3028 matched.push( n ); 3029 } 3030 } 3031 3032 return matched; 3033}; 3034 3035 3036var rneedsContext = jQuery.expr.match.needsContext; 3037 3038var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); 3039 3040 3041 3042var risSimple = /^.[^:#\[\.,]*$/; 3043 3044// Implement the identical functionality for filter and not 3045function winnow( elements, qualifier, not ) { 3046 if ( jQuery.isFunction( qualifier ) ) { 3047 return jQuery.grep( elements, function( elem, i ) { 3048 /* jshint -W018 */ 3049 return !!qualifier.call( elem, i, elem ) !== not; 3050 } ); 3051 3052 } 3053 3054 if ( qualifier.nodeType ) { 3055 return jQuery.grep( elements, function( elem ) { 3056 return ( elem === qualifier ) !== not; 3057 } ); 3058 3059 } 3060 3061 if ( typeof qualifier === "string" ) { 3062 if ( risSimple.test( qualifier ) ) { 3063 return jQuery.filter( qualifier, elements, not ); 3064 } 3065 3066 qualifier = jQuery.filter( qualifier, elements ); 3067 } 3068 3069 return jQuery.grep( elements, function( elem ) { 3070 return ( indexOf.call( qualifier, elem ) > -1 ) !== not; 3071 } ); 3072} 3073 3074jQuery.filter = function( expr, elems, not ) { 3075 var elem = elems[ 0 ]; 3076 3077 if ( not ) { 3078 expr = ":not(" + expr + ")"; 3079 } 3080 3081 return elems.length === 1 && elem.nodeType === 1 ? 3082 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : 3083 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { 3084 return elem.nodeType === 1; 3085 } ) ); 3086}; 3087 3088jQuery.fn.extend( { 3089 find: function( selector ) { 3090 var i, 3091 len = this.length, 3092 ret = [], 3093 self = this; 3094 3095 if ( typeof selector !== "string" ) { 3096 return this.pushStack( jQuery( selector ).filter( function() { 3097 for ( i = 0; i < len; i++ ) { 3098 if ( jQuery.contains( self[ i ], this ) ) { 3099 return true; 3100 } 3101 } 3102 } ) ); 3103 } 3104 3105 for ( i = 0; i < len; i++ ) { 3106 jQuery.find( selector, self[ i ], ret ); 3107 } 3108 3109 // Needed because $( selector, context ) becomes $( context ).find( selector ) 3110 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); 3111 ret.selector = this.selector ? this.selector + " " + selector : selector; 3112 return ret; 3113 }, 3114 filter: function( selector ) { 3115 return this.pushStack( winnow( this, selector || [], false ) ); 3116 }, 3117 not: function( selector ) { 3118 return this.pushStack( winnow( this, selector || [], true ) ); 3119 }, 3120 is: function( selector ) { 3121 return !!winnow( 3122 this, 3123 3124 // If this is a positional/relative selector, check membership in the returned set 3125 // so $("p:first").is("p:last") won't return true for a doc with two "p". 3126 typeof selector === "string" && rneedsContext.test( selector ) ? 3127 jQuery( selector ) : 3128 selector || [], 3129 false 3130 ).length; 3131 } 3132} ); 3133 3134 3135// Initialize a jQuery object 3136 3137 3138// A central reference to the root jQuery(document) 3139var rootjQuery, 3140 3141 // A simple way to check for HTML strings 3142 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) 3143 // Strict HTML recognition (#11290: must start with <) 3144 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, 3145 3146 init = jQuery.fn.init = function( selector, context, root ) { 3147 var match, elem; 3148 3149 // HANDLE: $(""), $(null), $(undefined), $(false) 3150 if ( !selector ) { 3151 return this; 3152 } 3153 3154 // Method init() accepts an alternate rootjQuery 3155 // so migrate can support jQuery.sub (gh-2101) 3156 root = root || rootjQuery; 3157 3158 // Handle HTML strings 3159 if ( typeof selector === "string" ) { 3160 if ( selector[ 0 ] === "<" && 3161 selector[ selector.length - 1 ] === ">" && 3162 selector.length >= 3 ) { 3163 3164 // Assume that strings that start and end with <> are HTML and skip the regex check 3165 match = [ null, selector, null ]; 3166 3167 } else { 3168 match = rquickExpr.exec( selector ); 3169 } 3170 3171 // Match html or make sure no context is specified for #id 3172 if ( match && ( match[ 1 ] || !context ) ) { 3173 3174 // HANDLE: $(html) -> $(array) 3175 if ( match[ 1 ] ) { 3176 context = context instanceof jQuery ? context[ 0 ] : context; 3177 3178 // Option to run scripts is true for back-compat 3179 // Intentionally let the error be thrown if parseHTML is not present 3180 jQuery.merge( this, jQuery.parseHTML( 3181 match[ 1 ], 3182 context && context.nodeType ? context.ownerDocument || context : document, 3183 true 3184 ) ); 3185 3186 // HANDLE: $(html, props) 3187 if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { 3188 for ( match in context ) { 3189 3190 // Properties of context are called as methods if possible 3191 if ( jQuery.isFunction( this[ match ] ) ) { 3192 this[ match ]( context[ match ] ); 3193 3194 // ...and otherwise set as attributes 3195 } else { 3196 this.attr( match, context[ match ] ); 3197 } 3198 } 3199 } 3200 3201 return this; 3202 3203 // HANDLE: $(#id) 3204 } else { 3205 elem = document.getElementById( match[ 2 ] ); 3206 3207 // Support: Blackberry 4.6 3208 // gEBID returns nodes no longer in the document (#6963) 3209 if ( elem && elem.parentNode ) { 3210 3211 // Inject the element directly into the jQuery object 3212 this.length = 1; 3213 this[ 0 ] = elem; 3214 } 3215 3216 this.context = document; 3217 this.selector = selector; 3218 return this; 3219 } 3220 3221 // HANDLE: $(expr, $(...)) 3222 } else if ( !context || context.jquery ) { 3223 return ( context || root ).find( selector ); 3224 3225 // HANDLE: $(expr, context) 3226 // (which is just equivalent to: $(context).find(expr) 3227 } else { 3228 return this.constructor( context ).find( selector ); 3229 } 3230 3231 // HANDLE: $(DOMElement) 3232 } else if ( selector.nodeType ) { 3233 this.context = this[ 0 ] = selector; 3234 this.length = 1; 3235 return this; 3236 3237 // HANDLE: $(function) 3238 // Shortcut for document ready 3239 } else if ( jQuery.isFunction( selector ) ) { 3240 return root.ready !== undefined ? 3241 root.ready( selector ) : 3242 3243 // Execute immediately if ready is not present 3244 selector( jQuery ); 3245 } 3246 3247 if ( selector.selector !== undefined ) { 3248 this.selector = selector.selector; 3249 this.context = selector.context; 3250 } 3251 3252 return jQuery.makeArray( selector, this ); 3253 }; 3254 3255// Give the init function the jQuery prototype for later instantiation 3256init.prototype = jQuery.fn; 3257 3258// Initialize central reference 3259rootjQuery = jQuery( document ); 3260 3261 3262var rparentsprev = /^(?:parents|prev(?:Until|All))/, 3263 3264 // Methods guaranteed to produce a unique set when starting from a unique set 3265 guaranteedUnique = { 3266 children: true, 3267 contents: true, 3268 next: true, 3269 prev: true 3270 }; 3271 3272jQuery.fn.extend( { 3273 has: function( target ) { 3274 var targets = jQuery( target, this ), 3275 l = targets.length; 3276 3277 return this.filter( function() { 3278 var i = 0; 3279 for ( ; i < l; i++ ) { 3280 if ( jQuery.contains( this, targets[ i ] ) ) { 3281 return true; 3282 } 3283 } 3284 } ); 3285 }, 3286 3287 closest: function( selectors, context ) { 3288 var cur, 3289 i = 0, 3290 l = this.length, 3291 matched = [], 3292 pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? 3293 jQuery( selectors, context || this.context ) : 3294 0; 3295 3296 for ( ; i < l; i++ ) { 3297 for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { 3298 3299 // Always skip document fragments 3300 if ( cur.nodeType < 11 && ( pos ? 3301 pos.index( cur ) > -1 : 3302 3303 // Don't pass non-elements to Sizzle 3304 cur.nodeType === 1 && 3305 jQuery.find.matchesSelector( cur, selectors ) ) ) { 3306 3307 matched.push( cur ); 3308 break; 3309 } 3310 } 3311 } 3312 3313 return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); 3314 }, 3315 3316 // Determine the position of an element within the set 3317 index: function( elem ) { 3318 3319 // No argument, return index in parent 3320 if ( !elem ) { 3321 return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; 3322 } 3323 3324 // Index in selector 3325 if ( typeof elem === "string" ) { 3326 return indexOf.call( jQuery( elem ), this[ 0 ] ); 3327 } 3328 3329 // Locate the position of the desired element 3330 return indexOf.call( this, 3331 3332 // If it receives a jQuery object, the first element is used 3333 elem.jquery ? elem[ 0 ] : elem 3334 ); 3335 }, 3336 3337 add: function( selector, context ) { 3338 return this.pushStack( 3339 jQuery.uniqueSort( 3340 jQuery.merge( this.get(), jQuery( selector, context ) ) 3341 ) 3342 ); 3343 }, 3344 3345 addBack: function( selector ) { 3346 return this.add( selector == null ? 3347 this.prevObject : this.prevObject.filter( selector ) 3348 ); 3349 } 3350} ); 3351 3352function sibling( cur, dir ) { 3353 while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} 3354 return cur; 3355} 3356 3357jQuery.each( { 3358 parent: function( elem ) { 3359 var parent = elem.parentNode; 3360 return parent && parent.nodeType !== 11 ? parent : null; 3361 }, 3362 parents: function( elem ) { 3363 return dir( elem, "parentNode" ); 3364 }, 3365 parentsUntil: function( elem, i, until ) { 3366 return dir( elem, "parentNode", until ); 3367 }, 3368 next: function( elem ) { 3369 return sibling( elem, "nextSibling" ); 3370 }, 3371 prev: function( elem ) { 3372 return sibling( elem, "previousSibling" ); 3373 }, 3374 nextAll: function( elem ) { 3375 return dir( elem, "nextSibling" ); 3376 }, 3377 prevAll: function( elem ) { 3378 return dir( elem, "previousSibling" ); 3379 }, 3380 nextUntil: function( elem, i, until ) { 3381 return dir( elem, "nextSibling", until ); 3382 }, 3383 prevUntil: function( elem, i, until ) { 3384 return dir( elem, "previousSibling", until ); 3385 }, 3386 siblings: function( elem ) { 3387 return siblings( ( elem.parentNode || {} ).firstChild, elem ); 3388 }, 3389 children: function( elem ) { 3390 return siblings( elem.firstChild ); 3391 }, 3392 contents: function( elem ) { 3393 return elem.contentDocument || jQuery.merge( [], elem.childNodes ); 3394 } 3395}, function( name, fn ) { 3396 jQuery.fn[ name ] = function( until, selector ) { 3397 var matched = jQuery.map( this, fn, until ); 3398 3399 if ( name.slice( -5 ) !== "Until" ) { 3400 selector = until; 3401 } 3402 3403 if ( selector && typeof selector === "string" ) { 3404 matched = jQuery.filter( selector, matched ); 3405 } 3406 3407 if ( this.length > 1 ) { 3408 3409 // Remove duplicates 3410 if ( !guaranteedUnique[ name ] ) { 3411 jQuery.uniqueSort( matched ); 3412 } 3413 3414 // Reverse order for parents* and prev-derivatives 3415 if ( rparentsprev.test( name ) ) { 3416 matched.reverse(); 3417 } 3418 } 3419 3420 return this.pushStack( matched ); 3421 }; 3422} ); 3423var rnotwhite = ( /\S+/g ); 3424 3425 3426 3427// Convert String-formatted options into Object-formatted ones 3428function createOptions( options ) { 3429 var object = {}; 3430 jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { 3431 object[ flag ] = true; 3432 } ); 3433 return object; 3434} 3435 3436/* 3437 * Create a callback list using the following parameters: 3438 * 3439 * options: an optional list of space-separated options that will change how 3440 * the callback list behaves or a more traditional option object 3441 * 3442 * By default a callback list will act like an event callback list and can be 3443 * "fired" multiple times. 3444 * 3445 * Possible options: 3446 * 3447 * once: will ensure the callback list can only be fired once (like a Deferred) 3448 * 3449 * memory: will keep track of previous values and will call any callback added 3450 * after the list has been fired right away with the latest "memorized" 3451 * values (like a Deferred) 3452 * 3453 * unique: will ensure a callback can only be added once (no duplicate in the list) 3454 * 3455 * stopOnFalse: interrupt callings when a callback returns false 3456 * 3457 */ 3458jQuery.Callbacks = function( options ) { 3459 3460 // Convert options from String-formatted to Object-formatted if needed 3461 // (we check in cache first) 3462 options = typeof options === "string" ? 3463 createOptions( options ) : 3464 jQuery.extend( {}, options ); 3465 3466 var // Flag to know if list is currently firing 3467 firing, 3468 3469 // Last fire value for non-forgettable lists 3470 memory, 3471 3472 // Flag to know if list was already fired 3473 fired, 3474 3475 // Flag to prevent firing 3476 locked, 3477 3478 // Actual callback list 3479 list = [], 3480 3481 // Queue of execution data for repeatable lists 3482 queue = [], 3483 3484 // Index of currently firing callback (modified by add/remove as needed) 3485 firingIndex = -1, 3486 3487 // Fire callbacks 3488 fire = function() { 3489 3490 // Enforce single-firing 3491 locked = options.once; 3492 3493 // Execute callbacks for all pending executions, 3494 // respecting firingIndex overrides and runtime changes 3495 fired = firing = true; 3496 for ( ; queue.length; firingIndex = -1 ) { 3497 memory = queue.shift(); 3498 while ( ++firingIndex < list.length ) { 3499 3500 // Run callback and check for early termination 3501 if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && 3502 options.stopOnFalse ) { 3503 3504 // Jump to end and forget the data so .add doesn't re-fire 3505 firingIndex = list.length; 3506 memory = false; 3507 } 3508 } 3509 } 3510 3511 // Forget the data if we're done with it 3512 if ( !options.memory ) { 3513 memory = false; 3514 } 3515 3516 firing = false; 3517 3518 // Clean up if we're done firing for good 3519 if ( locked ) { 3520 3521 // Keep an empty list if we have data for future add calls 3522 if ( memory ) { 3523 list = []; 3524 3525 // Otherwise, this object is spent 3526 } else { 3527 list = ""; 3528 } 3529 } 3530 }, 3531 3532 // Actual Callbacks object 3533 self = { 3534 3535 // Add a callback or a collection of callbacks to the list 3536 add: function() { 3537 if ( list ) { 3538 3539 // If we have memory from a past run, we should fire after adding 3540 if ( memory && !firing ) { 3541 firingIndex = list.length - 1; 3542 queue.push( memory ); 3543 } 3544 3545 ( function add( args ) { 3546 jQuery.each( args, function( _, arg ) { 3547 if ( jQuery.isFunction( arg ) ) { 3548 if ( !options.unique || !self.has( arg ) ) { 3549 list.push( arg ); 3550 } 3551 } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { 3552 3553 // Inspect recursively 3554 add( arg ); 3555 } 3556 } ); 3557 } )( arguments ); 3558 3559 if ( memory && !firing ) { 3560 fire(); 3561 } 3562 } 3563 return this; 3564 }, 3565 3566 // Remove a callback from the list 3567 remove: function() { 3568 jQuery.each( arguments, function( _, arg ) { 3569 var index; 3570 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { 3571 list.splice( index, 1 ); 3572 3573 // Handle firing indexes 3574 if ( index <= firingIndex ) { 3575 firingIndex--; 3576 } 3577 } 3578 } ); 3579 return this; 3580 }, 3581 3582 // Check if a given callback is in the list. 3583 // If no argument is given, return whether or not list has callbacks attached. 3584 has: function( fn ) { 3585 return fn ? 3586 jQuery.inArray( fn, list ) > -1 : 3587 list.length > 0; 3588 }, 3589 3590 // Remove all callbacks from the list 3591 empty: function() { 3592 if ( list ) { 3593 list = []; 3594 } 3595 return this; 3596 }, 3597 3598 // Disable .fire and .add 3599 // Abort any current/pending executions 3600 // Clear all callbacks and values 3601 disable: function() { 3602 locked = queue = []; 3603 list = memory = ""; 3604 return this; 3605 }, 3606 disabled: function() { 3607 return !list; 3608 }, 3609 3610 // Disable .fire 3611 // Also disable .add unless we have memory (since it would have no effect) 3612 // Abort any pending executions 3613 lock: function() { 3614 locked = queue = []; 3615 if ( !memory ) { 3616 list = memory = ""; 3617 } 3618 return this; 3619 }, 3620 locked: function() { 3621 return !!locked; 3622 }, 3623 3624 // Call all callbacks with the given context and arguments 3625 fireWith: function( context, args ) { 3626 if ( !locked ) { 3627 args = args || []; 3628 args = [ context, args.slice ? args.slice() : args ]; 3629 queue.push( args ); 3630 if ( !firing ) { 3631 fire(); 3632 } 3633 } 3634 return this; 3635 }, 3636 3637 // Call all the callbacks with the given arguments 3638 fire: function() { 3639 self.fireWith( this, arguments ); 3640 return this; 3641 }, 3642 3643 // To know if the callbacks have already been called at least once 3644 fired: function() { 3645 return !!fired; 3646 } 3647 }; 3648 3649 return self; 3650}; 3651 3652 3653jQuery.extend( { 3654 3655 Deferred: function( func ) { 3656 var tuples = [ 3657 3658 // action, add listener, listener list, final state 3659 [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], 3660 [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], 3661 [ "notify", "progress", jQuery.Callbacks( "memory" ) ] 3662 ], 3663 state = "pending", 3664 promise = { 3665 state: function() { 3666 return state; 3667 }, 3668 always: function() { 3669 deferred.done( arguments ).fail( arguments ); 3670 return this; 3671 }, 3672 then: function( /* fnDone, fnFail, fnProgress */ ) { 3673 var fns = arguments; 3674 return jQuery.Deferred( function( newDefer ) { 3675 jQuery.each( tuples, function( i, tuple ) { 3676 var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; 3677 3678 // deferred[ done | fail | progress ] for forwarding actions to newDefer 3679 deferred[ tuple[ 1 ] ]( function() { 3680 var returned = fn && fn.apply( this, arguments ); 3681 if ( returned && jQuery.isFunction( returned.promise ) ) { 3682 returned.promise() 3683 .progress( newDefer.notify ) 3684 .done( newDefer.resolve ) 3685 .fail( newDefer.reject ); 3686 } else { 3687 newDefer[ tuple[ 0 ] + "With" ]( 3688 this === promise ? newDefer.promise() : this, 3689 fn ? [ returned ] : arguments 3690 ); 3691 } 3692 } ); 3693 } ); 3694 fns = null; 3695 } ).promise(); 3696 }, 3697 3698 // Get a promise for this deferred 3699 // If obj is provided, the promise aspect is added to the object 3700 promise: function( obj ) { 3701 return obj != null ? jQuery.extend( obj, promise ) : promise; 3702 } 3703 }, 3704 deferred = {}; 3705 3706 // Keep pipe for back-compat 3707 promise.pipe = promise.then; 3708 3709 // Add list-specific methods 3710 jQuery.each( tuples, function( i, tuple ) { 3711 var list = tuple[ 2 ], 3712 stateString = tuple[ 3 ]; 3713 3714 // promise[ done | fail | progress ] = list.add 3715 promise[ tuple[ 1 ] ] = list.add; 3716 3717 // Handle state 3718 if ( stateString ) { 3719 list.add( function() { 3720 3721 // state = [ resolved | rejected ] 3722 state = stateString; 3723 3724 // [ reject_list | resolve_list ].disable; progress_list.lock 3725 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); 3726 } 3727 3728 // deferred[ resolve | reject | notify ] 3729 deferred[ tuple[ 0 ] ] = function() { 3730 deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); 3731 return this; 3732 }; 3733 deferred[ tuple[ 0 ] + "With" ] = list.fireWith; 3734 } ); 3735 3736 // Make the deferred a promise 3737 promise.promise( deferred ); 3738 3739 // Call given func if any 3740 if ( func ) { 3741 func.call( deferred, deferred ); 3742 } 3743 3744 // All done! 3745 return deferred; 3746 }, 3747 3748 // Deferred helper 3749 when: function( subordinate /* , ..., subordinateN */ ) { 3750 var i = 0, 3751 resolveValues = slice.call( arguments ), 3752 length = resolveValues.length, 3753 3754 // the count of uncompleted subordinates 3755 remaining = length !== 1 || 3756 ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, 3757 3758 // the master Deferred. 3759 // If resolveValues consist of only a single Deferred, just use that. 3760 deferred = remaining === 1 ? subordinate : jQuery.Deferred(), 3761 3762 // Update function for both resolve and progress values 3763 updateFunc = function( i, contexts, values ) { 3764 return function( value ) { 3765 contexts[ i ] = this; 3766 values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; 3767 if ( values === progressValues ) { 3768 deferred.notifyWith( contexts, values ); 3769 } else if ( !( --remaining ) ) { 3770 deferred.resolveWith( contexts, values ); 3771 } 3772 }; 3773 }, 3774 3775 progressValues, progressContexts, resolveContexts; 3776 3777 // Add listeners to Deferred subordinates; treat others as resolved 3778 if ( length > 1 ) { 3779 progressValues = new Array( length ); 3780 progressContexts = new Array( length ); 3781 resolveContexts = new Array( length ); 3782 for ( ; i < length; i++ ) { 3783 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { 3784 resolveValues[ i ].promise() 3785 .progress( updateFunc( i, progressContexts, progressValues ) ) 3786 .done( updateFunc( i, resolveContexts, resolveValues ) ) 3787 .fail( deferred.reject ); 3788 } else { 3789 --remaining; 3790 } 3791 } 3792 } 3793 3794 // If we're not waiting on anything, resolve the master 3795 if ( !remaining ) { 3796 deferred.resolveWith( resolveContexts, resolveValues ); 3797 } 3798 3799 return deferred.promise(); 3800 } 3801} ); 3802 3803 3804// The deferred used on DOM ready 3805var readyList; 3806 3807jQuery.fn.ready = function( fn ) { 3808 3809 // Add the callback 3810 jQuery.ready.promise().done( fn ); 3811 3812 return this; 3813}; 3814 3815jQuery.extend( { 3816 3817 // Is the DOM ready to be used? Set to true once it occurs. 3818 isReady: false, 3819 3820 // A counter to track how many items to wait for before 3821 // the ready event fires. See #6781 3822 readyWait: 1, 3823 3824 // Hold (or release) the ready event 3825 holdReady: function( hold ) { 3826 if ( hold ) { 3827 jQuery.readyWait++; 3828 } else { 3829 jQuery.ready( true ); 3830 } 3831 }, 3832 3833 // Handle when the DOM is ready 3834 ready: function( wait ) { 3835 3836 // Abort if there are pending holds or we're already ready 3837 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { 3838 return; 3839 } 3840 3841 // Remember that the DOM is ready 3842 jQuery.isReady = true; 3843 3844 // If a normal DOM Ready event fired, decrement, and wait if need be 3845 if ( wait !== true && --jQuery.readyWait > 0 ) { 3846 return; 3847 } 3848 3849 // If there are functions bound, to execute 3850 readyList.resolveWith( document, [ jQuery ] ); 3851 3852 // Trigger any bound ready events 3853 if ( jQuery.fn.triggerHandler ) { 3854 jQuery( document ).triggerHandler( "ready" ); 3855 jQuery( document ).off( "ready" ); 3856 } 3857 } 3858} ); 3859 3860/** 3861 * The ready event handler and self cleanup method 3862 */ 3863function completed() { 3864 document.removeEventListener( "DOMContentLoaded", completed ); 3865 window.removeEventListener( "load", completed ); 3866 jQuery.ready(); 3867} 3868 3869jQuery.ready.promise = function( obj ) { 3870 if ( !readyList ) { 3871 3872 readyList = jQuery.Deferred(); 3873 3874 // Catch cases where $(document).ready() is called 3875 // after the browser event has already occurred. 3876 // Support: IE9-10 only 3877 // Older IE sometimes signals "interactive" too soon 3878 if ( document.readyState === "complete" || 3879 ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { 3880 3881 // Handle it asynchronously to allow scripts the opportunity to delay ready 3882 window.setTimeout( jQuery.ready ); 3883 3884 } else { 3885 3886 // Use the handy event callback 3887 document.addEventListener( "DOMContentLoaded", completed ); 3888 3889 // A fallback to window.onload, that will always work 3890 window.addEventListener( "load", completed ); 3891 } 3892 } 3893 return readyList.promise( obj ); 3894}; 3895 3896// Kick off the DOM ready check even if the user does not 3897jQuery.ready.promise(); 3898 3899 3900 3901 3902// Multifunctional method to get and set values of a collection 3903// The value/s can optionally be executed if it's a function 3904var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { 3905 var i = 0, 3906 len = elems.length, 3907 bulk = key == null; 3908 3909 // Sets many values 3910 if ( jQuery.type( key ) === "object" ) { 3911 chainable = true; 3912 for ( i in key ) { 3913 access( elems, fn, i, key[ i ], true, emptyGet, raw ); 3914 } 3915 3916 // Sets one value 3917 } else if ( value !== undefined ) { 3918 chainable = true; 3919 3920 if ( !jQuery.isFunction( value ) ) { 3921 raw = true; 3922 } 3923 3924 if ( bulk ) { 3925 3926 // Bulk operations run against the entire set 3927 if ( raw ) { 3928 fn.call( elems, value ); 3929 fn = null; 3930 3931 // ...except when executing function values 3932 } else { 3933 bulk = fn; 3934 fn = function( elem, key, value ) { 3935 return bulk.call( jQuery( elem ), value ); 3936 }; 3937 } 3938 } 3939 3940 if ( fn ) { 3941 for ( ; i < len; i++ ) { 3942 fn( 3943 elems[ i ], key, raw ? 3944 value : 3945 value.call( elems[ i ], i, fn( elems[ i ], key ) ) 3946 ); 3947 } 3948 } 3949 } 3950 3951 return chainable ? 3952 elems : 3953 3954 // Gets 3955 bulk ? 3956 fn.call( elems ) : 3957 len ? fn( elems[ 0 ], key ) : emptyGet; 3958}; 3959var acceptData = function( owner ) { 3960 3961 // Accepts only: 3962 // - Node 3963 // - Node.ELEMENT_NODE 3964 // - Node.DOCUMENT_NODE 3965 // - Object 3966 // - Any 3967 /* jshint -W018 */ 3968 return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); 3969}; 3970 3971 3972 3973 3974function Data() { 3975 this.expando = jQuery.expando + Data.uid++; 3976} 3977 3978Data.uid = 1; 3979 3980Data.prototype = { 3981 3982 register: function( owner, initial ) { 3983 var value = initial || {}; 3984 3985 // If it is a node unlikely to be stringify-ed or looped over 3986 // use plain assignment 3987 if ( owner.nodeType ) { 3988 owner[ this.expando ] = value; 3989 3990 // Otherwise secure it in a non-enumerable, non-writable property 3991 // configurability must be true to allow the property to be 3992 // deleted with the delete operator 3993 } else { 3994 Object.defineProperty( owner, this.expando, { 3995 value: value, 3996 writable: true, 3997 configurable: true 3998 } ); 3999 } 4000 return owner[ this.expando ]; 4001 }, 4002 cache: function( owner ) { 4003 4004 // We can accept data for non-element nodes in modern browsers, 4005 // but we should not, see #8335. 4006 // Always return an empty object. 4007 if ( !acceptData( owner ) ) { 4008 return {}; 4009 } 4010 4011 // Check if the owner object already has a cache 4012 var value = owner[ this.expando ]; 4013 4014 // If not, create one 4015 if ( !value ) { 4016 value = {}; 4017 4018 // We can accept data for non-element nodes in modern browsers, 4019 // but we should not, see #8335. 4020 // Always return an empty object. 4021 if ( acceptData( owner ) ) { 4022 4023 // If it is a node unlikely to be stringify-ed or looped over 4024 // use plain assignment 4025 if ( owner.nodeType ) { 4026 owner[ this.expando ] = value; 4027 4028 // Otherwise secure it in a non-enumerable property 4029 // configurable must be true to allow the property to be 4030 // deleted when data is removed 4031 } else { 4032 Object.defineProperty( owner, this.expando, { 4033 value: value, 4034 configurable: true 4035 } ); 4036 } 4037 } 4038 } 4039 4040 return value; 4041 }, 4042 set: function( owner, data, value ) { 4043 var prop, 4044 cache = this.cache( owner ); 4045 4046 // Handle: [ owner, key, value ] args 4047 if ( typeof data === "string" ) { 4048 cache[ data ] = value; 4049 4050 // Handle: [ owner, { properties } ] args 4051 } else { 4052 4053 // Copy the properties one-by-one to the cache object 4054 for ( prop in data ) { 4055 cache[ prop ] = data[ prop ]; 4056 } 4057 } 4058 return cache; 4059 }, 4060 get: function( owner, key ) { 4061 return key === undefined ? 4062 this.cache( owner ) : 4063 owner[ this.expando ] && owner[ this.expando ][ key ]; 4064 }, 4065 access: function( owner, key, value ) { 4066 var stored; 4067 4068 // In cases where either: 4069 // 4070 // 1. No key was specified 4071 // 2. A string key was specified, but no value provided 4072 // 4073 // Take the "read" path and allow the get method to determine 4074 // which value to return, respectively either: 4075 // 4076 // 1. The entire cache object 4077 // 2. The data stored at the key 4078 // 4079 if ( key === undefined || 4080 ( ( key && typeof key === "string" ) && value === undefined ) ) { 4081 4082 stored = this.get( owner, key ); 4083 4084 return stored !== undefined ? 4085 stored : this.get( owner, jQuery.camelCase( key ) ); 4086 } 4087 4088 // When the key is not a string, or both a key and value 4089 // are specified, set or extend (existing objects) with either: 4090 // 4091 // 1. An object of properties 4092 // 2. A key and value 4093 // 4094 this.set( owner, key, value ); 4095 4096 // Since the "set" path can have two possible entry points 4097 // return the expected data based on which path was taken[*] 4098 return value !== undefined ? value : key; 4099 }, 4100 remove: function( owner, key ) { 4101 var i, name, camel, 4102 cache = owner[ this.expando ]; 4103 4104 if ( cache === undefined ) { 4105 return; 4106 } 4107 4108 if ( key === undefined ) { 4109 this.register( owner ); 4110 4111 } else { 4112 4113 // Support array or space separated string of keys 4114 if ( jQuery.isArray( key ) ) { 4115 4116 // If "name" is an array of keys... 4117 // When data is initially created, via ("key", "val") signature, 4118 // keys will be converted to camelCase. 4119 // Since there is no way to tell _how_ a key was added, remove 4120 // both plain key and camelCase key. #12786 4121 // This will only penalize the array argument path. 4122 name = key.concat( key.map( jQuery.camelCase ) ); 4123 } else { 4124 camel = jQuery.camelCase( key ); 4125 4126 // Try the string as a key before any manipulation 4127 if ( key in cache ) { 4128 name = [ key, camel ]; 4129 } else { 4130 4131 // If a key with the spaces exists, use it. 4132 // Otherwise, create an array by matching non-whitespace 4133 name = camel; 4134 name = name in cache ? 4135 [ name ] : ( name.match( rnotwhite ) || [] ); 4136 } 4137 } 4138 4139 i = name.length; 4140 4141 while ( i-- ) { 4142 delete cache[ name[ i ] ]; 4143 } 4144 } 4145 4146 // Remove the expando if there's no more data 4147 if ( key === undefined || jQuery.isEmptyObject( cache ) ) { 4148 4149 // Support: Chrome <= 35-45+ 4150 // Webkit & Blink performance suffers when deleting properties 4151 // from DOM nodes, so set to undefined instead 4152 // https://code.google.com/p/chromium/issues/detail?id=378607 4153 if ( owner.nodeType ) { 4154 owner[ this.expando ] = undefined; 4155 } else { 4156 delete owner[ this.expando ]; 4157 } 4158 } 4159 }, 4160 hasData: function( owner ) { 4161 var cache = owner[ this.expando ]; 4162 return cache !== undefined && !jQuery.isEmptyObject( cache ); 4163 } 4164}; 4165var dataPriv = new Data(); 4166 4167var dataUser = new Data(); 4168 4169 4170 4171// Implementation Summary 4172// 4173// 1. Enforce API surface and semantic compatibility with 1.9.x branch 4174// 2. Improve the module's maintainability by reducing the storage 4175// paths to a single mechanism. 4176// 3. Use the same single mechanism to support "private" and "user" data. 4177// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) 4178// 5. Avoid exposing implementation details on user objects (eg. expando properties) 4179// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 4180 4181var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, 4182 rmultiDash = /[A-Z]/g; 4183 4184function dataAttr( elem, key, data ) { 4185 var name; 4186 4187 // If nothing was found internally, try to fetch any 4188 // data from the HTML5 data-* attribute 4189 if ( data === undefined && elem.nodeType === 1 ) { 4190 name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); 4191 data = elem.getAttribute( name ); 4192 4193 if ( typeof data === "string" ) { 4194 try { 4195 data = data === "true" ? true : 4196 data === "false" ? false : 4197 data === "null" ? null : 4198 4199 // Only convert to a number if it doesn't change the string 4200 +data + "" === data ? +data : 4201 rbrace.test( data ) ? jQuery.parseJSON( data ) : 4202 data; 4203 } catch ( e ) {} 4204 4205 // Make sure we set the data so it isn't changed later 4206 dataUser.set( elem, key, data ); 4207 } else { 4208 data = undefined; 4209 } 4210 } 4211 return data; 4212} 4213 4214jQuery.extend( { 4215 hasData: function( elem ) { 4216 return dataUser.hasData( elem ) || dataPriv.hasData( elem ); 4217 }, 4218 4219 data: function( elem, name, data ) { 4220 return dataUser.access( elem, name, data ); 4221 }, 4222 4223 removeData: function( elem, name ) { 4224 dataUser.remove( elem, name ); 4225 }, 4226 4227 // TODO: Now that all calls to _data and _removeData have been replaced 4228 // with direct calls to dataPriv methods, these can be deprecated. 4229 _data: function( elem, name, data ) { 4230 return dataPriv.access( elem, name, data ); 4231 }, 4232 4233 _removeData: function( elem, name ) { 4234 dataPriv.remove( elem, name ); 4235 } 4236} ); 4237 4238jQuery.fn.extend( { 4239 data: function( key, value ) { 4240 var i, name, data, 4241 elem = this[ 0 ], 4242 attrs = elem && elem.attributes; 4243 4244 // Gets all values 4245 if ( key === undefined ) { 4246 if ( this.length ) { 4247 data = dataUser.get( elem ); 4248 4249 if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { 4250 i = attrs.length; 4251 while ( i-- ) { 4252 4253 // Support: IE11+ 4254 // The attrs elements can be null (#14894) 4255 if ( attrs[ i ] ) { 4256 name = attrs[ i ].name; 4257 if ( name.indexOf( "data-" ) === 0 ) { 4258 name = jQuery.camelCase( name.slice( 5 ) ); 4259 dataAttr( elem, name, data[ name ] ); 4260 } 4261 } 4262 } 4263 dataPriv.set( elem, "hasDataAttrs", true ); 4264 } 4265 } 4266 4267 return data; 4268 } 4269 4270 // Sets multiple values 4271 if ( typeof key === "object" ) { 4272 return this.each( function() { 4273 dataUser.set( this, key ); 4274 } ); 4275 } 4276 4277 return access( this, function( value ) { 4278 var data, camelKey; 4279 4280 // The calling jQuery object (element matches) is not empty 4281 // (and therefore has an element appears at this[ 0 ]) and the 4282 // `value` parameter was not undefined. An empty jQuery object 4283 // will result in `undefined` for elem = this[ 0 ] which will 4284 // throw an exception if an attempt to read a data cache is made. 4285 if ( elem && value === undefined ) { 4286 4287 // Attempt to get data from the cache 4288 // with the key as-is 4289 data = dataUser.get( elem, key ) || 4290 4291 // Try to find dashed key if it exists (gh-2779) 4292 // This is for 2.2.x only 4293 dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() ); 4294 4295 if ( data !== undefined ) { 4296 return data; 4297 } 4298 4299 camelKey = jQuery.camelCase( key ); 4300 4301 // Attempt to get data from the cache 4302 // with the key camelized 4303 data = dataUser.get( elem, camelKey ); 4304 if ( data !== undefined ) { 4305 return data; 4306 } 4307 4308 // Attempt to "discover" the data in 4309 // HTML5 custom data-* attrs 4310 data = dataAttr( elem, camelKey, undefined ); 4311 if ( data !== undefined ) { 4312 return data; 4313 } 4314 4315 // We tried really hard, but the data doesn't exist. 4316 return; 4317 } 4318 4319 // Set the data... 4320 camelKey = jQuery.camelCase( key ); 4321 this.each( function() { 4322 4323 // First, attempt to store a copy or reference of any 4324 // data that might've been store with a camelCased key. 4325 var data = dataUser.get( this, camelKey ); 4326 4327 // For HTML5 data-* attribute interop, we have to 4328 // store property names with dashes in a camelCase form. 4329 // This might not apply to all properties...* 4330 dataUser.set( this, camelKey, value ); 4331 4332 // *... In the case of properties that might _actually_ 4333 // have dashes, we need to also store a copy of that 4334 // unchanged property. 4335 if ( key.indexOf( "-" ) > -1 && data !== undefined ) { 4336 dataUser.set( this, key, value ); 4337 } 4338 } ); 4339 }, null, value, arguments.length > 1, null, true ); 4340 }, 4341 4342 removeData: function( key ) { 4343 return this.each( function() { 4344 dataUser.remove( this, key ); 4345 } ); 4346 } 4347} ); 4348 4349 4350jQuery.extend( { 4351 queue: function( elem, type, data ) { 4352 var queue; 4353 4354 if ( elem ) { 4355 type = ( type || "fx" ) + "queue"; 4356 queue = dataPriv.get( elem, type ); 4357 4358 // Speed up dequeue by getting out quickly if this is just a lookup 4359 if ( data ) { 4360 if ( !queue || jQuery.isArray( data ) ) { 4361 queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); 4362 } else { 4363 queue.push( data ); 4364 } 4365 } 4366 return queue || []; 4367 } 4368 }, 4369 4370 dequeue: function( elem, type ) { 4371 type = type || "fx"; 4372 4373 var queue = jQuery.queue( elem, type ), 4374 startLength = queue.length, 4375 fn = queue.shift(), 4376 hooks = jQuery._queueHooks( elem, type ), 4377 next = function() { 4378 jQuery.dequeue( elem, type ); 4379 }; 4380 4381 // If the fx queue is dequeued, always remove the progress sentinel 4382 if ( fn === "inprogress" ) { 4383 fn = queue.shift(); 4384 startLength--; 4385 } 4386 4387 if ( fn ) { 4388 4389 // Add a progress sentinel to prevent the fx queue from being 4390 // automatically dequeued 4391 if ( type === "fx" ) { 4392 queue.unshift( "inprogress" ); 4393 } 4394 4395 // Clear up the last queue stop function 4396 delete hooks.stop; 4397 fn.call( elem, next, hooks ); 4398 } 4399 4400 if ( !startLength && hooks ) { 4401 hooks.empty.fire(); 4402 } 4403 }, 4404 4405 // Not public - generate a queueHooks object, or return the current one 4406 _queueHooks: function( elem, type ) { 4407 var key = type + "queueHooks"; 4408 return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { 4409 empty: jQuery.Callbacks( "once memory" ).add( function() { 4410 dataPriv.remove( elem, [ type + "queue", key ] ); 4411 } ) 4412 } ); 4413 } 4414} ); 4415 4416jQuery.fn.extend( { 4417 queue: function( type, data ) { 4418 var setter = 2; 4419 4420 if ( typeof type !== "string" ) { 4421 data = type; 4422 type = "fx"; 4423 setter--; 4424 } 4425 4426 if ( arguments.length < setter ) { 4427 return jQuery.queue( this[ 0 ], type ); 4428 } 4429 4430 return data === undefined ? 4431 this : 4432 this.each( function() { 4433 var queue = jQuery.queue( this, type, data ); 4434 4435 // Ensure a hooks for this queue 4436 jQuery._queueHooks( this, type ); 4437 4438 if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { 4439 jQuery.dequeue( this, type ); 4440 } 4441 } ); 4442 }, 4443 dequeue: function( type ) { 4444 return this.each( function() { 4445 jQuery.dequeue( this, type ); 4446 } ); 4447 }, 4448 clearQueue: function( type ) { 4449 return this.queue( type || "fx", [] ); 4450 }, 4451 4452 // Get a promise resolved when queues of a certain type 4453 // are emptied (fx is the type by default) 4454 promise: function( type, obj ) { 4455 var tmp, 4456 count = 1, 4457 defer = jQuery.Deferred(), 4458 elements = this, 4459 i = this.length, 4460 resolve = function() { 4461 if ( !( --count ) ) { 4462 defer.resolveWith( elements, [ elements ] ); 4463 } 4464 }; 4465 4466 if ( typeof type !== "string" ) { 4467 obj = type; 4468 type = undefined; 4469 } 4470 type = type || "fx"; 4471 4472 while ( i-- ) { 4473 tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); 4474 if ( tmp && tmp.empty ) { 4475 count++; 4476 tmp.empty.add( resolve ); 4477 } 4478 } 4479 resolve(); 4480 return defer.promise( obj ); 4481 } 4482} ); 4483var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; 4484 4485var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); 4486 4487 4488var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; 4489 4490var isHidden = function( elem, el ) { 4491 4492 // isHidden might be called from jQuery#filter function; 4493 // in that case, element will be second argument 4494 elem = el || elem; 4495 return jQuery.css( elem, "display" ) === "none" || 4496 !jQuery.contains( elem.ownerDocument, elem ); 4497 }; 4498 4499 4500 4501function adjustCSS( elem, prop, valueParts, tween ) { 4502 var adjusted, 4503 scale = 1, 4504 maxIterations = 20, 4505 currentValue = tween ? 4506 function() { return tween.cur(); } : 4507 function() { return jQuery.css( elem, prop, "" ); }, 4508 initial = currentValue(), 4509 unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), 4510 4511 // Starting value computation is required for potential unit mismatches 4512 initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && 4513 rcssNum.exec( jQuery.css( elem, prop ) ); 4514 4515 if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { 4516 4517 // Trust units reported by jQuery.css 4518 unit = unit || initialInUnit[ 3 ]; 4519 4520 // Make sure we update the tween properties later on 4521 valueParts = valueParts || []; 4522 4523 // Iteratively approximate from a nonzero starting point 4524 initialInUnit = +initial || 1; 4525 4526 do { 4527 4528 // If previous iteration zeroed out, double until we get *something*. 4529 // Use string for doubling so we don't accidentally see scale as unchanged below 4530 scale = scale || ".5"; 4531 4532 // Adjust and apply 4533 initialInUnit = initialInUnit / scale; 4534 jQuery.style( elem, prop, initialInUnit + unit ); 4535 4536 // Update scale, tolerating zero or NaN from tween.cur() 4537 // Break the loop if scale is unchanged or perfect, or if we've just had enough. 4538 } while ( 4539 scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations 4540 ); 4541 } 4542 4543 if ( valueParts ) { 4544 initialInUnit = +initialInUnit || +initial || 0; 4545 4546 // Apply relative offset (+=/-=) if specified 4547 adjusted = valueParts[ 1 ] ? 4548 initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : 4549 +valueParts[ 2 ]; 4550 if ( tween ) { 4551 tween.unit = unit; 4552 tween.start = initialInUnit; 4553 tween.end = adjusted; 4554 } 4555 } 4556 return adjusted; 4557} 4558var rcheckableType = ( /^(?:checkbox|radio)$/i ); 4559 4560var rtagName = ( /<([\w:-]+)/ ); 4561 4562var rscriptType = ( /^$|\/(?:java|ecma)script/i ); 4563 4564 4565 4566// We have to close these tags to support XHTML (#13200) 4567var wrapMap = { 4568 4569 // Support: IE9 4570 option: [ 1, "<select multiple='multiple'>", "</select>" ], 4571 4572 // XHTML parsers do not magically insert elements in the 4573 // same way that tag soup parsers do. So we cannot shorten 4574 // this by omitting <tbody> or other required elements. 4575 thead: [ 1, "<table>", "</table>" ], 4576 col: [ 2, "<table><colgroup>", "</colgroup></table>" ], 4577 tr: [ 2, "<table><tbody>", "</tbody></table>" ], 4578 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], 4579 4580 _default: [ 0, "", "" ] 4581}; 4582 4583// Support: IE9 4584wrapMap.optgroup = wrapMap.option; 4585 4586wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 4587wrapMap.th = wrapMap.td; 4588 4589 4590function getAll( context, tag ) { 4591 4592 // Support: IE9-11+ 4593 // Use typeof to avoid zero-argument method invocation on host objects (#15151) 4594 var ret = typeof context.getElementsByTagName !== "undefined" ? 4595 context.getElementsByTagName( tag || "*" ) : 4596 typeof context.querySelectorAll !== "undefined" ? 4597 context.querySelectorAll( tag || "*" ) : 4598 []; 4599 4600 return tag === undefined || tag && jQuery.nodeName( context, tag ) ? 4601 jQuery.merge( [ context ], ret ) : 4602 ret; 4603} 4604 4605 4606// Mark scripts as having already been evaluated 4607function setGlobalEval( elems, refElements ) { 4608 var i = 0, 4609 l = elems.length; 4610 4611 for ( ; i < l; i++ ) { 4612 dataPriv.set( 4613 elems[ i ], 4614 "globalEval", 4615 !refElements || dataPriv.get( refElements[ i ], "globalEval" ) 4616 ); 4617 } 4618} 4619 4620 4621var rhtml = /<|&#?\w+;/; 4622 4623function buildFragment( elems, context, scripts, selection, ignored ) { 4624 var elem, tmp, tag, wrap, contains, j, 4625 fragment = context.createDocumentFragment(), 4626 nodes = [], 4627 i = 0, 4628 l = elems.length; 4629 4630 for ( ; i < l; i++ ) { 4631 elem = elems[ i ]; 4632 4633 if ( elem || elem === 0 ) { 4634 4635 // Add nodes directly 4636 if ( jQuery.type( elem ) === "object" ) { 4637 4638 // Support: Android<4.1, PhantomJS<2 4639 // push.apply(_, arraylike) throws on ancient WebKit 4640 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); 4641 4642 // Convert non-html into a text node 4643 } else if ( !rhtml.test( elem ) ) { 4644 nodes.push( context.createTextNode( elem ) ); 4645 4646 // Convert html into DOM nodes 4647 } else { 4648 tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); 4649 4650 // Deserialize a standard representation 4651 tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); 4652 wrap = wrapMap[ tag ] || wrapMap._default; 4653 tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; 4654 4655 // Descend through wrappers to the right content 4656 j = wrap[ 0 ]; 4657 while ( j-- ) { 4658 tmp = tmp.lastChild; 4659 } 4660 4661 // Support: Android<4.1, PhantomJS<2 4662 // push.apply(_, arraylike) throws on ancient WebKit 4663 jQuery.merge( nodes, tmp.childNodes ); 4664 4665 // Remember the top-level container 4666 tmp = fragment.firstChild; 4667 4668 // Ensure the created nodes are orphaned (#12392) 4669 tmp.textContent = ""; 4670 } 4671 } 4672 } 4673 4674 // Remove wrapper from fragment 4675 fragment.textContent = ""; 4676 4677 i = 0; 4678 while ( ( elem = nodes[ i++ ] ) ) { 4679 4680 // Skip elements already in the context collection (trac-4087) 4681 if ( selection && jQuery.inArray( elem, selection ) > -1 ) { 4682 if ( ignored ) { 4683 ignored.push( elem ); 4684 } 4685 continue; 4686 } 4687 4688 contains = jQuery.contains( elem.ownerDocument, elem ); 4689 4690 // Append to fragment 4691 tmp = getAll( fragment.appendChild( elem ), "script" ); 4692 4693 // Preserve script evaluation history 4694 if ( contains ) { 4695 setGlobalEval( tmp ); 4696 } 4697 4698 // Capture executables 4699 if ( scripts ) { 4700 j = 0; 4701 while ( ( elem = tmp[ j++ ] ) ) { 4702 if ( rscriptType.test( elem.type || "" ) ) { 4703 scripts.push( elem ); 4704 } 4705 } 4706 } 4707 } 4708 4709 return fragment; 4710} 4711 4712 4713( function() { 4714 var fragment = document.createDocumentFragment(), 4715 div = fragment.appendChild( document.createElement( "div" ) ), 4716 input = document.createElement( "input" ); 4717 4718 // Support: Android 4.0-4.3, Safari<=5.1 4719 // Check state lost if the name is set (#11217) 4720 // Support: Windows Web Apps (WWA) 4721 // `name` and `type` must use .setAttribute for WWA (#14901) 4722 input.setAttribute( "type", "radio" ); 4723 input.setAttribute( "checked", "checked" ); 4724 input.setAttribute( "name", "t" ); 4725 4726 div.appendChild( input ); 4727 4728 // Support: Safari<=5.1, Android<4.2 4729 // Older WebKit doesn't clone checked state correctly in fragments 4730 support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 4731 4732 // Support: IE<=11+ 4733 // Make sure textarea (and checkbox) defaultValue is properly cloned 4734 div.innerHTML = "<textarea>x</textarea>"; 4735 support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 4736} )(); 4737 4738 4739var 4740 rkeyEvent = /^key/, 4741 rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, 4742 rtypenamespace = /^([^.]*)(?:\.(.+)|)/; 4743 4744function returnTrue() { 4745 return true; 4746} 4747 4748function returnFalse() { 4749 return false; 4750} 4751 4752// Support: IE9 4753// See #13393 for more info 4754function safeActiveElement() { 4755 try { 4756 return document.activeElement; 4757 } catch ( err ) { } 4758} 4759 4760function on( elem, types, selector, data, fn, one ) { 4761 var origFn, type; 4762 4763 // Types can be a map of types/handlers 4764 if ( typeof types === "object" ) { 4765 4766 // ( types-Object, selector, data ) 4767 if ( typeof selector !== "string" ) { 4768 4769 // ( types-Object, data ) 4770 data = data || selector; 4771 selector = undefined; 4772 } 4773 for ( type in types ) { 4774 on( elem, type, selector, data, types[ type ], one ); 4775 } 4776 return elem; 4777 } 4778 4779 if ( data == null && fn == null ) { 4780 4781 // ( types, fn ) 4782 fn = selector; 4783 data = selector = undefined; 4784 } else if ( fn == null ) { 4785 if ( typeof selector === "string" ) { 4786 4787 // ( types, selector, fn ) 4788 fn = data; 4789 data = undefined; 4790 } else { 4791 4792 // ( types, data, fn ) 4793 fn = data; 4794 data = selector; 4795 selector = undefined; 4796 } 4797 } 4798 if ( fn === false ) { 4799 fn = returnFalse; 4800 } else if ( !fn ) { 4801 return elem; 4802 } 4803 4804 if ( one === 1 ) { 4805 origFn = fn; 4806 fn = function( event ) { 4807 4808 // Can use an empty set, since event contains the info 4809 jQuery().off( event ); 4810 return origFn.apply( this, arguments ); 4811 }; 4812 4813 // Use same guid so caller can remove using origFn 4814 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); 4815 } 4816 return elem.each( function() { 4817 jQuery.event.add( this, types, fn, data, selector ); 4818 } ); 4819} 4820 4821/* 4822 * Helper functions for managing events -- not part of the public interface. 4823 * Props to Dean Edwards' addEvent library for many of the ideas. 4824 */ 4825jQuery.event = { 4826 4827 global: {}, 4828 4829 add: function( elem, types, handler, data, selector ) { 4830 4831 var handleObjIn, eventHandle, tmp, 4832 events, t, handleObj, 4833 special, handlers, type, namespaces, origType, 4834 elemData = dataPriv.get( elem ); 4835 4836 // Don't attach events to noData or text/comment nodes (but allow plain objects) 4837 if ( !elemData ) { 4838 return; 4839 } 4840 4841 // Caller can pass in an object of custom data in lieu of the handler 4842 if ( handler.handler ) { 4843 handleObjIn = handler; 4844 handler = handleObjIn.handler; 4845 selector = handleObjIn.selector; 4846 } 4847 4848 // Make sure that the handler has a unique ID, used to find/remove it later 4849 if ( !handler.guid ) { 4850 handler.guid = jQuery.guid++; 4851 } 4852 4853 // Init the element's event structure and main handler, if this is the first 4854 if ( !( events = elemData.events ) ) { 4855 events = elemData.events = {}; 4856 } 4857 if ( !( eventHandle = elemData.handle ) ) { 4858 eventHandle = elemData.handle = function( e ) { 4859 4860 // Discard the second event of a jQuery.event.trigger() and 4861 // when an event is called after a page has unloaded 4862 return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? 4863 jQuery.event.dispatch.apply( elem, arguments ) : undefined; 4864 }; 4865 } 4866 4867 // Handle multiple events separated by a space 4868 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4869 t = types.length; 4870 while ( t-- ) { 4871 tmp = rtypenamespace.exec( types[ t ] ) || []; 4872 type = origType = tmp[ 1 ]; 4873 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 4874 4875 // There *must* be a type, no attaching namespace-only handlers 4876 if ( !type ) { 4877 continue; 4878 } 4879 4880 // If event changes its type, use the special event handlers for the changed type 4881 special = jQuery.event.special[ type ] || {}; 4882 4883 // If selector defined, determine special event api type, otherwise given type 4884 type = ( selector ? special.delegateType : special.bindType ) || type; 4885 4886 // Update special based on newly reset type 4887 special = jQuery.event.special[ type ] || {}; 4888 4889 // handleObj is passed to all event handlers 4890 handleObj = jQuery.extend( { 4891 type: type, 4892 origType: origType, 4893 data: data, 4894 handler: handler, 4895 guid: handler.guid, 4896 selector: selector, 4897 needsContext: selector && jQuery.expr.match.needsContext.test( selector ), 4898 namespace: namespaces.join( "." ) 4899 }, handleObjIn ); 4900 4901 // Init the event handler queue if we're the first 4902 if ( !( handlers = events[ type ] ) ) { 4903 handlers = events[ type ] = []; 4904 handlers.delegateCount = 0; 4905 4906 // Only use addEventListener if the special events handler returns false 4907 if ( !special.setup || 4908 special.setup.call( elem, data, namespaces, eventHandle ) === false ) { 4909 4910 if ( elem.addEventListener ) { 4911 elem.addEventListener( type, eventHandle ); 4912 } 4913 } 4914 } 4915 4916 if ( special.add ) { 4917 special.add.call( elem, handleObj ); 4918 4919 if ( !handleObj.handler.guid ) { 4920 handleObj.handler.guid = handler.guid; 4921 } 4922 } 4923 4924 // Add to the element's handler list, delegates in front 4925 if ( selector ) { 4926 handlers.splice( handlers.delegateCount++, 0, handleObj ); 4927 } else { 4928 handlers.push( handleObj ); 4929 } 4930 4931 // Keep track of which events have ever been used, for event optimization 4932 jQuery.event.global[ type ] = true; 4933 } 4934 4935 }, 4936 4937 // Detach an event or set of events from an element 4938 remove: function( elem, types, handler, selector, mappedTypes ) { 4939 4940 var j, origCount, tmp, 4941 events, t, handleObj, 4942 special, handlers, type, namespaces, origType, 4943 elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); 4944 4945 if ( !elemData || !( events = elemData.events ) ) { 4946 return; 4947 } 4948 4949 // Once for each type.namespace in types; type may be omitted 4950 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4951 t = types.length; 4952 while ( t-- ) { 4953 tmp = rtypenamespace.exec( types[ t ] ) || []; 4954 type = origType = tmp[ 1 ]; 4955 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 4956 4957 // Unbind all events (on this namespace, if provided) for the element 4958 if ( !type ) { 4959 for ( type in events ) { 4960 jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); 4961 } 4962 continue; 4963 } 4964 4965 special = jQuery.event.special[ type ] || {}; 4966 type = ( selector ? special.delegateType : special.bindType ) || type; 4967 handlers = events[ type ] || []; 4968 tmp = tmp[ 2 ] && 4969 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); 4970 4971 // Remove matching events 4972 origCount = j = handlers.length; 4973 while ( j-- ) { 4974 handleObj = handlers[ j ]; 4975 4976 if ( ( mappedTypes || origType === handleObj.origType ) && 4977 ( !handler || handler.guid === handleObj.guid ) && 4978 ( !tmp || tmp.test( handleObj.namespace ) ) && 4979 ( !selector || selector === handleObj.selector || 4980 selector === "**" && handleObj.selector ) ) { 4981 handlers.splice( j, 1 ); 4982 4983 if ( handleObj.selector ) { 4984 handlers.delegateCount--; 4985 } 4986 if ( special.remove ) { 4987 special.remove.call( elem, handleObj ); 4988 } 4989 } 4990 } 4991 4992 // Remove generic event handler if we removed something and no more handlers exist 4993 // (avoids potential for endless recursion during removal of special event handlers) 4994 if ( origCount && !handlers.length ) { 4995 if ( !special.teardown || 4996 special.teardown.call( elem, namespaces, elemData.handle ) === false ) { 4997 4998 jQuery.removeEvent( elem, type, elemData.handle ); 4999 } 5000 5001 delete events[ type ]; 5002 } 5003 } 5004 5005 // Remove data and the expando if it's no longer used 5006 if ( jQuery.isEmptyObject( events ) ) { 5007 dataPriv.remove( elem, "handle events" ); 5008 } 5009 }, 5010 5011 dispatch: function( event ) { 5012 5013 // Make a writable jQuery.Event from the native event object 5014 event = jQuery.event.fix( event ); 5015 5016 var i, j, ret, matched, handleObj, 5017 handlerQueue = [], 5018 args = slice.call( arguments ), 5019 handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], 5020 special = jQuery.event.special[ event.type ] || {}; 5021 5022 // Use the fix-ed jQuery.Event rather than the (read-only) native event 5023 args[ 0 ] = event; 5024 event.delegateTarget = this; 5025 5026 // Call the preDispatch hook for the mapped type, and let it bail if desired 5027 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { 5028 return; 5029 } 5030 5031 // Determine handlers 5032 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); 5033 5034 // Run delegates first; they may want to stop propagation beneath us 5035 i = 0; 5036 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { 5037 event.currentTarget = matched.elem; 5038 5039 j = 0; 5040 while ( ( handleObj = matched.handlers[ j++ ] ) && 5041 !event.isImmediatePropagationStopped() ) { 5042 5043 // Triggered event must either 1) have no namespace, or 2) have namespace(s) 5044 // a subset or equal to those in the bound event (both can have no namespace). 5045 if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { 5046 5047 event.handleObj = handleObj; 5048 event.data = handleObj.data; 5049 5050 ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || 5051 handleObj.handler ).apply( matched.elem, args ); 5052 5053 if ( ret !== undefined ) { 5054 if ( ( event.result = ret ) === false ) { 5055 event.preventDefault(); 5056 event.stopPropagation(); 5057 } 5058 } 5059 } 5060 } 5061 } 5062 5063 // Call the postDispatch hook for the mapped type 5064 if ( special.postDispatch ) { 5065 special.postDispatch.call( this, event ); 5066 } 5067 5068 return event.result; 5069 }, 5070 5071 handlers: function( event, handlers ) { 5072 var i, matches, sel, handleObj, 5073 handlerQueue = [], 5074 delegateCount = handlers.delegateCount, 5075 cur = event.target; 5076 5077 // Support (at least): Chrome, IE9 5078 // Find delegate handlers 5079 // Black-hole SVG <use> instance trees (#13180) 5080 // 5081 // Support: Firefox<=42+ 5082 // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) 5083 if ( delegateCount && cur.nodeType && 5084 ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { 5085 5086 for ( ; cur !== this; cur = cur.parentNode || this ) { 5087 5088 // Don't check non-elements (#13208) 5089 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) 5090 if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { 5091 matches = []; 5092 for ( i = 0; i < delegateCount; i++ ) { 5093 handleObj = handlers[ i ]; 5094 5095 // Don't conflict with Object.prototype properties (#13203) 5096 sel = handleObj.selector + " "; 5097 5098 if ( matches[ sel ] === undefined ) { 5099 matches[ sel ] = handleObj.needsContext ? 5100 jQuery( sel, this ).index( cur ) > -1 : 5101 jQuery.find( sel, this, null, [ cur ] ).length; 5102 } 5103 if ( matches[ sel ] ) { 5104 matches.push( handleObj ); 5105 } 5106 } 5107 if ( matches.length ) { 5108 handlerQueue.push( { elem: cur, handlers: matches } ); 5109 } 5110 } 5111 } 5112 } 5113 5114 // Add the remaining (directly-bound) handlers 5115 if ( delegateCount < handlers.length ) { 5116 handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); 5117 } 5118 5119 return handlerQueue; 5120 }, 5121 5122 // Includes some event props shared by KeyEvent and MouseEvent 5123 props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + 5124 "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), 5125 5126 fixHooks: {}, 5127 5128 keyHooks: { 5129 props: "char charCode key keyCode".split( " " ), 5130 filter: function( event, original ) { 5131 5132 // Add which for key events 5133 if ( event.which == null ) { 5134 event.which = original.charCode != null ? original.charCode : original.keyCode; 5135 } 5136 5137 return event; 5138 } 5139 }, 5140 5141 mouseHooks: { 5142 props: ( "button buttons clientX clientY offsetX offsetY pageX pageY " + 5143 "screenX screenY toElement" ).split( " " ), 5144 filter: function( event, original ) { 5145 var eventDoc, doc, body, 5146 button = original.button; 5147 5148 // Calculate pageX/Y if missing and clientX/Y available 5149 if ( event.pageX == null && original.clientX != null ) { 5150 eventDoc = event.target.ownerDocument || document; 5151 doc = eventDoc.documentElement; 5152 body = eventDoc.body; 5153 5154 event.pageX = original.clientX + 5155 ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - 5156 ( doc && doc.clientLeft || body && body.clientLeft || 0 ); 5157 event.pageY = original.clientY + 5158 ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - 5159 ( doc && doc.clientTop || body && body.clientTop || 0 ); 5160 } 5161 5162 // Add which for click: 1 === left; 2 === middle; 3 === right 5163 // Note: button is not normalized, so don't use it 5164 if ( !event.which && button !== undefined ) { 5165 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); 5166 } 5167 5168 return event; 5169 } 5170 }, 5171 5172 fix: function( event ) { 5173 if ( event[ jQuery.expando ] ) { 5174 return event; 5175 } 5176 5177 // Create a writable copy of the event object and normalize some properties 5178 var i, prop, copy, 5179 type = event.type, 5180 originalEvent = event, 5181 fixHook = this.fixHooks[ type ]; 5182 5183 if ( !fixHook ) { 5184 this.fixHooks[ type ] = fixHook = 5185 rmouseEvent.test( type ) ? this.mouseHooks : 5186 rkeyEvent.test( type ) ? this.keyHooks : 5187 {}; 5188 } 5189 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; 5190 5191 event = new jQuery.Event( originalEvent ); 5192 5193 i = copy.length; 5194 while ( i-- ) { 5195 prop = copy[ i ]; 5196 event[ prop ] = originalEvent[ prop ]; 5197 } 5198 5199 // Support: Cordova 2.5 (WebKit) (#13255) 5200 // All events should have a target; Cordova deviceready doesn't 5201 if ( !event.target ) { 5202 event.target = document; 5203 } 5204 5205 // Support: Safari 6.0+, Chrome<28 5206 // Target should not be a text node (#504, #13143) 5207 if ( event.target.nodeType === 3 ) { 5208 event.target = event.target.parentNode; 5209 } 5210 5211 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; 5212 }, 5213 5214 special: { 5215 load: { 5216 5217 // Prevent triggered image.load events from bubbling to window.load 5218 noBubble: true 5219 }, 5220 focus: { 5221 5222 // Fire native event if possible so blur/focus sequence is correct 5223 trigger: function() { 5224 if ( this !== safeActiveElement() && this.focus ) { 5225 this.focus(); 5226 return false; 5227 } 5228 }, 5229 delegateType: "focusin" 5230 }, 5231 blur: { 5232 trigger: function() { 5233 if ( this === safeActiveElement() && this.blur ) { 5234 this.blur(); 5235 return false; 5236 } 5237 }, 5238 delegateType: "focusout" 5239 }, 5240 click: { 5241 5242 // For checkbox, fire native event so checked state will be right 5243 trigger: function() { 5244 if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { 5245 this.click(); 5246 return false; 5247 } 5248 }, 5249 5250 // For cross-browser consistency, don't fire native .click() on links 5251 _default: function( event ) { 5252 return jQuery.nodeName( event.target, "a" ); 5253 } 5254 }, 5255 5256 beforeunload: { 5257 postDispatch: function( event ) { 5258 5259 // Support: Firefox 20+ 5260 // Firefox doesn't alert if the returnValue field is not set. 5261 if ( event.result !== undefined && event.originalEvent ) { 5262 event.originalEvent.returnValue = event.result; 5263 } 5264 } 5265 } 5266 } 5267}; 5268 5269jQuery.removeEvent = function( elem, type, handle ) { 5270 5271 // This "if" is needed for plain objects 5272 if ( elem.removeEventListener ) { 5273 elem.removeEventListener( type, handle ); 5274 } 5275}; 5276 5277jQuery.Event = function( src, props ) { 5278 5279 // Allow instantiation without the 'new' keyword 5280 if ( !( this instanceof jQuery.Event ) ) { 5281 return new jQuery.Event( src, props ); 5282 } 5283 5284 // Event object 5285 if ( src && src.type ) { 5286 this.originalEvent = src; 5287 this.type = src.type; 5288 5289 // Events bubbling up the document may have been marked as prevented 5290 // by a handler lower down the tree; reflect the correct value. 5291 this.isDefaultPrevented = src.defaultPrevented || 5292 src.defaultPrevented === undefined && 5293 5294 // Support: Android<4.0 5295 src.returnValue === false ? 5296 returnTrue : 5297 returnFalse; 5298 5299 // Event type 5300 } else { 5301 this.type = src; 5302 } 5303 5304 // Put explicitly provided properties onto the event object 5305 if ( props ) { 5306 jQuery.extend( this, props ); 5307 } 5308 5309 // Create a timestamp if incoming event doesn't have one 5310 this.timeStamp = src && src.timeStamp || jQuery.now(); 5311 5312 // Mark it as fixed 5313 this[ jQuery.expando ] = true; 5314}; 5315 5316// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 5317// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 5318jQuery.Event.prototype = { 5319 constructor: jQuery.Event, 5320 isDefaultPrevented: returnFalse, 5321 isPropagationStopped: returnFalse, 5322 isImmediatePropagationStopped: returnFalse, 5323 isSimulated: false, 5324 5325 preventDefault: function() { 5326 var e = this.originalEvent; 5327 5328 this.isDefaultPrevented = returnTrue; 5329 5330 if ( e && !this.isSimulated ) { 5331 e.preventDefault(); 5332 } 5333 }, 5334 stopPropagation: function() { 5335 var e = this.originalEvent; 5336 5337 this.isPropagationStopped = returnTrue; 5338 5339 if ( e && !this.isSimulated ) { 5340 e.stopPropagation(); 5341 } 5342 }, 5343 stopImmediatePropagation: function() { 5344 var e = this.originalEvent; 5345 5346 this.isImmediatePropagationStopped = returnTrue; 5347 5348 if ( e && !this.isSimulated ) { 5349 e.stopImmediatePropagation(); 5350 } 5351 5352 this.stopPropagation(); 5353 } 5354}; 5355 5356// Create mouseenter/leave events using mouseover/out and event-time checks 5357// so that event delegation works in jQuery. 5358// Do the same for pointerenter/pointerleave and pointerover/pointerout 5359// 5360// Support: Safari 7 only 5361// Safari sends mouseenter too often; see: 5362// https://code.google.com/p/chromium/issues/detail?id=470258 5363// for the description of the bug (it existed in older Chrome versions as well). 5364jQuery.each( { 5365 mouseenter: "mouseover", 5366 mouseleave: "mouseout", 5367 pointerenter: "pointerover", 5368 pointerleave: "pointerout" 5369}, function( orig, fix ) { 5370 jQuery.event.special[ orig ] = { 5371 delegateType: fix, 5372 bindType: fix, 5373 5374 handle: function( event ) { 5375 var ret, 5376 target = this, 5377 related = event.relatedTarget, 5378 handleObj = event.handleObj; 5379 5380 // For mouseenter/leave call the handler if related is outside the target. 5381 // NB: No relatedTarget if the mouse left/entered the browser window 5382 if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { 5383 event.type = handleObj.origType; 5384 ret = handleObj.handler.apply( this, arguments ); 5385 event.type = fix; 5386 } 5387 return ret; 5388 } 5389 }; 5390} ); 5391 5392jQuery.fn.extend( { 5393 on: function( types, selector, data, fn ) { 5394 return on( this, types, selector, data, fn ); 5395 }, 5396 one: function( types, selector, data, fn ) { 5397 return on( this, types, selector, data, fn, 1 ); 5398 }, 5399 off: function( types, selector, fn ) { 5400 var handleObj, type; 5401 if ( types && types.preventDefault && types.handleObj ) { 5402 5403 // ( event ) dispatched jQuery.Event 5404 handleObj = types.handleObj; 5405 jQuery( types.delegateTarget ).off( 5406 handleObj.namespace ? 5407 handleObj.origType + "." + handleObj.namespace : 5408 handleObj.origType, 5409 handleObj.selector, 5410 handleObj.handler 5411 ); 5412 return this; 5413 } 5414 if ( typeof types === "object" ) { 5415 5416 // ( types-object [, selector] ) 5417 for ( type in types ) { 5418 this.off( type, selector, types[ type ] ); 5419 } 5420 return this; 5421 } 5422 if ( selector === false || typeof selector === "function" ) { 5423 5424 // ( types [, fn] ) 5425 fn = selector; 5426 selector = undefined; 5427 } 5428 if ( fn === false ) { 5429 fn = returnFalse; 5430 } 5431 return this.each( function() { 5432 jQuery.event.remove( this, types, fn, selector ); 5433 } ); 5434 } 5435} ); 5436 5437 5438var 5439 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, 5440 5441 // Support: IE 10-11, Edge 10240+ 5442 // In IE/Edge using regex groups here causes severe slowdowns. 5443 // See https://connect.microsoft.com/IE/feedback/details/1736512/ 5444 rnoInnerhtml = /<script|<style|<link/i, 5445 5446 // checked="checked" or checked 5447 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, 5448 rscriptTypeMasked = /^true\/(.*)/, 5449 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g; 5450 5451// Manipulating tables requires a tbody 5452function manipulationTarget( elem, content ) { 5453 return jQuery.nodeName( elem, "table" ) && 5454 jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? 5455 5456 elem.getElementsByTagName( "tbody" )[ 0 ] || 5457 elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : 5458 elem; 5459} 5460 5461// Replace/restore the type attribute of script elements for safe DOM manipulation 5462function disableScript( elem ) { 5463 elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; 5464 return elem; 5465} 5466function restoreScript( elem ) { 5467 var match = rscriptTypeMasked.exec( elem.type ); 5468 5469 if ( match ) { 5470 elem.type = match[ 1 ]; 5471 } else { 5472 elem.removeAttribute( "type" ); 5473 } 5474 5475 return elem; 5476} 5477 5478function cloneCopyEvent( src, dest ) { 5479 var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; 5480 5481 if ( dest.nodeType !== 1 ) { 5482 return; 5483 } 5484 5485 // 1. Copy private data: events, handlers, etc. 5486 if ( dataPriv.hasData( src ) ) { 5487 pdataOld = dataPriv.access( src ); 5488 pdataCur = dataPriv.set( dest, pdataOld ); 5489 events = pdataOld.events; 5490 5491 if ( events ) { 5492 delete pdataCur.handle; 5493 pdataCur.events = {}; 5494 5495 for ( type in events ) { 5496 for ( i = 0, l = events[ type ].length; i < l; i++ ) { 5497 jQuery.event.add( dest, type, events[ type ][ i ] ); 5498 } 5499 } 5500 } 5501 } 5502 5503 // 2. Copy user data 5504 if ( dataUser.hasData( src ) ) { 5505 udataOld = dataUser.access( src ); 5506 udataCur = jQuery.extend( {}, udataOld ); 5507 5508 dataUser.set( dest, udataCur ); 5509 } 5510} 5511 5512// Fix IE bugs, see support tests 5513function fixInput( src, dest ) { 5514 var nodeName = dest.nodeName.toLowerCase(); 5515 5516 // Fails to persist the checked state of a cloned checkbox or radio button. 5517 if ( nodeName === "input" && rcheckableType.test( src.type ) ) { 5518 dest.checked = src.checked; 5519 5520 // Fails to return the selected option to the default selected state when cloning options 5521 } else if ( nodeName === "input" || nodeName === "textarea" ) { 5522 dest.defaultValue = src.defaultValue; 5523 } 5524} 5525 5526function domManip( collection, args, callback, ignored ) { 5527 5528 // Flatten any nested arrays 5529 args = concat.apply( [], args ); 5530 5531 var fragment, first, scripts, hasScripts, node, doc, 5532 i = 0, 5533 l = collection.length, 5534 iNoClone = l - 1, 5535 value = args[ 0 ], 5536 isFunction = jQuery.isFunction( value ); 5537 5538 // We can't cloneNode fragments that contain checked, in WebKit 5539 if ( isFunction || 5540 ( l > 1 && typeof value === "string" && 5541 !support.checkClone && rchecked.test( value ) ) ) { 5542 return collection.each( function( index ) { 5543 var self = collection.eq( index ); 5544 if ( isFunction ) { 5545 args[ 0 ] = value.call( this, index, self.html() ); 5546 } 5547 domManip( self, args, callback, ignored ); 5548 } ); 5549 } 5550 5551 if ( l ) { 5552 fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); 5553 first = fragment.firstChild; 5554 5555 if ( fragment.childNodes.length === 1 ) { 5556 fragment = first; 5557 } 5558 5559 // Require either new content or an interest in ignored elements to invoke the callback 5560 if ( first || ignored ) { 5561 scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); 5562 hasScripts = scripts.length; 5563 5564 // Use the original fragment for the last item 5565 // instead of the first because it can end up 5566 // being emptied incorrectly in certain situations (#8070). 5567 for ( ; i < l; i++ ) { 5568 node = fragment; 5569 5570 if ( i !== iNoClone ) { 5571 node = jQuery.clone( node, true, true ); 5572 5573 // Keep references to cloned scripts for later restoration 5574 if ( hasScripts ) { 5575 5576 // Support: Android<4.1, PhantomJS<2 5577 // push.apply(_, arraylike) throws on ancient WebKit 5578 jQuery.merge( scripts, getAll( node, "script" ) ); 5579 } 5580 } 5581 5582 callback.call( collection[ i ], node, i ); 5583 } 5584 5585 if ( hasScripts ) { 5586 doc = scripts[ scripts.length - 1 ].ownerDocument; 5587 5588 // Reenable scripts 5589 jQuery.map( scripts, restoreScript ); 5590 5591 // Evaluate executable scripts on first document insertion 5592 for ( i = 0; i < hasScripts; i++ ) { 5593 node = scripts[ i ]; 5594 if ( rscriptType.test( node.type || "" ) && 5595 !dataPriv.access( node, "globalEval" ) && 5596 jQuery.contains( doc, node ) ) { 5597 5598 if ( node.src ) { 5599 5600 // Optional AJAX dependency, but won't run scripts if not present 5601 if ( jQuery._evalUrl ) { 5602 jQuery._evalUrl( node.src ); 5603 } 5604 } else { 5605 jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); 5606 } 5607 } 5608 } 5609 } 5610 } 5611 } 5612 5613 return collection; 5614} 5615 5616function remove( elem, selector, keepData ) { 5617 var node, 5618 nodes = selector ? jQuery.filter( selector, elem ) : elem, 5619 i = 0; 5620 5621 for ( ; ( node = nodes[ i ] ) != null; i++ ) { 5622 if ( !keepData && node.nodeType === 1 ) { 5623 jQuery.cleanData( getAll( node ) ); 5624 } 5625 5626 if ( node.parentNode ) { 5627 if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { 5628 setGlobalEval( getAll( node, "script" ) ); 5629 } 5630 node.parentNode.removeChild( node ); 5631 } 5632 } 5633 5634 return elem; 5635} 5636 5637jQuery.extend( { 5638 htmlPrefilter: function( html ) { 5639 return html.replace( rxhtmlTag, "<$1></$2>" ); 5640 }, 5641 5642 clone: function( elem, dataAndEvents, deepDataAndEvents ) { 5643 var i, l, srcElements, destElements, 5644 clone = elem.cloneNode( true ), 5645 inPage = jQuery.contains( elem.ownerDocument, elem ); 5646 5647 // Fix IE cloning issues 5648 if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && 5649 !jQuery.isXMLDoc( elem ) ) { 5650 5651 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 5652 destElements = getAll( clone ); 5653 srcElements = getAll( elem ); 5654 5655 for ( i = 0, l = srcElements.length; i < l; i++ ) { 5656 fixInput( srcElements[ i ], destElements[ i ] ); 5657 } 5658 } 5659 5660 // Copy the events from the original to the clone 5661 if ( dataAndEvents ) { 5662 if ( deepDataAndEvents ) { 5663 srcElements = srcElements || getAll( elem ); 5664 destElements = destElements || getAll( clone ); 5665 5666 for ( i = 0, l = srcElements.length; i < l; i++ ) { 5667 cloneCopyEvent( srcElements[ i ], destElements[ i ] ); 5668 } 5669 } else { 5670 cloneCopyEvent( elem, clone ); 5671 } 5672 } 5673 5674 // Preserve script evaluation history 5675 destElements = getAll( clone, "script" ); 5676 if ( destElements.length > 0 ) { 5677 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); 5678 } 5679 5680 // Return the cloned set 5681 return clone; 5682 }, 5683 5684 cleanData: function( elems ) { 5685 var data, elem, type, 5686 special = jQuery.event.special, 5687 i = 0; 5688 5689 for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { 5690 if ( acceptData( elem ) ) { 5691 if ( ( data = elem[ dataPriv.expando ] ) ) { 5692 if ( data.events ) { 5693 for ( type in data.events ) { 5694 if ( special[ type ] ) { 5695 jQuery.event.remove( elem, type ); 5696 5697 // This is a shortcut to avoid jQuery.event.remove's overhead 5698 } else { 5699 jQuery.removeEvent( elem, type, data.handle ); 5700 } 5701 } 5702 } 5703 5704 // Support: Chrome <= 35-45+ 5705 // Assign undefined instead of using delete, see Data#remove 5706 elem[ dataPriv.expando ] = undefined; 5707 } 5708 if ( elem[ dataUser.expando ] ) { 5709 5710 // Support: Chrome <= 35-45+ 5711 // Assign undefined instead of using delete, see Data#remove 5712 elem[ dataUser.expando ] = undefined; 5713 } 5714 } 5715 } 5716 } 5717} ); 5718 5719jQuery.fn.extend( { 5720 5721 // Keep domManip exposed until 3.0 (gh-2225) 5722 domManip: domManip, 5723 5724 detach: function( selector ) { 5725 return remove( this, selector, true ); 5726 }, 5727 5728 remove: function( selector ) { 5729 return remove( this, selector ); 5730 }, 5731 5732 text: function( value ) { 5733 return access( this, function( value ) { 5734 return value === undefined ? 5735 jQuery.text( this ) : 5736 this.empty().each( function() { 5737 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 5738 this.textContent = value; 5739 } 5740 } ); 5741 }, null, value, arguments.length ); 5742 }, 5743 5744 append: function() { 5745 return domManip( this, arguments, function( elem ) { 5746 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 5747 var target = manipulationTarget( this, elem ); 5748 target.appendChild( elem ); 5749 } 5750 } ); 5751 }, 5752 5753 prepend: function() { 5754 return domManip( this, arguments, function( elem ) { 5755 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 5756 var target = manipulationTarget( this, elem ); 5757 target.insertBefore( elem, target.firstChild ); 5758 } 5759 } ); 5760 }, 5761 5762 before: function() { 5763 return domManip( this, arguments, function( elem ) { 5764 if ( this.parentNode ) { 5765 this.parentNode.insertBefore( elem, this ); 5766 } 5767 } ); 5768 }, 5769 5770 after: function() { 5771 return domManip( this, arguments, function( elem ) { 5772 if ( this.parentNode ) { 5773 this.parentNode.insertBefore( elem, this.nextSibling ); 5774 } 5775 } ); 5776 }, 5777 5778 empty: function() { 5779 var elem, 5780 i = 0; 5781 5782 for ( ; ( elem = this[ i ] ) != null; i++ ) { 5783 if ( elem.nodeType === 1 ) { 5784 5785 // Prevent memory leaks 5786 jQuery.cleanData( getAll( elem, false ) ); 5787 5788 // Remove any remaining nodes 5789 elem.textContent = ""; 5790 } 5791 } 5792 5793 return this; 5794 }, 5795 5796 clone: function( dataAndEvents, deepDataAndEvents ) { 5797 dataAndEvents = dataAndEvents == null ? false : dataAndEvents; 5798 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; 5799 5800 return this.map( function() { 5801 return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); 5802 } ); 5803 }, 5804 5805 html: function( value ) { 5806 return access( this, function( value ) { 5807 var elem = this[ 0 ] || {}, 5808 i = 0, 5809 l = this.length; 5810 5811 if ( value === undefined && elem.nodeType === 1 ) { 5812 return elem.innerHTML; 5813 } 5814 5815 // See if we can take a shortcut and just use innerHTML 5816 if ( typeof value === "string" && !rnoInnerhtml.test( value ) && 5817 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { 5818 5819 value = jQuery.htmlPrefilter( value ); 5820 5821 try { 5822 for ( ; i < l; i++ ) { 5823 elem = this[ i ] || {}; 5824 5825 // Remove element nodes and prevent memory leaks 5826 if ( elem.nodeType === 1 ) { 5827 jQuery.cleanData( getAll( elem, false ) ); 5828 elem.innerHTML = value; 5829 } 5830 } 5831 5832 elem = 0; 5833 5834 // If using innerHTML throws an exception, use the fallback method 5835 } catch ( e ) {} 5836 } 5837 5838 if ( elem ) { 5839 this.empty().append( value ); 5840 } 5841 }, null, value, arguments.length ); 5842 }, 5843 5844 replaceWith: function() { 5845 var ignored = []; 5846 5847 // Make the changes, replacing each non-ignored context element with the new content 5848 return domManip( this, arguments, function( elem ) { 5849 var parent = this.parentNode; 5850 5851 if ( jQuery.inArray( this, ignored ) < 0 ) { 5852 jQuery.cleanData( getAll( this ) ); 5853 if ( parent ) { 5854 parent.replaceChild( elem, this ); 5855 } 5856 } 5857 5858 // Force callback invocation 5859 }, ignored ); 5860 } 5861} ); 5862 5863jQuery.each( { 5864 appendTo: "append", 5865 prependTo: "prepend", 5866 insertBefore: "before", 5867 insertAfter: "after", 5868 replaceAll: "replaceWith" 5869}, function( name, original ) { 5870 jQuery.fn[ name ] = function( selector ) { 5871 var elems, 5872 ret = [], 5873 insert = jQuery( selector ), 5874 last = insert.length - 1, 5875 i = 0; 5876 5877 for ( ; i <= last; i++ ) { 5878 elems = i === last ? this : this.clone( true ); 5879 jQuery( insert[ i ] )[ original ]( elems ); 5880 5881 // Support: QtWebKit 5882 // .get() because push.apply(_, arraylike) throws 5883 push.apply( ret, elems.get() ); 5884 } 5885 5886 return this.pushStack( ret ); 5887 }; 5888} ); 5889 5890 5891var iframe, 5892 elemdisplay = { 5893 5894 // Support: Firefox 5895 // We have to pre-define these values for FF (#10227) 5896 HTML: "block", 5897 BODY: "block" 5898 }; 5899 5900/** 5901 * Retrieve the actual display of a element 5902 * @param {String} name nodeName of the element 5903 * @param {Object} doc Document object 5904 */ 5905 5906// Called only from within defaultDisplay 5907function actualDisplay( name, doc ) { 5908 var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), 5909 5910 display = jQuery.css( elem[ 0 ], "display" ); 5911 5912 // We don't have any data stored on the element, 5913 // so use "detach" method as fast way to get rid of the element 5914 elem.detach(); 5915 5916 return display; 5917} 5918 5919/** 5920 * Try to determine the default display value of an element 5921 * @param {String} nodeName 5922 */ 5923function defaultDisplay( nodeName ) { 5924 var doc = document, 5925 display = elemdisplay[ nodeName ]; 5926 5927 if ( !display ) { 5928 display = actualDisplay( nodeName, doc ); 5929 5930 // If the simple way fails, read from inside an iframe 5931 if ( display === "none" || !display ) { 5932 5933 // Use the already-created iframe if possible 5934 iframe = ( iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" ) ) 5935 .appendTo( doc.documentElement ); 5936 5937 // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse 5938 doc = iframe[ 0 ].contentDocument; 5939 5940 // Support: IE 5941 doc.write(); 5942 doc.close(); 5943 5944 display = actualDisplay( nodeName, doc ); 5945 iframe.detach(); 5946 } 5947 5948 // Store the correct default display 5949 elemdisplay[ nodeName ] = display; 5950 } 5951 5952 return display; 5953} 5954var rmargin = ( /^margin/ ); 5955 5956var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 5957 5958var getStyles = function( elem ) { 5959 5960 // Support: IE<=11+, Firefox<=30+ (#15098, #14150) 5961 // IE throws on elements created in popups 5962 // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" 5963 var view = elem.ownerDocument.defaultView; 5964 5965 if ( !view || !view.opener ) { 5966 view = window; 5967 } 5968 5969 return view.getComputedStyle( elem ); 5970 }; 5971 5972var swap = function( elem, options, callback, args ) { 5973 var ret, name, 5974 old = {}; 5975 5976 // Remember the old values, and insert the new ones 5977 for ( name in options ) { 5978 old[ name ] = elem.style[ name ]; 5979 elem.style[ name ] = options[ name ]; 5980 } 5981 5982 ret = callback.apply( elem, args || [] ); 5983 5984 // Revert the old values 5985 for ( name in options ) { 5986 elem.style[ name ] = old[ name ]; 5987 } 5988 5989 return ret; 5990}; 5991 5992 5993var documentElement = document.documentElement; 5994 5995 5996 5997( function() { 5998 var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, 5999 container = document.createElement( "div" ), 6000 div = document.createElement( "div" ); 6001 6002 // Finish early in limited (non-browser) environments 6003 if ( !div.style ) { 6004 return; 6005 } 6006 6007 // Support: IE9-11+ 6008 // Style of cloned element affects source element cloned (#8908) 6009 div.style.backgroundClip = "content-box"; 6010 div.cloneNode( true ).style.backgroundClip = ""; 6011 support.clearCloneStyle = div.style.backgroundClip === "content-box"; 6012 6013 container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + 6014 "padding:0;margin-top:1px;position:absolute"; 6015 container.appendChild( div ); 6016 6017 // Executing both pixelPosition & boxSizingReliable tests require only one layout 6018 // so they're executed at the same time to save the second computation. 6019 function computeStyleTests() { 6020 div.style.cssText = 6021 6022 // Support: Firefox<29, Android 2.3 6023 // Vendor-prefix box-sizing 6024 "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;" + 6025 "position:relative;display:block;" + 6026 "margin:auto;border:1px;padding:1px;" + 6027 "top:1%;width:50%"; 6028 div.innerHTML = ""; 6029 documentElement.appendChild( container ); 6030 6031 var divStyle = window.getComputedStyle( div ); 6032 pixelPositionVal = divStyle.top !== "1%"; 6033 reliableMarginLeftVal = divStyle.marginLeft === "2px"; 6034 boxSizingReliableVal = divStyle.width === "4px"; 6035 6036 // Support: Android 4.0 - 4.3 only 6037 // Some styles come back with percentage values, even though they shouldn't 6038 div.style.marginRight = "50%"; 6039 pixelMarginRightVal = divStyle.marginRight === "4px"; 6040 6041 documentElement.removeChild( container ); 6042 } 6043 6044 jQuery.extend( support, { 6045 pixelPosition: function() { 6046 6047 // This test is executed only once but we still do memoizing 6048 // since we can use the boxSizingReliable pre-computing. 6049 // No need to check if the test was already performed, though. 6050 computeStyleTests(); 6051 return pixelPositionVal; 6052 }, 6053 boxSizingReliable: function() { 6054 if ( boxSizingReliableVal == null ) { 6055 computeStyleTests(); 6056 } 6057 return boxSizingReliableVal; 6058 }, 6059 pixelMarginRight: function() { 6060 6061 // Support: Android 4.0-4.3 6062 // We're checking for boxSizingReliableVal here instead of pixelMarginRightVal 6063 // since that compresses better and they're computed together anyway. 6064 if ( boxSizingReliableVal == null ) { 6065 computeStyleTests(); 6066 } 6067 return pixelMarginRightVal; 6068 }, 6069 reliableMarginLeft: function() { 6070 6071 // Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37 6072 if ( boxSizingReliableVal == null ) { 6073 computeStyleTests(); 6074 } 6075 return reliableMarginLeftVal; 6076 }, 6077 reliableMarginRight: function() { 6078 6079 // Support: Android 2.3 6080 // Check if div with explicit width and no margin-right incorrectly 6081 // gets computed margin-right based on width of container. (#3333) 6082 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 6083 // This support function is only executed once so no memoizing is needed. 6084 var ret, 6085 marginDiv = div.appendChild( document.createElement( "div" ) ); 6086 6087 // Reset CSS: box-sizing; display; margin; border; padding 6088 marginDiv.style.cssText = div.style.cssText = 6089 6090 // Support: Android 2.3 6091 // Vendor-prefix box-sizing 6092 "-webkit-box-sizing:content-box;box-sizing:content-box;" + 6093 "display:block;margin:0;border:0;padding:0"; 6094 marginDiv.style.marginRight = marginDiv.style.width = "0"; 6095 div.style.width = "1px"; 6096 documentElement.appendChild( container ); 6097 6098 ret = !parseFloat( window.getComputedStyle( marginDiv ).marginRight ); 6099 6100 documentElement.removeChild( container ); 6101 div.removeChild( marginDiv ); 6102 6103 return ret; 6104 } 6105 } ); 6106} )(); 6107 6108 6109function curCSS( elem, name, computed ) { 6110 var width, minWidth, maxWidth, ret, 6111 style = elem.style; 6112 6113 computed = computed || getStyles( elem ); 6114 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined; 6115 6116 // Support: Opera 12.1x only 6117 // Fall back to style even without computed 6118 // computed is undefined for elems on document fragments 6119 if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) { 6120 ret = jQuery.style( elem, name ); 6121 } 6122 6123 // Support: IE9 6124 // getPropertyValue is only needed for .css('filter') (#12537) 6125 if ( computed ) { 6126 6127 // A tribute to the "awesome hack by Dean Edwards" 6128 // Android Browser returns percentage for some values, 6129 // but width seems to be reliably pixels. 6130 // This is against the CSSOM draft spec: 6131 // http://dev.w3.org/csswg/cssom/#resolved-values 6132 if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { 6133 6134 // Remember the original values 6135 width = style.width; 6136 minWidth = style.minWidth; 6137 maxWidth = style.maxWidth; 6138 6139 // Put in the new values to get a computed value out 6140 style.minWidth = style.maxWidth = style.width = ret; 6141 ret = computed.width; 6142 6143 // Revert the changed values 6144 style.width = width; 6145 style.minWidth = minWidth; 6146 style.maxWidth = maxWidth; 6147 } 6148 } 6149 6150 return ret !== undefined ? 6151 6152 // Support: IE9-11+ 6153 // IE returns zIndex value as an integer. 6154 ret + "" : 6155 ret; 6156} 6157 6158 6159function addGetHookIf( conditionFn, hookFn ) { 6160 6161 // Define the hook, we'll check on the first run if it's really needed. 6162 return { 6163 get: function() { 6164 if ( conditionFn() ) { 6165 6166 // Hook not needed (or it's not possible to use it due 6167 // to missing dependency), remove it. 6168 delete this.get; 6169 return; 6170 } 6171 6172 // Hook needed; redefine it so that the support test is not executed again. 6173 return ( this.get = hookFn ).apply( this, arguments ); 6174 } 6175 }; 6176} 6177 6178 6179var 6180 6181 // Swappable if display is none or starts with table 6182 // except "table", "table-cell", or "table-caption" 6183 // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display 6184 rdisplayswap = /^(none|table(?!-c[ea]).+)/, 6185 6186 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 6187 cssNormalTransform = { 6188 letterSpacing: "0", 6189 fontWeight: "400" 6190 }, 6191 6192 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], 6193 emptyStyle = document.createElement( "div" ).style; 6194 6195// Return a css property mapped to a potentially vendor prefixed property 6196function vendorPropName( name ) { 6197 6198 // Shortcut for names that are not vendor prefixed 6199 if ( name in emptyStyle ) { 6200 return name; 6201 } 6202 6203 // Check for vendor prefixed names 6204 var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), 6205 i = cssPrefixes.length; 6206 6207 while ( i-- ) { 6208 name = cssPrefixes[ i ] + capName; 6209 if ( name in emptyStyle ) { 6210 return name; 6211 } 6212 } 6213} 6214 6215function setPositiveNumber( elem, value, subtract ) { 6216 6217 // Any relative (+/-) values have already been 6218 // normalized at this point 6219 var matches = rcssNum.exec( value ); 6220 return matches ? 6221 6222 // Guard against undefined "subtract", e.g., when used as in cssHooks 6223 Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : 6224 value; 6225} 6226 6227function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { 6228 var i = extra === ( isBorderBox ? "border" : "content" ) ? 6229 6230 // If we already have the right measurement, avoid augmentation 6231 4 : 6232 6233 // Otherwise initialize for horizontal or vertical properties 6234 name === "width" ? 1 : 0, 6235 6236 val = 0; 6237 6238 for ( ; i < 4; i += 2 ) { 6239 6240 // Both box models exclude margin, so add it if we want it 6241 if ( extra === "margin" ) { 6242 val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); 6243 } 6244 6245 if ( isBorderBox ) { 6246 6247 // border-box includes padding, so remove it if we want content 6248 if ( extra === "content" ) { 6249 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6250 } 6251 6252 // At this point, extra isn't border nor margin, so remove border 6253 if ( extra !== "margin" ) { 6254 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6255 } 6256 } else { 6257 6258 // At this point, extra isn't content, so add padding 6259 val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6260 6261 // At this point, extra isn't content nor padding, so add border 6262 if ( extra !== "padding" ) { 6263 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6264 } 6265 } 6266 } 6267 6268 return val; 6269} 6270 6271function getWidthOrHeight( elem, name, extra ) { 6272 6273 // Start with offset property, which is equivalent to the border-box value 6274 var valueIsBorderBox = true, 6275 val = name === "width" ? elem.offsetWidth : elem.offsetHeight, 6276 styles = getStyles( elem ), 6277 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; 6278 6279 // Some non-html elements return undefined for offsetWidth, so check for null/undefined 6280 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 6281 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 6282 if ( val <= 0 || val == null ) { 6283 6284 // Fall back to computed then uncomputed css if necessary 6285 val = curCSS( elem, name, styles ); 6286 if ( val < 0 || val == null ) { 6287 val = elem.style[ name ]; 6288 } 6289 6290 // Computed unit is not pixels. Stop here and return. 6291 if ( rnumnonpx.test( val ) ) { 6292 return val; 6293 } 6294 6295 // Check for style in case a browser which returns unreliable values 6296 // for getComputedStyle silently falls back to the reliable elem.style 6297 valueIsBorderBox = isBorderBox && 6298 ( support.boxSizingReliable() || val === elem.style[ name ] ); 6299 6300 // Normalize "", auto, and prepare for extra 6301 val = parseFloat( val ) || 0; 6302 } 6303 6304 // Use the active box-sizing model to add/subtract irrelevant styles 6305 return ( val + 6306 augmentWidthOrHeight( 6307 elem, 6308 name, 6309 extra || ( isBorderBox ? "border" : "content" ), 6310 valueIsBorderBox, 6311 styles 6312 ) 6313 ) + "px"; 6314} 6315 6316function showHide( elements, show ) { 6317 var display, elem, hidden, 6318 values = [], 6319 index = 0, 6320 length = elements.length; 6321 6322 for ( ; index < length; index++ ) { 6323 elem = elements[ index ]; 6324 if ( !elem.style ) { 6325 continue; 6326 } 6327 6328 values[ index ] = dataPriv.get( elem, "olddisplay" ); 6329 display = elem.style.display; 6330 if ( show ) { 6331 6332 // Reset the inline display of this element to learn if it is 6333 // being hidden by cascaded rules or not 6334 if ( !values[ index ] && display === "none" ) { 6335 elem.style.display = ""; 6336 } 6337 6338 // Set elements which have been overridden with display: none 6339 // in a stylesheet to whatever the default browser style is 6340 // for such an element 6341 if ( elem.style.display === "" && isHidden( elem ) ) { 6342 values[ index ] = dataPriv.access( 6343 elem, 6344 "olddisplay", 6345 defaultDisplay( elem.nodeName ) 6346 ); 6347 } 6348 } else { 6349 hidden = isHidden( elem ); 6350 6351 if ( display !== "none" || !hidden ) { 6352 dataPriv.set( 6353 elem, 6354 "olddisplay", 6355 hidden ? display : jQuery.css( elem, "display" ) 6356 ); 6357 } 6358 } 6359 } 6360 6361 // Set the display of most of the elements in a second loop 6362 // to avoid the constant reflow 6363 for ( index = 0; index < length; index++ ) { 6364 elem = elements[ index ]; 6365 if ( !elem.style ) { 6366 continue; 6367 } 6368 if ( !show || elem.style.display === "none" || elem.style.display === "" ) { 6369 elem.style.display = show ? values[ index ] || "" : "none"; 6370 } 6371 } 6372 6373 return elements; 6374} 6375 6376jQuery.extend( { 6377 6378 // Add in style property hooks for overriding the default 6379 // behavior of getting and setting a style property 6380 cssHooks: { 6381 opacity: { 6382 get: function( elem, computed ) { 6383 if ( computed ) { 6384 6385 // We should always get a number back from opacity 6386 var ret = curCSS( elem, "opacity" ); 6387 return ret === "" ? "1" : ret; 6388 } 6389 } 6390 } 6391 }, 6392 6393 // Don't automatically add "px" to these possibly-unitless properties 6394 cssNumber: { 6395 "animationIterationCount": true, 6396 "columnCount": true, 6397 "fillOpacity": true, 6398 "flexGrow": true, 6399 "flexShrink": true, 6400 "fontWeight": true, 6401 "lineHeight": true, 6402 "opacity": true, 6403 "order": true, 6404 "orphans": true, 6405 "widows": true, 6406 "zIndex": true, 6407 "zoom": true 6408 }, 6409 6410 // Add in properties whose names you wish to fix before 6411 // setting or getting the value 6412 cssProps: { 6413 "float": "cssFloat" 6414 }, 6415 6416 // Get and set the style property on a DOM Node 6417 style: function( elem, name, value, extra ) { 6418 6419 // Don't set styles on text and comment nodes 6420 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 6421 return; 6422 } 6423 6424 // Make sure that we're working with the right name 6425 var ret, type, hooks, 6426 origName = jQuery.camelCase( name ), 6427 style = elem.style; 6428 6429 name = jQuery.cssProps[ origName ] || 6430 ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); 6431 6432 // Gets hook for the prefixed version, then unprefixed version 6433 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 6434 6435 // Check if we're setting a value 6436 if ( value !== undefined ) { 6437 type = typeof value; 6438 6439 // Convert "+=" or "-=" to relative numbers (#7345) 6440 if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { 6441 value = adjustCSS( elem, name, ret ); 6442 6443 // Fixes bug #9237 6444 type = "number"; 6445 } 6446 6447 // Make sure that null and NaN values aren't set (#7116) 6448 if ( value == null || value !== value ) { 6449 return; 6450 } 6451 6452 // If a number was passed in, add the unit (except for certain CSS properties) 6453 if ( type === "number" ) { 6454 value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); 6455 } 6456 6457 // Support: IE9-11+ 6458 // background-* props affect original clone's values 6459 if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { 6460 style[ name ] = "inherit"; 6461 } 6462 6463 // If a hook was provided, use that value, otherwise just set the specified value 6464 if ( !hooks || !( "set" in hooks ) || 6465 ( value = hooks.set( elem, value, extra ) ) !== undefined ) { 6466 6467 style[ name ] = value; 6468 } 6469 6470 } else { 6471 6472 // If a hook was provided get the non-computed value from there 6473 if ( hooks && "get" in hooks && 6474 ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { 6475 6476 return ret; 6477 } 6478 6479 // Otherwise just get the value from the style object 6480 return style[ name ]; 6481 } 6482 }, 6483 6484 css: function( elem, name, extra, styles ) { 6485 var val, num, hooks, 6486 origName = jQuery.camelCase( name ); 6487 6488 // Make sure that we're working with the right name 6489 name = jQuery.cssProps[ origName ] || 6490 ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); 6491 6492 // Try prefixed name followed by the unprefixed name 6493 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 6494 6495 // If a hook was provided get the computed value from there 6496 if ( hooks && "get" in hooks ) { 6497 val = hooks.get( elem, true, extra ); 6498 } 6499 6500 // Otherwise, if a way to get the computed value exists, use that 6501 if ( val === undefined ) { 6502 val = curCSS( elem, name, styles ); 6503 } 6504 6505 // Convert "normal" to computed value 6506 if ( val === "normal" && name in cssNormalTransform ) { 6507 val = cssNormalTransform[ name ]; 6508 } 6509 6510 // Make numeric if forced or a qualifier was provided and val looks numeric 6511 if ( extra === "" || extra ) { 6512 num = parseFloat( val ); 6513 return extra === true || isFinite( num ) ? num || 0 : val; 6514 } 6515 return val; 6516 } 6517} ); 6518 6519jQuery.each( [ "height", "width" ], function( i, name ) { 6520 jQuery.cssHooks[ name ] = { 6521 get: function( elem, computed, extra ) { 6522 if ( computed ) { 6523 6524 // Certain elements can have dimension info if we invisibly show them 6525 // but it must have a current display style that would benefit 6526 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && 6527 elem.offsetWidth === 0 ? 6528 swap( elem, cssShow, function() { 6529 return getWidthOrHeight( elem, name, extra ); 6530 } ) : 6531 getWidthOrHeight( elem, name, extra ); 6532 } 6533 }, 6534 6535 set: function( elem, value, extra ) { 6536 var matches, 6537 styles = extra && getStyles( elem ), 6538 subtract = extra && augmentWidthOrHeight( 6539 elem, 6540 name, 6541 extra, 6542 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 6543 styles 6544 ); 6545 6546 // Convert to pixels if value adjustment is needed 6547 if ( subtract && ( matches = rcssNum.exec( value ) ) && 6548 ( matches[ 3 ] || "px" ) !== "px" ) { 6549 6550 elem.style[ name ] = value; 6551 value = jQuery.css( elem, name ); 6552 } 6553 6554 return setPositiveNumber( elem, value, subtract ); 6555 } 6556 }; 6557} ); 6558 6559jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, 6560 function( elem, computed ) { 6561 if ( computed ) { 6562 return ( parseFloat( curCSS( elem, "marginLeft" ) ) || 6563 elem.getBoundingClientRect().left - 6564 swap( elem, { marginLeft: 0 }, function() { 6565 return elem.getBoundingClientRect().left; 6566 } ) 6567 ) + "px"; 6568 } 6569 } 6570); 6571 6572// Support: Android 2.3 6573jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight, 6574 function( elem, computed ) { 6575 if ( computed ) { 6576 return swap( elem, { "display": "inline-block" }, 6577 curCSS, [ elem, "marginRight" ] ); 6578 } 6579 } 6580); 6581 6582// These hooks are used by animate to expand properties 6583jQuery.each( { 6584 margin: "", 6585 padding: "", 6586 border: "Width" 6587}, function( prefix, suffix ) { 6588 jQuery.cssHooks[ prefix + suffix ] = { 6589 expand: function( value ) { 6590 var i = 0, 6591 expanded = {}, 6592 6593 // Assumes a single number if not a string 6594 parts = typeof value === "string" ? value.split( " " ) : [ value ]; 6595 6596 for ( ; i < 4; i++ ) { 6597 expanded[ prefix + cssExpand[ i ] + suffix ] = 6598 parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; 6599 } 6600 6601 return expanded; 6602 } 6603 }; 6604 6605 if ( !rmargin.test( prefix ) ) { 6606 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; 6607 } 6608} ); 6609 6610jQuery.fn.extend( { 6611 css: function( name, value ) { 6612 return access( this, function( elem, name, value ) { 6613 var styles, len, 6614 map = {}, 6615 i = 0; 6616 6617 if ( jQuery.isArray( name ) ) { 6618 styles = getStyles( elem ); 6619 len = name.length; 6620 6621 for ( ; i < len; i++ ) { 6622 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); 6623 } 6624 6625 return map; 6626 } 6627 6628 return value !== undefined ? 6629 jQuery.style( elem, name, value ) : 6630 jQuery.css( elem, name ); 6631 }, name, value, arguments.length > 1 ); 6632 }, 6633 show: function() { 6634 return showHide( this, true ); 6635 }, 6636 hide: function() { 6637 return showHide( this ); 6638 }, 6639 toggle: function( state ) { 6640 if ( typeof state === "boolean" ) { 6641 return state ? this.show() : this.hide(); 6642 } 6643 6644 return this.each( function() { 6645 if ( isHidden( this ) ) { 6646 jQuery( this ).show(); 6647 } else { 6648 jQuery( this ).hide(); 6649 } 6650 } ); 6651 } 6652} ); 6653 6654 6655function Tween( elem, options, prop, end, easing ) { 6656 return new Tween.prototype.init( elem, options, prop, end, easing ); 6657} 6658jQuery.Tween = Tween; 6659 6660Tween.prototype = { 6661 constructor: Tween, 6662 init: function( elem, options, prop, end, easing, unit ) { 6663 this.elem = elem; 6664 this.prop = prop; 6665 this.easing = easing || jQuery.easing._default; 6666 this.options = options; 6667 this.start = this.now = this.cur(); 6668 this.end = end; 6669 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); 6670 }, 6671 cur: function() { 6672 var hooks = Tween.propHooks[ this.prop ]; 6673 6674 return hooks && hooks.get ? 6675 hooks.get( this ) : 6676 Tween.propHooks._default.get( this ); 6677 }, 6678 run: function( percent ) { 6679 var eased, 6680 hooks = Tween.propHooks[ this.prop ]; 6681 6682 if ( this.options.duration ) { 6683 this.pos = eased = jQuery.easing[ this.easing ]( 6684 percent, this.options.duration * percent, 0, 1, this.options.duration 6685 ); 6686 } else { 6687 this.pos = eased = percent; 6688 } 6689 this.now = ( this.end - this.start ) * eased + this.start; 6690 6691 if ( this.options.step ) { 6692 this.options.step.call( this.elem, this.now, this ); 6693 } 6694 6695 if ( hooks && hooks.set ) { 6696 hooks.set( this ); 6697 } else { 6698 Tween.propHooks._default.set( this ); 6699 } 6700 return this; 6701 } 6702}; 6703 6704Tween.prototype.init.prototype = Tween.prototype; 6705 6706Tween.propHooks = { 6707 _default: { 6708 get: function( tween ) { 6709 var result; 6710 6711 // Use a property on the element directly when it is not a DOM element, 6712 // or when there is no matching style property that exists. 6713 if ( tween.elem.nodeType !== 1 || 6714 tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { 6715 return tween.elem[ tween.prop ]; 6716 } 6717 6718 // Passing an empty string as a 3rd parameter to .css will automatically 6719 // attempt a parseFloat and fallback to a string if the parse fails. 6720 // Simple values such as "10px" are parsed to Float; 6721 // complex values such as "rotate(1rad)" are returned as-is. 6722 result = jQuery.css( tween.elem, tween.prop, "" ); 6723 6724 // Empty strings, null, undefined and "auto" are converted to 0. 6725 return !result || result === "auto" ? 0 : result; 6726 }, 6727 set: function( tween ) { 6728 6729 // Use step hook for back compat. 6730 // Use cssHook if its there. 6731 // Use .style if available and use plain properties where available. 6732 if ( jQuery.fx.step[ tween.prop ] ) { 6733 jQuery.fx.step[ tween.prop ]( tween ); 6734 } else if ( tween.elem.nodeType === 1 && 6735 ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || 6736 jQuery.cssHooks[ tween.prop ] ) ) { 6737 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); 6738 } else { 6739 tween.elem[ tween.prop ] = tween.now; 6740 } 6741 } 6742 } 6743}; 6744 6745// Support: IE9 6746// Panic based approach to setting things on disconnected nodes 6747Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { 6748 set: function( tween ) { 6749 if ( tween.elem.nodeType && tween.elem.parentNode ) { 6750 tween.elem[ tween.prop ] = tween.now; 6751 } 6752 } 6753}; 6754 6755jQuery.easing = { 6756 linear: function( p ) { 6757 return p; 6758 }, 6759 swing: function( p ) { 6760 return 0.5 - Math.cos( p * Math.PI ) / 2; 6761 }, 6762 _default: "swing" 6763}; 6764 6765jQuery.fx = Tween.prototype.init; 6766 6767// Back Compat <1.8 extension point 6768jQuery.fx.step = {}; 6769 6770 6771 6772 6773var 6774 fxNow, timerId, 6775 rfxtypes = /^(?:toggle|show|hide)$/, 6776 rrun = /queueHooks$/; 6777 6778// Animations created synchronously will run synchronously 6779function createFxNow() { 6780 window.setTimeout( function() { 6781 fxNow = undefined; 6782 } ); 6783 return ( fxNow = jQuery.now() ); 6784} 6785 6786// Generate parameters to create a standard animation 6787function genFx( type, includeWidth ) { 6788 var which, 6789 i = 0, 6790 attrs = { height: type }; 6791 6792 // If we include width, step value is 1 to do all cssExpand values, 6793 // otherwise step value is 2 to skip over Left and Right 6794 includeWidth = includeWidth ? 1 : 0; 6795 for ( ; i < 4 ; i += 2 - includeWidth ) { 6796 which = cssExpand[ i ]; 6797 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; 6798 } 6799 6800 if ( includeWidth ) { 6801 attrs.opacity = attrs.width = type; 6802 } 6803 6804 return attrs; 6805} 6806 6807function createTween( value, prop, animation ) { 6808 var tween, 6809 collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), 6810 index = 0, 6811 length = collection.length; 6812 for ( ; index < length; index++ ) { 6813 if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { 6814 6815 // We're done with this property 6816 return tween; 6817 } 6818 } 6819} 6820 6821function defaultPrefilter( elem, props, opts ) { 6822 /* jshint validthis: true */ 6823 var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay, 6824 anim = this, 6825 orig = {}, 6826 style = elem.style, 6827 hidden = elem.nodeType && isHidden( elem ), 6828 dataShow = dataPriv.get( elem, "fxshow" ); 6829 6830 // Handle queue: false promises 6831 if ( !opts.queue ) { 6832 hooks = jQuery._queueHooks( elem, "fx" ); 6833 if ( hooks.unqueued == null ) { 6834 hooks.unqueued = 0; 6835 oldfire = hooks.empty.fire; 6836 hooks.empty.fire = function() { 6837 if ( !hooks.unqueued ) { 6838 oldfire(); 6839 } 6840 }; 6841 } 6842 hooks.unqueued++; 6843 6844 anim.always( function() { 6845 6846 // Ensure the complete handler is called before this completes 6847 anim.always( function() { 6848 hooks.unqueued--; 6849 if ( !jQuery.queue( elem, "fx" ).length ) { 6850 hooks.empty.fire(); 6851 } 6852 } ); 6853 } ); 6854 } 6855 6856 // Height/width overflow pass 6857 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { 6858 6859 // Make sure that nothing sneaks out 6860 // Record all 3 overflow attributes because IE9-10 do not 6861 // change the overflow attribute when overflowX and 6862 // overflowY are set to the same value 6863 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; 6864 6865 // Set display property to inline-block for height/width 6866 // animations on inline elements that are having width/height animated 6867 display = jQuery.css( elem, "display" ); 6868 6869 // Test default display if display is currently "none" 6870 checkDisplay = display === "none" ? 6871 dataPriv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display; 6872 6873 if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) { 6874 style.display = "inline-block"; 6875 } 6876 } 6877 6878 if ( opts.overflow ) { 6879 style.overflow = "hidden"; 6880 anim.always( function() { 6881 style.overflow = opts.overflow[ 0 ]; 6882 style.overflowX = opts.overflow[ 1 ]; 6883 style.overflowY = opts.overflow[ 2 ]; 6884 } ); 6885 } 6886 6887 // show/hide pass 6888 for ( prop in props ) { 6889 value = props[ prop ]; 6890 if ( rfxtypes.exec( value ) ) { 6891 delete props[ prop ]; 6892 toggle = toggle || value === "toggle"; 6893 if ( value === ( hidden ? "hide" : "show" ) ) { 6894 6895 // If there is dataShow left over from a stopped hide or show 6896 // and we are going to proceed with show, we should pretend to be hidden 6897 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { 6898 hidden = true; 6899 } else { 6900 continue; 6901 } 6902 } 6903 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); 6904 6905 // Any non-fx value stops us from restoring the original display value 6906 } else { 6907 display = undefined; 6908 } 6909 } 6910 6911 if ( !jQuery.isEmptyObject( orig ) ) { 6912 if ( dataShow ) { 6913 if ( "hidden" in dataShow ) { 6914 hidden = dataShow.hidden; 6915 } 6916 } else { 6917 dataShow = dataPriv.access( elem, "fxshow", {} ); 6918 } 6919 6920 // Store state if its toggle - enables .stop().toggle() to "reverse" 6921 if ( toggle ) { 6922 dataShow.hidden = !hidden; 6923 } 6924 if ( hidden ) { 6925 jQuery( elem ).show(); 6926 } else { 6927 anim.done( function() { 6928 jQuery( elem ).hide(); 6929 } ); 6930 } 6931 anim.done( function() { 6932 var prop; 6933 6934 dataPriv.remove( elem, "fxshow" ); 6935 for ( prop in orig ) { 6936 jQuery.style( elem, prop, orig[ prop ] ); 6937 } 6938 } ); 6939 for ( prop in orig ) { 6940 tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); 6941 6942 if ( !( prop in dataShow ) ) { 6943 dataShow[ prop ] = tween.start; 6944 if ( hidden ) { 6945 tween.end = tween.start; 6946 tween.start = prop === "width" || prop === "height" ? 1 : 0; 6947 } 6948 } 6949 } 6950 6951 // If this is a noop like .hide().hide(), restore an overwritten display value 6952 } else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : display ) === "inline" ) { 6953 style.display = display; 6954 } 6955} 6956 6957function propFilter( props, specialEasing ) { 6958 var index, name, easing, value, hooks; 6959 6960 // camelCase, specialEasing and expand cssHook pass 6961 for ( index in props ) { 6962 name = jQuery.camelCase( index ); 6963 easing = specialEasing[ name ]; 6964 value = props[ index ]; 6965 if ( jQuery.isArray( value ) ) { 6966 easing = value[ 1 ]; 6967 value = props[ index ] = value[ 0 ]; 6968 } 6969 6970 if ( index !== name ) { 6971 props[ name ] = value; 6972 delete props[ index ]; 6973 } 6974 6975 hooks = jQuery.cssHooks[ name ]; 6976 if ( hooks && "expand" in hooks ) { 6977 value = hooks.expand( value ); 6978 delete props[ name ]; 6979 6980 // Not quite $.extend, this won't overwrite existing keys. 6981 // Reusing 'index' because we have the correct "name" 6982 for ( index in value ) { 6983 if ( !( index in props ) ) { 6984 props[ index ] = value[ index ]; 6985 specialEasing[ index ] = easing; 6986 } 6987 } 6988 } else { 6989 specialEasing[ name ] = easing; 6990 } 6991 } 6992} 6993 6994function Animation( elem, properties, options ) { 6995 var result, 6996 stopped, 6997 index = 0, 6998 length = Animation.prefilters.length, 6999 deferred = jQuery.Deferred().always( function() { 7000 7001 // Don't match elem in the :animated selector 7002 delete tick.elem; 7003 } ), 7004 tick = function() { 7005 if ( stopped ) { 7006 return false; 7007 } 7008 var currentTime = fxNow || createFxNow(), 7009 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), 7010 7011 // Support: Android 2.3 7012 // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) 7013 temp = remaining / animation.duration || 0, 7014 percent = 1 - temp, 7015 index = 0, 7016 length = animation.tweens.length; 7017 7018 for ( ; index < length ; index++ ) { 7019 animation.tweens[ index ].run( percent ); 7020 } 7021 7022 deferred.notifyWith( elem, [ animation, percent, remaining ] ); 7023 7024 if ( percent < 1 && length ) { 7025 return remaining; 7026 } else { 7027 deferred.resolveWith( elem, [ animation ] ); 7028 return false; 7029 } 7030 }, 7031 animation = deferred.promise( { 7032 elem: elem, 7033 props: jQuery.extend( {}, properties ), 7034 opts: jQuery.extend( true, { 7035 specialEasing: {}, 7036 easing: jQuery.easing._default 7037 }, options ), 7038 originalProperties: properties, 7039 originalOptions: options, 7040 startTime: fxNow || createFxNow(), 7041 duration: options.duration, 7042 tweens: [], 7043 createTween: function( prop, end ) { 7044 var tween = jQuery.Tween( elem, animation.opts, prop, end, 7045 animation.opts.specialEasing[ prop ] || animation.opts.easing ); 7046 animation.tweens.push( tween ); 7047 return tween; 7048 }, 7049 stop: function( gotoEnd ) { 7050 var index = 0, 7051 7052 // If we are going to the end, we want to run all the tweens 7053 // otherwise we skip this part 7054 length = gotoEnd ? animation.tweens.length : 0; 7055 if ( stopped ) { 7056 return this; 7057 } 7058 stopped = true; 7059 for ( ; index < length ; index++ ) { 7060 animation.tweens[ index ].run( 1 ); 7061 } 7062 7063 // Resolve when we played the last frame; otherwise, reject 7064 if ( gotoEnd ) { 7065 deferred.notifyWith( elem, [ animation, 1, 0 ] ); 7066 deferred.resolveWith( elem, [ animation, gotoEnd ] ); 7067 } else { 7068 deferred.rejectWith( elem, [ animation, gotoEnd ] ); 7069 } 7070 return this; 7071 } 7072 } ), 7073 props = animation.props; 7074 7075 propFilter( props, animation.opts.specialEasing ); 7076 7077 for ( ; index < length ; index++ ) { 7078 result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); 7079 if ( result ) { 7080 if ( jQuery.isFunction( result.stop ) ) { 7081 jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = 7082 jQuery.proxy( result.stop, result ); 7083 } 7084 return result; 7085 } 7086 } 7087 7088 jQuery.map( props, createTween, animation ); 7089 7090 if ( jQuery.isFunction( animation.opts.start ) ) { 7091 animation.opts.start.call( elem, animation ); 7092 } 7093 7094 jQuery.fx.timer( 7095 jQuery.extend( tick, { 7096 elem: elem, 7097 anim: animation, 7098 queue: animation.opts.queue 7099 } ) 7100 ); 7101 7102 // attach callbacks from options 7103 return animation.progress( animation.opts.progress ) 7104 .done( animation.opts.done, animation.opts.complete ) 7105 .fail( animation.opts.fail ) 7106 .always( animation.opts.always ); 7107} 7108 7109jQuery.Animation = jQuery.extend( Animation, { 7110 tweeners: { 7111 "*": [ function( prop, value ) { 7112 var tween = this.createTween( prop, value ); 7113 adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); 7114 return tween; 7115 } ] 7116 }, 7117 7118 tweener: function( props, callback ) { 7119 if ( jQuery.isFunction( props ) ) { 7120 callback = props; 7121 props = [ "*" ]; 7122 } else { 7123 props = props.match( rnotwhite ); 7124 } 7125 7126 var prop, 7127 index = 0, 7128 length = props.length; 7129 7130 for ( ; index < length ; index++ ) { 7131 prop = props[ index ]; 7132 Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; 7133 Animation.tweeners[ prop ].unshift( callback ); 7134 } 7135 }, 7136 7137 prefilters: [ defaultPrefilter ], 7138 7139 prefilter: function( callback, prepend ) { 7140 if ( prepend ) { 7141 Animation.prefilters.unshift( callback ); 7142 } else { 7143 Animation.prefilters.push( callback ); 7144 } 7145 } 7146} ); 7147 7148jQuery.speed = function( speed, easing, fn ) { 7149 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { 7150 complete: fn || !fn && easing || 7151 jQuery.isFunction( speed ) && speed, 7152 duration: speed, 7153 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing 7154 }; 7155 7156 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? 7157 opt.duration : opt.duration in jQuery.fx.speeds ? 7158 jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; 7159 7160 // Normalize opt.queue - true/undefined/null -> "fx" 7161 if ( opt.queue == null || opt.queue === true ) { 7162 opt.queue = "fx"; 7163 } 7164 7165 // Queueing 7166 opt.old = opt.complete; 7167 7168 opt.complete = function() { 7169 if ( jQuery.isFunction( opt.old ) ) { 7170 opt.old.call( this ); 7171 } 7172 7173 if ( opt.queue ) { 7174 jQuery.dequeue( this, opt.queue ); 7175 } 7176 }; 7177 7178 return opt; 7179}; 7180 7181jQuery.fn.extend( { 7182 fadeTo: function( speed, to, easing, callback ) { 7183 7184 // Show any hidden elements after setting opacity to 0 7185 return this.filter( isHidden ).css( "opacity", 0 ).show() 7186 7187 // Animate to the value specified 7188 .end().animate( { opacity: to }, speed, easing, callback ); 7189 }, 7190 animate: function( prop, speed, easing, callback ) { 7191 var empty = jQuery.isEmptyObject( prop ), 7192 optall = jQuery.speed( speed, easing, callback ), 7193 doAnimation = function() { 7194 7195 // Operate on a copy of prop so per-property easing won't be lost 7196 var anim = Animation( this, jQuery.extend( {}, prop ), optall ); 7197 7198 // Empty animations, or finishing resolves immediately 7199 if ( empty || dataPriv.get( this, "finish" ) ) { 7200 anim.stop( true ); 7201 } 7202 }; 7203 doAnimation.finish = doAnimation; 7204 7205 return empty || optall.queue === false ? 7206 this.each( doAnimation ) : 7207 this.queue( optall.queue, doAnimation ); 7208 }, 7209 stop: function( type, clearQueue, gotoEnd ) { 7210 var stopQueue = function( hooks ) { 7211 var stop = hooks.stop; 7212 delete hooks.stop; 7213 stop( gotoEnd ); 7214 }; 7215 7216 if ( typeof type !== "string" ) { 7217 gotoEnd = clearQueue; 7218 clearQueue = type; 7219 type = undefined; 7220 } 7221 if ( clearQueue && type !== false ) { 7222 this.queue( type || "fx", [] ); 7223 } 7224 7225 return this.each( function() { 7226 var dequeue = true, 7227 index = type != null && type + "queueHooks", 7228 timers = jQuery.timers, 7229 data = dataPriv.get( this ); 7230 7231 if ( index ) { 7232 if ( data[ index ] && data[ index ].stop ) { 7233 stopQueue( data[ index ] ); 7234 } 7235 } else { 7236 for ( index in data ) { 7237 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { 7238 stopQueue( data[ index ] ); 7239 } 7240 } 7241 } 7242 7243 for ( index = timers.length; index--; ) { 7244 if ( timers[ index ].elem === this && 7245 ( type == null || timers[ index ].queue === type ) ) { 7246 7247 timers[ index ].anim.stop( gotoEnd ); 7248 dequeue = false; 7249 timers.splice( index, 1 ); 7250 } 7251 } 7252 7253 // Start the next in the queue if the last step wasn't forced. 7254 // Timers currently will call their complete callbacks, which 7255 // will dequeue but only if they were gotoEnd. 7256 if ( dequeue || !gotoEnd ) { 7257 jQuery.dequeue( this, type ); 7258 } 7259 } ); 7260 }, 7261 finish: function( type ) { 7262 if ( type !== false ) { 7263 type = type || "fx"; 7264 } 7265 return this.each( function() { 7266 var index, 7267 data = dataPriv.get( this ), 7268 queue = data[ type + "queue" ], 7269 hooks = data[ type + "queueHooks" ], 7270 timers = jQuery.timers, 7271 length = queue ? queue.length : 0; 7272 7273 // Enable finishing flag on private data 7274 data.finish = true; 7275 7276 // Empty the queue first 7277 jQuery.queue( this, type, [] ); 7278 7279 if ( hooks && hooks.stop ) { 7280 hooks.stop.call( this, true ); 7281 } 7282 7283 // Look for any active animations, and finish them 7284 for ( index = timers.length; index--; ) { 7285 if ( timers[ index ].elem === this && timers[ index ].queue === type ) { 7286 timers[ index ].anim.stop( true ); 7287 timers.splice( index, 1 ); 7288 } 7289 } 7290 7291 // Look for any animations in the old queue and finish them 7292 for ( index = 0; index < length; index++ ) { 7293 if ( queue[ index ] && queue[ index ].finish ) { 7294 queue[ index ].finish.call( this ); 7295 } 7296 } 7297 7298 // Turn off finishing flag 7299 delete data.finish; 7300 } ); 7301 } 7302} ); 7303 7304jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { 7305 var cssFn = jQuery.fn[ name ]; 7306 jQuery.fn[ name ] = function( speed, easing, callback ) { 7307 return speed == null || typeof speed === "boolean" ? 7308 cssFn.apply( this, arguments ) : 7309 this.animate( genFx( name, true ), speed, easing, callback ); 7310 }; 7311} ); 7312 7313// Generate shortcuts for custom animations 7314jQuery.each( { 7315 slideDown: genFx( "show" ), 7316 slideUp: genFx( "hide" ), 7317 slideToggle: genFx( "toggle" ), 7318 fadeIn: { opacity: "show" }, 7319 fadeOut: { opacity: "hide" }, 7320 fadeToggle: { opacity: "toggle" } 7321}, function( name, props ) { 7322 jQuery.fn[ name ] = function( speed, easing, callback ) { 7323 return this.animate( props, speed, easing, callback ); 7324 }; 7325} ); 7326 7327jQuery.timers = []; 7328jQuery.fx.tick = function() { 7329 var timer, 7330 i = 0, 7331 timers = jQuery.timers; 7332 7333 fxNow = jQuery.now(); 7334 7335 for ( ; i < timers.length; i++ ) { 7336 timer = timers[ i ]; 7337 7338 // Checks the timer has not already been removed 7339 if ( !timer() && timers[ i ] === timer ) { 7340 timers.splice( i--, 1 ); 7341 } 7342 } 7343 7344 if ( !timers.length ) { 7345 jQuery.fx.stop(); 7346 } 7347 fxNow = undefined; 7348}; 7349 7350jQuery.fx.timer = function( timer ) { 7351 jQuery.timers.push( timer ); 7352 if ( timer() ) { 7353 jQuery.fx.start(); 7354 } else { 7355 jQuery.timers.pop(); 7356 } 7357}; 7358 7359jQuery.fx.interval = 13; 7360jQuery.fx.start = function() { 7361 if ( !timerId ) { 7362 timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); 7363 } 7364}; 7365 7366jQuery.fx.stop = function() { 7367 window.clearInterval( timerId ); 7368 7369 timerId = null; 7370}; 7371 7372jQuery.fx.speeds = { 7373 slow: 600, 7374 fast: 200, 7375 7376 // Default speed 7377 _default: 400 7378}; 7379 7380 7381// Based off of the plugin by Clint Helfers, with permission. 7382// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ 7383jQuery.fn.delay = function( time, type ) { 7384 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 7385 type = type || "fx"; 7386 7387 return this.queue( type, function( next, hooks ) { 7388 var timeout = window.setTimeout( next, time ); 7389 hooks.stop = function() { 7390 window.clearTimeout( timeout ); 7391 }; 7392 } ); 7393}; 7394 7395 7396( function() { 7397 var input = document.createElement( "input" ), 7398 select = document.createElement( "select" ), 7399 opt = select.appendChild( document.createElement( "option" ) ); 7400 7401 input.type = "checkbox"; 7402 7403 // Support: iOS<=5.1, Android<=4.2+ 7404 // Default value for a checkbox should be "on" 7405 support.checkOn = input.value !== ""; 7406 7407 // Support: IE<=11+ 7408 // Must access selectedIndex to make default options select 7409 support.optSelected = opt.selected; 7410 7411 // Support: Android<=2.3 7412 // Options inside disabled selects are incorrectly marked as disabled 7413 select.disabled = true; 7414 support.optDisabled = !opt.disabled; 7415 7416 // Support: IE<=11+ 7417 // An input loses its value after becoming a radio 7418 input = document.createElement( "input" ); 7419 input.value = "t"; 7420 input.type = "radio"; 7421 support.radioValue = input.value === "t"; 7422} )(); 7423 7424 7425var boolHook, 7426 attrHandle = jQuery.expr.attrHandle; 7427 7428jQuery.fn.extend( { 7429 attr: function( name, value ) { 7430 return access( this, jQuery.attr, name, value, arguments.length > 1 ); 7431 }, 7432 7433 removeAttr: function( name ) { 7434 return this.each( function() { 7435 jQuery.removeAttr( this, name ); 7436 } ); 7437 } 7438} ); 7439 7440jQuery.extend( { 7441 attr: function( elem, name, value ) { 7442 var ret, hooks, 7443 nType = elem.nodeType; 7444 7445 // Don't get/set attributes on text, comment and attribute nodes 7446 if ( nType === 3 || nType === 8 || nType === 2 ) { 7447 return; 7448 } 7449 7450 // Fallback to prop when attributes are not supported 7451 if ( typeof elem.getAttribute === "undefined" ) { 7452 return jQuery.prop( elem, name, value ); 7453 } 7454 7455 // All attributes are lowercase 7456 // Grab necessary hook if one is defined 7457 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 7458 name = name.toLowerCase(); 7459 hooks = jQuery.attrHooks[ name ] || 7460 ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); 7461 } 7462 7463 if ( value !== undefined ) { 7464 if ( value === null ) { 7465 jQuery.removeAttr( elem, name ); 7466 return; 7467 } 7468 7469 if ( hooks && "set" in hooks && 7470 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 7471 return ret; 7472 } 7473 7474 elem.setAttribute( name, value + "" ); 7475 return value; 7476 } 7477 7478 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 7479 return ret; 7480 } 7481 7482 ret = jQuery.find.attr( elem, name ); 7483 7484 // Non-existent attributes return null, we normalize to undefined 7485 return ret == null ? undefined : ret; 7486 }, 7487 7488 attrHooks: { 7489 type: { 7490 set: function( elem, value ) { 7491 if ( !support.radioValue && value === "radio" && 7492 jQuery.nodeName( elem, "input" ) ) { 7493 var val = elem.value; 7494 elem.setAttribute( "type", value ); 7495 if ( val ) { 7496 elem.value = val; 7497 } 7498 return value; 7499 } 7500 } 7501 } 7502 }, 7503 7504 removeAttr: function( elem, value ) { 7505 var name, propName, 7506 i = 0, 7507 attrNames = value && value.match( rnotwhite ); 7508 7509 if ( attrNames && elem.nodeType === 1 ) { 7510 while ( ( name = attrNames[ i++ ] ) ) { 7511 propName = jQuery.propFix[ name ] || name; 7512 7513 // Boolean attributes get special treatment (#10870) 7514 if ( jQuery.expr.match.bool.test( name ) ) { 7515 7516 // Set corresponding property to false 7517 elem[ propName ] = false; 7518 } 7519 7520 elem.removeAttribute( name ); 7521 } 7522 } 7523 } 7524} ); 7525 7526// Hooks for boolean attributes 7527boolHook = { 7528 set: function( elem, value, name ) { 7529 if ( value === false ) { 7530 7531 // Remove boolean attributes when set to false 7532 jQuery.removeAttr( elem, name ); 7533 } else { 7534 elem.setAttribute( name, name ); 7535 } 7536 return name; 7537 } 7538}; 7539jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { 7540 var getter = attrHandle[ name ] || jQuery.find.attr; 7541 7542 attrHandle[ name ] = function( elem, name, isXML ) { 7543 var ret, handle; 7544 if ( !isXML ) { 7545 7546 // Avoid an infinite loop by temporarily removing this function from the getter 7547 handle = attrHandle[ name ]; 7548 attrHandle[ name ] = ret; 7549 ret = getter( elem, name, isXML ) != null ? 7550 name.toLowerCase() : 7551 null; 7552 attrHandle[ name ] = handle; 7553 } 7554 return ret; 7555 }; 7556} ); 7557 7558 7559 7560 7561var rfocusable = /^(?:input|select|textarea|button)$/i, 7562 rclickable = /^(?:a|area)$/i; 7563 7564jQuery.fn.extend( { 7565 prop: function( name, value ) { 7566 return access( this, jQuery.prop, name, value, arguments.length > 1 ); 7567 }, 7568 7569 removeProp: function( name ) { 7570 return this.each( function() { 7571 delete this[ jQuery.propFix[ name ] || name ]; 7572 } ); 7573 } 7574} ); 7575 7576jQuery.extend( { 7577 prop: function( elem, name, value ) { 7578 var ret, hooks, 7579 nType = elem.nodeType; 7580 7581 // Don't get/set properties on text, comment and attribute nodes 7582 if ( nType === 3 || nType === 8 || nType === 2 ) { 7583 return; 7584 } 7585 7586 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 7587 7588 // Fix name and attach hooks 7589 name = jQuery.propFix[ name ] || name; 7590 hooks = jQuery.propHooks[ name ]; 7591 } 7592 7593 if ( value !== undefined ) { 7594 if ( hooks && "set" in hooks && 7595 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 7596 return ret; 7597 } 7598 7599 return ( elem[ name ] = value ); 7600 } 7601 7602 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 7603 return ret; 7604 } 7605 7606 return elem[ name ]; 7607 }, 7608 7609 propHooks: { 7610 tabIndex: { 7611 get: function( elem ) { 7612 7613 // elem.tabIndex doesn't always return the 7614 // correct value when it hasn't been explicitly set 7615 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ 7616 // Use proper attribute retrieval(#12072) 7617 var tabindex = jQuery.find.attr( elem, "tabindex" ); 7618 7619 return tabindex ? 7620 parseInt( tabindex, 10 ) : 7621 rfocusable.test( elem.nodeName ) || 7622 rclickable.test( elem.nodeName ) && elem.href ? 7623 0 : 7624 -1; 7625 } 7626 } 7627 }, 7628 7629 propFix: { 7630 "for": "htmlFor", 7631 "class": "className" 7632 } 7633} ); 7634 7635// Support: IE <=11 only 7636// Accessing the selectedIndex property 7637// forces the browser to respect setting selected 7638// on the option 7639// The getter ensures a default option is selected 7640// when in an optgroup 7641if ( !support.optSelected ) { 7642 jQuery.propHooks.selected = { 7643 get: function( elem ) { 7644 var parent = elem.parentNode; 7645 if ( parent && parent.parentNode ) { 7646 parent.parentNode.selectedIndex; 7647 } 7648 return null; 7649 }, 7650 set: function( elem ) { 7651 var parent = elem.parentNode; 7652 if ( parent ) { 7653 parent.selectedIndex; 7654 7655 if ( parent.parentNode ) { 7656 parent.parentNode.selectedIndex; 7657 } 7658 } 7659 } 7660 }; 7661} 7662 7663jQuery.each( [ 7664 "tabIndex", 7665 "readOnly", 7666 "maxLength", 7667 "cellSpacing", 7668 "cellPadding", 7669 "rowSpan", 7670 "colSpan", 7671 "useMap", 7672 "frameBorder", 7673 "contentEditable" 7674], function() { 7675 jQuery.propFix[ this.toLowerCase() ] = this; 7676} ); 7677 7678 7679 7680 7681var rclass = /[\t\r\n\f]/g; 7682 7683function getClass( elem ) { 7684 return elem.getAttribute && elem.getAttribute( "class" ) || ""; 7685} 7686 7687jQuery.fn.extend( { 7688 addClass: function( value ) { 7689 var classes, elem, cur, curValue, clazz, j, finalValue, 7690 i = 0; 7691 7692 if ( jQuery.isFunction( value ) ) { 7693 return this.each( function( j ) { 7694 jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); 7695 } ); 7696 } 7697 7698 if ( typeof value === "string" && value ) { 7699 classes = value.match( rnotwhite ) || []; 7700 7701 while ( ( elem = this[ i++ ] ) ) { 7702 curValue = getClass( elem ); 7703 cur = elem.nodeType === 1 && 7704 ( " " + curValue + " " ).replace( rclass, " " ); 7705 7706 if ( cur ) { 7707 j = 0; 7708 while ( ( clazz = classes[ j++ ] ) ) { 7709 if ( cur.indexOf( " " + clazz + " " ) < 0 ) { 7710 cur += clazz + " "; 7711 } 7712 } 7713 7714 // Only assign if different to avoid unneeded rendering. 7715 finalValue = jQuery.trim( cur ); 7716 if ( curValue !== finalValue ) { 7717 elem.setAttribute( "class", finalValue ); 7718 } 7719 } 7720 } 7721 } 7722 7723 return this; 7724 }, 7725 7726 removeClass: function( value ) { 7727 var classes, elem, cur, curValue, clazz, j, finalValue, 7728 i = 0; 7729 7730 if ( jQuery.isFunction( value ) ) { 7731 return this.each( function( j ) { 7732 jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); 7733 } ); 7734 } 7735 7736 if ( !arguments.length ) { 7737 return this.attr( "class", "" ); 7738 } 7739 7740 if ( typeof value === "string" && value ) { 7741 classes = value.match( rnotwhite ) || []; 7742 7743 while ( ( elem = this[ i++ ] ) ) { 7744 curValue = getClass( elem ); 7745 7746 // This expression is here for better compressibility (see addClass) 7747 cur = elem.nodeType === 1 && 7748 ( " " + curValue + " " ).replace( rclass, " " ); 7749 7750 if ( cur ) { 7751 j = 0; 7752 while ( ( clazz = classes[ j++ ] ) ) { 7753 7754 // Remove *all* instances 7755 while ( cur.indexOf( " " + clazz + " " ) > -1 ) { 7756 cur = cur.replace( " " + clazz + " ", " " ); 7757 } 7758 } 7759 7760 // Only assign if different to avoid unneeded rendering. 7761 finalValue = jQuery.trim( cur ); 7762 if ( curValue !== finalValue ) { 7763 elem.setAttribute( "class", finalValue ); 7764 } 7765 } 7766 } 7767 } 7768 7769 return this; 7770 }, 7771 7772 toggleClass: function( value, stateVal ) { 7773 var type = typeof value; 7774 7775 if ( typeof stateVal === "boolean" && type === "string" ) { 7776 return stateVal ? this.addClass( value ) : this.removeClass( value ); 7777 } 7778 7779 if ( jQuery.isFunction( value ) ) { 7780 return this.each( function( i ) { 7781 jQuery( this ).toggleClass( 7782 value.call( this, i, getClass( this ), stateVal ), 7783 stateVal 7784 ); 7785 } ); 7786 } 7787 7788 return this.each( function() { 7789 var className, i, self, classNames; 7790 7791 if ( type === "string" ) { 7792 7793 // Toggle individual class names 7794 i = 0; 7795 self = jQuery( this ); 7796 classNames = value.match( rnotwhite ) || []; 7797 7798 while ( ( className = classNames[ i++ ] ) ) { 7799 7800 // Check each className given, space separated list 7801 if ( self.hasClass( className ) ) { 7802 self.removeClass( className ); 7803 } else { 7804 self.addClass( className ); 7805 } 7806 } 7807 7808 // Toggle whole class name 7809 } else if ( value === undefined || type === "boolean" ) { 7810 className = getClass( this ); 7811 if ( className ) { 7812 7813 // Store className if set 7814 dataPriv.set( this, "__className__", className ); 7815 } 7816 7817 // If the element has a class name or if we're passed `false`, 7818 // then remove the whole classname (if there was one, the above saved it). 7819 // Otherwise bring back whatever was previously saved (if anything), 7820 // falling back to the empty string if nothing was stored. 7821 if ( this.setAttribute ) { 7822 this.setAttribute( "class", 7823 className || value === false ? 7824 "" : 7825 dataPriv.get( this, "__className__" ) || "" 7826 ); 7827 } 7828 } 7829 } ); 7830 }, 7831 7832 hasClass: function( selector ) { 7833 var className, elem, 7834 i = 0; 7835 7836 className = " " + selector + " "; 7837 while ( ( elem = this[ i++ ] ) ) { 7838 if ( elem.nodeType === 1 && 7839 ( " " + getClass( elem ) + " " ).replace( rclass, " " ) 7840 .indexOf( className ) > -1 7841 ) { 7842 return true; 7843 } 7844 } 7845 7846 return false; 7847 } 7848} ); 7849 7850 7851 7852 7853var rreturn = /\r/g, 7854 rspaces = /[\x20\t\r\n\f]+/g; 7855 7856jQuery.fn.extend( { 7857 val: function( value ) { 7858 var hooks, ret, isFunction, 7859 elem = this[ 0 ]; 7860 7861 if ( !arguments.length ) { 7862 if ( elem ) { 7863 hooks = jQuery.valHooks[ elem.type ] || 7864 jQuery.valHooks[ elem.nodeName.toLowerCase() ]; 7865 7866 if ( hooks && 7867 "get" in hooks && 7868 ( ret = hooks.get( elem, "value" ) ) !== undefined 7869 ) { 7870 return ret; 7871 } 7872 7873 ret = elem.value; 7874 7875 return typeof ret === "string" ? 7876 7877 // Handle most common string cases 7878 ret.replace( rreturn, "" ) : 7879 7880 // Handle cases where value is null/undef or number 7881 ret == null ? "" : ret; 7882 } 7883 7884 return; 7885 } 7886 7887 isFunction = jQuery.isFunction( value ); 7888 7889 return this.each( function( i ) { 7890 var val; 7891 7892 if ( this.nodeType !== 1 ) { 7893 return; 7894 } 7895 7896 if ( isFunction ) { 7897 val = value.call( this, i, jQuery( this ).val() ); 7898 } else { 7899 val = value; 7900 } 7901 7902 // Treat null/undefined as ""; convert numbers to string 7903 if ( val == null ) { 7904 val = ""; 7905 7906 } else if ( typeof val === "number" ) { 7907 val += ""; 7908 7909 } else if ( jQuery.isArray( val ) ) { 7910 val = jQuery.map( val, function( value ) { 7911 return value == null ? "" : value + ""; 7912 } ); 7913 } 7914 7915 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; 7916 7917 // If set returns undefined, fall back to normal setting 7918 if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { 7919 this.value = val; 7920 } 7921 } ); 7922 } 7923} ); 7924 7925jQuery.extend( { 7926 valHooks: { 7927 option: { 7928 get: function( elem ) { 7929 7930 var val = jQuery.find.attr( elem, "value" ); 7931 return val != null ? 7932 val : 7933 7934 // Support: IE10-11+ 7935 // option.text throws exceptions (#14686, #14858) 7936 // Strip and collapse whitespace 7937 // https://html.spec.whatwg.org/#strip-and-collapse-whitespace 7938 jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " ); 7939 } 7940 }, 7941 select: { 7942 get: function( elem ) { 7943 var value, option, 7944 options = elem.options, 7945 index = elem.selectedIndex, 7946 one = elem.type === "select-one" || index < 0, 7947 values = one ? null : [], 7948 max = one ? index + 1 : options.length, 7949 i = index < 0 ? 7950 max : 7951 one ? index : 0; 7952 7953 // Loop through all the selected options 7954 for ( ; i < max; i++ ) { 7955 option = options[ i ]; 7956 7957 // IE8-9 doesn't update selected after form reset (#2551) 7958 if ( ( option.selected || i === index ) && 7959 7960 // Don't return options that are disabled or in a disabled optgroup 7961 ( support.optDisabled ? 7962 !option.disabled : option.getAttribute( "disabled" ) === null ) && 7963 ( !option.parentNode.disabled || 7964 !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { 7965 7966 // Get the specific value for the option 7967 value = jQuery( option ).val(); 7968 7969 // We don't need an array for one selects 7970 if ( one ) { 7971 return value; 7972 } 7973 7974 // Multi-Selects return an array 7975 values.push( value ); 7976 } 7977 } 7978 7979 return values; 7980 }, 7981 7982 set: function( elem, value ) { 7983 var optionSet, option, 7984 options = elem.options, 7985 values = jQuery.makeArray( value ), 7986 i = options.length; 7987 7988 while ( i-- ) { 7989 option = options[ i ]; 7990 if ( option.selected = 7991 jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 7992 ) { 7993 optionSet = true; 7994 } 7995 } 7996 7997 // Force browsers to behave consistently when non-matching value is set 7998 if ( !optionSet ) { 7999 elem.selectedIndex = -1; 8000 } 8001 return values; 8002 } 8003 } 8004 } 8005} ); 8006 8007// Radios and checkboxes getter/setter 8008jQuery.each( [ "radio", "checkbox" ], function() { 8009 jQuery.valHooks[ this ] = { 8010 set: function( elem, value ) { 8011 if ( jQuery.isArray( value ) ) { 8012 return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); 8013 } 8014 } 8015 }; 8016 if ( !support.checkOn ) { 8017 jQuery.valHooks[ this ].get = function( elem ) { 8018 return elem.getAttribute( "value" ) === null ? "on" : elem.value; 8019 }; 8020 } 8021} ); 8022 8023 8024 8025 8026// Return jQuery for attributes-only inclusion 8027 8028 8029var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; 8030 8031jQuery.extend( jQuery.event, { 8032 8033 trigger: function( event, data, elem, onlyHandlers ) { 8034 8035 var i, cur, tmp, bubbleType, ontype, handle, special, 8036 eventPath = [ elem || document ], 8037 type = hasOwn.call( event, "type" ) ? event.type : event, 8038 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; 8039 8040 cur = tmp = elem = elem || document; 8041 8042 // Don't do events on text and comment nodes 8043 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 8044 return; 8045 } 8046 8047 // focus/blur morphs to focusin/out; ensure we're not firing them right now 8048 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { 8049 return; 8050 } 8051 8052 if ( type.indexOf( "." ) > -1 ) { 8053 8054 // Namespaced trigger; create a regexp to match event type in handle() 8055 namespaces = type.split( "." ); 8056 type = namespaces.shift(); 8057 namespaces.sort(); 8058 } 8059 ontype = type.indexOf( ":" ) < 0 && "on" + type; 8060 8061 // Caller can pass in a jQuery.Event object, Object, or just an event type string 8062 event = event[ jQuery.expando ] ? 8063 event : 8064 new jQuery.Event( type, typeof event === "object" && event ); 8065 8066 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) 8067 event.isTrigger = onlyHandlers ? 2 : 3; 8068 event.namespace = namespaces.join( "." ); 8069 event.rnamespace = event.namespace ? 8070 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : 8071 null; 8072 8073 // Clean up the event in case it is being reused 8074 event.result = undefined; 8075 if ( !event.target ) { 8076 event.target = elem; 8077 } 8078 8079 // Clone any incoming data and prepend the event, creating the handler arg list 8080 data = data == null ? 8081 [ event ] : 8082 jQuery.makeArray( data, [ event ] ); 8083 8084 // Allow special events to draw outside the lines 8085 special = jQuery.event.special[ type ] || {}; 8086 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { 8087 return; 8088 } 8089 8090 // Determine event propagation path in advance, per W3C events spec (#9951) 8091 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) 8092 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { 8093 8094 bubbleType = special.delegateType || type; 8095 if ( !rfocusMorph.test( bubbleType + type ) ) { 8096 cur = cur.parentNode; 8097 } 8098 for ( ; cur; cur = cur.parentNode ) { 8099 eventPath.push( cur ); 8100 tmp = cur; 8101 } 8102 8103 // Only add window if we got to document (e.g., not plain obj or detached DOM) 8104 if ( tmp === ( elem.ownerDocument || document ) ) { 8105 eventPath.push( tmp.defaultView || tmp.parentWindow || window ); 8106 } 8107 } 8108 8109 // Fire handlers on the event path 8110 i = 0; 8111 while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { 8112 8113 event.type = i > 1 ? 8114 bubbleType : 8115 special.bindType || type; 8116 8117 // jQuery handler 8118 handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && 8119 dataPriv.get( cur, "handle" ); 8120 if ( handle ) { 8121 handle.apply( cur, data ); 8122 } 8123 8124 // Native handler 8125 handle = ontype && cur[ ontype ]; 8126 if ( handle && handle.apply && acceptData( cur ) ) { 8127 event.result = handle.apply( cur, data ); 8128 if ( event.result === false ) { 8129 event.preventDefault(); 8130 } 8131 } 8132 } 8133 event.type = type; 8134 8135 // If nobody prevented the default action, do it now 8136 if ( !onlyHandlers && !event.isDefaultPrevented() ) { 8137 8138 if ( ( !special._default || 8139 special._default.apply( eventPath.pop(), data ) === false ) && 8140 acceptData( elem ) ) { 8141 8142 // Call a native DOM method on the target with the same name name as the event. 8143 // Don't do default actions on window, that's where global variables be (#6170) 8144 if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { 8145 8146 // Don't re-trigger an onFOO event when we call its FOO() method 8147 tmp = elem[ ontype ]; 8148 8149 if ( tmp ) { 8150 elem[ ontype ] = null; 8151 } 8152 8153 // Prevent re-triggering of the same event, since we already bubbled it above 8154 jQuery.event.triggered = type; 8155 elem[ type ](); 8156 jQuery.event.triggered = undefined; 8157 8158 if ( tmp ) { 8159 elem[ ontype ] = tmp; 8160 } 8161 } 8162 } 8163 } 8164 8165 return event.result; 8166 }, 8167 8168 // Piggyback on a donor event to simulate a different one 8169 // Used only for `focus(in | out)` events 8170 simulate: function( type, elem, event ) { 8171 var e = jQuery.extend( 8172 new jQuery.Event(), 8173 event, 8174 { 8175 type: type, 8176 isSimulated: true 8177 } 8178 ); 8179 8180 jQuery.event.trigger( e, null, elem ); 8181 } 8182 8183} ); 8184 8185jQuery.fn.extend( { 8186 8187 trigger: function( type, data ) { 8188 return this.each( function() { 8189 jQuery.event.trigger( type, data, this ); 8190 } ); 8191 }, 8192 triggerHandler: function( type, data ) { 8193 var elem = this[ 0 ]; 8194 if ( elem ) { 8195 return jQuery.event.trigger( type, data, elem, true ); 8196 } 8197 } 8198} ); 8199 8200 8201jQuery.each( ( "blur focus focusin focusout load resize scroll unload click dblclick " + 8202 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 8203 "change select submit keydown keypress keyup error contextmenu" ).split( " " ), 8204 function( i, name ) { 8205 8206 // Handle event binding 8207 jQuery.fn[ name ] = function( data, fn ) { 8208 return arguments.length > 0 ? 8209 this.on( name, null, data, fn ) : 8210 this.trigger( name ); 8211 }; 8212} ); 8213 8214jQuery.fn.extend( { 8215 hover: function( fnOver, fnOut ) { 8216 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 8217 } 8218} ); 8219 8220 8221 8222 8223support.focusin = "onfocusin" in window; 8224 8225 8226// Support: Firefox 8227// Firefox doesn't have focus(in | out) events 8228// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 8229// 8230// Support: Chrome, Safari 8231// focus(in | out) events fire after focus & blur events, 8232// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order 8233// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857 8234if ( !support.focusin ) { 8235 jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { 8236 8237 // Attach a single capturing handler on the document while someone wants focusin/focusout 8238 var handler = function( event ) { 8239 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); 8240 }; 8241 8242 jQuery.event.special[ fix ] = { 8243 setup: function() { 8244 var doc = this.ownerDocument || this, 8245 attaches = dataPriv.access( doc, fix ); 8246 8247 if ( !attaches ) { 8248 doc.addEventListener( orig, handler, true ); 8249 } 8250 dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); 8251 }, 8252 teardown: function() { 8253 var doc = this.ownerDocument || this, 8254 attaches = dataPriv.access( doc, fix ) - 1; 8255 8256 if ( !attaches ) { 8257 doc.removeEventListener( orig, handler, true ); 8258 dataPriv.remove( doc, fix ); 8259 8260 } else { 8261 dataPriv.access( doc, fix, attaches ); 8262 } 8263 } 8264 }; 8265 } ); 8266} 8267var location = window.location; 8268 8269var nonce = jQuery.now(); 8270 8271var rquery = ( /\?/ ); 8272 8273 8274 8275// Support: Android 2.3 8276// Workaround failure to string-cast null input 8277jQuery.parseJSON = function( data ) { 8278 return JSON.parse( data + "" ); 8279}; 8280 8281 8282// Cross-browser xml parsing 8283jQuery.parseXML = function( data ) { 8284 var xml; 8285 if ( !data || typeof data !== "string" ) { 8286 return null; 8287 } 8288 8289 // Support: IE9 8290 try { 8291 xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); 8292 } catch ( e ) { 8293 xml = undefined; 8294 } 8295 8296 if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { 8297 jQuery.error( "Invalid XML: " + data ); 8298 } 8299 return xml; 8300}; 8301 8302 8303var 8304 rhash = /#.*$/, 8305 rts = /([?&])_=[^&]*/, 8306 rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, 8307 8308 // #7653, #8125, #8152: local protocol detection 8309 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, 8310 rnoContent = /^(?:GET|HEAD)$/, 8311 rprotocol = /^\/\//, 8312 8313 /* Prefilters 8314 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) 8315 * 2) These are called: 8316 * - BEFORE asking for a transport 8317 * - AFTER param serialization (s.data is a string if s.processData is true) 8318 * 3) key is the dataType 8319 * 4) the catchall symbol "*" can be used 8320 * 5) execution will start with transport dataType and THEN continue down to "*" if needed 8321 */ 8322 prefilters = {}, 8323 8324 /* Transports bindings 8325 * 1) key is the dataType 8326 * 2) the catchall symbol "*" can be used 8327 * 3) selection will start with transport dataType and THEN go to "*" if needed 8328 */ 8329 transports = {}, 8330 8331 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression 8332 allTypes = "*/".concat( "*" ), 8333 8334 // Anchor tag for parsing the document origin 8335 originAnchor = document.createElement( "a" ); 8336 originAnchor.href = location.href; 8337 8338// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport 8339function addToPrefiltersOrTransports( structure ) { 8340 8341 // dataTypeExpression is optional and defaults to "*" 8342 return function( dataTypeExpression, func ) { 8343 8344 if ( typeof dataTypeExpression !== "string" ) { 8345 func = dataTypeExpression; 8346 dataTypeExpression = "*"; 8347 } 8348 8349 var dataType, 8350 i = 0, 8351 dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || []; 8352 8353 if ( jQuery.isFunction( func ) ) { 8354 8355 // For each dataType in the dataTypeExpression 8356 while ( ( dataType = dataTypes[ i++ ] ) ) { 8357 8358 // Prepend if requested 8359 if ( dataType[ 0 ] === "+" ) { 8360 dataType = dataType.slice( 1 ) || "*"; 8361 ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); 8362 8363 // Otherwise append 8364 } else { 8365 ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); 8366 } 8367 } 8368 } 8369 }; 8370} 8371 8372// Base inspection function for prefilters and transports 8373function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { 8374 8375 var inspected = {}, 8376 seekingTransport = ( structure === transports ); 8377 8378 function inspect( dataType ) { 8379 var selected; 8380 inspected[ dataType ] = true; 8381 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { 8382 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); 8383 if ( typeof dataTypeOrTransport === "string" && 8384 !seekingTransport && !inspected[ dataTypeOrTransport ] ) { 8385 8386 options.dataTypes.unshift( dataTypeOrTransport ); 8387 inspect( dataTypeOrTransport ); 8388 return false; 8389 } else if ( seekingTransport ) { 8390 return !( selected = dataTypeOrTransport ); 8391 } 8392 } ); 8393 return selected; 8394 } 8395 8396 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); 8397} 8398 8399// A special extend for ajax options 8400// that takes "flat" options (not to be deep extended) 8401// Fixes #9887 8402function ajaxExtend( target, src ) { 8403 var key, deep, 8404 flatOptions = jQuery.ajaxSettings.flatOptions || {}; 8405 8406 for ( key in src ) { 8407 if ( src[ key ] !== undefined ) { 8408 ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; 8409 } 8410 } 8411 if ( deep ) { 8412 jQuery.extend( true, target, deep ); 8413 } 8414 8415 return target; 8416} 8417 8418/* Handles responses to an ajax request: 8419 * - finds the right dataType (mediates between content-type and expected dataType) 8420 * - returns the corresponding response 8421 */ 8422function ajaxHandleResponses( s, jqXHR, responses ) { 8423 8424 var ct, type, finalDataType, firstDataType, 8425 contents = s.contents, 8426 dataTypes = s.dataTypes; 8427 8428 // Remove auto dataType and get content-type in the process 8429 while ( dataTypes[ 0 ] === "*" ) { 8430 dataTypes.shift(); 8431 if ( ct === undefined ) { 8432 ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); 8433 } 8434 } 8435 8436 // Check if we're dealing with a known content-type 8437 if ( ct ) { 8438 for ( type in contents ) { 8439 if ( contents[ type ] && contents[ type ].test( ct ) ) { 8440 dataTypes.unshift( type ); 8441 break; 8442 } 8443 } 8444 } 8445 8446 // Check to see if we have a response for the expected dataType 8447 if ( dataTypes[ 0 ] in responses ) { 8448 finalDataType = dataTypes[ 0 ]; 8449 } else { 8450 8451 // Try convertible dataTypes 8452 for ( type in responses ) { 8453 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { 8454 finalDataType = type; 8455 break; 8456 } 8457 if ( !firstDataType ) { 8458 firstDataType = type; 8459 } 8460 } 8461 8462 // Or just use first one 8463 finalDataType = finalDataType || firstDataType; 8464 } 8465 8466 // If we found a dataType 8467 // We add the dataType to the list if needed 8468 // and return the corresponding response 8469 if ( finalDataType ) { 8470 if ( finalDataType !== dataTypes[ 0 ] ) { 8471 dataTypes.unshift( finalDataType ); 8472 } 8473 return responses[ finalDataType ]; 8474 } 8475} 8476 8477/* Chain conversions given the request and the original response 8478 * Also sets the responseXXX fields on the jqXHR instance 8479 */ 8480function ajaxConvert( s, response, jqXHR, isSuccess ) { 8481 var conv2, current, conv, tmp, prev, 8482 converters = {}, 8483 8484 // Work with a copy of dataTypes in case we need to modify it for conversion 8485 dataTypes = s.dataTypes.slice(); 8486 8487 // Create converters map with lowercased keys 8488 if ( dataTypes[ 1 ] ) { 8489 for ( conv in s.converters ) { 8490 converters[ conv.toLowerCase() ] = s.converters[ conv ]; 8491 } 8492 } 8493 8494 current = dataTypes.shift(); 8495 8496 // Convert to each sequential dataType 8497 while ( current ) { 8498 8499 if ( s.responseFields[ current ] ) { 8500 jqXHR[ s.responseFields[ current ] ] = response; 8501 } 8502 8503 // Apply the dataFilter if provided 8504 if ( !prev && isSuccess && s.dataFilter ) { 8505 response = s.dataFilter( response, s.dataType ); 8506 } 8507 8508 prev = current; 8509 current = dataTypes.shift(); 8510 8511 if ( current ) { 8512 8513 // There's only work to do if current dataType is non-auto 8514 if ( current === "*" ) { 8515 8516 current = prev; 8517 8518 // Convert response if prev dataType is non-auto and differs from current 8519 } else if ( prev !== "*" && prev !== current ) { 8520 8521 // Seek a direct converter 8522 conv = converters[ prev + " " + current ] || converters[ "* " + current ]; 8523 8524 // If none found, seek a pair 8525 if ( !conv ) { 8526 for ( conv2 in converters ) { 8527 8528 // If conv2 outputs current 8529 tmp = conv2.split( " " ); 8530 if ( tmp[ 1 ] === current ) { 8531 8532 // If prev can be converted to accepted input 8533 conv = converters[ prev + " " + tmp[ 0 ] ] || 8534 converters[ "* " + tmp[ 0 ] ]; 8535 if ( conv ) { 8536 8537 // Condense equivalence converters 8538 if ( conv === true ) { 8539 conv = converters[ conv2 ]; 8540 8541 // Otherwise, insert the intermediate dataType 8542 } else if ( converters[ conv2 ] !== true ) { 8543 current = tmp[ 0 ]; 8544 dataTypes.unshift( tmp[ 1 ] ); 8545 } 8546 break; 8547 } 8548 } 8549 } 8550 } 8551 8552 // Apply converter (if not an equivalence) 8553 if ( conv !== true ) { 8554 8555 // Unless errors are allowed to bubble, catch and return them 8556 if ( conv && s.throws ) { 8557 response = conv( response ); 8558 } else { 8559 try { 8560 response = conv( response ); 8561 } catch ( e ) { 8562 return { 8563 state: "parsererror", 8564 error: conv ? e : "No conversion from " + prev + " to " + current 8565 }; 8566 } 8567 } 8568 } 8569 } 8570 } 8571 } 8572 8573 return { state: "success", data: response }; 8574} 8575 8576jQuery.extend( { 8577 8578 // Counter for holding the number of active queries 8579 active: 0, 8580 8581 // Last-Modified header cache for next request 8582 lastModified: {}, 8583 etag: {}, 8584 8585 ajaxSettings: { 8586 url: location.href, 8587 type: "GET", 8588 isLocal: rlocalProtocol.test( location.protocol ), 8589 global: true, 8590 processData: true, 8591 async: true, 8592 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 8593 /* 8594 timeout: 0, 8595 data: null, 8596 dataType: null, 8597 username: null, 8598 password: null, 8599 cache: null, 8600 throws: false, 8601 traditional: false, 8602 headers: {}, 8603 */ 8604 8605 accepts: { 8606 "*": allTypes, 8607 text: "text/plain", 8608 html: "text/html", 8609 xml: "application/xml, text/xml", 8610 json: "application/json, text/javascript" 8611 }, 8612 8613 contents: { 8614 xml: /\bxml\b/, 8615 html: /\bhtml/, 8616 json: /\bjson\b/ 8617 }, 8618 8619 responseFields: { 8620 xml: "responseXML", 8621 text: "responseText", 8622 json: "responseJSON" 8623 }, 8624 8625 // Data converters 8626 // Keys separate source (or catchall "*") and destination types with a single space 8627 converters: { 8628 8629 // Convert anything to text 8630 "* text": String, 8631 8632 // Text to html (true = no transformation) 8633 "text html": true, 8634 8635 // Evaluate text as a json expression 8636 "text json": jQuery.parseJSON, 8637 8638 // Parse text as xml 8639 "text xml": jQuery.parseXML 8640 }, 8641 8642 // For options that shouldn't be deep extended: 8643 // you can add your own custom options here if 8644 // and when you create one that shouldn't be 8645 // deep extended (see ajaxExtend) 8646 flatOptions: { 8647 url: true, 8648 context: true 8649 } 8650 }, 8651 8652 // Creates a full fledged settings object into target 8653 // with both ajaxSettings and settings fields. 8654 // If target is omitted, writes into ajaxSettings. 8655 ajaxSetup: function( target, settings ) { 8656 return settings ? 8657 8658 // Building a settings object 8659 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : 8660 8661 // Extending ajaxSettings 8662 ajaxExtend( jQuery.ajaxSettings, target ); 8663 }, 8664 8665 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), 8666 ajaxTransport: addToPrefiltersOrTransports( transports ), 8667 8668 // Main method 8669 ajax: function( url, options ) { 8670 8671 // If url is an object, simulate pre-1.5 signature 8672 if ( typeof url === "object" ) { 8673 options = url; 8674 url = undefined; 8675 } 8676 8677 // Force options to be an object 8678 options = options || {}; 8679 8680 var transport, 8681 8682 // URL without anti-cache param 8683 cacheURL, 8684 8685 // Response headers 8686 responseHeadersString, 8687 responseHeaders, 8688 8689 // timeout handle 8690 timeoutTimer, 8691 8692 // Url cleanup var 8693 urlAnchor, 8694 8695 // To know if global events are to be dispatched 8696 fireGlobals, 8697 8698 // Loop variable 8699 i, 8700 8701 // Create the final options object 8702 s = jQuery.ajaxSetup( {}, options ), 8703 8704 // Callbacks context 8705 callbackContext = s.context || s, 8706 8707 // Context for global events is callbackContext if it is a DOM node or jQuery collection 8708 globalEventContext = s.context && 8709 ( callbackContext.nodeType || callbackContext.jquery ) ? 8710 jQuery( callbackContext ) : 8711 jQuery.event, 8712 8713 // Deferreds 8714 deferred = jQuery.Deferred(), 8715 completeDeferred = jQuery.Callbacks( "once memory" ), 8716 8717 // Status-dependent callbacks 8718 statusCode = s.statusCode || {}, 8719 8720 // Headers (they are sent all at once) 8721 requestHeaders = {}, 8722 requestHeadersNames = {}, 8723 8724 // The jqXHR state 8725 state = 0, 8726 8727 // Default abort message 8728 strAbort = "canceled", 8729 8730 // Fake xhr 8731 jqXHR = { 8732 readyState: 0, 8733 8734 // Builds headers hashtable if needed 8735 getResponseHeader: function( key ) { 8736 var match; 8737 if ( state === 2 ) { 8738 if ( !responseHeaders ) { 8739 responseHeaders = {}; 8740 while ( ( match = rheaders.exec( responseHeadersString ) ) ) { 8741 responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; 8742 } 8743 } 8744 match = responseHeaders[ key.toLowerCase() ]; 8745 } 8746 return match == null ? null : match; 8747 }, 8748 8749 // Raw string 8750 getAllResponseHeaders: function() { 8751 return state === 2 ? responseHeadersString : null; 8752 }, 8753 8754 // Caches the header 8755 setRequestHeader: function( name, value ) { 8756 var lname = name.toLowerCase(); 8757 if ( !state ) { 8758 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; 8759 requestHeaders[ name ] = value; 8760 } 8761 return this; 8762 }, 8763 8764 // Overrides response content-type header 8765 overrideMimeType: function( type ) { 8766 if ( !state ) { 8767 s.mimeType = type; 8768 } 8769 return this; 8770 }, 8771 8772 // Status-dependent callbacks 8773 statusCode: function( map ) { 8774 var code; 8775 if ( map ) { 8776 if ( state < 2 ) { 8777 for ( code in map ) { 8778 8779 // Lazy-add the new callback in a way that preserves old ones 8780 statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; 8781 } 8782 } else { 8783 8784 // Execute the appropriate callbacks 8785 jqXHR.always( map[ jqXHR.status ] ); 8786 } 8787 } 8788 return this; 8789 }, 8790 8791 // Cancel the request 8792 abort: function( statusText ) { 8793 var finalText = statusText || strAbort; 8794 if ( transport ) { 8795 transport.abort( finalText ); 8796 } 8797 done( 0, finalText ); 8798 return this; 8799 } 8800 }; 8801 8802 // Attach deferreds 8803 deferred.promise( jqXHR ).complete = completeDeferred.add; 8804 jqXHR.success = jqXHR.done; 8805 jqXHR.error = jqXHR.fail; 8806 8807 // Remove hash character (#7531: and string promotion) 8808 // Add protocol if not provided (prefilters might expect it) 8809 // Handle falsy url in the settings object (#10093: consistency with old signature) 8810 // We also use the url parameter if available 8811 s.url = ( ( url || s.url || location.href ) + "" ).replace( rhash, "" ) 8812 .replace( rprotocol, location.protocol + "//" ); 8813 8814 // Alias method option to type as per ticket #12004 8815 s.type = options.method || options.type || s.method || s.type; 8816 8817 // Extract dataTypes list 8818 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; 8819 8820 // A cross-domain request is in order when the origin doesn't match the current origin. 8821 if ( s.crossDomain == null ) { 8822 urlAnchor = document.createElement( "a" ); 8823 8824 // Support: IE8-11+ 8825 // IE throws exception if url is malformed, e.g. http://example.com:80x/ 8826 try { 8827 urlAnchor.href = s.url; 8828 8829 // Support: IE8-11+ 8830 // Anchor's host property isn't correctly set when s.url is relative 8831 urlAnchor.href = urlAnchor.href; 8832 s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== 8833 urlAnchor.protocol + "//" + urlAnchor.host; 8834 } catch ( e ) { 8835 8836 // If there is an error parsing the URL, assume it is crossDomain, 8837 // it can be rejected by the transport if it is invalid 8838 s.crossDomain = true; 8839 } 8840 } 8841 8842 // Convert data if not already a string 8843 if ( s.data && s.processData && typeof s.data !== "string" ) { 8844 s.data = jQuery.param( s.data, s.traditional ); 8845 } 8846 8847 // Apply prefilters 8848 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); 8849 8850 // If request was aborted inside a prefilter, stop there 8851 if ( state === 2 ) { 8852 return jqXHR; 8853 } 8854 8855 // We can fire global events as of now if asked to 8856 // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) 8857 fireGlobals = jQuery.event && s.global; 8858 8859 // Watch for a new set of requests 8860 if ( fireGlobals && jQuery.active++ === 0 ) { 8861 jQuery.event.trigger( "ajaxStart" ); 8862 } 8863 8864 // Uppercase the type 8865 s.type = s.type.toUpperCase(); 8866 8867 // Determine if request has content 8868 s.hasContent = !rnoContent.test( s.type ); 8869 8870 // Save the URL in case we're toying with the If-Modified-Since 8871 // and/or If-None-Match header later on 8872 cacheURL = s.url; 8873 8874 // More options handling for requests with no content 8875 if ( !s.hasContent ) { 8876 8877 // If data is available, append data to url 8878 if ( s.data ) { 8879 cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data ); 8880 8881 // #9682: remove data so that it's not used in an eventual retry 8882 delete s.data; 8883 } 8884 8885 // Add anti-cache in url if needed 8886 if ( s.cache === false ) { 8887 s.url = rts.test( cacheURL ) ? 8888 8889 // If there is already a '_' parameter, set its value 8890 cacheURL.replace( rts, "$1_=" + nonce++ ) : 8891 8892 // Otherwise add one to the end 8893 cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++; 8894 } 8895 } 8896 8897 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 8898 if ( s.ifModified ) { 8899 if ( jQuery.lastModified[ cacheURL ] ) { 8900 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); 8901 } 8902 if ( jQuery.etag[ cacheURL ] ) { 8903 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); 8904 } 8905 } 8906 8907 // Set the correct header, if data is being sent 8908 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { 8909 jqXHR.setRequestHeader( "Content-Type", s.contentType ); 8910 } 8911 8912 // Set the Accepts header for the server, depending on the dataType 8913 jqXHR.setRequestHeader( 8914 "Accept", 8915 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? 8916 s.accepts[ s.dataTypes[ 0 ] ] + 8917 ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : 8918 s.accepts[ "*" ] 8919 ); 8920 8921 // Check for headers option 8922 for ( i in s.headers ) { 8923 jqXHR.setRequestHeader( i, s.headers[ i ] ); 8924 } 8925 8926 // Allow custom headers/mimetypes and early abort 8927 if ( s.beforeSend && 8928 ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { 8929 8930 // Abort if not done already and return 8931 return jqXHR.abort(); 8932 } 8933 8934 // Aborting is no longer a cancellation 8935 strAbort = "abort"; 8936 8937 // Install callbacks on deferreds 8938 for ( i in { success: 1, error: 1, complete: 1 } ) { 8939 jqXHR[ i ]( s[ i ] ); 8940 } 8941 8942 // Get transport 8943 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); 8944 8945 // If no transport, we auto-abort 8946 if ( !transport ) { 8947 done( -1, "No Transport" ); 8948 } else { 8949 jqXHR.readyState = 1; 8950 8951 // Send global event 8952 if ( fireGlobals ) { 8953 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); 8954 } 8955 8956 // If request was aborted inside ajaxSend, stop there 8957 if ( state === 2 ) { 8958 return jqXHR; 8959 } 8960 8961 // Timeout 8962 if ( s.async && s.timeout > 0 ) { 8963 timeoutTimer = window.setTimeout( function() { 8964 jqXHR.abort( "timeout" ); 8965 }, s.timeout ); 8966 } 8967 8968 try { 8969 state = 1; 8970 transport.send( requestHeaders, done ); 8971 } catch ( e ) { 8972 8973 // Propagate exception as error if not done 8974 if ( state < 2 ) { 8975 done( -1, e ); 8976 8977 // Simply rethrow otherwise 8978 } else { 8979 throw e; 8980 } 8981 } 8982 } 8983 8984 // Callback for when everything is done 8985 function done( status, nativeStatusText, responses, headers ) { 8986 var isSuccess, success, error, response, modified, 8987 statusText = nativeStatusText; 8988 8989 // Called once 8990 if ( state === 2 ) { 8991 return; 8992 } 8993 8994 // State is "done" now 8995 state = 2; 8996 8997 // Clear timeout if it exists 8998 if ( timeoutTimer ) { 8999 window.clearTimeout( timeoutTimer ); 9000 } 9001 9002 // Dereference transport for early garbage collection 9003 // (no matter how long the jqXHR object will be used) 9004 transport = undefined; 9005 9006 // Cache response headers 9007 responseHeadersString = headers || ""; 9008 9009 // Set readyState 9010 jqXHR.readyState = status > 0 ? 4 : 0; 9011 9012 // Determine if successful 9013 isSuccess = status >= 200 && status < 300 || status === 304; 9014 9015 // Get response data 9016 if ( responses ) { 9017 response = ajaxHandleResponses( s, jqXHR, responses ); 9018 } 9019 9020 // Convert no matter what (that way responseXXX fields are always set) 9021 response = ajaxConvert( s, response, jqXHR, isSuccess ); 9022 9023 // If successful, handle type chaining 9024 if ( isSuccess ) { 9025 9026 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9027 if ( s.ifModified ) { 9028 modified = jqXHR.getResponseHeader( "Last-Modified" ); 9029 if ( modified ) { 9030 jQuery.lastModified[ cacheURL ] = modified; 9031 } 9032 modified = jqXHR.getResponseHeader( "etag" ); 9033 if ( modified ) { 9034 jQuery.etag[ cacheURL ] = modified; 9035 } 9036 } 9037 9038 // if no content 9039 if ( status === 204 || s.type === "HEAD" ) { 9040 statusText = "nocontent"; 9041 9042 // if not modified 9043 } else if ( status === 304 ) { 9044 statusText = "notmodified"; 9045 9046 // If we have data, let's convert it 9047 } else { 9048 statusText = response.state; 9049 success = response.data; 9050 error = response.error; 9051 isSuccess = !error; 9052 } 9053 } else { 9054 9055 // Extract error from statusText and normalize for non-aborts 9056 error = statusText; 9057 if ( status || !statusText ) { 9058 statusText = "error"; 9059 if ( status < 0 ) { 9060 status = 0; 9061 } 9062 } 9063 } 9064 9065 // Set data for the fake xhr object 9066 jqXHR.status = status; 9067 jqXHR.statusText = ( nativeStatusText || statusText ) + ""; 9068 9069 // Success/Error 9070 if ( isSuccess ) { 9071 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); 9072 } else { 9073 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); 9074 } 9075 9076 // Status-dependent callbacks 9077 jqXHR.statusCode( statusCode ); 9078 statusCode = undefined; 9079 9080 if ( fireGlobals ) { 9081 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", 9082 [ jqXHR, s, isSuccess ? success : error ] ); 9083 } 9084 9085 // Complete 9086 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); 9087 9088 if ( fireGlobals ) { 9089 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); 9090 9091 // Handle the global AJAX counter 9092 if ( !( --jQuery.active ) ) { 9093 jQuery.event.trigger( "ajaxStop" ); 9094 } 9095 } 9096 } 9097 9098 return jqXHR; 9099 }, 9100 9101 getJSON: function( url, data, callback ) { 9102 return jQuery.get( url, data, callback, "json" ); 9103 }, 9104 9105 getScript: function( url, callback ) { 9106 return jQuery.get( url, undefined, callback, "script" ); 9107 } 9108} ); 9109 9110jQuery.each( [ "get", "post" ], function( i, method ) { 9111 jQuery[ method ] = function( url, data, callback, type ) { 9112 9113 // Shift arguments if data argument was omitted 9114 if ( jQuery.isFunction( data ) ) { 9115 type = type || callback; 9116 callback = data; 9117 data = undefined; 9118 } 9119 9120 // The url can be an options object (which then must have .url) 9121 return jQuery.ajax( jQuery.extend( { 9122 url: url, 9123 type: method, 9124 dataType: type, 9125 data: data, 9126 success: callback 9127 }, jQuery.isPlainObject( url ) && url ) ); 9128 }; 9129} ); 9130 9131 9132jQuery._evalUrl = function( url ) { 9133 return jQuery.ajax( { 9134 url: url, 9135 9136 // Make this explicit, since user can override this through ajaxSetup (#11264) 9137 type: "GET", 9138 dataType: "script", 9139 async: false, 9140 global: false, 9141 "throws": true 9142 } ); 9143}; 9144 9145 9146jQuery.fn.extend( { 9147 wrapAll: function( html ) { 9148 var wrap; 9149 9150 if ( jQuery.isFunction( html ) ) { 9151 return this.each( function( i ) { 9152 jQuery( this ).wrapAll( html.call( this, i ) ); 9153 } ); 9154 } 9155 9156 if ( this[ 0 ] ) { 9157 9158 // The elements to wrap the target around 9159 wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); 9160 9161 if ( this[ 0 ].parentNode ) { 9162 wrap.insertBefore( this[ 0 ] ); 9163 } 9164 9165 wrap.map( function() { 9166 var elem = this; 9167 9168 while ( elem.firstElementChild ) { 9169 elem = elem.firstElementChild; 9170 } 9171 9172 return elem; 9173 } ).append( this ); 9174 } 9175 9176 return this; 9177 }, 9178 9179 wrapInner: function( html ) { 9180 if ( jQuery.isFunction( html ) ) { 9181 return this.each( function( i ) { 9182 jQuery( this ).wrapInner( html.call( this, i ) ); 9183 } ); 9184 } 9185 9186 return this.each( function() { 9187 var self = jQuery( this ), 9188 contents = self.contents(); 9189 9190 if ( contents.length ) { 9191 contents.wrapAll( html ); 9192 9193 } else { 9194 self.append( html ); 9195 } 9196 } ); 9197 }, 9198 9199 wrap: function( html ) { 9200 var isFunction = jQuery.isFunction( html ); 9201 9202 return this.each( function( i ) { 9203 jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); 9204 } ); 9205 }, 9206 9207 unwrap: function() { 9208 return this.parent().each( function() { 9209 if ( !jQuery.nodeName( this, "body" ) ) { 9210 jQuery( this ).replaceWith( this.childNodes ); 9211 } 9212 } ).end(); 9213 } 9214} ); 9215 9216 9217jQuery.expr.filters.hidden = function( elem ) { 9218 return !jQuery.expr.filters.visible( elem ); 9219}; 9220jQuery.expr.filters.visible = function( elem ) { 9221 9222 // Support: Opera <= 12.12 9223 // Opera reports offsetWidths and offsetHeights less than zero on some elements 9224 // Use OR instead of AND as the element is not visible if either is true 9225 // See tickets #10406 and #13132 9226 return elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0; 9227}; 9228 9229 9230 9231 9232var r20 = /%20/g, 9233 rbracket = /\[\]$/, 9234 rCRLF = /\r?\n/g, 9235 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 9236 rsubmittable = /^(?:input|select|textarea|keygen)/i; 9237 9238function buildParams( prefix, obj, traditional, add ) { 9239 var name; 9240 9241 if ( jQuery.isArray( obj ) ) { 9242 9243 // Serialize array item. 9244 jQuery.each( obj, function( i, v ) { 9245 if ( traditional || rbracket.test( prefix ) ) { 9246 9247 // Treat each array item as a scalar. 9248 add( prefix, v ); 9249 9250 } else { 9251 9252 // Item is non-scalar (array or object), encode its numeric index. 9253 buildParams( 9254 prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", 9255 v, 9256 traditional, 9257 add 9258 ); 9259 } 9260 } ); 9261 9262 } else if ( !traditional && jQuery.type( obj ) === "object" ) { 9263 9264 // Serialize object item. 9265 for ( name in obj ) { 9266 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 9267 } 9268 9269 } else { 9270 9271 // Serialize scalar item. 9272 add( prefix, obj ); 9273 } 9274} 9275 9276// Serialize an array of form elements or a set of 9277// key/values into a query string 9278jQuery.param = function( a, traditional ) { 9279 var prefix, 9280 s = [], 9281 add = function( key, value ) { 9282 9283 // If value is a function, invoke it and return its value 9284 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); 9285 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); 9286 }; 9287 9288 // Set traditional to true for jQuery <= 1.3.2 behavior. 9289 if ( traditional === undefined ) { 9290 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; 9291 } 9292 9293 // If an array was passed in, assume that it is an array of form elements. 9294 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 9295 9296 // Serialize the form elements 9297 jQuery.each( a, function() { 9298 add( this.name, this.value ); 9299 } ); 9300 9301 } else { 9302 9303 // If traditional, encode the "old" way (the way 1.3.2 or older 9304 // did it), otherwise encode params recursively. 9305 for ( prefix in a ) { 9306 buildParams( prefix, a[ prefix ], traditional, add ); 9307 } 9308 } 9309 9310 // Return the resulting serialization 9311 return s.join( "&" ).replace( r20, "+" ); 9312}; 9313 9314jQuery.fn.extend( { 9315 serialize: function() { 9316 return jQuery.param( this.serializeArray() ); 9317 }, 9318 serializeArray: function() { 9319 return this.map( function() { 9320 9321 // Can add propHook for "elements" to filter or add form elements 9322 var elements = jQuery.prop( this, "elements" ); 9323 return elements ? jQuery.makeArray( elements ) : this; 9324 } ) 9325 .filter( function() { 9326 var type = this.type; 9327 9328 // Use .is( ":disabled" ) so that fieldset[disabled] works 9329 return this.name && !jQuery( this ).is( ":disabled" ) && 9330 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && 9331 ( this.checked || !rcheckableType.test( type ) ); 9332 } ) 9333 .map( function( i, elem ) { 9334 var val = jQuery( this ).val(); 9335 9336 return val == null ? 9337 null : 9338 jQuery.isArray( val ) ? 9339 jQuery.map( val, function( val ) { 9340 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9341 } ) : 9342 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 9343 } ).get(); 9344 } 9345} ); 9346 9347 9348jQuery.ajaxSettings.xhr = function() { 9349 try { 9350 return new window.XMLHttpRequest(); 9351 } catch ( e ) {} 9352}; 9353 9354var xhrSuccessStatus = { 9355 9356 // File protocol always yields status code 0, assume 200 9357 0: 200, 9358 9359 // Support: IE9 9360 // #1450: sometimes IE returns 1223 when it should be 204 9361 1223: 204 9362 }, 9363 xhrSupported = jQuery.ajaxSettings.xhr(); 9364 9365support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); 9366support.ajax = xhrSupported = !!xhrSupported; 9367 9368jQuery.ajaxTransport( function( options ) { 9369 var callback, errorCallback; 9370 9371 // Cross domain only allowed if supported through XMLHttpRequest 9372 if ( support.cors || xhrSupported && !options.crossDomain ) { 9373 return { 9374 send: function( headers, complete ) { 9375 var i, 9376 xhr = options.xhr(); 9377 9378 xhr.open( 9379 options.type, 9380 options.url, 9381 options.async, 9382 options.username, 9383 options.password 9384 ); 9385 9386 // Apply custom fields if provided 9387 if ( options.xhrFields ) { 9388 for ( i in options.xhrFields ) { 9389 xhr[ i ] = options.xhrFields[ i ]; 9390 } 9391 } 9392 9393 // Override mime type if needed 9394 if ( options.mimeType && xhr.overrideMimeType ) { 9395 xhr.overrideMimeType( options.mimeType ); 9396 } 9397 9398 // X-Requested-With header 9399 // For cross-domain requests, seeing as conditions for a preflight are 9400 // akin to a jigsaw puzzle, we simply never set it to be sure. 9401 // (it can always be set on a per-request basis or even using ajaxSetup) 9402 // For same-domain requests, won't change header if already provided. 9403 if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { 9404 headers[ "X-Requested-With" ] = "XMLHttpRequest"; 9405 } 9406 9407 // Set headers 9408 for ( i in headers ) { 9409 xhr.setRequestHeader( i, headers[ i ] ); 9410 } 9411 9412 // Callback 9413 callback = function( type ) { 9414 return function() { 9415 if ( callback ) { 9416 callback = errorCallback = xhr.onload = 9417 xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; 9418 9419 if ( type === "abort" ) { 9420 xhr.abort(); 9421 } else if ( type === "error" ) { 9422 9423 // Support: IE9 9424 // On a manual native abort, IE9 throws 9425 // errors on any property access that is not readyState 9426 if ( typeof xhr.status !== "number" ) { 9427 complete( 0, "error" ); 9428 } else { 9429 complete( 9430 9431 // File: protocol always yields status 0; see #8605, #14207 9432 xhr.status, 9433 xhr.statusText 9434 ); 9435 } 9436 } else { 9437 complete( 9438 xhrSuccessStatus[ xhr.status ] || xhr.status, 9439 xhr.statusText, 9440 9441 // Support: IE9 only 9442 // IE9 has no XHR2 but throws on binary (trac-11426) 9443 // For XHR2 non-text, let the caller handle it (gh-2498) 9444 ( xhr.responseType || "text" ) !== "text" || 9445 typeof xhr.responseText !== "string" ? 9446 { binary: xhr.response } : 9447 { text: xhr.responseText }, 9448 xhr.getAllResponseHeaders() 9449 ); 9450 } 9451 } 9452 }; 9453 }; 9454 9455 // Listen to events 9456 xhr.onload = callback(); 9457 errorCallback = xhr.onerror = callback( "error" ); 9458 9459 // Support: IE9 9460 // Use onreadystatechange to replace onabort 9461 // to handle uncaught aborts 9462 if ( xhr.onabort !== undefined ) { 9463 xhr.onabort = errorCallback; 9464 } else { 9465 xhr.onreadystatechange = function() { 9466 9467 // Check readyState before timeout as it changes 9468 if ( xhr.readyState === 4 ) { 9469 9470 // Allow onerror to be called first, 9471 // but that will not handle a native abort 9472 // Also, save errorCallback to a variable 9473 // as xhr.onerror cannot be accessed 9474 window.setTimeout( function() { 9475 if ( callback ) { 9476 errorCallback(); 9477 } 9478 } ); 9479 } 9480 }; 9481 } 9482 9483 // Create the abort callback 9484 callback = callback( "abort" ); 9485 9486 try { 9487 9488 // Do send the request (this may raise an exception) 9489 xhr.send( options.hasContent && options.data || null ); 9490 } catch ( e ) { 9491 9492 // #14683: Only rethrow if this hasn't been notified as an error yet 9493 if ( callback ) { 9494 throw e; 9495 } 9496 } 9497 }, 9498 9499 abort: function() { 9500 if ( callback ) { 9501 callback(); 9502 } 9503 } 9504 }; 9505 } 9506} ); 9507 9508 9509 9510 9511// Install script dataType 9512jQuery.ajaxSetup( { 9513 accepts: { 9514 script: "text/javascript, application/javascript, " + 9515 "application/ecmascript, application/x-ecmascript" 9516 }, 9517 contents: { 9518 script: /\b(?:java|ecma)script\b/ 9519 }, 9520 converters: { 9521 "text script": function( text ) { 9522 jQuery.globalEval( text ); 9523 return text; 9524 } 9525 } 9526} ); 9527 9528// Handle cache's special case and crossDomain 9529jQuery.ajaxPrefilter( "script", function( s ) { 9530 if ( s.cache === undefined ) { 9531 s.cache = false; 9532 } 9533 if ( s.crossDomain ) { 9534 s.type = "GET"; 9535 } 9536} ); 9537 9538// Bind script tag hack transport 9539jQuery.ajaxTransport( "script", function( s ) { 9540 9541 // This transport only deals with cross domain requests 9542 if ( s.crossDomain ) { 9543 var script, callback; 9544 return { 9545 send: function( _, complete ) { 9546 script = jQuery( "<script>" ).prop( { 9547 charset: s.scriptCharset, 9548 src: s.url 9549 } ).on( 9550 "load error", 9551 callback = function( evt ) { 9552 script.remove(); 9553 callback = null; 9554 if ( evt ) { 9555 complete( evt.type === "error" ? 404 : 200, evt.type ); 9556 } 9557 } 9558 ); 9559 9560 // Use native DOM manipulation to avoid our domManip AJAX trickery 9561 document.head.appendChild( script[ 0 ] ); 9562 }, 9563 abort: function() { 9564 if ( callback ) { 9565 callback(); 9566 } 9567 } 9568 }; 9569 } 9570} ); 9571 9572 9573 9574 9575var oldCallbacks = [], 9576 rjsonp = /(=)\?(?=&|$)|\?\?/; 9577 9578// Default jsonp settings 9579jQuery.ajaxSetup( { 9580 jsonp: "callback", 9581 jsonpCallback: function() { 9582 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); 9583 this[ callback ] = true; 9584 return callback; 9585 } 9586} ); 9587 9588// Detect, normalize options and install callbacks for jsonp requests 9589jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 9590 9591 var callbackName, overwritten, responseContainer, 9592 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 9593 "url" : 9594 typeof s.data === "string" && 9595 ( s.contentType || "" ) 9596 .indexOf( "application/x-www-form-urlencoded" ) === 0 && 9597 rjsonp.test( s.data ) && "data" 9598 ); 9599 9600 // Handle iff the expected data type is "jsonp" or we have a parameter to set 9601 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 9602 9603 // Get callback name, remembering preexisting value associated with it 9604 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? 9605 s.jsonpCallback() : 9606 s.jsonpCallback; 9607 9608 // Insert callback into url or form data 9609 if ( jsonProp ) { 9610 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 9611 } else if ( s.jsonp !== false ) { 9612 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 9613 } 9614 9615 // Use data converter to retrieve json after script execution 9616 s.converters[ "script json" ] = function() { 9617 if ( !responseContainer ) { 9618 jQuery.error( callbackName + " was not called" ); 9619 } 9620 return responseContainer[ 0 ]; 9621 }; 9622 9623 // Force json dataType 9624 s.dataTypes[ 0 ] = "json"; 9625 9626 // Install callback 9627 overwritten = window[ callbackName ]; 9628 window[ callbackName ] = function() { 9629 responseContainer = arguments; 9630 }; 9631 9632 // Clean-up function (fires after converters) 9633 jqXHR.always( function() { 9634 9635 // If previous value didn't exist - remove it 9636 if ( overwritten === undefined ) { 9637 jQuery( window ).removeProp( callbackName ); 9638 9639 // Otherwise restore preexisting value 9640 } else { 9641 window[ callbackName ] = overwritten; 9642 } 9643 9644 // Save back as free 9645 if ( s[ callbackName ] ) { 9646 9647 // Make sure that re-using the options doesn't screw things around 9648 s.jsonpCallback = originalSettings.jsonpCallback; 9649 9650 // Save the callback name for future use 9651 oldCallbacks.push( callbackName ); 9652 } 9653 9654 // Call if it was a function and we have a response 9655 if ( responseContainer && jQuery.isFunction( overwritten ) ) { 9656 overwritten( responseContainer[ 0 ] ); 9657 } 9658 9659 responseContainer = overwritten = undefined; 9660 } ); 9661 9662 // Delegate to script 9663 return "script"; 9664 } 9665} ); 9666 9667 9668 9669 9670// Argument "data" should be string of html 9671// context (optional): If specified, the fragment will be created in this context, 9672// defaults to document 9673// keepScripts (optional): If true, will include scripts passed in the html string 9674jQuery.parseHTML = function( data, context, keepScripts ) { 9675 if ( !data || typeof data !== "string" ) { 9676 return null; 9677 } 9678 if ( typeof context === "boolean" ) { 9679 keepScripts = context; 9680 context = false; 9681 } 9682 context = context || document; 9683 9684 var parsed = rsingleTag.exec( data ), 9685 scripts = !keepScripts && []; 9686 9687 // Single tag 9688 if ( parsed ) { 9689 return [ context.createElement( parsed[ 1 ] ) ]; 9690 } 9691 9692 parsed = buildFragment( [ data ], context, scripts ); 9693 9694 if ( scripts && scripts.length ) { 9695 jQuery( scripts ).remove(); 9696 } 9697 9698 return jQuery.merge( [], parsed.childNodes ); 9699}; 9700 9701 9702// Keep a copy of the old load method 9703var _load = jQuery.fn.load; 9704 9705/** 9706 * Load a url into a page 9707 */ 9708jQuery.fn.load = function( url, params, callback ) { 9709 if ( typeof url !== "string" && _load ) { 9710 return _load.apply( this, arguments ); 9711 } 9712 9713 var selector, type, response, 9714 self = this, 9715 off = url.indexOf( " " ); 9716 9717 if ( off > -1 ) { 9718 selector = jQuery.trim( url.slice( off ) ); 9719 url = url.slice( 0, off ); 9720 } 9721 9722 // If it's a function 9723 if ( jQuery.isFunction( params ) ) { 9724 9725 // We assume that it's the callback 9726 callback = params; 9727 params = undefined; 9728 9729 // Otherwise, build a param string 9730 } else if ( params && typeof params === "object" ) { 9731 type = "POST"; 9732 } 9733 9734 // If we have elements to modify, make the request 9735 if ( self.length > 0 ) { 9736 jQuery.ajax( { 9737 url: url, 9738 9739 // If "type" variable is undefined, then "GET" method will be used. 9740 // Make value of this field explicit since 9741 // user can override it through ajaxSetup method 9742 type: type || "GET", 9743 dataType: "html", 9744 data: params 9745 } ).done( function( responseText ) { 9746 9747 // Save response for use in complete callback 9748 response = arguments; 9749 9750 self.html( selector ? 9751 9752 // If a selector was specified, locate the right elements in a dummy div 9753 // Exclude scripts to avoid IE 'Permission Denied' errors 9754 jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : 9755 9756 // Otherwise use the full result 9757 responseText ); 9758 9759 // If the request succeeds, this function gets "data", "status", "jqXHR" 9760 // but they are ignored because response was set above. 9761 // If it fails, this function gets "jqXHR", "status", "error" 9762 } ).always( callback && function( jqXHR, status ) { 9763 self.each( function() { 9764 callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); 9765 } ); 9766 } ); 9767 } 9768 9769 return this; 9770}; 9771 9772 9773 9774 9775// Attach a bunch of functions for handling common AJAX events 9776jQuery.each( [ 9777 "ajaxStart", 9778 "ajaxStop", 9779 "ajaxComplete", 9780 "ajaxError", 9781 "ajaxSuccess", 9782 "ajaxSend" 9783], function( i, type ) { 9784 jQuery.fn[ type ] = function( fn ) { 9785 return this.on( type, fn ); 9786 }; 9787} ); 9788 9789 9790 9791 9792jQuery.expr.filters.animated = function( elem ) { 9793 return jQuery.grep( jQuery.timers, function( fn ) { 9794 return elem === fn.elem; 9795 } ).length; 9796}; 9797 9798 9799 9800 9801/** 9802 * Gets a window from an element 9803 */ 9804function getWindow( elem ) { 9805 return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView; 9806} 9807 9808jQuery.offset = { 9809 setOffset: function( elem, options, i ) { 9810 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, 9811 position = jQuery.css( elem, "position" ), 9812 curElem = jQuery( elem ), 9813 props = {}; 9814 9815 // Set position first, in-case top/left are set even on static elem 9816 if ( position === "static" ) { 9817 elem.style.position = "relative"; 9818 } 9819 9820 curOffset = curElem.offset(); 9821 curCSSTop = jQuery.css( elem, "top" ); 9822 curCSSLeft = jQuery.css( elem, "left" ); 9823 calculatePosition = ( position === "absolute" || position === "fixed" ) && 9824 ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1; 9825 9826 // Need to be able to calculate position if either 9827 // top or left is auto and position is either absolute or fixed 9828 if ( calculatePosition ) { 9829 curPosition = curElem.position(); 9830 curTop = curPosition.top; 9831 curLeft = curPosition.left; 9832 9833 } else { 9834 curTop = parseFloat( curCSSTop ) || 0; 9835 curLeft = parseFloat( curCSSLeft ) || 0; 9836 } 9837 9838 if ( jQuery.isFunction( options ) ) { 9839 9840 // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) 9841 options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); 9842 } 9843 9844 if ( options.top != null ) { 9845 props.top = ( options.top - curOffset.top ) + curTop; 9846 } 9847 if ( options.left != null ) { 9848 props.left = ( options.left - curOffset.left ) + curLeft; 9849 } 9850 9851 if ( "using" in options ) { 9852 options.using.call( elem, props ); 9853 9854 } else { 9855 curElem.css( props ); 9856 } 9857 } 9858}; 9859 9860jQuery.fn.extend( { 9861 offset: function( options ) { 9862 if ( arguments.length ) { 9863 return options === undefined ? 9864 this : 9865 this.each( function( i ) { 9866 jQuery.offset.setOffset( this, options, i ); 9867 } ); 9868 } 9869 9870 var docElem, win, 9871 elem = this[ 0 ], 9872 box = { top: 0, left: 0 }, 9873 doc = elem && elem.ownerDocument; 9874 9875 if ( !doc ) { 9876 return; 9877 } 9878 9879 docElem = doc.documentElement; 9880 9881 // Make sure it's not a disconnected DOM node 9882 if ( !jQuery.contains( docElem, elem ) ) { 9883 return box; 9884 } 9885 9886 box = elem.getBoundingClientRect(); 9887 win = getWindow( doc ); 9888 return { 9889 top: box.top + win.pageYOffset - docElem.clientTop, 9890 left: box.left + win.pageXOffset - docElem.clientLeft 9891 }; 9892 }, 9893 9894 position: function() { 9895 if ( !this[ 0 ] ) { 9896 return; 9897 } 9898 9899 var offsetParent, offset, 9900 elem = this[ 0 ], 9901 parentOffset = { top: 0, left: 0 }; 9902 9903 // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, 9904 // because it is its only offset parent 9905 if ( jQuery.css( elem, "position" ) === "fixed" ) { 9906 9907 // Assume getBoundingClientRect is there when computed position is fixed 9908 offset = elem.getBoundingClientRect(); 9909 9910 } else { 9911 9912 // Get *real* offsetParent 9913 offsetParent = this.offsetParent(); 9914 9915 // Get correct offsets 9916 offset = this.offset(); 9917 if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) { 9918 parentOffset = offsetParent.offset(); 9919 } 9920 9921 // Add offsetParent borders 9922 parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ); 9923 parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ); 9924 } 9925 9926 // Subtract parent offsets and element margins 9927 return { 9928 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), 9929 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) 9930 }; 9931 }, 9932 9933 // This method will return documentElement in the following cases: 9934 // 1) For the element inside the iframe without offsetParent, this method will return 9935 // documentElement of the parent window 9936 // 2) For the hidden or detached element 9937 // 3) For body or html element, i.e. in case of the html node - it will return itself 9938 // 9939 // but those exceptions were never presented as a real life use-cases 9940 // and might be considered as more preferable results. 9941 // 9942 // This logic, however, is not guaranteed and can change at any point in the future 9943 offsetParent: function() { 9944 return this.map( function() { 9945 var offsetParent = this.offsetParent; 9946 9947 while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) { 9948 offsetParent = offsetParent.offsetParent; 9949 } 9950 9951 return offsetParent || documentElement; 9952 } ); 9953 } 9954} ); 9955 9956// Create scrollLeft and scrollTop methods 9957jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { 9958 var top = "pageYOffset" === prop; 9959 9960 jQuery.fn[ method ] = function( val ) { 9961 return access( this, function( elem, method, val ) { 9962 var win = getWindow( elem ); 9963 9964 if ( val === undefined ) { 9965 return win ? win[ prop ] : elem[ method ]; 9966 } 9967 9968 if ( win ) { 9969 win.scrollTo( 9970 !top ? val : win.pageXOffset, 9971 top ? val : win.pageYOffset 9972 ); 9973 9974 } else { 9975 elem[ method ] = val; 9976 } 9977 }, method, val, arguments.length ); 9978 }; 9979} ); 9980 9981// Support: Safari<7-8+, Chrome<37-44+ 9982// Add the top/left cssHooks using jQuery.fn.position 9983// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 9984// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280 9985// getComputedStyle returns percent when specified for top/left/bottom/right; 9986// rather than make the css module depend on the offset module, just check for it here 9987jQuery.each( [ "top", "left" ], function( i, prop ) { 9988 jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, 9989 function( elem, computed ) { 9990 if ( computed ) { 9991 computed = curCSS( elem, prop ); 9992 9993 // If curCSS returns percentage, fallback to offset 9994 return rnumnonpx.test( computed ) ? 9995 jQuery( elem ).position()[ prop ] + "px" : 9996 computed; 9997 } 9998 } 9999 ); 10000} ); 10001 10002 10003// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods 10004jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { 10005 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, 10006 function( defaultExtra, funcName ) { 10007 10008 // Margin is only for outerHeight, outerWidth 10009 jQuery.fn[ funcName ] = function( margin, value ) { 10010 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), 10011 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); 10012 10013 return access( this, function( elem, type, value ) { 10014 var doc; 10015 10016 if ( jQuery.isWindow( elem ) ) { 10017 10018 // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there 10019 // isn't a whole lot we can do. See pull request at this URL for discussion: 10020 // https://github.com/jquery/jquery/pull/764 10021 return elem.document.documentElement[ "client" + name ]; 10022 } 10023 10024 // Get document width or height 10025 if ( elem.nodeType === 9 ) { 10026 doc = elem.documentElement; 10027 10028 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], 10029 // whichever is greatest 10030 return Math.max( 10031 elem.body[ "scroll" + name ], doc[ "scroll" + name ], 10032 elem.body[ "offset" + name ], doc[ "offset" + name ], 10033 doc[ "client" + name ] 10034 ); 10035 } 10036 10037 return value === undefined ? 10038 10039 // Get width or height on the element, requesting but not forcing parseFloat 10040 jQuery.css( elem, type, extra ) : 10041 10042 // Set width or height on the element 10043 jQuery.style( elem, type, value, extra ); 10044 }, type, chainable ? margin : undefined, chainable, null ); 10045 }; 10046 } ); 10047} ); 10048 10049 10050jQuery.fn.extend( { 10051 10052 bind: function( types, data, fn ) { 10053 return this.on( types, null, data, fn ); 10054 }, 10055 unbind: function( types, fn ) { 10056 return this.off( types, null, fn ); 10057 }, 10058 10059 delegate: function( selector, types, data, fn ) { 10060 return this.on( types, selector, data, fn ); 10061 }, 10062 undelegate: function( selector, types, fn ) { 10063 10064 // ( namespace ) or ( selector, types [, fn] ) 10065 return arguments.length === 1 ? 10066 this.off( selector, "**" ) : 10067 this.off( types, selector || "**", fn ); 10068 }, 10069 size: function() { 10070 return this.length; 10071 } 10072} ); 10073 10074jQuery.fn.andSelf = jQuery.fn.addBack; 10075 10076 10077 10078 10079// Register as a named AMD module, since jQuery can be concatenated with other 10080// files that may use define, but not via a proper concatenation script that 10081// understands anonymous AMD modules. A named AMD is safest and most robust 10082// way to register. Lowercase jquery is used because AMD module names are 10083// derived from file names, and jQuery is normally delivered in a lowercase 10084// file name. Do this after creating the global so that if an AMD module wants 10085// to call noConflict to hide this version of jQuery, it will work. 10086 10087// Note that for maximum portability, libraries that are not jQuery should 10088// declare themselves as anonymous modules, and avoid setting a global if an 10089// AMD loader is present. jQuery is a special case. For more information, see 10090// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon 10091 10092if ( typeof define === "function" && define.amd ) { 10093 define( "jquery", [], function() { 10094 return jQuery; 10095 } ); 10096} 10097 10098 10099 10100var 10101 10102 // Map over jQuery in case of overwrite 10103 _jQuery = window.jQuery, 10104 10105 // Map over the $ in case of overwrite 10106 _$ = window.$; 10107 10108jQuery.noConflict = function( deep ) { 10109 if ( window.$ === jQuery ) { 10110 window.$ = _$; 10111 } 10112 10113 if ( deep && window.jQuery === jQuery ) { 10114 window.jQuery = _jQuery; 10115 } 10116 10117 return jQuery; 10118}; 10119 10120// Expose jQuery and $ identifiers, even in AMD 10121// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) 10122// and CommonJS for browser emulators (#13566) 10123if ( !noGlobal ) { 10124 window.jQuery = window.$ = jQuery; 10125} 10126 10127return jQuery; 10128})); 10129
10130;;(function() { 10131/*! 10132 * @overview Ember - JavaScript Application Framework 10133 * @copyright Copyright 2011-2016 Tilde Inc. and contributors 10134 * Portions Copyright 2006-2011 Strobe Inc. 10135 * Portions Copyright 2008-2011 Apple Inc. All rights reserved. 10136 * @license Licensed under MIT license 10137 * See https://raw.github.com/emberjs/ember.js/master/LICENSE 10138 * @version 2.5.1 10139 */ 10140 10141var enifed, requireModule, require, requirejs, Ember; 10142var mainContext = this; 10143 10144(function() { 10145 var isNode = typeof window === 'undefined' && 10146 typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; 10147 10148 if (!isNode) { 10149 Ember = this.Ember = this.Ember || {}; 10150 } 10151 10152 if (typeof Ember === 'undefined') { Ember = {}; }; 10153 10154 if (typeof Ember.__loader === 'undefined') { 10155 var registry = {}; 10156 var seen = {}; 10157 10158 enifed = function(name, deps, callback) { 10159 var value = { }; 10160 10161 if (!callback) { 10162 value.deps = []; 10163 value.callback = deps; 10164 } else { 10165 value.deps = deps; 10166 value.callback = callback; 10167 } 10168 10169 registry[name] = value; 10170 }; 10171 10172 requirejs = require = requireModule = function(name) { 10173 return internalRequire(name, null); 10174 } 10175 10176 // setup `require` module 10177 require['default'] = require; 10178 10179 require.has = function registryHas(moduleName) { 10180 return !!registry[moduleName] || !!registry[moduleName + '/index']; 10181 }; 10182 10183 function missingModule(name, referrerName) { 10184 if (referrerName) { 10185 throw new Error('Could not find module ' + name + ' required by: ' + referrerName); 10186 } else { 10187 throw new Error('Could not find module ' + name); 10188 } 10189 } 10190 10191 function internalRequire(_name, referrerName) { 10192 var name = _name; 10193 var mod = registry[name]; 10194 10195 if (!mod) { 10196 name = name + '/index'; 10197 mod = registry[name]; 10198 } 10199 10200 var exports = seen[name]; 10201 10202 if (exports !== undefined) { 10203 return exports; 10204 } 10205 10206 exports = seen[name] = {}; 10207 10208 if (!mod) { 10209 missingModule(_name, referrerName); 10210 } 10211 10212 var deps = mod.deps; 10213 var callback = mod.callback; 10214 var length = deps.length; 10215 var reified = new Array(length);; 10216 10217 for (var i = 0; i < length; i++) { 10218 if (deps[i] === 'exports') { 10219 reified[i] = exports; 10220 } else if (deps[i] === 'require') { 10221 reified[i] = require; 10222 } else { 10223 reified[i] = internalRequire(deps[i], name); 10224 } 10225 } 10226 10227 callback.apply(this, reified); 10228 10229 return exports; 10230 }; 10231 10232 requirejs._eak_seen = registry; 10233 10234 Ember.__loader = { 10235 define: enifed, 10236 require: require, 10237 registry: registry 10238 }; 10239 } else { 10240 enifed = Ember.__loader.define; 10241 requirejs = require = requireModule = Ember.__loader.require; 10242 } 10243})(); 10244 10245enifed("backburner/binary-search", ["exports"], function (exports) { 10246 "use strict"; 10247 10248 exports.default = binarySearch; 10249 10250 function binarySearch(time, timers) { 10251 var start = 0; 10252 var end = timers.length - 2; 10253 var middle, l; 10254 10255 while (start < end) { 10256 // since timers is an array of pairs 'l' will always 10257 // be an integer 10258 l = (end - start) / 2; 10259 10260 // compensate for the index in case even number 10261 // of pairs inside timers 10262 middle = start + l - l % 2; 10263 10264 if (time >= timers[middle]) { 10265 start = middle + 2; 10266 } else { 10267 end = middle; 10268 } 10269 } 10270 10271 return time >= timers[start] ? start + 2 : start; 10272 } 10273}); 10274enifed('backburner/deferred-action-queues', ['exports', 'backburner/utils', 'backburner/queue'], function (exports, _backburnerUtils, _backburnerQueue) { 10275 'use strict'; 10276 10277 exports.default = DeferredActionQueues; 10278 10279 function DeferredActionQueues(queueNames, options) { 10280 var queues = this.queues = {}; 10281 this.queueNames = queueNames = queueNames || []; 10282 10283 this.options = options; 10284 10285 _backburnerUtils.each(queueNames, function (queueName) { 10286 queues[queueName] = new _backburnerQueue.default(queueName, options[queueName], options); 10287 }); 10288 } 10289 10290 function noSuchQueue(name) { 10291 throw new Error('You attempted to schedule an action in a queue (' + name + ') that doesn\'t exist'); 10292 } 10293 10294 function noSuchMethod(name) { 10295 throw new Error('You attempted to schedule an action in a queue (' + name + ') for a method that doesn\'t exist'); 10296 } 10297 10298 DeferredActionQueues.prototype = { 10299 schedule: function (name, target, method, args, onceFlag, stack) { 10300 var queues = this.queues; 10301 var queue = queues[name]; 10302 10303 if (!queue) { 10304 noSuchQueue(name); 10305 } 10306
10307 if (!method) { 10308 noSuchMethod(name); 10309 } 10310 10311 if (onceFlag) { 10312 return queue.pushUnique(target, method, args, stack); 10313 } else { 10314 return queue.push(target, method, args, stack); 10315 } 10316 }, 10317 10318 flush: function () { 10319 var queues = this.queues; 10320 var queueNames = this.queueNames; 10321 var queueName, queue; 10322 var queueNameIndex = 0; 10323 var numberOfQueues = queueNames.length; 10324 10325 while (queueNameIndex < numberOfQueues) { 10326 queueName = queueNames[queueNameIndex]; 10327 queue = queues[queueName]; 10328 10329 var numberOfQueueItems = queue._queue.length; 10330 10331 if (numberOfQueueItems === 0) { 10332 queueNameIndex++; 10333 } else { 10334 queue.flush(false /* async */); 10335 queueNameIndex = 0; 10336 } 10337 } 10338 } 10339 }; 10340}); 10341enifed('backburner/platform', ['exports'], function (exports) { 10342 'use strict'; 10343 10344 var GlobalContext; 10345 10346 /* global self */ 10347 if (typeof self === 'object') { 10348 GlobalContext = self; 10349 10350 /* global global */ 10351 } else if (typeof global === 'object') { 10352 GlobalContext = global; 10353 10354 /* global window */ 10355 } else if (typeof window === 'object') { 10356 GlobalContext = window; 10357 } else { 10358 throw new Error('no global: `self`, `global` nor `window` was found'); 10359 } 10360 10361 exports.default = GlobalContext; 10362}); 10363enifed('backburner/queue', ['exports', 'backburner/utils'], function (exports, _backburnerUtils) { 10364 'use strict'; 10365 10366 exports.default = Queue; 10367 10368 function Queue(name, options, globalOptions) { 10369 this.name = name; 10370 this.globalOptions = globalOptions || {}; 10371 this.options = options; 10372 this._queue = []; 10373 this.targetQueues = {}; 10374 this._queueBeingFlushed = undefined; 10375 } 10376 10377 Queue.prototype = { 10378 push: function (target, method, args, stack) { 10379 var queue = this._queue; 10380 queue.push(target, method, args, stack); 10381 10382 return { 10383 queue: this, 10384 target: target, 10385 method: method 10386 }; 10387 }, 10388 10389 pushUniqueWithoutGuid: function (target, method, args, stack) { 10390 var queue = this._queue; 10391 10392 for (var i = 0, l = queue.length; i < l; i += 4) { 10393 var currentTarget = queue[i]; 10394 var currentMethod = queue[i + 1]; 10395 10396 if (currentTarget === target && currentMethod === method) { 10397 queue[i + 2] = args; // replace args 10398 queue[i + 3] = stack; // replace stack 10399 return; 10400 } 10401 } 10402 10403 queue.push(target, method, args, stack); 10404 }, 10405 10406 targetQueue: function (targetQueue, target, method, args, stack) { 10407 var queue = this._queue; 10408 10409 for (var i = 0, l = targetQueue.length; i < l; i += 2) { 10410 var currentMethod = targetQueue[i]; 10411 var currentIndex = targetQueue[i + 1]; 10412 10413 if (currentMethod === method) { 10414 queue[currentIndex + 2] = args; // replace args 10415 queue[currentIndex + 3] = stack; // replace stack 10416 return; 10417 } 10418 } 10419 10420 targetQueue.push(method, queue.push(target, method, args, stack) - 4); 10421 }, 10422 10423 pushUniqueWithGuid: function (guid, target, method, args, stack) { 10424 var hasLocalQueue = this.targetQueues[guid]; 10425 10426 if (hasLocalQueue) { 10427 this.targetQueue(hasLocalQueue, target, method, args, stack); 10428 } else { 10429 this.targetQueues[guid] = [method, this._queue.push(target, method, args, stack) - 4]; 10430 } 10431 10432 return { 10433 queue: this, 10434 target: target, 10435 method: method 10436 }; 10437 }, 10438 10439 pushUnique: function (target, method, args, stack) { 10440 var KEY = this.globalOptions.GUID_KEY; 10441 10442 if (target && KEY) { 10443 var guid = target[KEY]; 10444 if (guid) { 10445 return this.pushUniqueWithGuid(guid, target, method, args, stack); 10446 } 10447 } 10448 10449 this.pushUniqueWithoutGuid(target, method, args, stack); 10450 10451 return { 10452 queue: this, 10453 target: target, 10454 method: method 10455 }; 10456 }, 10457 10458 invoke: function (target, method, args, _, _errorRecordedForStack) { 10459 if (args && args.length > 0) { 10460 method.apply(target, args); 10461 } else { 10462 method.call(target); 10463 } 10464 }, 10465 10466 invokeWithOnError: function (target, method, args, onError, errorRecordedForStack) {
10467 try { 10468 if (args && args.length > 0) { 10469 method.apply(target, args); 10470 } else { 10471 method.call(target); 10472 } 10473 } catch (error) { 10474 onError(error, errorRecordedForStack); 10475 } 10476 }, 10477 10478 flush: function (sync) { 10479 var queue = this._queue; 10480 var length = queue.length; 10481 10482 if (length === 0) { 10483 return; 10484 } 10485 10486 var globalOptions = this.globalOptions; 10487 var options = this.options; 10488 var before = options && options.before; 10489 var after = options && options.after; 10490 var onError = globalOptions.onError || globalOptions.onErrorTarget && globalOptions.onErrorTarget[globalOptions.onErrorMethod]; 10491 var target, method, args, errorRecordedForStack; 10492 var invoke = onError ? this.invokeWithOnError : this.invoke; 10493 10494 this.targetQueues = Object.create(null); 10495 var queueItems = this._queueBeingFlushed = this._queue.slice(); 10496 this._queue = []; 10497 10498 if (before) { 10499 before(); 10500 } 10501 10502 for (var i = 0; i < length; i += 4) { 10503 target = queueItems[i]; 10504 method = queueItems[i + 1]; 10505 args = queueItems[i + 2]; 10506 errorRecordedForStack = queueItems[i + 3]; // Debugging assistance 10507 10508 if (_backburnerUtils.isString(method)) { 10509 method = target[method]; 10510 } 10511 10512 // method could have been nullified / canceled during flush 10513 if (method) { 10514 // 10515 // ** Attention intrepid developer ** 10516 // 10517 // To find out the stack of this task when it was scheduled onto 10518 // the run loop, add the following to your app.js: 10519 // 10520 // Ember.run.backburner.DEBUG = true; // NOTE: This slows your app, don't leave it on in production. 10521 // 10522 // Once that is in place, when you are at a breakpoint and navigate 10523 // here in the stack explorer, you can look at `errorRecordedForStack.stack`, 10524 // which will be the captured stack when this job was scheduled. 10525 // 10526 invoke(target, method, args, onError, errorRecordedForStack); 10527 } 10528 } 10529 10530 if (after) { 10531 after(); 10532 } 10533 10534 this._queueBeingFlushed = undefined; 10535 10536 if (sync !== false && this._queue.length > 0) { 10537 // check if new items have been added 10538 this.flush(true); 10539 } 10540 }, 10541 10542 cancel: function (actionToCancel) { 10543 var queue = this._queue, 10544 currentTarget, 10545 currentMethod, 10546 i, 10547 l; 10548 var target = actionToCancel.target; 10549 var method = actionToCancel.method; 10550 var GUID_KEY = this.globalOptions.GUID_KEY; 10551 10552 if (GUID_KEY && this.targetQueues && target) { 10553 var targetQueue = this.targetQueues[target[GUID_KEY]]; 10554 10555 if (targetQueue) { 10556 for (i = 0, l = targetQueue.length; i < l; i++) { 10557 if (targetQueue[i] === method) { 10558 targetQueue.splice(i, 1); 10559 } 10560 } 10561 } 10562 } 10563 10564 for (i = 0, l = queue.length; i < l; i += 4) { 10565 currentTarget = queue[i]; 10566 currentMethod = queue[i + 1]; 10567 10568 if (currentTarget === target && currentMethod === method) { 10569 queue.splice(i, 4); 10570 return true; 10571 } 10572 } 10573 10574 // if not found in current queue 10575 // could be in the queue that is being flushed 10576 queue = this._queueBeingFlushed; 10577 10578 if (!queue) { 10579 return; 10580 } 10581 10582 for (i = 0, l = queue.length; i < l; i += 4) { 10583 currentTarget = queue[i]; 10584 currentMethod = queue[i + 1]; 10585 10586 if (currentTarget === target && currentMethod === method) { 10587 // don't mess with array during flush 10588 // just nullify the method 10589 queue[i + 1] = null; 10590 return true; 10591 } 10592 } 10593 } 10594 }; 10595}); 10596enifed('backburner/utils', ['exports'], function (exports) { 10597 'use strict'; 10598 10599 exports.each = each; 10600 exports.isString = isString; 10601 exports.isFunction = isFunction; 10602 exports.isNumber = isNumber; 10603 exports.isCoercableNumber = isCoercableNumber; 10604 var NUMBER = /\d+/; 10605 10606 function each(collection, callback) { 10607 for (var i = 0; i < collection.length; i++) { 10608 callback(collection[i]); 10609 } 10610 } 10611 10612 function isString(suspect) { 10613 return typeof suspect === 'string'; 10614 } 10615 10616 function isFunction(suspect) { 10617 return typeof suspect === 'function'; 10618 } 10619 10620 function isNumber(suspect) { 10621 return typeof suspect === 'number'; 10622 } 10623 10624 function isCoercableNumber(number) { 10625 return isNumber(number) || NUMBER.test(number); 10626 } 10627}); 10628enifed('backburner', ['exports', 'backburner/utils', 'backburner/platform', 'backburner/binary-search', 'backburner/deferred-action-queues'], function (exports, _backburnerUtils, _backburnerPlatform, _backburnerBinarySearch, _backburnerDeferredActionQueues) { 10629 'use strict'; 10630 10631 exports.default = Backburner; 10632 10633 function Backburner(queueNames, options) { 10634 this.queueNames = queueNames; 10635 this.options = options || {}; 10636 if (!this.options.defaultQueue) { 10637 this.options.defaultQueue = queueNames[0]; 10638 } 10639 this.instanceStack = []; 10640 this._debouncees = []; 10641 this._throttlers = []; 10642 this._eventCallbacks = { 10643 end: [], 10644 begin: [] 10645 }; 10646 10647 var _this = this; 10648 this._boundClearItems = function () { 10649 clearItems(); 10650 }; 10651 10652 this._timerTimeoutId = undefined; 10653 this._timers = []; 10654 10655 this._platform = this.options._platform || _backburnerPlatform.default; 10656 10657 this._boundRunExpiredTimers = function () { 10658 _this._runExpiredTimers(); 10659 }; 10660 } 10661 10662 Backburner.prototype = { 10663 begin: function () { 10664 var options = this.options; 10665 var onBegin = options && options.onBegin; 10666 var previousInstance = this.currentInstance; 10667 10668 if (previousInstance) { 10669 this.instanceStack.push(previousInstance); 10670 } 10671 10672 this.currentInstance = new _backburnerDeferredActionQueues.default(this.queueNames, options); 10673 this._trigger('begin', this.currentInstance, previousInstance); 10674 if (onBegin) { 10675 onBegin(this.currentInstance, previousInstance); 10676 } 10677 }, 10678 10679 end: function () { 10680 var options = this.options; 10681 var onEnd = options && options.onEnd; 10682 var currentInstance = this.currentInstance; 10683 var nextInstance = null; 10684 10685 // Prevent double-finally bug in Safari 6.0.2 and iOS 6
10686 // This bug appears to be resolved in Safari 6.0.5 and iOS 7 10687 var finallyAlreadyCalled = false; 10688 try { 10689 currentInstance.flush(); 10690 } finally { 10691 if (!finallyAlreadyCalled) { 10692 finallyAlreadyCalled = true; 10693 10694 this.currentInstance = null; 10695 10696 if (this.instanceStack.length) { 10697 nextInstance = this.instanceStack.pop(); 10698 this.currentInstance = nextInstance; 10699 } 10700 this._trigger('end', currentInstance, nextInstance); 10701 if (onEnd) { 10702 onEnd(currentInstance, nextInstance); 10703 } 10704 } 10705 } 10706 }, 10707 10708 /** 10709 Trigger an event. Supports up to two arguments. Designed around 10710 triggering transition events from one run loop instance to the 10711 next, which requires an argument for the first instance and then 10712 an argument for the next instance. 10713 @private 10714 @method _trigger 10715 @param {String} eventName 10716 @param {any} arg1 10717 @param {any} arg2 10718 */ 10719 _trigger: function (eventName, arg1, arg2) { 10720 var callbacks = this._eventCallbacks[eventName]; 10721 if (callbacks) { 10722 for (var i = 0; i < callbacks.length; i++) { 10723 callbacks[i](arg1, arg2); 10724 } 10725 } 10726 }, 10727 10728 on: function (eventName, callback) { 10729 if (typeof callback !== 'function') { 10730 throw new TypeError('Callback must be a function'); 10731 } 10732 var callbacks = this._eventCallbacks[eventName]; 10733 if (callbacks) { 10734 callbacks.push(callback); 10735 } else { 10736 throw new TypeError('Cannot on() event "' + eventName + '" because it does not exist'); 10737 } 10738 }, 10739 10740 off: function (eventName, callback) { 10741 if (eventName) { 10742 var callbacks = this._eventCallbacks[eventName]; 10743 var callbackFound = false; 10744 if (!callbacks) return; 10745 if (callback) { 10746 for (var i = 0; i < callbacks.length; i++) { 10747 if (callbacks[i] === callback) { 10748 callbackFound = true; 10749 callbacks.splice(i, 1); 10750 i--; 10751 } 10752 } 10753 } 10754 if (!callbackFound) { 10755 throw new TypeError('Cannot off() callback that does not exist'); 10756 } 10757 } else { 10758 throw new TypeError('Cannot off() event "' + eventName + '" because it does not exist'); 10759 } 10760 }, 10761 10762 run: function () /* target, method, args */{ 10763 var length = arguments.length; 10764 var method, target, args; 10765 10766 if (length === 1) { 10767 method = arguments[0]; 10768 target = null; 10769 } else { 10770 target = arguments[0]; 10771 method = arguments[1]; 10772 } 10773 10774 if (_backburnerUtils.isString(method)) { 10775 method = target[method]; 10776 } 10777 10778 if (length > 2) { 10779 args = new Array(length - 2); 10780 for (var i = 0, l = length - 2; i < l; i++) { 10781 args[i] = arguments[i + 2]; 10782 } 10783 } else { 10784 args = []; 10785 } 10786 10787 var onError = getOnError(this.options); 10788 10789 this.begin(); 10790 10791 // guard against Safari 6's double-finally bug 10792 var didFinally = false; 10793 10794 if (onError) { 10795 try { 10796 return method.apply(target, args); 10797 } catch (error) { 10798 onError(error); 10799 } finally { 10800 if (!didFinally) { 10801 didFinally = true; 10802 this.end(); 10803 } 10804 } 10805 } else { 10806 try { 10807 return method.apply(target, args); 10808 } finally { 10809 if (!didFinally) { 10810 didFinally = true; 10811 this.end(); 10812 } 10813 } 10814 } 10815 }, 10816 10817 /* 10818 Join the passed method with an existing queue and execute immediately, 10819 if there isn't one use `Backburner#run`. 10820 The join method is like the run method except that it will schedule into 10821 an existing queue if one already exists. In either case, the join method will 10822 immediately execute the passed in function and return its result. 10823 @method join 10824 @param {Object} target 10825 @param {Function} method The method to be executed 10826 @param {any} args The method arguments 10827 @return method result 10828 */ 10829 join: function () /* target, method, args */{ 10830 if (!this.currentInstance) { 10831 return this.run.apply(this, arguments); 10832 } 10833 10834 var length = arguments.length; 10835 var method, target; 10836 10837 if (length === 1) { 10838 method = arguments[0]; 10839 target = null; 10840 } else { 10841 target = arguments[0]; 10842 method = arguments[1]; 10843 } 10844 10845 if (_backburnerUtils.isString(method)) { 10846 method = target[method]; 10847 } 10848 10849 if (length === 1) { 10850 return method(); 10851 } else if (length === 2) { 10852 return method.call(target); 10853 } else { 10854 var args = new Array(length - 2); 10855 for (var i = 0, l = length - 2; i < l; i++) { 10856 args[i] = arguments[i + 2]; 10857 } 10858 return method.apply(target, args); 10859 } 10860 }, 10861 10862 /* 10863 Defer the passed function to run inside the specified queue. 10864 @method defer 10865 @param {String} queueName 10866 @param {Object} target 10867 @param {Function|String}
10867 method The method or method name to be executed 10868 @param {any} args The method arguments 10869 @return method result 10870 */ 10871 defer: function (queueName /* , target, method, args */) { 10872 var length = arguments.length; 10873 var method, target, args; 10874 10875 if (length === 2) { 10876 method = arguments[1]; 10877 target = null; 10878 } else { 10879 target = arguments[1]; 10880 method = arguments[2]; 10881 } 10882 10883 if (_backburnerUtils.isString(method)) { 10884 method = target[method]; 10885 } 10886 10887 var stack = this.DEBUG ? new Error() : undefined; 10888 10889 if (length > 3) { 10890 args = new Array(length - 3); 10891 for (var i = 3; i < length; i++) { 10892 args[i - 3] = arguments[i]; 10893 } 10894 } else { 10895 args = undefined; 10896 } 10897 10898 if (!this.currentInstance) { 10899 createAutorun(this); 10900 } 10901 return this.currentInstance.schedule(queueName, target, method, args, false, stack); 10902 }, 10903 10904 deferOnce: function (queueName /* , target, method, args */) { 10905 var length = arguments.length; 10906 var method, target, args; 10907 10908 if (length === 2) { 10909 method = arguments[1]; 10910 target = null; 10911 } else { 10912 target = arguments[1]; 10913 method = arguments[2]; 10914 } 10915 10916 if (_backburnerUtils.isString(method)) { 10917 method = target[method]; 10918 } 10919 10920 var stack = this.DEBUG ? new Error() : undefined; 10921 10922 if (length > 3) { 10923 args = new Array(length - 3); 10924 for (var i = 3; i < length; i++) { 10925 args[i - 3] = arguments[i]; 10926 } 10927 } else { 10928 args = undefined; 10929 } 10930 10931 if (!this.currentInstance) { 10932 createAutorun(this); 10933 } 10934 return this.currentInstance.schedule(queueName, target, method, args, true, stack); 10935 }, 10936 10937 setTimeout: function () { 10938 var l = arguments.length; 10939 var args = new Array(l); 10940 10941 for (var x = 0; x < l; x++) { 10942 args[x] = arguments[x]; 10943 } 10944 10945 var length = args.length, 10946 method, 10947 wait, 10948 target, 10949 methodOrTarget, 10950 methodOrWait, 10951 methodOrArgs; 10952 10953 if (length === 0) { 10954 return; 10955 } else if (length === 1) { 10956 method = args.shift(); 10957 wait = 0; 10958 } else if (length === 2) { 10959 methodOrTarget = args[0]; 10960 methodOrWait = args[1]; 10961 10962 if (_backburnerUtils.isFunction(methodOrWait) || _backburnerUtils.isFunction(methodOrTarget[methodOrWait])) { 10963 target = args.shift(); 10964 method = args.shift(); 10965 wait = 0; 10966 } else if (_backburnerUtils.isCoercableNumber(methodOrWait)) { 10967 method = args.shift(); 10968 wait = args.shift(); 10969 } else { 10970 method = args.shift(); 10971 wait = 0; 10972 } 10973 } else { 10974 var last = args[args.length - 1]; 10975 10976 if (_backburnerUtils.isCoercableNumber(last)) { 10977 wait = args.pop(); 10978 } else { 10979 wait = 0; 10980 } 10981 10982 methodOrTarget = args[0]; 10983 methodOrArgs = args[1]; 10984 10985 if (_backburnerUtils.isFunction(methodOrArgs) || _backburnerUtils.isString(methodOrArgs) && methodOrTarget !== null && methodOrArgs in methodOrTarget) { 10986 target = args.shift(); 10987 method = args.shift(); 10988 } else { 10989 method = args.shift(); 10990 } 10991 } 10992 10993 var executeAt = Date.now() + parseInt(wait, 10); 10994 10995 if (_backburnerUtils.isString(method)) { 10996 method = target[method]; 10997 } 10998 10999 var onError = getOnError(this.options); 11000 11001 function fn() { 11002 if (onError) { 11003 try { 11004 method.apply(target, args); 11005 } catch (e) { 11006 onError(e); 11007 } 11008 } else { 11009 method.apply(target, args); 11010 } 11011 } 11012 11013 return this._setTimeout(fn, executeAt); 11014 }, 11015 11016 _setTimeout: function (fn, executeAt) { 11017 if (this._timers.length === 0) { 11018 this._timers.push(executeAt, fn); 11019 this._installTimerTimeout(); 11020 return fn; 11021 } 11022 11023 // find position to insert 11024 var i = _backburnerBinarySearch.default(executeAt, this._timers); 11025 11026 this._timers.splice(i, 0, executeAt, fn); 11027 11028 // we should be the new earliest timer if i == 0 11029 if (i === 0) { 11030 this._reinstallTimerTimeout(); 11031 } 11032 11033 return fn; 11034 }, 11035 11036 throttle: function (target, method /* , args, wait, [immediate] */) { 11037 var backburner = this; 11038 var args = new Array(arguments.length); 11039 for (var i = 0; i < arguments.length; i++) { 11040 args[i] = arguments[i]; 11041 } 11042 var immediate = args.pop(); 11043 var wait, throttler, index, timer; 11044 11045 if (_backburnerUtils.isNumber(immediate) || _backburnerUtils.isString(immediate)) { 11046 wait = immediate; 11047 immediate = true; 11048 } else { 11049 wait = args.pop(); 11050 } 11051 11052 wait = parseInt(wait, 10); 11053 11054 index = findThrottler(target, method, this._throttlers); 11055 if (index > -1) { 11056 return this._throttlers[index]; 11057 } // throttled 11058 11059 timer = this._platform.setTimeout(function () { 11060 if (!immediate) {
11061 backburner.run.apply(backburner, args); 11062 } 11063 var index = findThrottler(target, method, backburner._throttlers); 11064 if (index > -1) { 11065 backburner._throttlers.splice(index, 1); 11066 } 11067 }, wait); 11068 11069 if (immediate) { 11070 this.run.apply(this, args); 11071 } 11072 11073 throttler = [target, method, timer]; 11074 11075 this._throttlers.push(throttler); 11076 11077 return throttler; 11078 }, 11079 11080 debounce: function (target, method /* , args, wait, [immediate] */) { 11081 var backburner = this; 11082 var args = new Array(arguments.length); 11083 for (var i = 0; i < arguments.length; i++) { 11084 args[i] = arguments[i]; 11085 } 11086 11087 var immediate = args.pop(); 11088 var wait, index, debouncee, timer; 11089 11090 if (_backburnerUtils.isNumber(immediate) || _backburnerUtils.isString(immediate)) { 11091 wait = immediate; 11092 immediate = false; 11093 } else { 11094 wait = args.pop(); 11095 } 11096 11097 wait = parseInt(wait, 10); 11098 // Remove debouncee 11099 index = findDebouncee(target, method, this._debouncees); 11100 11101 if (index > -1) { 11102 debouncee = this._debouncees[index]; 11103 this._debouncees.splice(index, 1); 11104 this._platform.clearTimeout(debouncee[2]); 11105 } 11106 11107 timer = this._platform.setTimeout(function () { 11108 if (!immediate) { 11109 backburner.run.apply(backburner, args); 11110 } 11111 var index = findDebouncee(target, method, backburner._debouncees); 11112 if (index > -1) { 11113 backburner._debouncees.splice(index, 1); 11114 } 11115 }, wait); 11116 11117 if (immediate && index === -1) { 11118 backburner.run.apply(backburner, args); 11119 } 11120 11121 debouncee = [target, method, timer]; 11122 11123 backburner._debouncees.push(debouncee); 11124 11125 return debouncee; 11126 }, 11127 11128 cancelTimers: function () { 11129 _backburnerUtils.each(this._throttlers, this._boundClearItems); 11130 this._throttlers = []; 11131 11132 _backburnerUtils.each(this._debouncees, this._boundClearItems); 11133 this._debouncees = []; 11134 11135 this._clearTimerTimeout(); 11136 this._timers = []; 11137 11138 if (this._autorun) { 11139 this._platform.clearTimeout(this._autorun); 11140 this._autorun = null; 11141 } 11142 }, 11143 11144 hasTimers: function () { 11145 return !!this._timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; 11146 }, 11147 11148 cancel: function (timer) { 11149 var timerType = typeof timer; 11150 11151 if (timer && timerType === 'object' && timer.queue && timer.method) { 11152 // we're cancelling a deferOnce 11153 return timer.queue.cancel(timer); 11154 } else if (timerType === 'function') { 11155 // we're cancelling a setTimeout 11156 for (var i = 0, l = this._timers.length; i < l; i += 2) { 11157 if (this._timers[i + 1] === timer) { 11158 this._timers.splice(i, 2); // remove the two elements 11159 if (i === 0) { 11160 this._reinstallTimerTimeout(); 11161 } 11162 return true; 11163 } 11164 } 11165 } else if (Object.prototype.toString.call(timer) === '[object Array]') { 11166 // we're cancelling a throttle or debounce 11167 return this._cancelItem(findThrottler, this._throttlers, timer) || this._cancelItem(findDebouncee, this._debouncees, timer); 11168 } else { 11169 return; // timer was null or not a timer 11170 } 11171 }, 11172 11173 _cancelItem: function (findMethod, array, timer) { 11174 var item, index; 11175 11176 if (timer.length < 3) { 11177 return false; 11178 } 11179 11180 index = findMethod(timer[0], timer[1], array); 11181 11182 if (index > -1) { 11183 11184 item = array[index]; 11185 11186 if (item[2] === timer[2]) { 11187 array.splice(index, 1); 11188 this._platform.clearTimeout(timer[2]); 11189 return true; 11190 } 11191 } 11192 11193 return false; 11194 }, 11195 11196 _runExpiredTimers: function () { 11197 this._timerTimeoutId = undefined; 11198 this.run(this, this._scheduleExpiredTimers); 11199 }, 11200 11201 _scheduleExpiredTimers: function () { 11202 var n = Date.now(); 11203 var timers = this._timers; 11204 var i = 0; 11205 var l = timers.length; 11206 for (; i < l; i += 2) { 11207 var executeAt = timers[i]; 11208 var fn = timers[i + 1];
11209 if (executeAt <= n) { 11210 this.schedule(this.options.defaultQueue, null, fn); 11211 } else { 11212 break; 11213 } 11214 } 11215 timers.splice(0, i); 11216 this._installTimerTimeout(); 11217 }, 11218 11219 _reinstallTimerTimeout: function () { 11220 this._clearTimerTimeout(); 11221 this._installTimerTimeout(); 11222 }, 11223 11224 _clearTimerTimeout: function () { 11225 if (!this._timerTimeoutId) { 11226 return; 11227 } 11228 this._platform.clearTimeout(this._timerTimeoutId); 11229 this._timerTimeoutId = undefined; 11230 }, 11231 11232 _installTimerTimeout: function () { 11233 if (!this._timers.length) { 11234 return; 11235 } 11236 var minExpiresAt = this._timers[0]; 11237 var n = Date.now(); 11238 var wait = Math.max(0, minExpiresAt - n); 11239 this._timerTimeoutId = this._platform.setTimeout(this._boundRunExpiredTimers, wait); 11240 } 11241 }; 11242 11243 Backburner.prototype.schedule = Backburner.prototype.defer; 11244 Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; 11245 Backburner.prototype.later = Backburner.prototype.setTimeout; 11246 11247 function getOnError(options) { 11248 return options.onError || options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]; 11249 } 11250 11251 function createAutorun(backburner) { 11252 backburner.begin(); 11253 backburner._autorun = backburner._platform.setTimeout(function () { 11254 backburner._autorun = null; 11255 backburner.end(); 11256 }); 11257 } 11258 11259 function findDebouncee(target, method, debouncees) { 11260 return findItem(target, method, debouncees); 11261 } 11262 11263 function findThrottler(target, method, throttlers) { 11264 return findItem(target, method, throttlers); 11265 } 11266 11267 function findItem(target, method, collection) { 11268 var item; 11269 var index = -1; 11270 11271 for (var i = 0, l = collection.length; i < l; i++) { 11272 item = collection[i]; 11273 if (item[0] === target && item[1] === method) { 11274 index = i; 11275 break; 11276 } 11277 } 11278 11279 return index; 11280 } 11281 11282 function clearItems(item) { 11283 this._platform.clearTimeout(item[2]); 11284 } 11285}); 11286enifed('container/container', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-metal/dictionary', 'ember-metal/features', 'container/owner', 'ember-runtime/mixins/container_proxy', 'ember-metal/symbol'], function (exports, _emberMetalCore, _emberMetalDebug, _emberMetalDictionary, _emberMetalFeatures, _containerOwner, _emberRuntimeMixinsContainer_proxy, _emberMetalSymbol) { 11287 'use strict'; 11288 11289 var CONTAINER_OVERRIDE = _emberMetalSymbol.default('CONTAINER_OVERRIDE'); 11290 11291 /** 11292 A container used to instantiate and cache objects. 11293 11294 Every `Container` must be associated with a `Registry`, which is referenced 11295 to determine the factory and options that should be used to instantiate 11296 objects. 11297 11298 The public API for `Container` is still in flux and should not be considered 11299 stable. 11300 11301 @private 11302 @class Container 11303 */ 11304 function Container(registry, options) { 11305 this.registry = registry; 11306 this.owner = options && options.owner ? options.owner : null; 11307 this.cache = _emberMetalDictionary.default(options && options.cache ? options.cache : null); 11308 this.factoryCache = _emberMetalDictionary.default(options && options.factoryCache ? options.factoryCache : null); 11309 this.validationCache = _emberMetalDictionary.default(options && options.validationCache ? options.validationCache : null); 11310 11311 this._fakeContainerToInject = _emberRuntimeMixinsContainer_proxy.buildFakeContainerWithDeprecations(this); 11312 this[CONTAINER_OVERRIDE] = undefined; 11313 } 11314 11315 Container.prototype = { 11316 /** 11317 @private 11318 @property owner 11319 @type Object 11320 */ 11321 owner: null, 11322 11323 /** 11324 @private 11325 @property registry 11326 @type Registry 11327 @since 1.11.0 11328 */ 11329 registry: null, 11330 11331 /** 11332 @private 11333 @property cache 11334 @type InheritingDict 11335 */ 11336 cache: null, 11337 11338 /** 11339 @private 11340 @property factoryCache 11341 @type InheritingDict 11342 */ 11343 factoryCache: null, 11344 11345 /** 11346 @private 11347 @property validationCache 11348 @type InheritingDict 11349 */ 11350 validationCache: null, 11351 11352 /** 11353 Given a fullName return a corresponding instance. 11354 The default behaviour is for lookup to return a singleton instance. 11355 The singleton is scoped to the container, allowing multiple containers 11356 to all have their own locally scoped singletons. 11357 ```javascript 11358 var registry = new Registry(); 11359 var container = registry.container(); 11360 registry.register('api:twitter', Twitter); 11361 var twitter = container.lookup('api:twitter'); 11362 twitter instanceof Twitter; // => true 11363 // by default the container will return singletons 11364 var twitter2 = container.lookup('api:twitter'); 11365 twitter2 instanceof Twitter; // => true 11366 twitter === twitter2; //=> true 11367 ``` 11368 If singletons are not wanted, an optional flag can be provided at lookup. 11369 ```javascript 11370 var registry = new Registry(); 11371 var container = registry.container(); 11372 registry.register('api:twitter', Twitter); 11373 var twitter = container.lookup('api:twitter', { singleton: fal
11373se }); 11374 var twitter2 = container.lookup('api:twitter', { singleton: false }); 11375 twitter === twitter2; //=> false 11376 ``` 11377 @private 11378 @method lookup 11379 @param {String} fullName 11380 @param {Object} [options] 11381 @param {String} [options.source] The fullname of the request source (used for local lookup) 11382 @return {any} 11383 */ 11384 lookup: function (fullName, options) { 11385 _emberMetalDebug.assert('fullName must be a proper full name', this.registry.validateFullName(fullName)); 11386 return lookup(this, this.registry.normalize(fullName), options); 11387 }, 11388 11389 /** 11390 Given a fullName, return the corresponding factory. 11391 @private 11392 @method lookupFactory 11393 @param {String} fullName 11394 @param {Object} [options] 11395 @param {String} [options.source] The fullname of the request source (used for local lookup) 11396 @return {any} 11397 */ 11398 lookupFactory: function (fullName, options) { 11399 _emberMetalDebug.assert('fullName must be a proper full name', this.registry.validateFullName(fullName)); 11400 return factoryFor(this, this.registry.normalize(fullName), options); 11401 }, 11402 11403 /** 11404 A depth first traversal, destroying the container, its descendant containers and all 11405 their managed objects. 11406 @private 11407 @method destroy 11408 */ 11409 destroy: function () { 11410 eachDestroyable(this, function (item) { 11411 if (item.destroy) { 11412 item.destroy(); 11413 } 11414 }); 11415 11416 this.isDestroyed = true; 11417 }, 11418 11419 /** 11420 Clear either the entire cache or just the cache for a particular key. 11421 @private 11422 @method reset 11423 @param {String} fullName optional key to reset; if missing, resets everything 11424 */ 11425 reset: function (fullName) { 11426 if (arguments.length > 0) { 11427 resetMember(this, this.registry.normalize(fullName)); 11428 } else { 11429 resetCache(this); 11430 } 11431 }, 11432 11433 /** 11434 Returns an object that can be used to provide an owner to a 11435 manually created instance. 11436 @private 11437 @method ownerInjection 11438 @returns { Object } 11439 */ 11440 ownerInjection: function () { 11441 var _ref; 11442 11443 return _ref = {}, _ref[_containerOwner.OWNER] = this.owner, _ref; 11444 } 11445 }; 11446 11447 function isSingleton(container, fullName) { 11448 return container.registry.getOption(fullName, 'singleton') !== false; 11449 } 11450 11451 function lookup(container, fullName) { 11452 var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 11453 11454 if (options.source) { 11455 fullName = container.registry.expandLocalLookup(fullName, options); 11456 11457 // if expandLocalLookup returns falsey, we do not support local lookup 11458 if (!fullName) { 11459 return; 11460 } 11461 } 11462 11463 if (container.cache[fullName] !== undefined && options.singleton !== false) { 11464 return container.cache[fullName]; 11465 } 11466 11467 var value = instantiate(container, fullName); 11468 11469 if (value === undefined) { 11470 return; 11471 } 11472 11473 if (isSingleton(container, fullName) && options.singleton !== false) { 11474 container.cache[fullName] = value; 11475 } 11476 11477 return value; 11478 } 11479 11480 function markInjectionsAsDynamic(injections) { 11481 injections._dynamic = true; 11482 } 11483 11484 function areInjectionsDynamic(injections) { 11485 return !!injections._dynamic; 11486 } 11487 11488 function buildInjections() /* container, ...injections */{ 11489 var hash = {}; 11490 11491 if (arguments.length > 1) { 11492 var container = arguments[0]; 11493 var injections = []; 11494 var injection; 11495 11496 for (var i = 1, l = arguments.length; i < l; i++) { 11497 if (arguments[i]) { 11498 injections = injections.concat(arguments[i]); 11499 } 11500 } 11501 11502 container.registry.validateInjections(injections); 11503 11504 for (i = 0, l = injections.length; i < l; i++) { 11505 injection = injections[i]; 11506 hash[injection.property] = lookup(container, injection.fullName); 11507 if (!isSingleton(container, injection.fullName)) { 11508 markInjectionsAsDynamic(hash); 11509 } 11510 } 11511 } 11512 11513 return hash; 11514 } 11515 11516 function factoryFor(container, fullName) { 11517 var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 11518 11519 var registry = container.registry; 11520 11521 if (options.source) { 11522 fullName = registry.expandLocalLookup(fullName, options); 11523 11524 // if expandLocalLookup returns falsey, we do not support local lookup 11525 if (!fullName) { 11526 return; 11527 } 11528 } 11529 11530 var cache = container.factoryCache; 11531 if (cache[fullName]) { 11532 return cache[fullName]; 11533 } 11534 var factory = registry.resolve(fullName); 11535 if (factory === undefined) { 11536 return; 11537 } 11538 11539 var type = fullName.split(':')[0]; 11540 if (!factory || typeof factory.extend !== 'function' || !_emberMetalCore.default.MODEL_FACTORY_INJECTIONS && type === 'model') { 11541 if (factory && typeof factory._onLookup === 'function') { 11542 factory._onLookup(fullName); 11543 } 11544 11545 // TODO: think about a 'safe' merge style extension 11546 // for now just fallback to create time injection 11547 cache[fullName] = factory; 11548 return factory; 11549 } else { 11550 var injections = injectionsFor(container, fullName); 11551 var factoryInjections = factoryInjectionsFor(container, fullName); 11552 var cacheable = !areInjectionsDynamic(injections) && !areInjectionsDynamic(factoryInjections); 11553 11554 factoryInjections._toString = registry.makeToString(factory, fullName); 11555 11556 var injectedFactory = factory.extend(injections); 11557 11558 // TODO - remove all `container` injections when Ember reaches v3.0.0 11559 11560 injectDeprecatedContainer(injectedFactory.prototype, container); 11561 11562 injectedFactory.reopenClass(factoryInjections); 11563 11564 if (factory && typeof factory._onLookup === 'function') { 11565 factory._onLookup(fullName); 11566 } 11567 11568 if (cacheable) { 11569 cache[fullName] = injectedFactory; 11570 } 11571 11572 return injectedFactory; 11573 } 11574 } 11575 11576 function injectionsFor(container, fullName) { 11577 var registry = container.registry; 11578 var splitName = fullName.split(':'); 11579 var type = splitName[0]; 11580 11581 var injections = buildInjections(container, registry.getTypeInjections(type), registry.getInjections(fullName)); 11582 injections._debugContainerKey = fullName; 11583 11584 _containerOwner.setOwner(injections, container.owner); 11585 11586 return injections; 11587 } 11588 11589 function factoryInjectionsFor(container, fullName) { 11590 var registry = container.registry; 11591 var splitName = fullName.split(':'); 11592 var type = splitName[0]; 11593 11594 var factoryInjections = buildInjections(container, registry.getFactoryTypeInjections(type), registry.getFactoryInjections(fullName)); 11595 factoryInjections._debugContainerKey = fullName; 11596 11597 return factoryInjections; 11598 } 11599 11600 function instantiate(container, fullName) { 11601 var factory = factoryFor(container, fullName); 11602 var lazyInjections, validationCache; 11603 11604 if (container.registry.getOption(fullName, 'instantiate') === false) { 11605 return factory; 11606 } 11607 11608 if (factory) { 11609 if (typeof factory.create !== 'function') { 11610 throw new Error('Failed to create an instance of \'' + fullName + '\'. ' + 'Most likely an improperly defined class or an invali
11610d module export.'); 11611 } 11612 11613 validationCache = container.validationCache; 11614 11615 // Ensure that all lazy injections are valid at instantiation time 11616 if (!validationCache[fullName] && typeof factory._lazyInjections === 'function') { 11617 lazyInjections = factory._lazyInjections(); 11618 lazyInjections = container.registry.normalizeInjectionsHash(lazyInjections); 11619 11620 container.registry.validateInjections(lazyInjections); 11621 } 11622 11623 validationCache[fullName] = true; 11624 11625 var obj = undefined; 11626 11627 if (typeof factory.extend === 'function') { 11628 // assume the factory was extendable and is already injected 11629 obj = factory.create(); 11630 } else { 11631 // assume the factory was extendable 11632 // to create time injections 11633 // TODO: support new'ing for instantiation and merge injections for pure JS Functions 11634 var injections = injectionsFor(container, fullName); 11635 11636 // Ensure that a container is available to an object during instantiation. 11637 // TODO - remove when Ember reaches v3.0.0 11638 11639 // This "fake" container will be replaced after instantiation with a 11640 // property that raises deprecations every time it is accessed. 11641 injections.container = container._fakeContainerToInject; 11642 11643 obj = factory.create(injections); 11644 11645 // TODO - remove when Ember reaches v3.0.0 11646 11647 if (!Object.isFrozen(obj) && 'container' in obj) { 11648 injectDeprecatedContainer(obj, container); 11649 } 11650 } 11651 11652 return obj; 11653 } 11654 } 11655 11656 // TODO - remove when Ember reaches v3.0.0 11657 function injectDeprecatedContainer(object, container) { 11658 Object.defineProperty(object, 'container', { 11659 configurable: true, 11660 enumerable: false, 11661 get: function () { 11662 _emberMetalDebug.deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', false, { id: 'ember-application.injected-container', until: '3.0.0', url: 'http://emberjs.com/deprecations/v2.x#toc_injected-container-access' }); 11663 return this[CONTAINER_OVERRIDE] || container; 11664 }, 11665 11666 set: function (value) { 11667 _emberMetalDebug.deprecate('Providing the `container` property to ' + this + ' is deprecated. Please use `Ember.setOwner` or `owner.ownerInjection()` instead to provide an owner to the instance being created.', false, { id: 'ember-application.injected-container', until: '3.0.0', url: 'http://emberjs.com/deprecations/v2.x#toc_injected-container-access' }); 11668 11669 this[CONTAINER_OVERRIDE] = value; 11670 11671 return value; 11672 } 11673 }); 11674 } 11675 11676 function eachDestroyable(container, callback) { 11677 var cache = container.cache; 11678 var keys = Object.keys(cache); 11679 var key, value; 11680 11681 for (var i = 0, l = keys.length; i < l; i++) { 11682 key = keys[i]; 11683 value = cache[key]; 11684 11685 if (container.registry.getOption(key, 'instantiate') !== false) { 11686 callback(value); 11687 } 11688 } 11689 } 11690 11691 function resetCache(container) { 11692 eachDestroyable(container, function (value) { 11693 if (value.destroy) { 11694 value.destroy(); 11695 } 11696 }); 11697 11698 container.cache.dict = _emberMetalDictionary.default(null); 11699 } 11700 11701 function resetMember(container, fullName) { 11702 var member = container.cache[fullName]; 11703 11704 delete container.factoryCache[fullName]; 11705 11706 if (member) { 11707 delete container.cache[fullName]; 11708 11709 if (member.destroy) { 11710 member.destroy(); 11711 } 11712 } 11713 } 11714 11715 exports.default = Container; 11716}); 11717enifed('container/index', ['exports', 'ember-metal/core', 'container/registry', 'container/container', 'container/owner'], function (exports, _emberMetalCore, _containerRegistry, _containerContainer, _containerOwner) { 11718 'use strict'; 11719 11720 /* 11721 Public API for the container is still in flux. 11722 The public API, specified on the application namespace should be considered the stable API. 11723 // @module container 11724 @private 11725 */ 11726 11727 /* 11728 Flag to enable/disable model factory injections (disabled by default). 11729 If model factory injections are enabled, models should not be 11730 accessed globally (only through `container.lookupFactory('model:modelName'))`); 11731 */ 11732 _emberMetalCore.default.MODEL_FACTORY_INJECTIONS = false;
11733 11734 if (_emberMetalCore.default.ENV && typeof _emberMetalCore.default.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') { 11735 _emberMetalCore.default.MODEL_FACTORY_INJECTIONS = !!_emberMetalCore.default.ENV.MODEL_FACTORY_INJECTIONS; 11736 } 11737 11738 exports.Registry = _containerRegistry.default; 11739 exports.Container = _containerContainer.default; 11740 exports.getOwner = _containerOwner.getOwner; 11741 exports.setOwner = _containerOwner.setOwner; 11742}); 11743enifed('container/owner', ['exports', 'ember-metal/symbol'], function (exports, _emberMetalSymbol) { 11744 /** 11745 @module ember 11746 @submodule ember-runtime 11747 */ 11748 11749 'use strict'; 11750 11751 exports.getOwner = getOwner; 11752 exports.setOwner = setOwner; 11753 var OWNER = _emberMetalSymbol.default('OWNER'); 11754 11755 exports.OWNER = OWNER; 11756 /** 11757 Framework objects in an Ember application (components, services, routes, etc.) 11758 are created via a factory and dependency injection system. Each of these 11759 objects is the responsibility of an "owner", which handled its 11760 instantiation and manages its lifetime. 11761 11762 `getOwner` fetches the owner object responsible for an instance. This can 11763 be used to lookup or resolve other class instances, or register new factories 11764 into the owner. 11765 11766 For example, this component dynamically looks up a service based on the 11767 `audioType` passed as an attribute: 11768 11769 ``` 11770
11770// app/components/play-audio.js 11771 import Ember from 'ember'; 11772 11773 // Usage: 11774 // 11775 // {{play-audio audioType=model.audioType audioFile=model.file}} 11776 // 11777 export default Ember.Component.extend({ 11778 audioService: Ember.computed('audioType', function() { 11779 let owner = Ember.getOwner(this); 11780 return owner.lookup(`service:${this.get('audioType')}`); 11781 }), 11782 click() { 11783 let player = this.get('audioService'); 11784 player.play(this.get('audioFile')); 11785 } 11786 }); 11787 ``` 11788 11789 @method getOwner 11790 @param {Object} object An object with an owner. 11791 @return {Object} An owner object. 11792 @for Ember 11793 @public 11794 */ 11795 11796 function getOwner(object) { 11797 return object[OWNER]; 11798 } 11799 11800 /** 11801 `setOwner` forces a new owner on a given object instance. This is primarily 11802 useful in some testing cases. 11803 11804 @method setOwner 11805 @param {Object} object An object with an owner. 11806 @return {Object} An owner object. 11807 @for Ember 11808 @public 11809 */ 11810 11811 function setOwner(object, owner) { 11812 object[OWNER] = owner; 11813 } 11814}); 11815enifed('container/registry', ['exports', 'ember-metal/features', 'ember-metal/debug', 'ember-metal/dictionary', 'ember-metal/empty_object', 'ember-metal/assign', 'container/container'], function (exports, _emberMetalFeatures, _emberMetalDebug, _emberMetalDictionary, _emberMetalEmpty_object, _emberMetalAssign, _containerContainer) { 11816 'use strict'; 11817 11818 var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; 11819 11820 /** 11821 A registry used to store factory and option information keyed 11822 by type. 11823 11824 A `Registry` stores the factory and option information needed by a 11825 `Container` to instantiate and cache objects. 11826 11827 The API for `Registry` is still in flux and should not be considered stable. 11828 11829 @private 11830 @class Registry 11831 @since 1.11.0 11832 */ 11833 function Registry(options) { 11834 this.fallback = options && options.fallback ? options.fallback : null; 11835 11836 if (options && options.resolver) { 11837 this.resolver = options.resolver; 11838 11839 if (typeof this.resolver === 'function') { 11840 deprecateResolverFunction(this); 11841 } 11842 } 11843 11844 this.registrations = _emberMetalDictionary.default(options && options.registrations ? options.registrations : null); 11845 11846 this._typeInjections = _emberMetalDictionary.default(null); 11847 this._injections = _emberMetalDictionary.default(null); 11848 this._factoryTypeInjections = _emberMetalDictionary.default(null); 11849 this._factoryInjections = _emberMetalDictionary.default(null); 11850 11851 this._localLookupCache = new _emberMetalEmpty_object.default(); 11852 this._normalizeCache = _emberMetalDictionary.default(null); 11853 this._resolveCache = _emberMetalDictionary.default(null); 11854 this._failCache = _emberMetalDictionary.default(null); 11855 11856 this._options = _emberMetalDictionary.default(null); 11857 this._typeOptions = _emberMetalDictionary.default(null); 11858 } 11859 11860 Registry.prototype = { 11861 /** 11862 A backup registry for resolving registrations when no matches can be found. 11863 @private 11864 @property fallback 11865 @type Registry 11866 */ 11867 fallback: null, 11868 11869 /** 11870 An object that has a `resolve` method that resolves a name. 11871 @private 11872 @property resolver 11873 @type Resolver 11874 */ 11875 resolver: null, 11876 11877 /** 11878 @private 11879 @property registrations 11880 @type InheritingDict 11881 */ 11882 registrations: null, 11883 11884 /** 11885 @private 11886 @property _typeInjections 11887 @type InheritingDict 11888 */ 11889 _typeInjections: null, 11890 11891 /** 11892 @private 11893 @property _injections 11894 @type InheritingDict 11895 */ 11896 _injections: null, 11897 11898 /** 11899 @private 11900 @property _factoryTypeInjections 11901 @type InheritingDict 11902 */ 11903 _factoryTypeInjections: null, 11904 11905 /** 11906 @private 11907 @property _factoryInjections 11908 @type InheritingDict 11909 */ 11910 _factoryInjections: null, 11911 11912 /** 11913 @private 11914 @property _normalizeCache 11915 @type InheritingDict 11916 */ 11917 _normalizeCache: null, 11918 11919 /** 11920 @private 11921 @property _resolveCache 11922 @type InheritingDict 11923 */ 11924 _resolveCache: null, 11925 11926 /** 11927 @private 11928 @property _options 11929 @type InheritingDict 11930 */ 11931 _options: null, 11932 11933 /** 11934 @private 11935 @property _typeOptions 11936 @type InheritingDict 11937 */ 11938 _typeOptions: null, 11939 11940 /** 11941 Creates a container based on this registry. 11942 @private 11943 @method container 11944 @param {Object} options 11945 @return {Container} created container 11946 */ 11947 container: function (options) { 11948 return new _containerContainer.default(this, options); 11949 }, 11950 11951 /** 11952 Registers a factory for later injection. 11953 Example: 11954 ```javascript 11955 var registry = new Registry();
11956 registry.register('model:user', Person, {singleton: false }); 11957 registry.register('fruit:favorite', Orange); 11958 registry.register('communication:main', Email, {singleton: false}); 11959 ``` 11960 @private 11961 @method register 11962 @param {String} fullName 11963 @param {Function} factory 11964 @param {Object} options 11965 */ 11966 register: function (fullName, factory) { 11967 var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 11968 11969 _emberMetalDebug.assert('fullName must be a proper full name', this.validateFullName(fullName)); 11970 11971 if (factory === undefined) { 11972 throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); 11973 } 11974 11975 var normalizedName = this.normalize(fullName); 11976 11977 if (this._resolveCache[normalizedName]) { 11978 throw new Error('Cannot re-register: `' + fullName + '`, as it has already been resolved.'); 11979 } 11980 11981 delete this._failCache[normalizedName]; 11982 this.registrations[normalizedName] = factory; 11983 this._options[normalizedName] = options; 11984 }, 11985 11986 /** 11987 Unregister a fullName 11988 ```javascript 11989 var registry = new Registry(); 11990 registry.register('model:user', User); 11991 registry.resolve('model:user').create() instanceof User //=> true 11992 registry.unregister('model:user') 11993 registry.resolve('model:user') === undefined //=> true 11994 ``` 11995 @private 11996 @method unregister 11997 @param {String} fullName 11998 */ 11999 unregister: function (fullName) { 12000 _emberMetalDebug.assert('fullName must be a proper full name', this.validateFullName(fullName)); 12001 12002 var normalizedName = this.normalize(fullName); 12003 12004 this._localLookupCache = new _emberMetalEmpty_object.default(); 12005 12006 delete this.registrations[normalizedName]; 12007 delete this._resolveCache[normalizedName]; 12008 delete this._failCache[normalizedName]; 12009 delete this._options[normalizedName]; 12010 }, 12011 12012 /** 12013 Given a fullName return the corresponding factory. 12014 By default `resolve` will retrieve the factory from 12015 the registry. 12016 ```javascript 12017 var registry = new Registry(); 12018 registry.register('api:twitter', Twitter); 12019 registry.resolve('api:twitter') // => Twitter 12020 ``` 12021 Optionally the registry can be provided with a custom resolver. 12022 If provided, `resolve` will first provide the custom resolver 12023 the opportunity to resolve the fullName, otherwise it will fallback 12024 to the registry. 12025 ```javascript 12026 var registry = new Registry(); 12027 registry.resolver = function(fullName) { 12028 // lookup via the module system of choice 12029 }; 12030 // the twitter factory is added to the module system 12031 registry.resolve('api:twitter') // => Twitter 12032 ``` 12033 @private 12034 @method resolve 12035 @param {String} fullName 12036 @param {Object} [options] 12037 @param {String} [options.source] the fullname of the request source (used for local lookups) 12038 @return {Function} fullName's factory 12039 */ 12040 resolve: function (fullName, options) { 12041 _emberMetalDebug.assert('fullName must be a proper full name', this.validateFullName(fullName)); 12042 var factory = resolve(this, this.normalize(fullName), options); 12043 if (factory === undefined && this.fallback) { 12044 var _fallback; 12045 12046 factory = (_fallback = this.fallback).resolve.apply(_fallback, arguments); 12047 } 12048 return factory; 12049 }, 12050 12051 /** 12052 A hook that can be used to describe how the resolver will 12053 attempt to find the factory. 12054 For example, the default Ember `.describe` returns the full 12055 class name (including namespace) where Ember's resolver expects 12056 to find the `fullName`. 12057 @private 12058 @method describe 12059 @param {String} fullName 12060 @return {string} described fullName 12061 */ 12062 describe: function (fullName) { 12063 if (this.resolver && this.resolver.lookupDescription) { 12064 return this.resolver.lookupDescription(fullName); 12065 } else if (this.fallback) { 12066 return this.fallback.describe(fullName); 12067 } else { 12068 return fullName; 12069 } 12070 }, 12071 12072 /** 12073 A hook to enable custom fullName normalization behaviour 12074 @private 12075 @method normalizeFullName 12076 @param {String} fullName 12077 @return {string} normalized fullName 12078 */ 12079 normalizeFullName: function (fullName) { 12080 if (this.resolver && this.resolver.normalize) { 12081 return this.resolver.normalize(fullName); 12082 } else if (this.fallback) { 12083 return this.fallback.normalizeFullName(fullName); 12084 } else { 12085 return fullName; 12086 } 12087 }, 12088 12089 /** 12090 Normalize a fullName based on the application's conventions 12091 @private 12092 @method normalize 12093 @param {String} fullName 12094 @return {string} normalized fullName 12095 */ 12096 normalize: function (fullName) { 12097 return this._normalizeCache[fullName] || (this._normalizeCache[fullName] = this.normalizeFullName(fullName)); 12098 }, 12099 12100 /** 12101 @method makeToString 12102 @private 12103 @param {any} factory 12104 @param {string} fullName 12105 @return {function} toString function 12106 */ 12107 makeToString: function (factory, fullName) { 12108 if (this.resolver && this.resolver.makeToString) { 12109 return this.resolver.makeToString(factory, fullName); 12110 } else if (this.fallback) { 12111 return this.fallback.makeToString(factory, fullName); 12112 } else { 12113 return factory.toString(); 12114 } 12115 }, 12116 12117 /** 12118 Given a fullName check if the container is aware of its factory 12119 or singleton instance. 12120 @private 12121 @method has 12122 @param {String} fullName 12123 @param {Object} [options] 12124 @param {String} [options.source] the fullname of the request source (used for local lookups) 12125 @return {Boolean} 12126 */ 12127 has: function (fullName, options) { 12128 _emberMetalDebug.assert('fullName must be a proper full name', this.validateFullName(fullName)); 12129 12130 var source = undefined; 12131 12132 source = options && options.source && this.normalize(options.source); 12133 12134 return has(this, this.normalize(fullName), source); 12135 }, 12136 12137 /** 12138 Allow registering options for all factories of a type. 12139 ```javascript 12140 var registry = new Registry(); 12141 var container = registry.container(); 12142 // if all of type `connection` must not be singletons
12143 registry.optionsForType('connection', { singleton: false }); 12144 registry.register('connection:twitter', TwitterConnection); 12145 registry.register('connection:facebook', FacebookConnection); 12146 var twitter = container.lookup('connection:twitter'); 12147 var twitter2 = container.lookup('connection:twitter'); 12148 twitter === twitter2; // => false 12149 var facebook = container.lookup('connection:facebook'); 12150 var facebook2 = container.lookup('connection:facebook'); 12151 facebook === facebook2; // => false 12152 ``` 12153 @private 12154 @method optionsForType 12155 @param {String} type 12156 @param {Object} options 12157 */ 12158 optionsForType: function (type, options) { 12159 this._typeOptions[type] = options; 12160 }, 12161 12162 getOptionsForType: function (type) { 12163 var optionsForType = this._typeOptions[type]; 12164 if (optionsForType === undefined && this.fallback) { 12165 optionsForType = this.fallback.getOptionsForType(type); 12166 } 12167 return optionsForType; 12168 }, 12169 12170 /** 12171 @private 12172 @method options 12173 @param {String} fullName 12174 @param {Object} options 12175 */ 12176 options: function (fullName) { 12177 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 12178 12179 var normalizedName = this.normalize(fullName); 12180 this._options[normalizedName] = options; 12181 }, 12182 12183 getOptions: function (fullName) { 12184 var normalizedName = this.normalize(fullName); 12185 var options = this._options[normalizedName]; 12186 if (options === undefined && this.fallback) { 12187 options = this.fallback.getOptions(fullName); 12188 } 12189 return options; 12190 }, 12191 12192 getOption: function (fullName, optionName) { 12193 var options = this._options[fullName]; 12194 12195 if (options && options[optionName] !== undefined) { 12196 return options[optionName]; 12197 } 12198 12199 var type = fullName.split(':')[0]; 12200 options = this._typeOptions[type]; 12201 12202 if (options && options[optionName] !== undefined) { 12203 return options[optionName]; 12204 } else if (this.fallback) { 12205 return this.fallback.getOption(fullName, optionName); 12206 } 12207 }, 12208 12209 /** 12210 Used only via `injection`. 12211 Provides a specialized form of injection, specifically enabling 12212 all objects of one type to be injected with a reference to another 12213 object. 12214 For example, provided each object of type `controller` needed a `router`. 12215 one would do the following: 12216 ```javascript 12217 var registry = new Registry(); 12218 var container = registry.container(); 12219 registry.register('router:main', Router); 12220 registry.register('controller:user', UserController); 12221 registry.register('controller:post', PostController); 12222 registry.typeInjection('controller', 'router', 'router:main'); 12223 var user = container.lookup('controller:user'); 12224 var post = container.lookup('controller:post'); 12225 user.router instanceof Router; //=> true 12226 post.router instanceof Router; //=> true 12227 // both controllers share the same router 12228 user.router === post.router; //=> true 12229 ``` 12230 @private 12231 @method typeInjection 12232 @param {String} type 12233 @param {String} property 12234 @param {String} fullName 12235 */ 12236 typeInjection: function (type, property, fullName) { 12237 _emberMetalDebug.assert('fullName must be a proper full name', this.validateFullName(fullName)); 12238 12239 var fullNameType = fullName.split(':')[0]; 12240 if (fullNameType === type) { 12241 throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s).'); 12242 } 12243 12244 var injections = this._typeInjections[type] || (this._typeInjections[type] = []); 12245 12246 injections.push({ 12247 property: property, 12248 fullName: fullName 12249 }); 12250 }, 12251 12252 /** 12253 Defines injection rules. 12254 These rules are used to inject dependencies onto objects when they 12255 are instantiated. 12256 Two forms of injections are possible: 12257 * Injecting one fullName on another fullName 12258 * Injecting one fullName on a type 12259 Example: 12260 ```javascript 12261 var registry = new Registry(); 12262 var container = registry.container(); 12263 registry.register('source:main', Source); 12264 registry.register('model:user', User); 12265 registry.register('model:post', Post); 12266 // injecting one fullName on another fullName 12267 // eg. each user model gets a post model 12268 registry.injection('model:user', 'post', 'model:post'); 12269 // injecting one fullName on another type 12270 registry.injection('model', 'source', 'source:main'); 12271 var user = container.lookup('model:user'); 12272 var post = container.lookup('model:post'); 12273 user.source instanceof Source; //=> true 12274 post.source instanceof Source; //=> true 12275 user.post instanceof Post; //=> true 12276 // and both models share the same source 12277 user.source === post.source; //=> true 12278 ``` 12279 @private 12280 @method injection 12281 @param {String} factoryName 12282 @param {String} property 12283 @param {String} injectionName 12284 */ 12285 injection: function (fullName, property, injectionName) { 12286 this.validateFullName(injectionName); 12287 var normalizedInjectionName = this.normalize(injectionName); 12288 12289 if (fullName.indexOf(':') === -1) { 12290 return this.typeInjection(fullName, property, normalizedInjectionName); 12291 } 12292 12293 _emberMetalDebug.assert('fullName must be a proper full name', this.validateFullName(fullName)); 12294 var normalizedName = this.normalize(fullName); 12295 12296 var injections = this._injections[normalizedName] || (this._injections[normalizedName] = []); 12297 12298 injections.push({ 12299 property: property, 12300 fullName: normalizedInjectionName 12301 }); 12302 }, 12303 12304 /** 12305 Used only via `factoryInjection`. 12306 Provides a specialized form of injection, specifically enabling 12307 all factory of one type to be injected with a reference to another 12308 object. 12309 For example, provided each factory of type `model` needed a `store`. 12310 one would do the following: 12311 ```javascript 12312 var registry = new Registry(); 12313 registry.register('store:main', SomeStore); 12314 registry.factoryTypeInjection('model', 'store', 'store:main'); 12315 var store = registry.lookup('store:main'); 12316 var UserFactory = registry.lookupFactory('model:user'); 12317 UserFactory.store instanceof SomeStore; //=> true 12318 ``` 12319 @private 12320 @method factoryTypeInjection 12321 @param {String} type 12322 @param {String} property 12323 @param {String} fullName 12324 */ 12325 factoryTypeInjection: function (type, property, fullName) { 12326 var injections = this._factoryTypeInjections[type] || (this._factoryTypeInjections[type] = []); 12327 12328 injections.push({ 12329 property: property, 12330 fullName: this.normalize(fullName) 12331 }); 12332 }, 12333 12334 /** 12335 Defines factory injection rules. 12336 Similar to regular injection rules, but are run against factories, via 12337 `Registry#lookupFactory`. 12338 These rules are used to inject objects onto factories when they 12339 are looked up. 12340 Two forms of injections are possible: 12341 * Injecting one fullName on another fullName 12342 * Injecting one fullName on a type 12343 Example: 12344 ```javascript 12345 var registry = new Registry(); 12346 var container = registry.container(); 12347 registry.register('store:main', Store); 12348 registry.register('store:secondary', OtherStore); 12349 registry.register('model:user', User); 12350 registry.register('model:post', Post); 12351 // injecting one fullName on another type 12352 registry.factoryInjection('model', 'store', 'store:main'); 12353 // injecting one fullName on another fullName 12354 registry.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); 12355 var UserFactory = container.lookupFactory('model:user'); 12356 var PostFactory = container.lookupFactory('model:post'); 12357 var store = container.lookup('store:main'); 12358 UserFactory.store instanceof Store; //=> true 12359 UserFactory.secondaryStore instanceof OtherStore; //=> false 12360 PostFactory.store instanceof Store; //=> true 12361 PostFactory.secondaryStore instanceof OtherStore; //=> true 12362 // and both models share the same source instance 12363 UserFactory.store === PostFactory.store; //=> true 12364 ``` 12365 @private 12366 @method factoryInjection 12367 @param {String} factoryName 12368 @param {String} property 12369 @param {String} injectionName 12370 */ 12371 factoryInjection: function (fullName, property, injectionName) { 12372 var normalizedName = this.normalize(fullName); 12373 var normalizedInjectionName = this.normalize(injectionName); 12374 12375 this.validateFullName(injectionName); 12376 12377 if (fullName.indexOf(':') === -1) { 12378 return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); 12379 } 12380 12381 var injections = this._factoryInjections[normalizedName] || (this._factoryInjections[normalizedName] = []); 12382 12383 injections.push({ 12384 property: property, 12385 fullName: normalizedInjectionName 12386 }); 12387 }, 12388 12389 /** 12390 @private 12391 @method knownForType 12392 @param {String} type the type to iterate over 12393 */ 12394 knownForType: function (type) { 12395 var fallbackKnown = undefined, 12396 resolverKnown = undefined; 12397 12398 var localKnown = _emberMetalDictionary.default(null); 12399 var registeredNames = Object.keys(this.registrations); 12400 for (var index = 0, _length = registeredNames.length; index < _length; index++) { 12401 var fullName = registeredNames[index]; 12402 var itemType = fullName.split(':')[0]; 12403 12404 if (itemType === type) { 12405 localKnown[fullName] = true; 12406 } 12407 } 12408 12409 if (this.fallback) { 12410 fallbackKnown = this.fallback.knownForType(type); 12411 } 12412 12413 if (this.resolver && this.resolver.knownForType) { 12414 resolverKnown = this.resolver.knownForType(type); 12415 } 12416 12417 return _emberMetalAssign.default({}, fallbackKnown, localKnown, resolverKnown); 12418 }, 12419 12420 validateFullName: function (fullName) { 12421 if (!VALID_FULL_NAME_REGEXP.test(fullName)) { 12422 throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); 12423 } 12424 return true; 12425 }, 12426 12427 validateInjections: function (injections) { 12428 if (!injections) { 12429 return; 12430 } 12431 12432 var fullName; 12433 12434 for (var i = 0, length = injections.length; i < length; i++) { 12435 fullName = injections[i].fullName; 12436 12437 if (!this.has(fullName)) { 12438 throw new Error('Attempting to inject an unknown injection: `' + fullName + '`'); 12439 } 12440 } 12441 }, 12442
12443 normalizeInjectionsHash: function (hash) { 12444 var injections = []; 12445 12446 for (var key in hash) { 12447 if (hash.hasOwnProperty(key)) { 12448 _emberMetalDebug.assert('Expected a proper full name, given \'' + hash[key] + '\'', this.validateFullName(hash[key])); 12449 12450 injections.push({ 12451 property: key, 12452 fullName: hash[key] 12453 }); 12454 } 12455 } 12456 12457 return injections; 12458 }, 12459 12460 getInjections: function (fullName) { 12461 var injections = this._injections[fullName] || []; 12462 if (this.fallback) { 12463 injections = injections.concat(this.fallback.getInjections(fullName)); 12464 } 12465 return injections; 12466 }, 12467 12468 getTypeInjections: function (type) { 12469 var injections = this._typeInjections[type] || []; 12470 if (this.fallback) { 12471 injections = injections.concat(this.fallback.getTypeInjections(type)); 12472 } 12473 return injections; 12474 }, 12475 12476 getFactoryInjections: function (fullName) { 12477 var injections = this._factoryInjections[fullName] || []; 12478 if (this.fallback) { 12479 injections = injections.concat(this.fallback.getFactoryInjections(fullName)); 12480 } 12481 return injections; 12482 }, 12483 12484 getFactoryTypeInjections: function (type) { 12485 var injections = this._factoryTypeInjections[type] || []; 12486 if (this.fallback) { 12487 injections = injections.concat(this.fallback.getFactoryTypeInjections(type)); 12488 } 12489 return injections; 12490 } 12491 }; 12492 12493 function deprecateResolverFunction(registry) { 12494 _emberMetalDebug.deprecate('Passing a `resolver` function into a Registry is deprecated. Please pass in a Resolver object with a `resolve` method.', false, { id: 'ember-application.registry-resolver-as-function', until: '3.0.0', url: 'http://emberjs.com/deprecations/v2.x#toc_registry-resolver-as-function' }); 12495 registry.resolver = { 12496 resolve: registry.resolver 12497 }; 12498 } 12499 12500 /** 12501 Given a fullName and a source fullName returns the fully resolved 12502 fullName. Used to allow for local lookup. 12503 ```javascript 12504 var registry = new Registry(); 12505 // the twitter factory is added to the module system 12506 registry.expandLocalLookup('component:post-title', { source: 'template:post' }) // => component:post/post-title 12507 ``` 12508 @private 12509 @method expandLocalLookup 12510 @param {String} fullName 12511 @param {Object} [options] 12512 @param {String} [options.source] the fullname of the request source (used for local lookups) 12513 @return {String} fullName 12514 */ 12515 Registry.prototype.expandLocalLookup = function Registry_expandLocalLookup(fullName, options) { 12516 if (this.resolver && this.resolver.expandLocalLookup) { 12517 _emberMetalDebug.assert('fullName must be a proper full name', this.validateFullName(fullName)); 12518 _emberMetalDebug.assert('options.source must be provided to expandLocalLookup', options && options.source); 12519 _emberMetalDebug.assert('options.source must be a proper full name', this.validateFullName(options.source)); 12520 12521 var normalizedFullName = this.normalize(fullName); 12522 var normalizedSource = this.normalize(options.source); 12523 12524 return expandLocalLookup(this, normalizedFullName, normalizedSource); 12525 } else if (this.fallback) { 12526 return this.fallback.expandLocalLookup(fullName, options); 12527 } else { 12528 return null; 12529 } 12530 }; 12531 12532 function expandLocalLookup(registry, normalizedName, normalizedSource) { 12533 var cache = registry._localLookupCache; 12534 var normalizedNameCache = cache[normalizedName]; 12535 12536 if (!normalizedNameCache) { 12537 normalizedNameCache = cache[normalizedName] = new _emberMetalEmpty_object.default(); 12538 } 12539 12540 var cached = normalizedNameCache[normalizedSource]; 12541 12542 if (cached !== undefined) { 12543 return cached; 12544 } 12545 12546 var expanded = registry.resolver.expandLocalLookup(normalizedName, normalizedSource); 12547 12548 return normalizedNameCache[normalizedSource] = expanded; 12549 } 12550 12551 function resolve(registry, normalizedName, options) { 12552 if (options && options.source) { 12553 // when `source` is provided expand normalizedName 12554 // and source into the full normalizedName 12555 normalizedName = registry.expandLocalLookup(normalizedName, options); 12556 12557 // if expandLocalLookup returns falsey, we do not support local lookup 12558 if (!normalizedName) { 12559 return; 12560 } 12561 } 12562 12563 var cached = registry._resolveCache[normalizedName]; 12564 if (cached !== undefined) { 12565 return cached; 12566 } 12567 if (registry._failCache[normalizedName]) { 12568 return; 12569 } 12570 12571 var resolved = undefined; 12572 12573 if (registry.resolver) { 12574 resolved = registry.resolver.resolve(normalizedName); 12575 } 12576 12577 if (resolved === undefined) { 12578 resolved = registry.registrations[normalizedName]; 12579 } 12580 12581 if (resolved === undefined) { 12582 registry._failCache[normalizedName] = true; 12583 } else { 12584 registry._resolveCache[normalizedName] = resolved; 12585 } 12586 12587 return resolved; 12588 } 12589 12590 function has(registry, fullName, source) { 12591 return registry.resolve(fullName, { source: source }) !== undefined; 12592 } 12593 12594 exports.default = Registry; 12595}); 12596enifed('dag-map/platform', ['exports'], function (exports) { 12597 'use strict'; 12598 12599 var platform; 12600 12601 /* global self */ 12602 if (typeof self === 'object') { 12603 platform = self; 12604 12605 /* global global */ 12606 } else if (typeof global === 'object') { 12607 platform = global; 12608 } else { 12609 throw new Error('no global: `self` or `global` found'); 12610 } 12611 12612 exports.default = platform; 12613}); 12614enifed('dag-map', ['exports', 'vertex', 'visit'], function (exports, _vertex, _visit) { 12615 'use strict'; 12616 12617 exports.default = DAG; 12618 12619 /** 12620 * DAG stands for Directed acyclic graph. 12621 * 12622 * It is used to build a graph of dependencies checking that there isn't circular
12623 * dependencies. p.e Registering initializers with a certain precedence order. 12624 * 12625 * @class DAG 12626 * @constructor 12627 */ 12628 12629 function DAG() { 12630 this.names = []; 12631 this.vertices = Object.create(null); 12632 } 12633 12634 /** 12635 * Adds a vertex entry to the graph unless it is already added. 12636 * 12637 * @private 12638 * @method add 12639 * @param {String} name The name of the vertex to add 12640 */ 12641 DAG.prototype.add = function (name) { 12642 if (!name) { 12643 throw new Error("Can't add Vertex without name"); 12644 } 12645 if (this.vertices[name] !== undefined) { 12646 return this.vertices[name]; 12647 } 12648 var vertex = new _vertex.default(name); 12649 this.vertices[name] = vertex; 12650 this.names.push(name); 12651 return vertex; 12652 }; 12653 12654 /** 12655 * Adds a vertex to the graph and sets its value. 12656 * 12657 * @private 12658 * @method map 12659 * @param {String} name The name of the vertex. 12660 * @param value The value to put in the vertex. 12661 */ 12662 DAG.prototype.map = function (name, value) { 12663 this.add(name).value = value; 12664 }; 12665 12666 /** 12667 * Connects the vertices with the given names, adding them to the graph if 12668 * necessary, only if this does not produce is any circular dependency. 12669 * 12670 * @private 12671 * @method addEdge 12672 * @param {String} fromName The name the vertex where the edge starts. 12673 * @param {String} toName The name the vertex where the edge ends. 12674 */ 12675 DAG.prototype.addEdge = function (fromName, toName) { 12676 if (!fromName || !toName || fromName === toName) { 12677 return; 12678 } 12679 var from = this.add(fromName); 12680 var to = this.add(toName); 12681 if (to.incoming.hasOwnProperty(fromName)) { 12682 return; 12683 } 12684 function checkCycle(vertex, path) { 12685 if (vertex.name === toName) { 12686 throw new Error("cycle detected: " + toName + " <- " + path.join(" <- ")); 12687 } 12688 } 12689 _visit.default(from, checkCycle); 12690 from.hasOutgoing = true; 12691 to.incoming[fromName] = from; 12692 to.incomingNames.push(fromName); 12693 }; 12694 12695 /** 12696 * Visits all the vertex of the graph calling the given function with each one, 12697 * ensuring that the vertices are visited respecting their precedence. 12698 * 12699 * @method topsort 12700 * @param {Function} fn The function to be invoked on each vertex. 12701 */ 12702 DAG.prototype.topsort = function (fn) { 12703 var visited = {}; 12704 var vertices = this.vertices; 12705 var names = this.names; 12706 var len = names.length; 12707 var i, vertex; 12708 12709 for (i = 0; i < len; i++) { 12710 vertex = vertices[names[i]]; 12711 if (!vertex.hasOutgoing) { 12712 _visit.default(vertex, fn, visited); 12713 } 12714 } 12715 }; 12716 12717 /** 12718 * Adds a vertex with the given name and value to the graph and joins it with the 12719 * vertices referenced in _before_ and _after_. If there isn't vertices with those 12720 * names, they are added too. 12721 * 12722 * If either _before_ or _after_ are falsy/empty, the added vertex will not have 12723 * an incoming/outgoing edge. 12724 * 12725 * @method addEdges 12726 * @param {String} name The name of the vertex to be added. 12727 * @param value The value of that vertex. 12728 * @param before An string or array of strings with the names of the vertices before 12729 * which this vertex must be visited. 12730 * @param after An string or array of strings with the names of the vertex after 12731 * which this vertex must be visited. 12732 * 12733 */ 12734 DAG.prototype.addEdges = function (name, value, before, after) { 12735 var i; 12736 this.map(name, value); 12737 if (before) { 12738 if (typeof before === 'string') { 12739 this.addEdge(name, before); 12740 } else { 12741 for (i = 0; i < before.length; i++) { 12742 this.addEdge(name, before[i]); 12743 } 12744 } 12745 } 12746 if (after) { 12747 if (typeof after === 'string') { 12748 this.addEdge(after, name); 12749 } else { 12750 for (i = 0; i < after.length; i++) { 12751 this.addEdge(after[i], name); 12752 } 12753 } 12754 } 12755 }; 12756}); 12757enifed('dag-map.umd', ['exports', 'dag-map/platform', 'dag-map'], function (exports, _dagMapPlatform, _dagMap) { 12758 'use strict'; 12759 12760 /* global define:true module:true window: true */ 12761 if (typeof define === 'function' && define.amd) { 12762 define(function () { 12763 return _dagMap.default; 12764 }); 12765 } else if (typeof module !== 'undefined' && module.exports) { 12766 module.exports = _dagMap.default; 12767 } else if (typeof _dagMapPlatform.default !== 'undefined') { 12768 _dagMapPlatform.default['DAG'] = _dagMap.default; 12769 } 12770}); 12771enifed('dom-helper/build-html-dom', ['exports'], function (exports) { 12772 /* global XMLSerializer:false */ 12773 'use strict'; 12774 12775 var svgHTMLIntegrationPoints = { foreignObject: 1, desc: 1, title: 1 }; 12776 exports.svgHTMLIntegrationPoints = svgHTMLIntegrationPoints; 12777 var svgNamespace = 'http://www.w3.org/2000/svg'; 12778 12779 exports.svgNamespace = svgNamespace; 12780 var doc = typeof document === 'undefined' ? false : document; 12781 12782 // Safari does not like using innerHTML on SVG HTML integration 12783 // points (desc/title/foreignObject). 12784 var needsIntegrationPointFix = doc && (function (document) { 12785 if (document.createElementNS === undefined) { 12786 return; 12787 } 12788 // In FF title will not accept innerHTML. 12789 var testEl = document.createElementNS(svgNamespace, 'title'); 12790 testEl.innerHTML = "<div></div>"; 12791 return testEl.childNodes.length === 0 || testEl.childNodes[0].nodeType !== 1; 12792 })(doc); 12793 12794 // Internet Explorer prior to 9 does not allow setting innerHTML if the first element 12795 // is a "zero-scope" element. This problem can be worked around by making 12796 // the first node an invisible text node. We, like Modernizr, use ­ 12797 var needsShy = doc && (function (document) { 12798 var testEl = document.createElement('div'); 12799 testEl.innerHTML = "<div></div>"; 12800 testEl.firstChild.innerHTML = "<script><\/script>"; 12801 return testEl.firstChild.innerHTML === ''; 12802 })(doc); 12803 12804 // IE 8 (and likely earlier) likes to move whitespace preceeding 12805 // a script tag to appear after it. This means that we can 12806 // accidentally remove whitespace when updating a morph. 12807 var movesWhitespace = doc && (function (document) { 12808 var testEl = document.createElement('div'); 12809 testEl.innerHTML = "Test: <script type='text/x-placeholder'><\/script>Value"; 12810 return testEl.childNodes[0].nodeValue === 'Test:' && testEl.childNodes[2].nodeValue === ' Value'; 12811 })(doc); 12812 12813 var tagNamesRequiringInnerHTMLFix = doc && (function (document) { 12814 var tagNamesRequiringInnerHTMLFix; 12815 // IE 9 and earlier don't allow us to set innerHTML on col, colgroup, frameset, 12816 // html, style, table, tbody, tfoot, thead, title, tr. Detect this and add 12817 // them to an initial list of corrected tags. 12818 // 12819 // Here we are only dealing with the ones which can have child nodes. 12820 // 12821 var tableNeedsInnerHTMLFix; 12822 var tableInnerHTMLTestElement = document.createElement('table'); 12823 try { 12824 tableInnerHTMLTestElement.innerHTML = '<tbody></tbody>'; 12825 } catch (e) {} finally { 12826 tableNeedsInnerHTMLFix = tableInnerHTMLTestElement.childNodes.length === 0; 12827 } 12828 if (tableNeedsInnerHTMLFix) { 12829 tagNamesRequiringInnerHTMLFix = { 12830 colgroup: ['table'], 12831 table: [], 12832 tbody: ['table'], 12833 tfoot: ['table'], 12834 thead: ['table'], 12835 tr: ['table', 'tbody'] 12836 }; 12837 } 12838 12839 // IE 8 doesn't allow setting innerHTML on a select tag. Detect this and 12840 // add it to the list of corrected tags. 12841 // 12842 var selectInnerHTMLTestElement = document.createElement('select'); 12843 selectInnerHTMLTestElement.innerHTML = '<option></option>'; 12844 if (!selectInnerHTMLTestElement.childNodes[0]) { 12845 tagNamesRequiringInnerHTMLFix = tagNamesRequiringInnerHTMLFix || {}; 12846 tagNamesRequiringInnerHTMLFix.select = []; 12847 } 12848 return tagNamesRequiringInnerHTMLFix; 12849 })(doc); 12850 12851 function scriptSafeInnerHTML(element, html) { 12852 // without a leading text node, IE will drop a leading script tag. 12853 html = '­' + html; 12854 12855 element.innerHTML = html; 12856 12857 var nodes = element.childNodes; 12858 12859 // Look for ­ to remove it. 12860 var shyElement = nodes[0]; 12861 while (shyElement.nodeType === 1 && !shyElement.nodeName) { 12862 shyElement = shyElement.firstChild; 12863 } 12864 // At this point it's the actual unicode character. 12865 if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") { 12866 var newValue = shyElement.nodeValue.slice(1); 12867 if (newValue.length) { 12868 shyElement.nodeValue = shyElement.nodeValue.slice(1); 12869 } else { 12870 shyElement.parentNode.removeChild(shyElement); 12871 } 12872 } 12873 12874 return nodes; 12875 } 12876 12877 function buildDOMWithFix(html, contextualElement) { 12878 var tagName = contextualElement.tagName; 12879 12880 // Firefox versions < 11 do not have support for element.outerHTML. 12881 var outerHTML = contextualElement.outerHTML || new XMLSerializer().serializeToString(contextualElement); 12882 if (!outerHTML) { 12883 throw "Can't set innerHTML on " + tagName + " in this browser"; 12884 } 12885 12886 html = fixSelect(html, contextualElement); 12887 12888 var wrappingTags = tagNamesRequiringInnerHTMLFix[tagName.toLowerCase()]; 12889 12890 var startTag = outerHTML.match(new RegExp("<" + tagName + "([^>]*)>", 'i'))[0]; 12891 var endTag = '</' + tagName + '>'; 12892
12893 var wrappedHTML = [startTag, html, endTag]; 12894 12895 var i = wrappingTags.length; 12896 var wrappedDepth = 1 + i; 12897 while (i--) { 12898 wrappedHTML.unshift('<' + wrappingTags[i] + '>'); 12899 wrappedHTML.push('</' + wrappingTags[i] + '>'); 12900 } 12901 12902 var wrapper = document.createElement('div'); 12903 scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); 12904 var element = wrapper; 12905 while (wrappedDepth--) { 12906 element = element.firstChild; 12907 while (element && element.nodeType !== 1) { 12908 element = element.nextSibling; 12909 } 12910 } 12911 while (element && element.tagName !== tagName) { 12912 element = element.nextSibling; 12913 } 12914 return element ? element.childNodes : []; 12915 } 12916 12917 var buildDOM; 12918 if (needsShy) { 12919 buildDOM = function buildDOM(html, contextualElement, dom) { 12920 html = fixSelect(html, contextualElement); 12921 12922 contextualElement = dom.cloneNode(contextualElement, false); 12923 scriptSafeInnerHTML(contextualElement, html); 12924 return contextualElement.childNodes; 12925 }; 12926 } else { 12927 buildDOM = function buildDOM(html, contextualElement, dom) { 12928 html = fixSelect(html, contextualElement); 12929 12930 contextualElement = dom.cloneNode(contextualElement, false); 12931 contextualElement.innerHTML = html; 12932 return contextualElement.childNodes; 12933 }; 12934 } 12935 12936 function fixSelect(html, contextualElement) { 12937 if (contextualElement.tagName === 'SELECT') { 12938 html = "<option></option>" + html; 12939 } 12940 12941 return html; 12942 } 12943 12944 var buildIESafeDOM; 12945 if (tagNamesRequiringInnerHTMLFix || movesWhitespace) { 12946 buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { 12947 // Make a list of the leading text on script nodes. Include 12948 // script tags without any whitespace for easier processing later. 12949 var spacesBefore = []; 12950 var spacesAfter = []; 12951 if (typeof html === 'string') { 12952 html = html.replace(/(\s*)(<script)/g, function (match, spaces, tag) { 12953 spacesBefore.push(spaces); 12954 return tag; 12955 }); 12956 12957 html = html.replace(/(<\/script>)(\s*)/g, function (match, tag, spaces) { 12958 spacesAfter.push(spaces); 12959 return tag; 12960 }); 12961 } 12962 12963 // Fetch nodes 12964 var nodes; 12965 if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { 12966 // buildDOMWithFix uses string wrappers for problematic innerHTML. 12967 nodes = buildDOMWithFix(html, contextualElement); 12968 } else { 12969 nodes = buildDOM(html, contextualElement, dom); 12970 } 12971 12972 // Build a list of script tags, the nodes themselves will be 12973 // mutated as we add test nodes. 12974 var i, j, node, nodeScriptNodes; 12975 var scriptNodes = []; 12976 for (i = 0; i < nodes.length; i++) { 12977 node = nodes[i]; 12978 if (node.nodeType !== 1) { 12979 continue; 12980 } 12981 if (node.tagName === 'SCRIPT') { 12982 scriptNodes.push(node); 12983 } else { 12984 nodeScriptNodes = node.getElementsByTagName('script'); 12985 for (j = 0; j < nodeScriptNodes.length; j++) { 12986 scriptNodes.push(nodeScriptNodes[j]); 12987 } 12988 } 12989 } 12990 12991 // Walk the script tags and put back their leading text nodes. 12992 var scriptNode, textNode, spaceBefore, spaceAfter; 12993 for (i = 0; i < scriptNodes.length; i++) { 12994 scriptNode = scriptNodes[i]; 12995 spaceBefore = spacesBefore[i]; 12996 if (spaceBefore && spaceBefore.length > 0) { 12997 textNode = dom.document.createTextNode(spaceBefore); 12998 scriptNode.parentNode.insertBefore(textNode, scriptNode); 12999 } 13000 13001 spaceAfter = spacesAfter[i]; 13002 if (spaceAfter && spaceAfter.length > 0) { 13003 textNode = dom.document.createTextNode(spaceAfter); 13004 scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); 13005 } 13006 } 13007 13008 return nodes; 13009 }; 13010 } else { 13011 buildIESafeDOM = buildDOM; 13012 } 13013 13014 var buildHTMLDOM; 13015 if (needsIntegrationPointFix) { 13016 exports.buildHTMLDOM = buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom) { 13017 if (svgHTMLIntegrationPoints[contextualElement.tagName]) { 13018 return buildIESafeDOM(html, document.createElement('div'), dom); 13019 } else { 13020 return buildIESafeDOM(html, contextualElement, dom); 13021 } 13022 }; 13023 } else { 13024 exports.buildHTMLDOM = buildHTMLDOM = buildIESafeDOM; 13025 } 13026 13027 exports.buildHTMLDOM = buildHTMLDOM; 13028}); 13029enifed('dom-helper/classes', ['exports'], function (exports) { 13030 'use strict'; 13031 13032 var doc = typeof document === 'undefined' ? false : document; 13033 13034 // PhantomJS has a broken classList. See https://github.com/ariya/phantomjs/issues/12782 13035 var canClassList = doc && (function () { 13036 var d = document.createElement('div'); 13037 if (!d.classList) { 13038 return false;
13039 } 13040 d.classList.add('boo'); 13041 d.classList.add('boo', 'baz'); 13042 return d.className === 'boo baz'; 13043 })(); 13044 13045 function buildClassList(element) { 13046 var classString = element.getAttribute('class') || ''; 13047 return classString !== '' && classString !== ' ' ? classString.split(' ') : []; 13048 } 13049 13050 function intersect(containingArray, valuesArray) { 13051 var containingIndex = 0; 13052 var containingLength = containingArray.length; 13053 var valuesIndex = 0; 13054 var valuesLength = valuesArray.length; 13055 13056 var intersection = new Array(valuesLength); 13057 13058 // TODO: rewrite this loop in an optimal manner 13059 for (; containingIndex < containingLength; containingIndex++) { 13060 valuesIndex = 0; 13061 for (; valuesIndex < valuesLength; valuesIndex++) { 13062 if (valuesArray[valuesIndex] === containingArray[containingIndex]) { 13063 intersection[valuesIndex] = containingIndex; 13064 break; 13065 } 13066 } 13067 } 13068 13069 return intersection; 13070 } 13071 13072 function addClassesViaAttribute(element, classNames) { 13073 var existingClasses = buildClassList(element); 13074 13075 var indexes = intersect(existingClasses, classNames); 13076 var didChange = false; 13077 13078 for (var i = 0, l = classNames.length; i < l; i++) { 13079 if (indexes[i] === undefined) { 13080 didChange = true; 13081 existingClasses.push(classNames[i]); 13082 } 13083 } 13084 13085 if (didChange) { 13086 element.setAttribute('class', existingClasses.length > 0 ? existingClasses.join(' ') : ''); 13087 } 13088 } 13089 13090 function removeClassesViaAttribute(element, classNames) { 13091 var existingClasses = buildClassList(element); 13092 13093 var indexes = intersect(classNames, existingClasses); 13094 var didChange = false; 13095 var newClasses = []; 13096 13097 for (var i = 0, l = existingClasses.length; i < l; i++) { 13098 if (indexes[i] === undefined) { 13099 newClasses.push(existingClasses[i]); 13100 } else { 13101 didChange = true; 13102 } 13103 } 13104 13105 if (didChange) { 13106 element.setAttribute('class', newClasses.length > 0 ? newClasses.join(' ') : ''); 13107 } 13108 } 13109 13110 var addClasses, removeClasses; 13111 if (canClassList) { 13112 exports.addClasses = addClasses = function addClasses(element, classNames) { 13113 if (element.classList) { 13114 if (classNames.length === 1) { 13115 element.classList.add(classNames[0]); 13116 } else if (classNames.length === 2) { 13117 element.classList.add(classNames[0], classNames[1]); 13118 } else { 13119 element.classList.add.apply(element.classList, classNames); 13120 } 13121 } else { 13122 addClassesViaAttribute(element, classNames); 13123 } 13124 }; 13125 exports.removeClasses = removeClasses = function removeClasses(element, classNames) { 13126 if (element.classList) { 13127 if (classNames.length === 1) { 13128 element.classList.remove(classNames[0]); 13129 } else if (classNames.length === 2) { 13130 element.classList.remove(classNames[0], classNames[1]); 13131 } else { 13132 element.classList.remove.apply(element.classList, classNames); 13133 } 13134 } else { 13135 removeClassesViaAttribute(element, classNames); 13136 } 13137 }; 13138 } else { 13139 exports.addClasses = addClasses = addClassesViaAttribute; 13140 exports.removeClasses = removeClasses = removeClassesViaAttribute; 13141 } 13142 13143 exports.addClasses = addClasses; 13144 exports.removeClasses = removeClasses; 13145}); 13146enifed('dom-helper/prop', ['exports'], function (exports) { 13147 'use strict'; 13148 13149 exports.isAttrRemovalValue = isAttrRemovalValue; 13150 exports.normalizeProperty = normalizeProperty; 13151 13152 function isAttrRemovalValue(value) { 13153 return value === null || value === undefined; 13154 } 13155 13156 /* 13157 * 13158 * @method normalizeProperty 13159 * @param element {HTMLElement} 13160 * @param slotName {String} 13161 * @returns {Object} { name, type } 13162 */ 13163 13164 function normalizeProperty(element, slotName) { 13165 var type, normalized; 13166 13167 if (slotName in element) { 13168 normalized = slotName; 13169 type = 'prop'; 13170 } else { 13171 var lower = slotName.toLowerCase(); 13172 if (lower in element) { 13173 type = 'prop'; 13174 normalized = lower; 13175 } else { 13176 type = 'attr'; 13177 normalized = slotName; 13178 } 13179 } 13180 13181 if (type === 'prop' && (normalized.toLowerCase() === 'style' || preferAttr(element.tagName, normalized))) { 13182 type = 'attr'; 13183 } 13184 13185 return { normalized: normalized, type: type }; 13186 } 13187 13188 // properties that MUST be set as attributes, due to: 13189 // * browser bug 13190 // * strange spec outlier 13191 var ATTR_OVERRIDES = { 13192 13193 // phantomjs < 2.0 lets you set it as a prop but won't reflect it 13194 // back to the attribute. button.getAttribute('type') === null 13195 BUTTON: { type: true, form: true }, 13196 13197 INPUT: { 13198 // TODO: remove when IE8 is droped 13199 // Some versions of IE (IE8) throw an exception when setting 13200 // `input.list = 'somestring'`: 13201 // https://github.com/emberjs/ember.js/issues/10908 13202 // https://github.com/emberjs/ember.js/issues/11364 13203 list: true, 13204 // Some version of IE (like IE9) actually throw an exception 13205 // if you set input.type = 'something-unknown' 13206 type: true, 13207 form: true, 13208 // Chrome 46.0.2464.0: 'autocorrect' in document.createElement('input') === false 13209 // Safari 8.0.7: 'autocorrect' in document.createElement('input') === false 13210 // Mobile Safari (iOS 8.4 simulator): 'autocorrect' in document.createElement('input') === true 13211 autocorrect: true 13212 }, 13213 13214 // element.form is actually a legitimate readOnly property, that is to be 13215 // mutated, but must be mutated by setAttribute... 13216 SELECT: { form: true }, 13217 OPTION: { form: true }, 13218 TEXTAREA: { form: true }, 13219 LABEL: { form: true }, 13220 FIELDSET: { form: true }, 13221 LEGEND: { form: true }, 13222 OBJECT: { form: true } 13223 }; 13224 13225 function preferAttr(tagName, propName) { 13226 var tag = ATTR_OVERRIDES[tagName.toUpperCase()]; 13227 return tag && tag[propName.toLowerCase()] || false; 13228 } 13229}); 13230enifed("dom-helper", ["exports", "htmlbars-runtime/morph", "morph-attr", "dom-helper/build-html-dom", "dom-helper/classes", "dom-helper/prop"], function (exports, _htmlbarsRuntimeMorph, _morphAttr, _domHelperBuildHtmlDom, _domHelperClasses, _domHelperProp) { 13231 /*globals module, URL*/ 13232 13233 "use strict"; 13234 13235 var doc = typeof document === 'undefined' ? false : document; 13236 13237 var deletesBlankTextNodes = doc && (function (document) { 13238 var element = document.createElement('div'); 13239 element.appendChild(document.createTextNode('')); 13240 var clonedElement = element.cloneNode(true); 13241 return clonedElement.childNodes.length === 0; 13242 })(doc); 13243 13244 var ignoresCheckedAttribute = doc && (function (document) { 13245 var element = document.createElement('input'); 13246 element.setAttribute('checked', 'checked'); 13247 var clonedElement = element.cloneNode(false); 13248 return !clonedElement.checked; 13249 })(doc); 13250 13251 var canRemoveSvgViewBoxAttribute = doc && (doc.createElementNS ? (function (document) { 13252 var element = document.createElementNS(_domHelperBuildHtmlDom.svgN
13252amespace, 'svg'); 13253 element.setAttribute('viewBox', '0 0 100 100'); 13254 element.removeAttribute('viewBox'); 13255 return !element.getAttribute('viewBox'); 13256 })(doc) : true); 13257 13258 var canClone = doc && (function (document) { 13259 var element = document.createElement('div'); 13260 element.appendChild(document.createTextNode(' ')); 13261 element.appendChild(document.createTextNode(' ')); 13262 var clonedElement = element.cloneNode(true); 13263 return clonedElement.childNodes[0].nodeValue === ' '; 13264 })(doc); 13265 13266 // This is not the namespace of the element, but of 13267 // the elements inside that elements. 13268 function interiorNamespace(element) { 13269 if (element && element.namespaceURI === _domHelperBuildHtmlDom.svgNamespace && !_domHelperBuildHtmlDom.svgHTMLIntegrationPoints[element.tagName]) { 13270 return _domHelperBuildHtmlDom.svgNamespace; 13271 } else { 13272 return null; 13273 } 13274 } 13275 13276 // The HTML spec allows for "omitted start tags". These tags are optional 13277 // when their intended child is the first thing in the parent tag. For 13278 // example, this is a tbody start tag: 13279 // 13280 // <table> 13281 // <tbody> 13282 // <tr> 13283 // 13284 // The tbody may be omitted, and the browser will accept and render: 13285 // 13286 // <table> 13287 // <tr> 13288 // 13289 // However, the omitted start tag will still be added to the DOM. Here 13290 // we test the string and context to see if the browser is about to 13291 // perform this cleanup. 13292 // 13293 // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags 13294 // describes which tags are omittable. The spec for tbody and colgroup 13295 // explains this behavior: 13296 // 13297 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element 13298 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element 13299 // 13300 13301 var omittedStartTagChildTest = /<([\w:]+)/; 13302 function detectOmittedStartTag(string, contextualElement) { 13303 // Omitted start tags are only inside table tags. 13304 if (contextualElement.tagName === 'TABLE') { 13305 var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); 13306 if (omittedStartTagChildMatch) { 13307 var omittedStartTagChild = omittedStartTagChildMatch[1]; 13308 // It is already asserted that the contextual element is a table 13309 // and not the proper start tag. Just see if a tag was omitted. 13310 return omittedStartTagChild === 'tr' || omittedStartTagChild === 'col'; 13311 } 13312 } 13313 } 13314 13315 function buildSVGDOM(html, dom) { 13316 var div = dom.document.createElement('div'); 13317 div.innerHTML = '<svg>' + html + '</svg>'; 13318 return div.firstChild.childNodes; 13319 } 13320 13321 var guid = 1; 13322 13323 function ElementMorph(element, dom, namespace) { 13324 this.element = element; 13325 this.dom = dom; 13326 this.namespace = namespace; 13327 this.guid = "element" + guid++; 13328 13329 this._state = undefined; 13330 this.isDirty = true; 13331 } 13332 13333 ElementMorph.prototype.getState = function () { 13334 if (!this._state) { 13335 this._state = {}; 13336 } 13337 13338 return this._state; 13339 }; 13340 13341 ElementMorph.prototype.setState = function (newState) { 13342 /*jshint -W093 */ 13343 13344 return this._state = newState; 13345 }; 13346 13347 // renderAndCleanup calls `clear` on all items in the morph map 13348 // just before calling `destroy` on the morph. 13349 // 13350 // As a future refactor this could be changed to set the property 13351 // back to its original/default value. 13352 ElementMorph.prototype.clear = function () {}; 13353 13354 ElementMorph.prototype.destroy = function () { 13355 this.element = null; 13356 this.dom = null; 13357 }; 13358 13359 /* 13360 * A class wrapping DOM functions to address environment compatibility, 13361 * namespaces, contextual elements for morph un-escaped content 13362 * insertion. 13363 * 13364 * When entering a template, a DOMHelper should be passed: 13365 * 13366 * template(context, { hooks: hooks, dom: new DOMHelper() }); 13367 * 13368 * TODO: support foreignObject as a passed contextual element. It has 13369 * a namespace (svg) that does not match its internal namespace 13370 * (xhtml). 13371 * 13372 * @class DOMHelper 13373 * @constructor 13374 * @param {HTMLDocument} _document The document DOM methods are proxied to 13375 */ 13376 function DOMHelper(_document) { 13377 this.document = _document || document; 13378 if (!this.document) { 13379 throw new Error("A document object must be passed to the DOMHelper, or available on the global scope"); 13380 } 13381 this.canClone = canClone; 13382 this.namespace = null; 13383 13384 installEnvironmentSpecificMethods(this); 13385 } 13386 13387 var prototype = DOMHelper.prototype; 13388 prototype.constructor = DOMHelper; 13389 13390 prototype.getElementById = function (id, rootNode) { 13391 rootNode = rootNode || this.document; 13392 return rootNode.getElementById(id); 13393 }; 13394 13395 prototype.insertBefore = function (element, childElement, referenceChild) { 13396 return element.insertBefore(childElement, referenceChild); 13397 }; 13398 13399 prototype.appendChild = function (element, childElement) { 13400 return element.appendChild(childElement); 13401 }; 13402 13403 var itemAt; 13404 13405 // It appears that sometimes, in yet to be itentified scenarios PhantomJS 2.0 13406 // crashes on childNodes.item(index), but works as expected with childNodes[index]; 13407 // 13408 // Although it would be nice to move to childNodes[index] in all scenarios, 13409 // this would require SimpleDOM to maintain the childNodes array. This would be 13410 // quite costly, in both dev time and runtime. 13411 // 13412 // So instead, we choose the best possible method and call it a day. 13413 // 13414 /*global navigator */ 13415 if (typeof navigator !== 'undefined' && navigator.userAgent.indexOf('PhantomJS')) { 13416 itemAt = function (nodes, index) { 13417 return nodes[index]; 13418 }; 13419 } else { 13420 itemAt = function (nodes, index) { 13421 return nodes.item(index); 13422 }; 13423 } 13424 13425 prototype.childAt = function (element, indices) { 13426 var child = element; 13427 13428 for (var i = 0; i < indices.length; i++) { 13429 child = itemAt(child.childNodes, indices[i]); 13430 } 13431 13432 return child; 13433 }; 13434 13435 // Note to a Fellow Implementor: 13436 // Ahh, accessing a child node at an index. Seems like it should be so simple, 13437 // doesn't it? Unfortunately, this particular method has caused us a surprising 13438 // amount of pain. As you'll note below, this method has been modified to walk 13439 // the linked list of child nodes rather than access the child by index 13440 // directly, even though there are two (2) APIs in the DOM that do this for us. 13441 // If you're thinking to yourself, "What an oversight! What an opportunity to 13442 // optimize this code!" then to you I say: stop! For I have a tale to tell. 13443 // 13444 // First, this code must be compatible with simple-dom for rendering on the 13445 // server where there is no real DOM. Previously, we accessed a child node 13446 // directly via `element.childNodes[index]`. While we *could* in theory do a 13447 // full-fidelity simulation of a live `childNodes` array, this is slow, 13448 // complicated and error-prone. 13449 // 13450 // "No problem," we thought, "we'll just use the similar 13451 // `childNodes.item(index)` API." Then, we could just implement our own `item` 13452 // method in simple-dom and walk the child node linked list there, allowing 13453 // us to retain the performance advantages of the (surely optimized) `item()` 13454 // API in the browser. 13455 // 13456 // Unfortunately, an enterprising soul named Samy Alzahrani discovered that in 13457 // IE8, accessing an item out-of-bounds via `item()` causes an exception where 13458 // other browsers return null. This necessitated a... check of 13459 // `childNodes.length`, bringing us back around to having to supp
13459ort a 13460 // full-fidelity `childNodes` array! 13461 // 13462 // Worst of all, Kris Selden investigated how browsers are actualy implemented 13463 // and discovered that they're all linked lists under the hood anyway. Accessing 13464 // `childNodes` requires them to allocate a new live collection backed by that 13465 // linked list, which is itself a rather expensive operation. Our assumed 13466 // optimization had backfired! That is the danger of magical thinking about 13467 // the performance of native implementations. 13468 // 13469 // And this, my friends, is why the following implementation just walks the 13470 // linked list, as surprised as that may make you. Please ensure you understand 13471 // the above before changing this and submitting a PR. 13472 // 13473 // Tom Dale, January 18th, 2015, Portland OR 13474 prototype.childAtIndex = function (element, index) { 13475 var node = element.firstChild; 13476 13477 for (var idx = 0; node && idx < index; idx++) { 13478 node = node.nextSibling; 13479 } 13480 13481 return node; 13482 }; 13483 13484 prototype.appendText = function (element, text) { 13485 return element.appendChild(this.document.createTextNode(text)); 13486 }; 13487 13488 prototype.setAttribute = function (element, name, value) { 13489 element.setAttribute(name, String(value)); 13490 }; 13491 13492 prototype.getAttribute = function (element, name) { 13493 return element.getAttribute(name); 13494 }; 13495 13496 prototype.setAttributeNS = function (element, namespace, name, value) { 13497 element.setAttributeNS(namespace, name, String(value)); 13498 }; 13499 13500 prototype.getAttributeNS = function (element, namespace, name) { 13501 return element.getAttributeNS(namespace, name); 13502 }; 13503 13504 if (canRemoveSvgViewBoxAttribute) { 13505 prototype.removeAttribute = function (element, name) { 13506 element.removeAttribute(name); 13507 }; 13508 } else { 13509 prototype.removeAttribute = function (element, name) { 13510 if (element.tagName === 'svg' && name === 'viewBox') { 13511 element.setAttribute(name, null); 13512 } else { 13513 element.removeAttribute(name); 13514 } 13515 }; 13516 } 13517 13518 prototype.setPropertyStrict = function (element, name, value) { 13519 if (value === undefined) { 13520 value = null; 13521 } 13522 13523 if (value === null && (name === 'value' || name === 'type' || name === 'src')) { 13524 value = ''; 13525 } 13526 13527 element[name] = value; 13528 }; 13529 13530 prototype.getPropertyStrict = function (element, name) { 13531 return element[name]; 13532 }; 13533 13534 prototype.setProperty = function (element, name, value, namespace) { 13535 if (element.namespaceURI === _domHelperBuildHtmlDom.svgNamespace) { 13536 if (_domHelperProp.isAttrRemovalValue(value)) { 13537 element.removeAttribute(name); 13538 } else { 13539 if (namespace) { 13540 element.setAttributeNS(namespace, name, value); 13541 } else { 13542 element.setAttribute(name, value); 13543 } 13544 } 13545 } else { 13546 var _normalizeProperty = _domHelperProp.normalizeProperty(element, name); 13547 13548 var normalized = _normalizeProperty.normalized; 13549 var type = _normalizeProperty.type; 13550 13551 if (type === 'prop') { 13552 element[normalized] = value; 13553 } else { 13554 if (_domHelperProp.isAttrRemovalValue(value)) { 13555 element.removeAttribute(name); 13556 } else { 13557 if (namespace && element.setAttributeNS) { 13558 element.setAttributeNS(namespace, name, value); 13559 } else { 13560 element.setAttribute(name, value); 13561 } 13562 } 13563 } 13564 } 13565 }; 13566 13567 if (doc && doc.createElementNS) { 13568 // Only opt into namespace detection if a contextualElement 13569 // is passed. 13570 prototype.createElement = function (tagName, contextualElement) { 13571 var namespace = this.namespace; 13572 if (contextualElement) { 13573 if (tagName === 'svg') { 13574 namespace = _domHelperBuildHtmlDom.svgNamespace; 13575 } else { 13576 namespace = interiorNamespace(contextualElement); 13577 } 13578 } 13579 if (namespace) { 13580 return this.document.createElementNS(namespace, tagName); 13581 } else { 13582 return this.document.createElement(tagName); 13583 } 13584 }; 13585 prototype.setAttributeNS = function (element, namespace, name, value) { 13586 element.setAttributeNS(namespace, name, String(value)); 13587 }; 13588 } else { 13589 prototype.createElement = function (tagName) { 13590 return this.document.createElement(tagName); 13591 }; 13592 prototype.setAttributeNS = function (element, namespace, name, value) { 13593 element.setAttribute(name, String(value)); 13594 }; 13595 } 13596 13597 prototype.addClasses = _domHelperClasses.addClasses; 13598 prototype.removeClasses = _domHelperClasses.removeClasses; 13599 13600 prototype.setNamespace = function (ns) { 13601 this.namespace = ns; 13602 }; 13603 13604 prototype.detectNamespace = function (element) { 13605 this.namespace = interiorNamespace(element); 13606 }; 13607 13608 prototype.createDocumentFragment = function () { 13609 return this.document.createDocumentFragment(); 13610 }; 13611 13612 prototype.createTextNode = function (text) { 13613 return this.document.createTextNode(text); 13614 }; 13615 13616 prototype.createComment = function (text) { 13617 return this.document.createComment(text); 13618 }; 13619 13620 prototype.repairClonedNode = function (element, blankChildTextNodes, isChecked) { 13621 if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { 13622 for (var i = 0, len = blankChildTextNodes.length; i < len; i++) { 13623 var textNode = this.document.createTextNode(''), 13624 offset = blankChildTextNodes[i], 13625 before = this.childAtIndex(element, offset); 13626 if (before) { 13627 element.insertBefore(textNode, before); 13628 } else { 13629 element.appendChild(textNode); 13630 } 13631 } 13632 } 13633 if (ignoresCheckedAttribute && isChecked) { 13634 element.setAttribute('checked', 'checked'); 13635 } 13636 }; 13637 13638 prototype.cloneNode = function (element, deep) { 13639 var clone = element.cloneNode(!!deep); 13640 return clone; 13641 }; 13642 13643 prototype.AttrMorphClass = _morphAttr.default; 13644 13645 prototype.createAttrMorph = function (element, attrName, namespace) { 13646 return this.AttrMorphClass.create(element, attrName, this, namespace); 13647 }; 13648 13649 prototype.ElementMorphClass = ElementMorph; 13650 13651 prototype.createElementMorph = function (element, namespace) { 13652 return new this.ElementMorphClass(element, this, namespace); 13653 }; 13654 13655 prototype.createUnsafeAttrMorph = function (element, attrName, namespace) { 13656 var morph = this.createAttrMorph(element, attrName, namespace); 13657 morph.escaped = false;
13658 return morph; 13659 }; 13660 13661 prototype.MorphClass = _htmlbarsRuntimeMorph.default; 13662 13663 prototype.createMorph = function (parent, start, end, contextualElement) { 13664 if (contextualElement && contextualElement.nodeType === 11) { 13665 throw new Error("Cannot pass a fragment as the contextual element to createMorph"); 13666 } 13667 13668 if (!contextualElement && parent && parent.nodeType === 1) { 13669 contextualElement = parent; 13670 } 13671 var morph = new this.MorphClass(this, contextualElement); 13672 morph.firstNode = start; 13673 morph.lastNode = end; 13674 return morph; 13675 }; 13676 13677 prototype.createFragmentMorph = function (contextualElement) { 13678 if (contextualElement && contextualElement.nodeType === 11) { 13679 throw new Error("Cannot pass a fragment as the contextual element to createMorph"); 13680 } 13681 13682 var fragment = this.createDocumentFragment(); 13683 return _htmlbarsRuntimeMorph.default.create(this, contextualElement, fragment); 13684 }; 13685 13686 prototype.replaceContentWithMorph = function (element) { 13687 var firstChild = element.firstChild; 13688 13689 if (!firstChild) { 13690 var comment = this.createComment(''); 13691 this.appendChild(element, comment); 13692 return _htmlbarsRuntimeMorph.default.create(this, element, comment); 13693 } else { 13694 var morph = _htmlbarsRuntimeMorph.default.attach(this, element, firstChild, element.lastChild); 13695 morph.clear(); 13696 return morph; 13697 } 13698 }; 13699 13700 prototype.createUnsafeMorph = function (parent, start, end, contextualElement) { 13701 var morph = this.createMorph(parent, start, end, contextualElement); 13702 morph.parseTextAsHTML = true; 13703 return morph; 13704 }; 13705 13706 // This helper is just to keep the templates good looking, 13707 // passing integers instead of element references. 13708 prototype.createMorphAt = function (parent, startIndex, endIndex, contextualElement) { 13709 var single = startIndex === endIndex; 13710 var start = this.childAtIndex(parent, startIndex); 13711 var end = single ? start : this.childAtIndex(parent, endIndex); 13712 return this.createMorph(parent, start, end, contextualElement); 13713 }; 13714 13715 prototype.createUnsafeMorphAt = function (parent, startIndex, endIndex, contextualElement) { 13716 var morph = this.createMorphAt(parent, startIndex, endIndex, contextualElement); 13717 morph.parseTextAsHTML = true; 13718 return morph; 13719 }; 13720 13721 prototype.insertMorphBefore = function (element, referenceChild, contextualElement) { 13722 var insertion = this.document.createComment(''); 13723 element.insertBefore(insertion, referenceChild); 13724 return this.createMorph(element, insertion, insertion, contextualElement); 13725 }; 13726 13727 prototype.appendMorph = function (element, contextualElement) { 13728 var insertion = this.document.createComment(''); 13729 element.appendChild(insertion); 13730 return this.createMorph(element, insertion, insertion, contextualElement); 13731 }; 13732 13733 prototype.insertBoundary = function (fragment, index) { 13734 // this will always be null or firstChild 13735 var child = index === null ? null : this.childAtIndex(fragment, index); 13736 this.insertBefore(fragment, this.createTextNode(''), child); 13737 }; 13738 13739 prototype.setMorphHTML = function (morph, html) { 13740 morph.setHTML(html); 13741 }; 13742 13743 prototype.parseHTML = function (html, contextualElement) { 13744 var childNodes; 13745 13746 if (interiorNamespace(contextualElement) === _domHelperBuildHtmlDom.svgNamespace) { 13747 childNodes = buildSVGDOM(html, this); 13748 } else { 13749 var nodes = _domHelperBuildHtmlDom.buildHTMLDOM(html, contextualElement, this); 13750 if (detectOmittedStartTag(html, contextualElement)) { 13751 var node = nodes[0]; 13752 while (node && node.nodeType !== 1) { 13753 node = node.nextSibling; 13754 } 13755 childNodes = node.childNodes; 13756 } else { 13757 childNodes = nodes; 13758 } 13759 } 13760 13761 // Copy node list to a fragment. 13762 var fragment = this.document.createDocumentFragment(); 13763 13764 if (childNodes && childNodes.length > 0) { 13765 var currentNode = childNodes[0]; 13766 13767 // We prepend an <option> to <select> boxes to absorb any browser bugs 13768 // related to auto-select behavior. Skip past it. 13769 if (contextualElement.tagName === 'SELECT') { 13770 currentNode = currentNode.nextSibling; 13771 } 13772 13773 while (currentNode) { 13774 var tempNode = currentNode; 13775 currentNode = currentNode.nextSibling; 13776 13777 fragment.appendChild(tempNode); 13778 } 13779 } 13780 13781 return fragment; 13782 }; 13783
13784 var nodeURL; 13785 var parsingNode; 13786 13787 function installEnvironmentSpecificMethods(domHelper) { 13788 var protocol = browserProtocolForURL.call(domHelper, 'foobar:baz'); 13789 13790 // Test to see if our DOM implementation parses 13791 // and normalizes URLs. 13792 if (protocol === 'foobar:') { 13793 // Swap in the method that doesn't do this test now that 13794 // we know it works. 13795 domHelper.protocolForURL = browserProtocolForURL; 13796 } else if (typeof URL === 'object') { 13797 // URL globally provided, likely from FastBoot's sandbox 13798 nodeURL = URL; 13799 domHelper.protocolForURL = nodeProtocolForURL; 13800 } else if (typeof module === 'object' && typeof module.require === 'function') { 13801 // Otherwise, we need to fall back to our own URL parsing. 13802 // Global `require` is shadowed by Ember's loader so we have to use the fully 13803 // qualified `module.require`. 13804 nodeURL = module.require('url'); 13805 domHelper.protocolForURL = nodeProtocolForURL; 13806 } else { 13807 throw new Error("DOM Helper could not find valid URL parsing mechanism"); 13808 } 13809 13810 // A SimpleDOM-specific extension that allows us to place HTML directly 13811 // into the DOM tree, for when the output target is always serialized HTML. 13812 if (domHelper.document.createRawHTMLSection) { 13813 domHelper.setMorphHTML = nodeSetMorphHTML; 13814 } 13815 } 13816 13817 function nodeSetMorphHTML(morph, html) { 13818 var section = this.document.createRawHTMLSection(html); 13819 morph.setNode(section); 13820 } 13821 13822 function browserProtocolForURL(url) { 13823 if (!parsingNode) { 13824 parsingNode = this.document.createElement('a'); 13825 } 13826 13827 parsingNode.href = url; 13828 return parsingNode.protocol; 13829 } 13830 13831 function nodeProtocolForURL(url) { 13832 var protocol = nodeURL.parse(url).protocol; 13833 return protocol === null ? ':' : protocol; 13834 } 13835 13836 exports.default = DOMHelper; 13837}); 13838enifed('ember/index', ['exports', 'ember-metal', 'ember-runtime', 'ember-views', 'ember-routing', 'ember-application', 'ember-extension-support', 'ember-htmlbars', 'ember-routing-htmlbars', 'ember-routing-views', 'require', 'ember-runtime/system/lazy_load'], function (exports, _emberMetal, _emberRuntime, _emberViews, _emberRouting, _emberApplication, _emberExtensionSupport, _emberHtmlbars, _emberRoutingHtmlbars, _emberRoutingViews, _require, _emberRuntimeSystemLazy_load) { 13839 // require the main entry points for each of these packages 13840 // this is so that the global exports occur properly 13841 'use strict'; 13842 13843 if (_require.has('ember-template-compiler')) { 13844 _require.default('ember-template-compiler'); 13845 } 13846 13847 // do this to ensure that Ember.Test is defined properly on the global 13848 // if it is present. 13849 if (_require.has('ember-testing')) { 13850 _require.default('ember-testing'); 13851 } 13852 13853 _emberRuntimeSystemLazy_load.runLoadHooks('Ember'); 13854 13855 /** 13856 @module ember 13857 */ 13858}); 13859enifed('ember-application/index', ['exports', 'ember-metal/core', 'ember-metal/features', 'ember-runtime/system/lazy_load', 'ember-application/system/resolver', 'ember-application/system/application', 'ember-application/system/application-instance', 'ember-application/system/engine', 'ember-application/system/engine-instance'], function (exports, _emberMetalCore, _emberMetalFeatures, _emberRuntimeSystemLazy_load, _emberApplicationSystemResolver, _emberApplicationSystemApplication, _emberApplicationSystemApplicationInstance, _emberApplicationSystemEngine, _emberApplicationSystemEngineInstance) { 13860 'use strict'; 13861 13862 _emberMetalCore.default.Application = _emberApplicationSystemApplication.default; 13863 _emberMetalCore.default.Resolver = _emberApplicationSystemResolver.Resolver; 13864 _emberMetalCore.default.DefaultResolver = _emberApplicationSystemResolver.default; 13865 13866 _emberRuntimeSystemLazy_load.runLoadHooks('Ember.Application', _emberApplicationSystemApplication.default); 13867}); 13868 13869/** 13870@module ember 13871@submodule ember-application 13872*/ 13873 13874// Expose `EngineInstance` and `ApplicationInstance` for easy overriding. 13875// Reanalyze whether to continue exposing these after feature flag is removed. 13876enifed('ember-application/system/application-instance', ['exports', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/run_loop', 'ember-metal/computed', 'ember-htmlbars/system/dom-helper', 'ember-runtime/mixins/registry_proxy', 'ember-metal-views', 'ember-metal/assign', 'ember-metal/environment', 'ember-runtime/ext/rsvp', 'ember-views/system/jquery', 'ember-application/system/engine-instance'], function (exports, _emberMetalDebug, _emberMetalFeatures, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalRun_loop, _emberMetalComputed, _emberHtmlbarsSystemDomHelper, _emberRuntimeMixinsReg
13876istry_proxy, _emberMetalViews, _emberMetalAssign, _emberMetalEnvironment, _emberRuntimeExtRsvp, _emberViewsSystemJquery, _emberApplicationSystemEngineInstance) { 13877 /** 13878 @module ember 13879 @submodule ember-application 13880 */ 13881 13882 'use strict'; 13883 13884 var BootOptions = undefined; 13885 13886 /** 13887 The `ApplicationInstance` encapsulates all of the stateful aspects of a 13888 running `Application`. 13889 13890 At a high-level, we break application boot into two distinct phases: 13891 13892 * Definition time, where all of the classes, templates, and other 13893 dependencies are loaded (typically in the browser). 13894 * Run time, where we begin executing the application once everything 13895 has loaded. 13896 13897 Definition time can be expensive and only needs to happen once since it is 13898 an idempotent operation. For example, between test runs and FastBoot 13899 requests, the application stays the same. It is only the state that we want 13900 to reset. 13901 13902 That state is what the `ApplicationInstance` manages: it is responsible for 13903 creating the container that contains all application state, and disposing of 13904 it once the particular test run or FastBoot request has finished. 13905 13906 @public 13907 @class Ember.ApplicationInstance 13908 @extends Ember.EngineInstance 13909 */ 13910 13911 var ApplicationInstance = _emberApplicationSystemEngineInstance.default.extend({ 13912 /** 13913 The `Application` for which this is an instance. 13914 @property {Ember.Application} application 13915 @private 13916 */ 13917 application: null, 13918 13919 /** 13920 The DOM events for which the event dispatcher should listen. 13921 By default, the application's `Ember.EventDispatcher` listens 13922 for a set of standard DOM events, such as `mousedown` and 13923 `keyup`, and delegates them to your application's `Ember.View` 13924 instances. 13925 @private 13926 @property {Object} customEvents 13927 */ 13928 customEvents: null, 13929 13930 /** 13931 The root DOM element of the Application as an element or a 13932 [jQuery-compatible selector 13933 string](http://api.jquery.com/category/selectors/). 13934 @private 13935 @property {String|DOMElement} rootElement 13936 */ 13937 rootElement: null, 13938 13939 init: function () { 13940 this._super.apply(this, arguments); 13941 13942 var application = this.application; 13943 13944 // Register this instance in the per-instance registry. 13945 // 13946 // Why do we need to register the instance in the first place? 13947 // Because we need a good way for the root route (a.k.a ApplicationRoute) 13948 // to notify us when it has created the root-most view. That view is then 13949 // appended to the rootElement, in the case of apps, to the fixture harness 13950 // in tests, or rendered to a string in the case of FastBoot. 13951 this.register('-application-instance:main', this, { instantiate: false }); 13952 13953 this._booted = false; 13954 }, 13955 13956 /** 13957 Initialize the `Ember.ApplicationInstance` and return a promise that resolves 13958 with the instance itself when the boot process is complete. 13959 The primary task here is to run any registered instance initializers. 13960 See the documentation on `BootOptions` for the options it takes. 13961 @private 13962 @method boot 13963 @param options 13964 @return {Promise<Ember.ApplicationInstance,Error>} 13965 */ 13966 boot: function () { 13967 var _this = this; 13968 13969 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 13970 13971 if (this._bootPromise) { 13972 return this._bootPromise; 13973 } 13974 13975 this._bootPromise = new _emberRuntimeExtRsvp.default.Promise(function (resolve) { 13976 return resolve(_this._bootSync(options)); 13977 }); 13978 13979 return this._bootPromise; 13980 }, 13981 13982 /** 13983 Unfortunately, a lot of existing code assumes booting an instance is 13984 synchronous â specifically, a lot of tests assumes the last call to 13985 `app.advanceReadiness()` or `app.reset()` will result in a new instance 13986 being fully-booted when the current runloop completes. 13987 We would like new code (like the `visit` API) to stop making this assumption, 13988 so we created the asynchronous version above that returns a promise. But until 13989 we have migrated all the code, we would have to expose this method for use 13990 *internally* in places where we need to boot an instance synchronously. 13991 @private 13992 */ 13993 _bootSync: function (options) { 13994 if (this._booted) { 13995 return this; 13996 } 13997 13998 options = new BootOptions(options); 13999 14000 var registry = this.__registry__; 14001 14002 registry.register('-environment:main', options.toEnvironment(), { instantiate: false }); 14003 registry.injection('view', '_environment', '-environment:main'); 14004 registry.injection('route', '_environment', '-environment:main'); 14005 14006 registry.register('renderer:-dom', { 14007 create: function () {
14008 return new _emberMetalViews.Renderer(new _emberHtmlbarsSystemDomHelper.default(options.document), { destinedForDOM: options.isInteractive }); 14009 } 14010 }); 14011 14012 if (options.rootElement) { 14013 this.rootElement = options.rootElement; 14014 } else { 14015 this.rootElement = this.application.rootElement; 14016 } 14017 14018 if (options.location) { 14019 var router = _emberMetalProperty_get.get(this, 'router'); 14020 _emberMetalProperty_set.set(router, 'location', options.location); 14021 } 14022 14023 this.application.runInstanceInitializers(this); 14024 14025 if (options.isInteractive) { 14026 this.setupEventDispatcher(); 14027 } 14028 14029 this._booted = true; 14030 14031 return this; 14032 }, 14033 14034 router: _emberMetalComputed.computed(function () { 14035 return this.lookup('router:main'); 14036 }).readOnly(), 14037 14038 /** 14039 This hook is called by the root-most Route (a.k.a. the ApplicationRoute) 14040 when it has finished creating the root View. By default, we simply take the 14041 view and append it to the `rootElement` specified on the Application. 14042 In cases like FastBoot and testing, we can override this hook and implement 14043 custom behavior, such as serializing to a string and sending over an HTTP 14044 socket rather than appending to DOM. 14045 @param view {Ember.View} the root-most view 14046 @private 14047 */ 14048 didCreateRootView: function (view) { 14049 view.appendTo(this.rootElement); 14050 }, 14051 14052 /** 14053 Tells the router to start routing. The router will ask the location for the 14054 current URL of the page to determine the initial URL to start routing to. 14055 To start the app at a specific URL, call `handleURL` instead. 14056 @private 14057 */ 14058 startRouting: function () { 14059 var router = _emberMetalProperty_get.get(this, 'router'); 14060 router.startRouting(); 14061 this._didSetupRouter = true; 14062 }, 14063 14064 /** 14065 @private 14066 Sets up the router, initializing the child router and configuring the 14067 location before routing begins. 14068 Because setup should only occur once, multiple calls to `setupRouter` 14069 beyond the first call have no effect. 14070 */ 14071 setupRouter: function () { 14072 if (this._didSetupRouter) { 14073 return; 14074 } 14075 this._didSetupRouter = true; 14076 14077 var router = _emberMetalProperty_get.get(this, 'router'); 14078 router.setupRouter(); 14079 }, 14080 14081 /** 14082 Directs the router to route to a particular URL. This is useful in tests, 14083 for example, to tell the app to start at a particular URL. 14084 @param url {String} the URL the router should route to 14085 @private 14086 */ 14087 handleURL: function (url) { 14088 var router = _emberMetalProperty_get.get(this, 'router'); 14089 14090 this.setupRouter(); 14091 return router.handleURL(url); 14092 }, 14093 14094 /** 14095 @private 14096 */ 14097 setupEventDispatcher: function () { 14098 var dispatcher = this.lookup('event_dispatcher:main'); 14099 var applicationCustomEvents = _emberMetalProperty_get.get(this.application, 'customEvents'); 14100 var instanceCustomEvents = _emberMetalProperty_get.get(this, 'customEvents'); 14101 14102 var customEvents = _emberMetalAssign.default({}, applicationCustomEvents, instanceCustomEvents); 14103 dispatcher.setup(customEvents, this.rootElement); 14104 14105 return dispatcher; 14106 } 14107 }); 14108 14109 ApplicationInstance.reopen({ 14110 /** 14111 Returns the current URL of the app instance. This is useful when your 14112 app does not update the browsers URL bar (i.e. it uses the `'none'` 14113 location adapter). 14114 @public 14115 @return {String} the current URL 14116 */ 14117 getURL: function () { 14118 var router = _emberMetalProperty_get.get(this, 'router'); 14119 return _emberMetalProperty_get.get(router, 'url'); 14120 }, 14121 14122 // `instance.visit(url)` should eventually replace `instance.handleURL()`; 14123 // the test helpers can probably be switched to use this implementation too 14124 14125 /** 14126 Navigate the instance to a particular URL. This is useful in tests, for 14127 example, or to tell the app to start at a particular URL. This method 14128 returns a promise that resolves with the app instance when the transition 14129 is complete, or rejects if the transion was aborted due to an error. 14130 @public 14131 @param url {String} the destination URL 14132 @return {Promise} 14133 */ 14134 visit: function (url) { 14135 var _this2 = this; 14136 14137 this.setupRouter(); 14138 14139 var router = _emberMetalProperty_get.get(this, 'router'); 14140 14141 var handleResolve = function () { 14142 // Resolve only after rendering is complete 14143 return new _emberRuntimeExtRsvp.default.Promise(function (resolve) { 14144 // TODO: why is this necessary? Shouldn't 'actions' queue be enough? 14145 // Also, aren't proimses supposed to be async anyway? 14146 _emberMetalRun_loop.default.next(null, resolve, _this2); 14147 }); 14148 }; 14149 14150 var handleReject = function (error) { 14151 if (error.error) { 14152 throw error.error; 14153 } else if (error.name === 'TransitionAborted' && router.router.activeTransition) { 14154 return router.router.activeTransition.then(handleResolve, handleReject); 14155 } else if (error.name === 'TransitionAborted') { 14156 throw new Error(error.message); 14157 } else { 14158 throw error; 14159 } 14160 }; 14161 14162 // Keeps the location adapter's internal URL in-sync 14163 _emberMetalProperty_get.get(router, 'location').setURL(url); 14164 14165 return router.handleURL(url).then(handleResolve, handleReject); 14166 } 14167 }); 14168 14169 /** 14170 A list of boot-time configuration options for customizing the behavior of 14171 an `Ember.ApplicationInstance`. 14172 This is an interface class that exists purely to document the available 14173 options; you do not need to construct it manually. Simply pass a regular
14174 JavaScript object containing the desired options into methods that require 14175 one of these options object: 14176 ```javascript 14177 MyApp.visit("/", { location: "none", rootElement: "#container" }); 14178 ``` 14179 Not all combinations of the supported options are valid. See the documentation 14180 on `Ember.Application#visit` for the supported configurations. 14181 Internal, experimental or otherwise unstable flags are marked as private. 14182 @class BootOptions 14183 @namespace Ember.ApplicationInstance 14184 @public 14185 */ 14186 BootOptions = function BootOptions() { 14187 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 14188 14189 /** 14190 Provide a specific instance of jQuery. This is useful in conjunction with 14191 the `document` option, as it allows you to use a copy of `jQuery` that is 14192 appropriately bound to the foreign `document` (e.g. a jsdom). 14193 This is highly experimental and support very incomplete at the moment. 14194 @property jQuery 14195 @type Object 14196 @default auto-detected 14197 @private 14198 */ 14199 this.jQuery = _emberViewsSystemJquery.default; // This default is overridable below 14200 14201 /** 14202 Interactive mode: whether we need to set up event delegation and invoke 14203 lifecycle callbacks on Components. 14204 @property isInteractive 14205 @type boolean 14206 @default auto-detected 14207 @private 14208 */ 14209 this.isInteractive = _emberMetalEnvironment.default.hasDOM; // This default is overridable below 14210 14211 /** 14212 Run in a full browser environment. 14213 When this flag is set to `false`, it will disable most browser-specific 14214 and interactive features. Specifically: 14215 * It does not use `jQuery` to append the root view; the `rootElement` 14216 (either specified as a subsequent option or on the application itself) 14217 must already be an `Element` in the given `document` (as opposed to a 14218 string selector). 14219 * It does not set up an `EventDispatcher`. 14220 * It does not run any `Component` lifecycle hooks (such as `didInsertElement`). 14221 * It sets the `location` option to `"none"`. (If you would like to use 14222 the location adapter specified in the app's router instead, you can also 14223 specify `{ location: null }` to specifically opt-out.) 14224 @property isBrowser 14225 @type boolean 14226 @default auto-detected 14227 @public 14228 */ 14229 if (options.isBrowser !== undefined) { 14230 this.isBrowser = !!options.isBrowser; 14231 } else { 14232 this.isBrowser = _emberMetalEnvironment.default.hasDOM; 14233 } 14234 14235 if (!this.isBrowser) { 14236 this.jQuery = null; 14237 this.isInteractive = false; 14238 this.location = 'none'; 14239 } 14240 14241 /** 14242 Disable rendering completely. 14243 When this flag is set to `true`, it will disable the entire rendering 14244 pipeline. Essentially, this puts the app into "routing-only" mode. No 14245 templates will be rendered, and no Components will be created. 14246 @property shouldRender 14247 @type boolean 14248 @default true 14249 @public 14250 */ 14251 if (options.shouldRender !== undefined) { 14252 this.shouldRender = !!options.shouldRender; 14253 } else { 14254 this.shouldRender = true; 14255 } 14256 14257 if (!this.shouldRender) { 14258 this.jQuery = null; 14259 this.isInteractive = false; 14260 } 14261 14262 /** 14263 If present, render into the given `Document` object instead of the 14264 global `window.document` object. 14265 In practice, this is only useful in non-browser environment or in 14266 non-interactive mode, because Ember's `jQuery` dependency is 14267 implicitly bound to the current document, causing event delegation 14268 to not work properly when the app is rendered into a foreign 14269 document object (such as an iframe's `contentDocument`). 14270 In non-browser mode, this could be a "`Document`-like" object as 14271 Ember only interact with a small subset of the DOM API in non- 14272 interactive mode. While the exact requirements have not yet been 14273 formalized, the `SimpleDOM` library's implementation is known to 14274 work. 14275 @property document 14276 @type Document 14277 @default the global `document` object 14278 @public 14279 */ 14280 if (options.document) { 14281 this.document = options.document; 14282 } else { 14283 this.document = typeof document !== 'undefined' ? document : null; 14284 } 14285 14286 /** 14287 If present, overrides the application's `rootElement` property on 14288 the instance. This is useful for testing environment, where you 14289 might want to append the root view to a fixture area. 14290 In non-browser mode, because Ember does not have access to jQuery, 14291 this options must be specified as a DOM `Element` object instead of 14292 a selector string. 14293 See the documentation on `Ember.Applications`'s `rootElement` for 14294 details. 14295 @property rootElement
14296 @type String|Element 14297 @default null 14298 @public 14299 */ 14300 if (options.rootElement) { 14301 this.rootElement = options.rootElement; 14302 } 14303 14304 // Set these options last to give the user a chance to override the 14305 // defaults from the "combo" options like `isBrowser` (although in 14306 // practice, the resulting combination is probably invalid) 14307 14308 /** 14309 If present, overrides the router's `location` property with this 14310 value. This is useful for environments where trying to modify the 14311 URL would be inappropriate. 14312 @property location 14313 @type string 14314 @default null 14315 @public 14316 */ 14317 if (options.location !== undefined) { 14318 this.location = options.location; 14319 } 14320 14321 if (options.jQuery !== undefined) { 14322 this.jQuery = options.jQuery; 14323 } 14324 14325 if (options.isInteractive !== undefined) { 14326 this.isInteractive = !!options.isInteractive; 14327 } 14328 }; 14329 14330 BootOptions.prototype.toEnvironment = function () { 14331 var env = _emberMetalAssign.default({}, _emberMetalEnvironment.default); 14332 // For compatibility with existing code 14333 env.hasDOM = this.isBrowser; 14334 env.options = this; 14335 return env; 14336 }; 14337 14338 Object.defineProperty(ApplicationInstance.prototype, 'container', { 14339 configurable: true, 14340 enumerable: false, 14341 get: function () { 14342 var instance = this; 14343 return { 14344 lookup: function () { 14345 _emberMetalDebug.deprecate('Using `ApplicationInstance.container.lookup` is deprecated. Please use `ApplicationInstance.lookup` instead.', false, { 14346 id: 'ember-application.app-instance-container', 14347 until: '3.0.0', 14348 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-applicationinstance-container' 14349 }); 14350 return instance.lookup.apply(instance, arguments); 14351 } 14352 }; 14353 } 14354 }); 14355 14356 Object.defineProperty(ApplicationInstance.prototype, 'registry', { 14357 configurable: true, 14358 enumerable: false, 14359 get: function () { 14360 return _emberRuntimeMixinsRegistry_proxy.buildFakeRegistryWithDeprecations(this, 'ApplicationInstance'); 14361 } 14362 }); 14363 14364 exports.default = ApplicationInstance; 14365}); 14366enifed('ember-application/system/application', ['exports', 'ember-metal', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/property_get', 'ember-runtime/system/lazy_load', 'ember-metal/run_loop', 'ember-runtime/controllers/controller', 'ember-metal-views', 'ember-htmlbars/system/dom-helper', 'ember-views/views/select', 'ember-routing-views/views/outlet', 'ember-views/views/view', 'ember-views/system/event_dispatcher', 'ember-views/system/jquery', 'ember-routing/system/route', 'ember-routing/system/router', 'ember-routing/location/hash_location', 'ember-routing/location/history_location', 'ember-routing/location/auto_location', 'ember-routing/location/none_location', 'ember-routing/system/cache', 'ember-application/system/application-instance', 'ember-views/views/text_field', 'ember-views/views/text_area', 'ember-views/views/checkbox', 'ember-views/views/legacy_each_view', 'ember-routing-views/components/link-to', 'ember-routing/services/routing', 'ember-extension-support/container_debug_adapter', 'ember-runtime/mixins/registry_proxy', 'ember-metal/environment', 'ember-runtime/ext/rsvp', 'ember-application/system/engine'], function (exports, _emberMetal, _emberMetalDebug, _emberMetalFeatures, _emberMetalProperty_get, _emberRuntimeSystemLazy_load, _emberMetalRun_loop, _emberRuntimeControllersController, _emberMetalViews, _emberHtmlbarsSystemDomHelper, _emberViewsViewsSelect, _emberRoutingViewsViewsOutlet, _emberViewsViewsView, _emberViewsSystemEvent_dispatcher, _emberViewsSystemJquery, _emberRoutingSystemRoute, _emberRoutingSystemRouter, _emberRoutingLocationHash_location, _emberRoutingLocationHistory_location, _emberRoutingLocationAuto_location, _emberRoutingLocationNone_location, _emberRoutingSystemCache, _emberApplicationSystemApplicationInstance, _emberViewsViewsText_field, _emberViewsViewsText_area, _emberViewsViewsCheckbox, _emberViewsViewsLegacy_each_view, _emberRoutingViewsComponentsLinkTo, _emberRoutingServicesRouting, _emberExtensionSupportContainer_debug_adapter, _emberRuntimeMixinsReg
14366istry_proxy, _emberMetalEnvironment, _emberRuntimeExtRsvp, _emberApplicationSystemEngine) { 14367 /** 14368 @module ember 14369 @submodule ember-application 14370 */ 14371 'use strict'; 14372 14373 exports._resetLegacyAddonWarnings = _resetLegacyAddonWarnings; 14374 14375 var librariesRegistered = false; 14376 14377 var warnedAboutLegacyViewAddon = false; 14378 var warnedAboutLegacyControllerAddon = false; 14379 14380 // For testing 14381 14382 function _resetLegacyAddonWarnings() { 14383 warnedAboutLegacyViewAddon = false; 14384 warnedAboutLegacyControllerAddon = false; 14385 } 14386 14387 /** 14388 An instance of `Ember.Application` is the starting point for every Ember 14389 application. It helps to instantiate, initialize and coordinate the many 14390 objects that make up your app. 14391 14392 Each Ember app has one and only one `Ember.Application` object. In fact, the 14393 very first thing you should do in your application is create the instance: 14394 14395 ```javascript 14396 window.App = Ember.Application.create(); 14397 ``` 14398 14399 Typically, the application object is the only global variable. All other 14400 classes in your app should be properties on the `Ember.Application` instance, 14401 which highlights its first role: a global namespace. 14402 14403 For example, if you define a view class, it might look like this: 14404 14405 ```javascript 14406 App.MyView = Ember.View.extend(); 14407 ``` 14408 14409 By default, calling `Ember.Application.create()` will automatically initialize 14410 your application by calling the `Ember.Application.initialize()` method. If 14411 you need to delay initialization, you can call your app's `deferReadiness()` 14412 method. When you are ready for your app to be initialized, call its 14413 `advanceReadiness()` method. 14414 14415 You can define a `ready` method on the `Ember.Application` instance, which 14416 will be run by Ember when the application is initialized. 14417 14418 Because `Ember.Application` inherits from `Ember.Namespace`, any classes 14419 you create will have useful string representations when calling `toString()`. 14420 See the `Ember.Namespace` documentation for more information. 14421 14422 While you can think of your `Ember.Application` as a container that holds the 14423 other classes in your application, there are several other responsibilities 14424 going on under-the-hood that you may want to understand. 14425 14426 ### Event Delegation 14427 14428 Ember uses a technique called _event delegation_. This allows the framework 14429 to set up a global, shared event listener instead of requiring each view to 14430 do it manually. For example, instead of each view registering its own 14431 `mousedown` listener on its associated element, Ember sets up a `mousedown` 14432 listener on the `body`. 14433 14434 If a `mousedown` event occurs, Ember will look at the target of the event and 14435 start walking up the DOM node tree, finding corresponding views and invoking 14436 their `mouseDown` method as it goes. 14437 14438 `Ember.Application` has a number of default events that it listens for, as 14439 well as a mapping from lowercase events to camel-cased view method names. For 14440 example, the `keypress` event causes the `keyPress` method on the view to be 14441 called, the `dblclick` event causes `doubleClick` to be called, and so on. 14442 14443 If there is a bubbling browser event that Ember does not listen for by 14444 default, you can specify custom events and their corresponding view method 14445 names by setting the application's `customEvents` property: 14446 14447 ```javascript 14448 var App = Ember.Application.create({ 14449 customEvents: { 14450 // add support for the paste event 14451 paste: 'paste' 14452 } 14453 }); 14454 ``` 14455 14456 To prevent Ember from setting up a listener for a default event, 14457 specify the event name with a `null` value in the `customEvents` 14458 property: 14459 14460 ```javascript 14461 var App = Ember.Application.create({ 14462 customEvents: { 14463 // prevent listeners for mouseenter/mouseleave events 14464 mouseenter: null, 14465 mouseleave: null 14466 } 14467 }); 14468 ``` 14469 14470 By default, the application sets up these event listeners on the document 14471 body. However, in cases where you are embedding an Ember application inside 14472 an existing page, you may want it to set up the listeners on an element 14473 inside the body. 14474 14475 For example, if only events inside a DOM element with the ID of `ember-app` 14476 should be delegated, set your application's `rootElement` property: 14477 14478 ```javascript 14479 var App = Ember.Application.create({ 14480 rootElement: '#ember-app' 14481 }); 14482 ``` 14483 14484 The `rootElement` can be either a DOM element or a jQuery-compatible selector 14485 string. Note that *views appended to the DOM outside the root element will 14486 not receive events.* If you specify a custom root element, make sure you only 14487 append views inside it! 14488 14489 To learn more about the advantages of event delegation and the Ember view 14490 layer, and a list of the event listeners that are setup by default, visit the 14491 [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). 14492
14493 ### Initializers 14494 14495 Libraries on top of Ember can add initializers, like so: 14496 14497 ```javascript 14498 Ember.Application.initializer({ 14499 name: 'api-adapter', 14500 14501 initialize: function(application) { 14502 application.register('api-adapter:main', ApiAdapter); 14503 } 14504 }); 14505 ``` 14506 14507 Initializers provide an opportunity to access the internal registry, which 14508 organizes the different components of an Ember application. Additionally 14509 they provide a chance to access the instantiated application. Beyond 14510 being used for libraries, initializers are also a great way to organize 14511 dependency injection or setup in your own application. 14512 14513 ### Routing 14514 14515 In addition to creating your application's router, `Ember.Application` is 14516 also responsible for telling the router when to start routing. Transitions 14517 between routes can be logged with the `LOG_TRANSITIONS` flag, and more 14518 detailed intra-transition logging can be logged with 14519 the `LOG_TRANSITIONS_INTERNAL` flag: 14520 14521 ```javascript 14522 var App = Ember.Application.create({ 14523 LOG_TRANSITIONS: true, // basic logging of successful transitions 14524 LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps 14525 }); 14526 ``` 14527 14528 By default, the router will begin trying to translate the current URL into 14529 application state once the browser emits the `DOMContentReady` event. If you 14530 need to defer routing, you can call the application's `deferReadiness()` 14531 method. Once routing can begin, call the `advanceReadiness()` method. 14532 14533 If there is any setup required before routing begins, you can implement a 14534 `ready()` method on your app that will be invoked immediately before routing 14535 begins. 14536 14537 @class Application 14538 @namespace Ember 14539 @extends Ember.Engine 14540 @uses RegistryProxyMixin 14541 @public 14542 */ 14543 14544 var Application = _emberApplicationSystemEngine.default.extend({ 14545 _suppressDeferredDeprecation: true, 14546 14547 /** 14548 The root DOM element of the Application. This can be specified as an 14549 element or a 14550 [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). 14551 This is the element that will be passed to the Application's, 14552 `eventDispatcher`, which sets up the listeners for event delegation. Every 14553 view in your application should be a child of the element you specify here. 14554 @property rootElement 14555 @type DOMElement 14556 @default 'body' 14557 @public 14558 */ 14559 rootElement: 'body', 14560 14561 /** 14562 The `Ember.EventDispatcher` responsible for delegating events to this 14563 application's views. 14564 The event dispatcher is created by the application at initialization time 14565 and sets up event listeners on the DOM element described by the 14566 application's `rootElement` property. 14567 See the documentation for `Ember.EventDispatcher` for more information. 14568 @property eventDispatcher 14569 @type Ember.EventDispatcher 14570 @default null 14571 @public 14572 */ 14573 eventDispatcher: null, 14574 14575 /** 14576 The DOM events for which the event dispatcher should listen. 14577 By default, the application's `Ember.EventDispatcher` listens 14578 for a set of standard DOM events, such as `mousedown` and 14579 `keyup`, and delegates them to your application's `Ember.View` 14580 instances. 14581 If you would like additional bubbling events to be delegated to your 14582 views, set your `Ember.Application`'s `customEvents` property 14583 to a hash containing the DOM event name as the key and the 14584 corresponding view method name as the value. Setting an event to 14585 a value of `null` will prevent a default event listener from being 14586 added for that event. 14587 To add new events to be listened to: 14588 ```javascript 14589 var App = Ember.Application.create({ 14590 customEvents: { 14591 // add support for the paste event 14592 paste: 'paste' 14593 } 14594 }); 14595 ``` 14596 To prevent default events from being listened to: 14597 ```javascript 14598 var App = Ember.Application.create({ 14599 customEvents: { 14600 // remove support for mouseenter / mouseleave events 14601 mouseenter: null, 14602 mouseleave: null 14603 } 14604 }); 14605 ``` 14606 @property customEvents 14607 @type Object 14608 @default null 14609 @public 14610 */ 14611 customEvents: null, 14612 14613 /** 14614 Whether the application should automatically start routing and render 14615 templates to the `rootElement` on DOM ready. While default by true, 14616 other environments such as FastBoot or a testing harness can set this 14617 property to `false` and control the precise timing and behavior of the boot 14618 process. 14619 @property autoboot 14620 @type Boolean 14621 @default true 14622 @private 14623 */ 14624 autoboot: true, 14625 14626 /** 14627 Whether the application should be configured for the legacy "globals mode". 14628 Under this mode, the Application object serves as a global namespace for all 14629 classes. 14630 ```javascript 14631 var App = Ember.Application.create({ 14632 ... 14633 }); 14634 App.Router.reopen({ 14635 location: 'none' 14636 }); 14637 App.Router.map({ 14638 ... 14639 }); 14640 App.MyComponent = Ember.Component.extend({ 14641 ... 14642 }); 14643 ``` 14644 This flag also exposes other internal APIs that assumes the existence of 14645 a special "default instance", like `App.__container__.lookup(...)`. 14646 This option is currently not configurable, its value is derived from 14647 the `autoboot` flag â disabling `autoboot` also implies opting-out of 14648 globals mode support, although they are ultimately orthogonal concerns. 14649 Some of the global modes features are already deprecated
14649in 1.x. The 14650 existence of this flag is to untangle the globals mode code paths from 14651 the autoboot code paths, so that these legacy features can be reviewed 14652 for deprecation/removal separately. 14653 Forcing the (autoboot=true, _globalsMode=false) here and running the tests 14654 would reveal all the places where we are still relying on these legacy 14655 behavior internally (mostly just tests). 14656 @property _globalsMode 14657 @type Boolean 14658 @default true 14659 @private 14660 */ 14661 _globalsMode: true, 14662 14663 init: function () { 14664 this._super.apply(this, arguments); 14665 14666 if (!this.$) { 14667 this.$ = _emberViewsSystemJquery.default; 14668 } 14669 14670 registerLibraries(); 14671 logLibraryVersions(); 14672 14673 // Start off the number of deferrals at 1. This will be decremented by 14674 // the Application's own `boot` method. 14675 this._readinessDeferrals = 1; 14676 this._booted = false; 14677 14678 this.autoboot = this._globalsMode = !!this.autoboot; 14679 14680 if (this._globalsMode) { 14681 this._prepareForGlobalsMode(); 14682 } 14683 14684 if (this.autoboot) { 14685 this.waitForDOMReady(); 14686 } 14687 }, 14688 14689 /** 14690 Create an ApplicationInstance for this application. 14691 @private 14692 @method buildInstance 14693 @return {Ember.ApplicationInstance} the application instance 14694 */ 14695 buildInstance: function () { 14696 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 14697 14698 options.base = this; 14699 options.application = this; 14700 return _emberApplicationSystemApplicationInstance.default.create(options); 14701 }, 14702 14703 /** 14704 Enable the legacy globals mode by allowing this application to act 14705 as a global namespace. See the docs on the `_globalsMode` property 14706 for details. 14707 Most of these features are already deprecated in 1.x, so we can 14708 stop using them internally and try to remove them. 14709 @private 14710 @method _prepareForGlobalsMode 14711 */ 14712 _prepareForGlobalsMode: function () { 14713 // Create subclass of Ember.Router for this Application instance. 14714 // This is to ensure that someone reopening `App.Router` does not 14715 // tamper with the default `Ember.Router`. 14716 this.Router = (this.Router || _emberRoutingSystemRouter.default).extend(); 14717 14718 this._buildDeprecatedInstance(); 14719 }, 14720 14721 /*
14722 Build the deprecated instance for legacy globals mode support. 14723 Called when creating and resetting the application. 14724 This is orthogonal to autoboot: the deprecated instance needs to 14725 be created at Application construction (not boot) time to expose 14726 App.__container__ and the global Ember.View.views registry. If 14727 autoboot sees that this instance exists, it will continue booting 14728 it to avoid doing unncessary work (as opposed to building a new 14729 instance at boot time), but they are otherwise unrelated. 14730 @private 14731 @method _buildDeprecatedInstance 14732 */ 14733 _buildDeprecatedInstance: function () { 14734 // Build a default instance 14735 var instance = this.buildInstance(); 14736 14737 // Legacy support for App.__container__ and other global methods 14738 // on App that rely on a single, default instance. 14739 this.__deprecatedInstance__ = instance; 14740 this.__container__ = instance.__container__; 14741 14742 // For the default instance only, set the view registry to the global 14743 // Ember.View.views hash for backwards-compatibility. 14744 _emberViewsViewsView.default.views = instance.lookup('-view-registry:main'); 14745 }, 14746 14747 /** 14748 Automatically kick-off the boot process for the application once the 14749 DOM has become ready. 14750 The initialization itself is scheduled on the actions queue which 14751 ensures that code-loading finishes before booting. 14752 If you are asynchronously loading code, you should call `deferReadiness()` 14753 to defer booting, and then call `advanceReadiness()` once all of your code 14754 has finished loading. 14755 @private 14756 @method waitForDOMReady 14757 */ 14758 waitForDOMReady: function () { 14759 if (!this.$ || this.$.isReady) { 14760 _emberMetalRun_loop.default.schedule('actions', this, 'domReady'); 14761 } else { 14762 this.$().ready(_emberMetalRun_loop.default.bind(this, 'domReady')); 14763 } 14764 }, 14765 14766 /** 14767 This is the autoboot flow: 14768 1. Boot the app by calling `this.boot()` 14769 2. Create an instance (or use the `__deprecatedInstance__` in globals mode) 14770 3. Boot the instance by calling `instance.boot()` 14771 4. Invoke the `App.ready()` callback 14772 5. Kick-off routing on the instance 14773 Ideally, this is all we would need to do: 14774 ```javascript 14775 _autoBoot() { 14776 this.boot().then(() => { 14777 let instance = (this._globalsMode) ? this.__deprecatedInstance__ : this.buildInstance(); 14778 return instance.boot(); 14779 }).then((instance) => { 14780 App.ready(); 14781 instance.startRouting(); 14782 }); 14783 } 14784 ``` 14785 Unfortunately, we cannot actually write this because we need to participate 14786 in the "synchronous" boot process. While the code above would work fine on 14787 the initial boot (i.e. DOM ready), when `App.reset()` is called, we need to 14788 boot a new instance synchronously (see the documentation on `_bootSync()` 14789 for details). 14790 Because of this restriction, the actual logic of this method is located 14791 inside `didBecomeReady()`. 14792 @private 14793 @method domReady 14794 */ 14795 domReady: function () { 14796 if (this.isDestroyed) { 14797 return; 14798 } 14799 14800 this._bootSync(); 14801 14802 // Continues to `didBecomeReady` 14803 }, 14804 14805 /** 14806 Use this to defer readiness until some condition is true. 14807 Example: 14808 ```javascript 14809 var App = Ember.Application.create(); 14810 App.deferReadiness(); 14811 // Ember.$ is a reference to the jQuery object/function 14812 Ember.$.getJSON('/auth-token', function(token) { 14813 App.token = token; 14814 App.advanceReadiness(); 14815 }); 14816 ``` 14817 This allows you to perform asynchronous setup logic and defer 14818 booting your application until the setup has finished. 14819 However, if the setup requires a loading UI, it might be better 14820 to use the router for this purpose. 14821 @method deferReadiness 14822 @public 14823 */ 14824 deferReadiness: function () { 14825 _emberMetalDebug.assert('You must call deferReadiness on an instance of Ember.Application', this instanceof Application); 14826 _emberMetalDebug.assert('You cannot defer readiness since the `ready()` hook has already been called.', this._readinessDeferrals > 0); 14827 this._readinessDeferrals++; 14828 }, 14829 14830 /** 14831 Call `advanceReadiness` after any asynchronous setup logic has completed. 14832 Each call to `deferReadiness` must be matched by a call to `advanceReadiness` 14833 or the application will never become ready and routing will not begin. 14834 @method advanceReadiness 14835 @see {Ember.Application#deferReadiness} 14836 @public 14837 */ 14838 advanceReadiness: function () { 14839 _emberMetalDebug.assert('You must call advanceReadiness on an instance of Ember.Application', this instanceof Application); 14840 this._readinessDeferrals--; 14841 14842 if (this._readinessDeferrals === 0) { 14843 _emberMetalRun_loop.default.once(this, this.didBecomeReady); 14844 } 14845 }, 14846 14847 /** 14848 Initialize the application and return a promise that resolves with the `Ember.Application` 14849 object when the boot process is complete.
14850 Run any application initializers and run the application load hook. These hooks may 14851 choose to defer readiness. For example, an authentication hook might want to defer 14852 readiness until the auth token has been retrieved. 14853 By default, this method is called automatically on "DOM ready"; however, if autoboot 14854 is disabled, this is automatically called when the first application instance is 14855 created via `visit`. 14856 @private 14857 @method boot 14858 @return {Promise<Ember.Application,Error>} 14859 */ 14860 boot: function () { 14861 if (this._bootPromise) { 14862 return this._bootPromise; 14863 } 14864 14865 try { 14866 this._bootSync(); 14867 } catch (_) { 14868 // Ignore th error: in the asynchronous boot path, the error is already reflected 14869 // in the promise rejection 14870 } 14871 14872 return this._bootPromise; 14873 }, 14874 14875 /** 14876 Unfortunately, a lot of existing code assumes the booting process is 14877 "synchronous". Specifically, a lot of tests assumes the last call to 14878 `app.advanceReadiness()` or `app.reset()` will result in the app being 14879 fully-booted when the current runloop completes. 14880 We would like new code (like the `visit` API) to stop making this assumption, 14881 so we created the asynchronous version above that returns a promise. But until 14882 we have migrated all the code, we would have to expose this method for use 14883 *internally* in places where we need to boot an app "synchronously". 14884 @private 14885 */ 14886 _bootSync: function () { 14887 if (this._booted) { 14888 return; 14889 } 14890 14891 if (_emberMetal.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT && !warnedAboutLegacyViewAddon) { 14892 _emberMetalDebug.deprecate('Support for the `ember-legacy-views` addon will end soon, please remove it from your application.', false, { id: 'ember-legacy-views', until: '2.6.0', url: 'http://emberjs.com/deprecations/v1.x/#toc_ember-view' }); 14893 14894 warnedAboutLegacyViewAddon = true; 14895 } 14896 14897 if (_emberMetal.default.ENV._ENABLE_LEGACY_CONTROLLER_SUPPORT && !warnedAboutLegacyControllerAddon) { 14898 _emberMetalDebug.deprecate('Support for the `ember-legacy-controllers` addon will end soon, please remove it from your application.', false, { id: 'ember-legacy-controllers', until: '2.6.0', url: 'http://emberjs.com/deprecations/v1.x/#toc_objectcontroller' }); 14899 14900 warnedAboutLegacyControllerAddon = true; 14901 } 14902 14903 // Even though this returns synchronously, we still need to make sure the 14904 // boot promise exists for book-keeping purposes: if anything went wrong in 14905 // the boot process, we need to store the error as a rejection on the boot 14906 // promise so that a future caller of `boot()` can tell what failed. 14907 var defer = this._bootResolver = new _emberRuntimeExtRsvp.default.defer(); 14908 this._bootPromise = defer.promise; 14909 14910 try { 14911 this.runInitializers(); 14912 _emberRuntimeSystemLazy_load.runLoadHooks('application', this); 14913 this.advanceReadiness(); 14914 // Continues to `didBecomeReady` 14915 } catch (error) { 14916 // For the asynchronous boot path 14917 defer.reject(error); 14918 14919 // For the synchronous boot path 14920 throw error; 14921 } 14922 }, 14923 14924 /** 14925 Reset the application. This is typically used only in tests. It cleans up 14926 the application in the following order: 14927 1. Deactivate existing routes 14928 2. Destroy all objects in the container 14929 3. Create a new application container 14930 4. Re-route to the existing url 14931 Typical Example: 14932 ```javascript 14933 var App; 14934 run(function() { 14935 App = Ember.Application.create(); 14936 }); 14937 module('acceptance test', { 14938 setup: function() { 14939 App.reset(); 14940 } 14941 }); 14942 test('first test', function() { 14943 // App is freshly reset 14944 }); 14945 test('second test', function() { 14946 // App is again freshly reset 14947 }); 14948 ``` 14949 Advanced Example: 14950 Occasionally you may want to prevent the app from initializing during 14951 setup. This could enable extra configuration, or enable asserting prior 14952 to the app becoming ready. 14953 ```javascript 14954 var App; 14955 run(function() { 14956 App = Ember.Application.create(); 14957 }); 14958 module('acceptance test', { 14959 setup: function() { 14960 run(function() { 14961 App.reset(); 14962 App.deferReadiness(); 14963 }); 14964 } 14965 }); 14966 test('first test', function() { 14967 ok(true, 'something before app is initialized'); 14968 run(function() { 14969 App.advanceReadiness(); 14970 }); 14971 ok(true, 'something after app is initialized'); 14972 }); 14973 ``` 14974 @method reset 14975 @public 14976 */ 14977 reset: function () { 14978 _emberMetalDebug.assert('Calling reset() on instances of `Ember.Application` is not\n supported when globals mode is disabled; call `visit()` to\n create new `Ember.ApplicationInstance`s and dispose them\n via their `destroy()` method instead.', this._globalsMode && this.autoboot); 14979 14980 var instance = this.__deprecatedInstance__; 14981 14982 this._readinessDeferrals = 1; 14983 this._bootPromise = null; 14984 this._bootResolver = null; 14985 this._booted = false;
14986 14987 function handleReset() { 14988 _emberMetalRun_loop.default(instance, 'destroy'); 14989 this._buildDeprecatedInstance(); 14990 _emberMetalRun_loop.default.schedule('actions', this, '_bootSync'); 14991 } 14992 14993 _emberMetalRun_loop.default.join(this, handleReset); 14994 }, 14995 14996 /** 14997 @private 14998 @method didBecomeReady 14999 */ 15000 didBecomeReady: function () { 15001 try { 15002 // TODO: Is this still needed for _globalsMode = false? 15003 if (!_emberMetal.default.testing) { 15004 // Eagerly name all classes that are already loaded 15005 _emberMetal.default.Namespace.processAll(); 15006 _emberMetal.default.BOOTED = true; 15007 } 15008 15009 // See documentation on `_autoboot()` for details 15010 if (this.autoboot) { 15011 var instance = undefined; 15012 15013 if (this._globalsMode) { 15014 // If we already have the __deprecatedInstance__ lying around, boot it to 15015 // avoid unnecessary work 15016 instance = this.__deprecatedInstance__; 15017 } else { 15018 // Otherwise, build an instance and boot it. This is currently unreachable, 15019 // because we forced _globalsMode to === autoboot; but having this branch 15020 // allows us to locally toggle that flag for weeding out legacy globals mode 15021 // dependencies independently 15022 instance = this.buildInstance(); 15023 } 15024 15025 instance._bootSync(); 15026 15027 // TODO: App.ready() is not called when autoboot is disabled, is this correct? 15028 this.ready(); 15029 15030 instance.startRouting(); 15031 } 15032 15033 // For the asynchronous boot path 15034 this._bootResolver.resolve(this); 15035 15036 // For the synchronous boot path 15037 this._booted = true; 15038 } catch (error) { 15039 // For the asynchronous boot path 15040 this._bootResolver.reject(error); 15041 15042 // For the synchronous boot path 15043 throw error; 15044 } 15045 }, 15046 15047 /** 15048 Called when the Application has become ready, immediately before routing 15049 begins. The call will be delayed until the DOM has become ready. 15050 @event ready 15051 @public 15052 */ 15053 ready: function () { 15054 return this; 15055 }, 15056 15057 // This method must be moved to the application instance object 15058 willDestroy: function () { 15059 this._super.apply(this, arguments); 15060 _emberMetal.default.BOOTED = false; 15061 this._booted = false; 15062 this._bootPromise = null; 15063 this._bootResolver = null; 15064 15065 if (_emberRuntimeSystemLazy_load._loaded.application === this) { 15066 _emberRuntimeSystemLazy_load._loaded.application = undefined; 15067 } 15068 15069 if (this._globalsMode && this.__deprecatedInstance__) { 15070 this.__deprecatedInstance__.destroy(); 15071 } 15072 } 15073 }); 15074 15075 Object.defineProperty(Application.prototype, 'registry', { 15076 configurable: true, 15077 enumerable: false, 15078 get: function () { 15079 return _emberRuntimeMixinsRegistry_proxy.buildFakeRegistryWithDeprecations(this, 'Application'); 15080 } 15081 }); 15082 15083 Application.reopen({ 15084 /** 15085 Boot a new instance of `Ember.ApplicationInstance` for the current 15086 application and navigate it to the given `url`. Returns a `Promise` that 15087 resolves with the instance when the initial routing and rendering is 15088 complete, or rejects with any error that occured during the boot process. 15089 When `autoboot` is disabled, calling `visit` would first cause the 15090 application to boot, which runs the application initializers. 15091 This method also takes a hash of boot-time configuration options for 15092 customizing the instance's behavior. See the documentation on 15093 `Ember.ApplicationInstance.BootOptions` for details. 15094 `Ember.ApplicationInstance.BootOptions` is an interface class that exists 15095 purely to document the available options; you do not need to construct it 15096 manually. Simply pass a regular JavaScript object containing of the 15097 desired options: 15098 ```javascript 15099 MyApp.visit("/", { location: "none", rootElement: "#container" }); 15100 ``` 15101 ### Supported Scenarios 15102 While the `BootOptions` class exposes a large number of knobs, not all 15103 combinations of them are valid; certain incompatible combinations might 15104 result in unexpected behavior. 15105 For example, booting the instance in the full browser environment 15106 while specifying a foriegn `document` object (e.g. `{ isBrowser: true, 15107 document: iframe.contentDocument }`) does not work correctly today,
15108 largely due to Ember's jQuery dependency. 15109 Currently, there are three officially supported scenarios/configurations. 15110 Usages outside of these scenarios are not guaranteed to work, but please 15111 feel free to file bug reports documenting your experience and any issues 15112 you encountered to help expand support. 15113 #### Browser Applications (Manual Boot) 15114 The setup is largely similar to how Ember works out-of-the-box. Normally, 15115 Ember will boot a default instance for your Application on "DOM ready". 15116 However, you can customize this behavior by disabling `autoboot`. 15117 For example, this allows you to render a miniture demo of your application 15118 into a specific area on your marketing website: 15119 ```javascript 15120 import MyApp from 'my-app'; 15121 $(function() { 15122 let App = MyApp.create({ autoboot: false }); 15123 let options = { 15124 // Override the router's location adapter to prevent it from updating 15125 // the URL in the address bar 15126 location: 'none', 15127 // Override the default `rootElement` on the app to render into a 15128 // specific `div` on the page 15129 rootElement: '#demo' 15130 }; 15131 // Start the app at the special demo URL 15132 App.visit('/demo', options); 15133 }); 15134 ```` 15135 Or perhaps you might want to boot two instances of your app on the same 15136 page for a split-screen multiplayer experience: 15137 ```javascript 15138 import MyApp from 'my-app'; 15139 $(function() { 15140 let App = MyApp.create({ autoboot: false }); 15141 let sessionId = MyApp.generateSessionID(); 15142 let player1 = App.visit(`/matches/join?name=Player+1&session=${sessionId}`, { rootElement: '#left', location: 'none' }); 15143 let player2 = App.visit(`/matches/join?name=Player+2&session=${sessionId}`, { rootElement: '#right', location: 'none' }); 15144 Promise.all([player1, player2]).then(() => { 15145 // Both apps have completed the initial render 15146 $('#loading').fadeOut(); 15147 }); 15148 }); 15149 ``` 15150 Do note that each app instance maintains their own registry/container, so 15151 they will run in complete isolation by default. 15152 #### Server-Side Rendering (also known as FastBoot) 15153 This setup allows you to run your Ember app in a server environment using 15154 Node.js and render its content into static HTML for SEO purposes. 15155 ```javascript 15156 const HTMLSerializer = new SimpleDOM.HTMLSerializer(SimpleDOM.voidMap); 15157 function renderURL(url) { 15158 let dom = new SimpleDOM.Document(); 15159 let rootElement = dom.body; 15160 let options = { isBrowser: false, document: dom, rootElement: rootElement }; 15161 return MyApp.visit(options).then(instance => { 15162 try { 15163 return HTMLSerializer.serialize(rootElement.firstChild); 15164 } finally { 15165 instance.destroy(); 15166 } 15167 }); 15168 } 15169 ``` 15170 In this scenario, because Ember does not have access to a global `document` 15171 object in the Node.js environment, you must provide one explicitly. In practice, 15172 in the non-browser environment, the stand-in `document` object only need to 15173 implement a limited subset of the full DOM API. The `SimpleDOM` library is known 15174 to work. 15175 Since there is no access to jQuery in the non-browser environment, you must also 15176 specify a DOM `Element` object in the same `document` for the `rootElement` option 15177 (as opposed to a selector string like `"body"`). 15178 See the documentation on the `isBrowser`, `document` and `rootElement` properties 15179 on `Ember.ApplicationInstance.BootOptions` for details. 15180 #### Server-Side Resource Discovery 15181 This setup allows you to run the routing layer of your Ember app in a server 15182 environment using Node.js and completely disable rendering. This allows you 15183 to simulate and discover the resources (i.e. AJAX requests) needed to fufill 15184 a given request and eagerly "push" these resources to the client. 15185 ```app/initializers/network-service.js 15186 import BrowserNetworkService from 'app/services/network/browser'; 15187 import NodeNetworkService from 'app/services/network/node'; 15188 // Inject a (hypothetical) service for abstracting all AJAX calls and use 15189 // the appropiate implementaion on the client/server. This also allows the 15190 // server to log all the AJAX calls made during a particular request and use 15191 // that for resource-discovery purpose. 15192 export function initialize(application) { 15193 if (window) { // browser
15194 application.register('service:network', BrowserNetworkService); 15195 } else { // node 15196 application.register('service:network', NodeNetworkService); 15197 } 15198 application.inject('route', 'network', 'service:network'); 15199 }; 15200 export default { 15201 name: 'network-service', 15202 initialize: initialize 15203 }; 15204 ``` 15205 ```app/routes/post.js 15206 import Ember from 'ember'; 15207 // An example of how the (hypothetical) service is used in routes. 15208 export default Ember.Route.extend({ 15209 model(params) { 15210 return this.network.fetch(`/api/posts/${params.post_id}.json`); 15211 }, 15212 afterModel(post) { 15213 if (post.isExternalContent) { 15214 return this.network.fetch(`/api/external/?url=${post.externalURL}`); 15215 } else { 15216 return post; 15217 } 15218 } 15219 }); 15220 ``` 15221 ```javascript 15222 // Finally, put all the pieces together 15223 function discoverResourcesFor(url) { 15224 return MyApp.visit(url, { isBrowser: false, shouldRender: false }).then(instance => { 15225 let networkService = instance.lookup('service:network'); 15226 return networkService.requests; // => { "/api/posts/123.json": "..." } 15227 }); 15228 } 15229 ``` 15230 @public 15231 @method visit 15232 @param url {String} The initial URL to navigate to 15233 @param options {Ember.ApplicationInstance.BootOptions} 15234 @return {Promise<Ember.ApplicationInstance, Error>} 15235 */ 15236 visit: function (url, options) { 15237 var _this = this; 15238 15239 return this.boot().then(function () {
15240 return _this.buildInstance().boot(options).then(function (instance) { 15241 return instance.visit(url); 15242 }); 15243 }); 15244 } 15245 }); 15246 15247 Application.reopenClass({ 15248 /** 15249 This creates a registry with the default Ember naming conventions. 15250 It also configures the registry: 15251 * registered views are created every time they are looked up (they are 15252 not singletons) 15253 * registered templates are not factories; the registered value is 15254 returned directly. 15255 * the router receives the application as its `namespace` property 15256 * all controllers receive the router as their `target` and `controllers` 15257 properties 15258 * all controllers receive the application as their `namespace` property 15259 * the application view receives the application controller as its 15260 `controller` property 15261 * the application view receives the application template as its 15262 `defaultTemplate` property 15263 @private 15264 @method buildRegistry 15265 @static 15266 @param {Ember.Application} namespace the application for which to 15267 build the registry 15268 @return {Ember.Registry} the built registry 15269 @public 15270 */ 15271 buildRegistry: function (namespace) { 15272 var registry = this._super.apply(this, arguments); 15273 15274 registry.optionsForType('component', { singleton: false }); 15275 registry.optionsForType('view', { singleton: false }); 15276 registry.optionsForType('template', { instantiate: false }); 15277 15278 registry.register('application:main', namespace, { instantiate: false }); 15279 15280 registry.register('controller:basic', _emberRuntimeControllersController.default, { instantiate: false }); 15281 15282 registry.register('renderer:-dom', { create: function () { 15283 return new _emberMetalViews.Renderer(new _emberHtmlbarsSystemDomHelper.default()); 15284 } }); 15285 15286 registry.injection('view', 'renderer', 'renderer:-dom'); 15287 if (_emberMetal.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 15288 registry.register('view:select', _emberViewsViewsSelect.default); 15289 } 15290 registry.register('view:-outlet', _emberRoutingViewsViewsOutlet.OutletView); 15291 15292 registry.register('-view-registry:main', { create: function () { 15293 return {}; 15294 } }); 15295 15296 registry.injection('view', '_viewRegistry', '-view-registry:main'); 15297 15298 registry.register('view:toplevel', _emberViewsViewsView.default.extend()); 15299 15300 registry.register('route:basic', _emberRoutingSystemRoute.default, { instantiate: false }); 15301 registry.register('event_dispatcher:main', _emberViewsSystemEvent_dispatcher.default); 15302 15303 registry.injection('router:main', 'namespace', 'application:main'); 15304 registry.injection('view:-outlet', 'namespace', 'application:main'); 15305 15306 registry.register('location:auto', _emberRoutingLocationAuto_location.default); 15307 registry.register('location:hash', _emberRoutingLocationHash_location.default); 15308 registry.register('location:history', _emberRoutingLocationHistory_location.default); 15309 registry.register('location:none', _emberRoutingLocationNone_location.default); 15310 15311 registry.injection('controller', 'target', 'router:main'); 15312 registry.injection('controller', 'namespace', 'application:main'); 15313 15314 registry.register('-bucket-cache:main', _emberRoutingSystemCache.default); 15315 registry.injection('router', '_bucketCache', '-bucket-cache:main'); 15316 registry.injection('route', '_bucketCache', '-bucket-cache:main'); 15317 registry.injection('controller', '_bucketCache', '-bucket-cache:main'); 15318 15319 registry.injection('route', 'router', 'router:main'); 15320 15321 registry.register('component:-text-field', _emberViewsViewsText_field.default); 15322 registry.register('component:-text-area', _emberViewsViewsText_area.default); 15323 registry.register('component:-checkbox', _emberViewsViewsCheckbox.default); 15324 registry.register('view:-legacy-each', _emberViewsViewsLegacy_each_view.default); 15325 registry.register('component:link-to', _emberRoutingViewsComponentsLinkTo.default); 15326 15327 // Register the routing service... 15328 registry.register('service:-routing', _emberRoutingServicesRouting.default); 15329 // Then inject the app router into it 15330 registry.injection('service:-routing', 'router', 'router:main'); 15331 15332 // DEBUGGING 15333 registry.register('resolver-for-debugging:main', registry.resolver, { instantiate: false }); 15334 registry.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); 15335 registry.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); 15336 // Custom resolver authors may want to register their own ContainerDebugAdapter with this key 15337 15338 registry.register('container-debug-adapter:main', _emberExtensionSupportContainer_debug_adapter.default); 15339 15340 return registry; 15341 } 15342 }); 15343 15344 function registerLibraries() { 15345 if (!librariesRegistered) { 15346 librariesRegistered = true; 15347 15348 if (_emberMetalEnvironment.default.hasDOM) { 15349 _emberMetal.default.libraries.registerCoreLibrary('jQuery', _emberViewsSystemJquery.default().jquery); 15350 } 15351 } 15352 } 15353 15354 function logLibraryVersions() { 15355 if (_emberMetal.default.LOG_VERSION) { 15356 // we only need to see this once per Application#init 15357 _emberMetal.default.LOG_VERSION = false;
15358 var libs = _emberMetal.default.libraries._registry; 15359 15360 var nameLengths = libs.map(function (item) { 15361 return _emberMetalProperty_get.get(item, 'name.length'); 15362 }); 15363 15364 var maxNameLength = Math.max.apply(this, nameLengths); 15365 15366 _emberMetalDebug.debug('-------------------------------'); 15367 for (var i = 0, l = libs.length; i < l; i++) { 15368 var lib = libs[i]; 15369 var spaces = new Array(maxNameLength - lib.name.length + 1).join(' '); 15370 _emberMetalDebug.debug([lib.name, spaces, ' : ', lib.version].join('')); 15371 } 15372 _emberMetalDebug.debug('-------------------------------'); 15373 } 15374 } 15375 15376 exports.default = Application; 15377}); 15378// Ember.libraries, LOG_VERSION, Namespace, BOOTED 15379 15380// Force-assign these flags to their default values when the feature is 15381// disabled, this ensures we can rely on their values in other paths. 15382enifed('ember-application/system/engine-instance', ['exports', 'ember-runtime/system/object', 'container/registry', 'ember-runtime/mixins/container_proxy', 'ember-runtime/mixins/registry_proxy', 'ember-metal/run_loop'], function (exports, _emberRuntimeSystemObject, _containerRegistry, _emberRuntimeMixinsContainer_proxy, _emberRuntimeMixinsRegistry_proxy, _emberMetalRun_loop) { 15383 /** 15384 @module ember 15385 @submodule ember-application 15386 */ 15387 15388 'use strict'; 15389 15390 /** 15391 The `EngineInstance` encapsulates all of the stateful aspects of a 15392 running `Engine`. 15393 15394 @public 15395 @class Ember.EngineInstance 15396 @extends Ember.Object 15397 @uses RegistryProxyMixin 15398 @uses ContainerProxyMixin 15399 @category ember-application-engines 15400 */ 15401 15402 var EngineInstance = _emberRuntimeSystemObject.default.extend(_emberRuntimeMixinsRegistry_proxy.default, _emberRuntimeMixinsContainer_proxy.default, { 15403 /** 15404 The base `Engine` for which this is an instance. 15405 @property {Ember.Engine} engine 15406 @private 15407 */ 15408 base: null, 15409 15410 init: function () { 15411 this._super.apply(this, arguments); 15412 15413 var base = this.base; 15414 15415 if (!base) { 15416 base = this.application; 15417 this.base = base; 15418 } 15419 15420 // Create a per-instance registry that will use the application's registry 15421 // as a fallback for resolving registrations. 15422 var registry = this.__registry__ = new _containerRegistry.default({ 15423 fallback: base.__registry__ 15424 }); 15425 15426 // Create a per-instance container from the instance's registry 15427 this.__container__ = registry.container({ owner: this }); 15428 }, 15429 15430 /** 15431 Unregister a factory. 15432 Overrides `RegistryProxy#unregister` in order to clear any cached instances 15433 of the unregistered factory. 15434 @public 15435 @method unregister 15436 @param {String} fullName 15437 */ 15438 unregister: function (fullName) { 15439 this.__container__.reset(fullName); 15440 this._super.apply(this, arguments); 15441 }, 15442 15443 /** 15444 @private 15445 */ 15446 willDestroy: function () { 15447 this._super.apply(this, arguments); 15448 _emberMetalRun_loop.default(this.__container__, 'destroy'); 15449 } 15450 }); 15451 15452 exports.default = EngineInstance; 15453}); 15454enifed('ember-application/system/engine', ['exports', 'ember-runtime/system/namespace', 'container/registry', 'ember-runtime/mixins/registry_proxy', 'dag-map', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/debug', 'ember-metal/utils', 'ember-metal/empty_object', 'ember-application/system/resolver', 'ember-application/system/engine-instance'], function (exports, _emberRuntimeSystemNamespace, _containerRegistry, _emberRuntimeMixinsRegistry_proxy, _dagMap, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalDebug, _emberMetalUtils, _emberMetalEmpty_object, _emberApplicationSystemResolver, _emberApplicationSystemEngineInstance) { 15455 /** 15456 @module ember 15457 @submodule ember-application 15458 */ 15459 'use strict'; 15460 15461 function props(obj) { 15462 var properties = []; 15463 15464 for (var key in obj) { 15465 properties.push(key); 15466 } 15467 15468 return properties; 15469 } 15470 15471 /** 15472 The `Engine` class contains core functionality for both applications and 15473 engines. 15474 15475 Each engine manages a registry that's used for dependency injection and 15476 exposed through `RegistryProxy`. 15477
15478 Engines also manage initializers and instance initializers. 15479 15480 Engines can spawn `EngineInstance` instances via `buildInstance()`. 15481 15482 @class Engine 15483 @namespace Ember 15484 @extends Ember.Namespace 15485 @uses RegistryProxy 15486 @category ember-application-engines 15487 @public 15488 */ 15489 var Engine = _emberRuntimeSystemNamespace.default.extend(_emberRuntimeMixinsRegistry_proxy.default, { 15490 init: function () { 15491 this._super.apply(this, arguments); 15492 15493 this.buildRegistry(); 15494 }, 15495 15496 /** 15497 Create an EngineInstance for this application. 15498 @private 15499 @method buildInstance 15500 @return {Ember.EngineInstance} the application instance 15501 */ 15502 buildInstance: function () { 15503 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 15504 15505 options.base = this; 15506 return _emberApplicationSystemEngineInstance.default.create(options); 15507 }, 15508 15509 /** 15510 Build and configure the registry for the current application. 15511 @private 15512 @method buildRegistry 15513 @return {Ember.Registry} the configured registry 15514 */ 15515 buildRegistry: function () { 15516 var registry = this.__registry__ = this.constructor.buildRegistry(this); 15517 15518 return registry; 15519 }, 15520 15521 /** 15522 @private 15523 @method initializer 15524 */ 15525 initializer: function (options) { 15526 this.constructor.initializer(options); 15527 }, 15528 15529 /** 15530 @private 15531 @method instanceInitializer 15532 */ 15533 instanceInitializer: function (options) { 15534 this.constructor.instanceInitializer(options); 15535 }, 15536 15537 /** 15538 @private 15539 @method runInitializers 15540 */ 15541 runInitializers: function () { 15542 var _this = this; 15543 15544 this._runInitializer('initializers', function (name, initializer) { 15545 _emberMetalDebug.assert('No application initializer named \'' + name + '\'', !!initializer); 15546 if (initializer.initialize.length === 2) { 15547 _emberMetalDebug.deprecate('The `initialize` method for Application initializer \'' + name + '\' should take only one argument - `App`, an instance of an `Application`.', false, { 15548 id: 'ember-application.app-initializer-initialize-arguments', 15549 until: '3.0.0', 15550 url: 'http://emberjs.com/deprecations/v2.x/#toc_initializer-arity' 15551 }); 15552 15553 initializer.initialize(_this.__registry__, _this); 15554 } else { 15555 initializer.initialize(_this); 15556 } 15557 }); 15558 }, 15559 15560 /** 15561 @private 15562 @since 1.12.0 15563 @method runInstanceInitializers 15564 */ 15565 runInstanceInitializers: function (instance) { 15566 this._runInitializer('instanceInitializers', function (name, initializer) { 15567 _emberMetalDebug.assert('No instance initializer named \'' + name + '\'', !!initializer); 15568 initializer.initialize(instance); 15569 }); 15570 }, 15571 15572 _runInitializer: function (bucketName, cb) { 15573 var initializersByName = _emberMetalProperty_get.get(this.constructor, bucketName); 15574 var initializers = props(initializersByName); 15575 var graph = new _dagMap.default(); 15576 var initializer; 15577 15578 for (var i = 0; i < initializers.length; i++) { 15579 initializer = initializersByName[initializers[i]]; 15580 graph.addEdges(initializer.name, initializer, initializer.before, initializer.after); 15581 } 15582 15583 graph.topsort(function (vertex) { 15584 cb(vertex.name, vertex.value); 15585 }); 15586 } 15587 }); 15588 15589 Engine.reopenClass({ 15590 initializers: new _emberMetalEmpty_object.default(), 15591 instanceInitializers: new _emberMetalEmpty_object.default(), 15592 15593 /** 15594 The goal of initializers should be to register dependencies and injections. 15595 This phase runs once. Because these initializers may load code, they are 15596 allowed to defer application readiness and advance it. If you need to access 15597 the container or store you should use an InstanceInitializer that will be run 15598 after all initializers and therefore after all code is loaded and the app is 15599 ready. 15600 Initializer receives an object which has the following attributes: 15601 `name`, `before`, `after`, `initialize`. The only required attribute is 15602 `initialize`, all others are optional. 15603 * `name` allows you to specify under which name the initializer is registered. 15604 This must be a unique name, as trying to register two initializer
15604s with the 15605 same name will result in an error. 15606 ```javascript 15607 Ember.Application.initializer({ 15608 name: 'namedInitializer', 15609 initialize: function(application) { 15610 Ember.debug('Running namedInitializer!'); 15611 } 15612 }); 15613 ``` 15614 * `before` and `after` are used to ensure that this initializer is ran prior 15615 or after the one identified by the value. This value can be a single string 15616 or an array of strings, referencing the `name` of other initializers. 15617 An example of ordering initializers, we create an initializer named `first`: 15618 ```javascript 15619 Ember.Application.initializer({ 15620 name: 'first', 15621 initialize: function(application) { 15622 Ember.debug('First initializer!'); 15623 } 15624 }); 15625 // DEBUG: First initializer! 15626 ``` 15627 We add another initializer named `second`, specifying that it should run 15628 after the initializer named `first`: 15629 ```javascript 15630 Ember.Application.initializer({ 15631 name: 'second', 15632 after: 'first', 15633 initialize: function(application) { 15634 Ember.debug('Second initializer!'); 15635 } 15636 }); 15637 // DEBUG: First initializer! 15638 // DEBUG: Second initializer! 15639 ``` 15640 Afterwards we add a further initializer named `pre`, this time specifying 15641 that it should run before the initializer named `first`: 15642 ```javascript 15643 Ember.Application.initializer({ 15644 name: 'pre', 15645 before: 'first', 15646 initialize: function(application) { 15647 Ember.debug('Pre initializer!'); 15648 } 15649 }); 15650 // DEBUG: Pre initializer! 15651 // DEBUG: First initializer! 15652 // DEBUG: Second initializer! 15653 ``` 15654 Finally we add an initializer named `post`, specifying it should run after 15655 both the `first` and the `second` initializers: 15656 ```javascript 15657 Ember.Application.initializer({ 15658 name: 'post', 15659 after: ['first', 'second'], 15660 initialize: function(application) { 15661 Ember.debug('Post initializer!'); 15662 } 15663 }); 15664 // DEBUG: Pre initializer! 15665 // DEBUG: First initializer! 15666 // DEBUG: Second initializer! 15667 // DEBUG: Post initializer! 15668 ``` 15669 * `initialize` is a callback function that receives one argument, 15670 `application`, on which you can operate. 15671 Example of using `application` to register an adapter: 15672 ```javascript 15673 Ember.Application.initializer({ 15674 name: 'api-adapter', 15675 initialize: function(application) { 15676 application.register('api-adapter:main', ApiAdapter); 15677 } 15678 }); 15679 ``` 15680 @method initializer 15681 @param initializer {Object} 15682 @public 15683 */ 15684 15685 initializer: buildInitializerMethod('initializers', 'initializer'), 15686 15687 /** 15688 Instance initializers run after all initializers have run. Because 15689 instance initializers run after the app is fully set up. We have access 15690 to the store, container, and other items. However, these initializers run 15691 after code has loaded and are not allowed to defer readiness. 15692 Instance initializer receives an object which has the following attributes: 15693 `name`, `before`, `after`, `initialize`. The only required attribute is 15694 `initialize`, all others are optional. 15695 * `name` allows you to specify under which name the instanceInitializer is 15696 registered. This must be a unique name, as trying to register two 15697 instanceInitializer with the same name will result in an error. 15698 ```javascript 15699 Ember.Application.instanceInitializer({ 15700 name: 'namedinstanceInitializer', 15701 initialize: function(application) { 15702 Ember.debug('Running namedInitializer!'); 15703 } 15704 }); 15705 ``` 15706 * `before` and `after` are used to ensure that this initializer is ran prior 15707 or after the one identified by the value. This value can be a single string 15708 or an array of strings, referencing the `name` of other initializers. 15709 * See Ember.Application.initializer for discussion on the usage of before 15710 and after. 15711 Example instanceInitializer to preload data into the store. 15712 ```javascript 15713 Ember.Application.initializer({ 15714 name: 'preload-data', 15715 initialize: function(application) { 15716 var userConfig, userConfigEncoded, store; 15717 // We have a HTML escaped JSON representation of the user's basic 15718 // configuration generated server side and stored in the DOM of the main 15719 // index.html file. This allows the app to have access to a set of data 15720 // without making any additional remote calls. Good for basic data that is 15721 // needed for immediate rendering of the page. Keep in mind, this data, 15722 // like all local models and data can be manipulated by the user, so it 15723 // should not be relied upon for security or authorization. 15724 // 15725 // Grab the encoded data from the meta tag 15726 userConfigEncoded = Ember.$('head meta[name=app-user-config]').attr('content'); 15727 // Unescape the text, then parse the resulting JSON into a real object 15728 userConfig = JSON.parse(unescape(userConfigEncoded)); 15729 // Lookup the store 15730 store = application.lookup('service:store'); 15731 // Push the encoded JSON into the store 15732 store.pushPayload(userConfig); 15733 } 15734 }); 15735 ``` 15736 @method instanceInitializer 15737 @param instanceInitializer 15738 @public 15739 */ 15740 instanceInitializer: buildInitializerMethod('instanceInitializer
15740s', 'instance initializer'), 15741 15742 /** 15743 This creates a registry with the default Ember naming conventions. 15744 It also configures the registry: 15745 * registered views are created every time they are looked up (they are 15746 not singletons) 15747 * registered templates are not factories; the registered value is 15748 returned directly. 15749 * the router receives the application as its `namespace` property 15750 * all controllers receive the router as their `target` and `controllers` 15751 properties 15752 * all controllers receive the application as their `namespace` property 15753 * the application view receives the application controller as its 15754 `controller` property 15755 * the application view receives the application template as its 15756 `defaultTemplate` property 15757 @private 15758 @method buildRegistry 15759 @static 15760 @param {Ember.Application} namespace the application for which to 15761 build the registry 15762 @return {Ember.Registry} the built registry 15763 @public 15764 */ 15765 buildRegistry: function (namespace) { 15766 var registry = new _containerRegistry.default({ 15767 resolver: resolverFor(namespace) 15768 }); 15769 15770 registry.set = _emberMetalProperty_set.set; 15771 15772 return registry; 15773 }, 15774 15775 /** 15776 Set this to provide an alternate class to `Ember.DefaultResolver` 15777 @deprecated Use 'Resolver' instead 15778 @property resolver 15779 @public 15780 */ 15781 resolver: null, 15782 15783 /** 15784 Set this to provide an alternate class to `Ember.DefaultResolver` 15785 @property resolver 15786 @public 15787 */ 15788 Resolver: null 15789 }); 15790 15791 /** 15792 This function defines the default lookup rules for container lookups: 15793 15794 * templates are looked up on `Ember.TEMPLATES` 15795 * other names are looked up on the application after classifying the name. 15796 For example, `controller:post` looks up `App.PostController` by default. 15797 * if the default lookup fails, look for registered classes on the container 15798 15799 This allows the application to register default injections in the container 15800 that could be overridden by the normal naming convention. 15801 15802 @private 15803 @method resolverFor 15804 @param {Ember.Namespace} namespace the namespace to look for classes 15805 @return {*} the resolved value for a given lookup 15806 */ 15807 function resolverFor(namespace) { 15808 var ResolverClass = namespace.get('Resolver') || _emberApplicationSystemResolver.default; 15809 15810 return ResolverClass.create({ 15811 namespace: namespace 15812 }); 15813 } 15814 15815 function buildInitializerMethod(bucketName, humanName) { 15816 return function (initializer) { 15817 // If this is the first initializer being added to a subclass, we are going to reopen the class 15818 // to make sure we have a new `initializers` object, which extends from the parent class' using 15819 // prototypal inheritance. Without this, attempting to add initializers to the subclass would 15820 // pollute the parent class as well as other subclasses. 15821 if (this.superclass[bucketName] !== undefined && this.superclass[bucketName] === this[bucketName]) { 15822 var attrs = {}; 15823 attrs[bucketName] = Object.create(this[bucketName]); 15824 this.reopenClass(attrs); 15825 } 15826 15827 _emberMetalDebug.assert('The ' + humanName + ' \'' + initializer.name + '\' has already been registered', !this[bucketName][initializer.name]); 15828 _emberMetalDebug.assert('An ' + humanName + ' cannot be registered without an initialize function', _emberMetalUtils.canInvoke(initializer, 'initialize')); 15829 _emberMetalDebug.assert('An ' + humanName + ' cannot be registered without a name property', initializer.name !== undefined); 15830 15831 this[bucketName][initializer.name] = initializer; 15832 }; 15833 } 15834 15835 exports.default = Engine; 15836}); 15837enifed('ember-application/system/resolver', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-runtime/system/string', 'ember-runtime/system/object', 'ember-runtime/system/namespace', 'ember-htmlbars/helpers', 'ember-application/utils/validate-type', 'ember-metal/dictionary', 'ember-htmlbars/template_registry'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberRuntimeSystemString, _emberRuntimeSystemObject, _emberRuntimeSystemNamespace, _emberHtmlbarsHelpers, _emberApplicationUtilsValidateType, _emberMetalDictionary, _emberHtmlbarsTemplate_registry) { 15838 /** 15839 @module ember 15840 @submodule ember-application 15841 */ 15842 15843 'use strict'; 15844 15845 var Resolver = _emberRuntimeSystemObject.default.extend({ 15846 /* 15847 This will be set to the Application instance when it is 15848 created. 15849 @property namespace 15850 */ 15851 namespace: null, 15852 normalize: null, // required 15853 resolve: null, // required 15854 parseName: null, // required 15855 lookupDescription: null, // required 15856 makeToString: null, // required 15857 resolveOther: null, // required 15858 _logLookup: null // required 15859 }); 15860 15861 exports.Resolver = Resolver; 15862 /** 15863 The DefaultResolver defines the default lookup rules to resolve 15864 container lookups before consulting the container for registered 15865 items: 15866 15867 * templates are looked up on `Ember.TEMPLATES` 15868 * other names are looked up on the application after converting 15869 the name. For example, `controller:post` looks up 15870 `App.PostController` by default. 15871 * there are some nuances (see examples below) 15872 15873 ### How Resolving Works 15874 15875 The container calls this object's `resolve` method with the 15876 `fullName` argument. 15877 15878 It first parses the fullName into an object using `parseName`. 15879 15880 Then it checks for the presence of a type-specific instance 15881 method of the form `resolve[Type]` and calls it if it exists. 15882 For example if it was resolving 'template:post', it would call 15883 the `resolveTemplate` method. 15884 15885 Its last resort is to call the `resolveOther` method. 15886 15887 The methods of this object are designed to be easy to override 15888 in a subclass. For example, you could enhance how a template 15889 is resolved like so: 15890 15891 ```javascript 15892 App = Ember.Application.create({ 15893 Resolver: Ember.DefaultResolver.extend({ 15894 resolveTemplate: function(parsedName) { 15895 var resolvedTemplate = this._super(parsedName); 15896 if (resolvedTemplate) { return resolvedTemplate; } 15897 return Ember.TEMPLATES['not_found']; 15898 } 15899 }) 15900 }); 15901 ``` 15902 15903 Some examples of how names are resolved: 15904 15905 ``` 15906 'template:post' //=> Ember.TEMPLATES['post'] 15907 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] 15908 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] 15909 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] 15910 // OR 15911 // Ember.TEMPLATES['blog_post'] 15912 'controller:post' //=> App.PostController 15913 'controller:posts.index' //=> App.PostsIndexController 15914 'controller:blog/post' //=> Blog.PostController 15915 'controller:basic' //=> Ember.Controller 15916 'route:post' //=> App.PostRoute 15917 'route:posts.index' //=> App.PostsIndexRoute 15918 'route:blog/post' //=> Blog.PostRoute 15919 'route:basic' //=> Ember.Route 15920 'view:post' //=> App.PostView 15921 'view:posts.index' //=> App.PostsIndexView 15922 'view:blog/post' //=> Blog.PostView 15923 'view:basic' //=> Ember.View 15924 'foo:post' //=> App.PostFoo 15925 'model:post' //=> App.Post 15926 ``` 15927 15928 @class DefaultResolver 15929 @namespace Ember
15930 @extends Ember.Object 15931 @public 15932 */ 15933 15934 exports.default = _emberRuntimeSystemObject.default.extend({ 15935 /** 15936 This will be set to the Application instance when it is 15937 created. 15938 @property namespace 15939 @public 15940 */ 15941 namespace: null, 15942 15943 init: function () { 15944 this._parseNameCache = _emberMetalDictionary.default(null); 15945 }, 15946 normalize: function (fullName) { 15947 var _fullName$split = fullName.split(':', 2); 15948 15949 var type = _fullName$split[0]; 15950 var name = _fullName$split[1]; 15951 15952 _emberMetalDebug.assert('Tried to normalize a container name without a colon (:) in it. ' + 'You probably tried to lookup a name that did not contain a type, ' + 'a colon, and a name. A proper lookup name would be `view:post`.', fullName.split(':').length === 2); 15953 15954 if (type !== 'template') { 15955 var result = name; 15956 15957 if (result.indexOf('.') > -1) { 15958 result = result.replace(/\.(.)/g, function (m) { 15959 return m.charAt(1).toUpperCase(); 15960 }); 15961 } 15962 15963 if (name.indexOf('_') > -1) { 15964 result = result.replace(/_(.)/g, function (m) { 15965 return m.charAt(1).toUpperCase(); 15966 }); 15967 } 15968 15969 if (name.indexOf('-') > -1) { 15970 result = result.replace(/-(.)/g, function (m) { 15971 return m.charAt(1).toUpperCase(); 15972 }); 15973 } 15974 15975 return type + ':' + result; 15976 } else { 15977 return fullName; 15978 } 15979 }, 15980 15981 /** 15982 This method is called via the container's resolver method. 15983 It parses the provided `fullName` and then looks up and 15984 returns the appropriate template or class. 15985 @method resolve 15986 @param {String} fullName the lookup string 15987 @return {Object} the resolved factory 15988 @public 15989 */ 15990 resolve: function (fullName) { 15991 var parsedName = this.parseName(fullName); 15992 var resolveMethodName = parsedName.resolveMethodName; 15993 var resolved; 15994 15995 if (this[resolveMethodName]) { 15996 resolved = this[resolveMethodName](parsedName); 15997 } 15998 15999 resolved = resolved || this.resolveOther(parsedName); 16000 16001 if (parsedName.root && parsedName.root.LOG_RESOLVER) { 16002 this._logLookup(resolved, parsedName); 16003 } 16004 16005 if (resolved) { 16006 _emberApplicationUtilsValidateType.default(resolved, parsedName); 16007 } 16008 16009 return resolved; 16010 }, 16011 16012 /** 16013 Convert the string name of the form 'type:name' to 16014 a Javascript object with the parsed aspects of the name 16015 broken out. 16016 @protected 16017 @param {String} fullName the lookup string 16018 @method parseName 16019 @public 16020 */ 16021 16022 parseName: function (fullName) { 16023 return this._parseNameCache[fullName] || (this._parseNameCache[fullName] = this._parseName(fullName)); 16024 }, 16025 16026 _parseName: function (fullName) { 16027 var _fullName$split2 = fullName.split(':'); 16028 16029 var type = _fullName$split2[0]; 16030 var fullNameWithoutType = _fullName$split2[1]; 16031 16032 var name = fullNameWithoutType; 16033 var namespace = _emberMetalProperty_get.get(this, 'namespace'); 16034 var root = namespace; 16035 var lastSlashIndex = name.lastIndexOf('/'); 16036 var dirname = lastSlashIndex !== -1 ? name.slice(0, lastSlashIndex) : null; 16037 16038 if (type !== 'template' && lastSlashIndex !== -1) { 16039 var parts = name.split('/'); 16040 name = parts[parts.length - 1]; 16041 var namespaceName = _emberRuntimeSystemString.capitalize(parts.slice(0, -1).join('.')); 16042 root = _emberRuntimeSystemNamespace.default.byName(namespaceName); 16043 16044 _emberMetalDebug.assert('You are looking for a ' + name + ' ' + type + ' in the ' + namespaceName + ' namespace, but the namespace could not be found', root); 16045 } 16046 16047 var resolveMethodName = fullNameWithoutType === 'main' ? 'Main' : _emberRuntimeSystemString.classify(type); 16048 16049 if (!(name && type)) { 16050 throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); 16051 } 16052 16053 return { 16054 fullName: fullName, 16055 type: type, 16056 fullNameWithoutType: fullNameWithoutType, 16057 dirname: dirname, 16058 name: name, 16059 root: root, 16060 resolveMethodName: 'resolve' + resolveMethodName 16061 }; 16062 }, 16063 16064 /** 16065 Returns a human-readable description for a fullName. Used by the 16066 Application namespace in assertions to describe the 16067 precise name of the class that Ember is looking for, rather than 16068 container keys. 16069 @protected 16070 @param {String} fullName the lookup string 16071 @method lookupDescription 16072 @public 16073 */ 16074 lookupDescription: function (fullName) { 16075 var parsedName = this.parseName(fullName); 16076 var description; 16077 16078 if (parsedName.type === 'template') { 16079 return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); 16080 } 16081 16082 description = parsedName.root + '.' + _emberRuntimeSystemString.classify(parsedName.name).replace(/\./g, ''); 16083 16084 if (parsedName.type !== 'model') { 16085 description += _emberRuntimeSystemString.classify(parsedName.type); 16086 } 16087 16088 return description; 16089 }, 16090 16091 makeToString: function (factory, fullName) { 16092 return factory.toString(); 16093 }, 16094 16095 /** 16096 Given a parseName object (output from `parseName`), apply 16097 the conventions expected by `Ember.Router` 16098 @protected 16099 @param {Object} parsedName a parseName object with the parsed 16100 fullName lookup string 16101 @method useRouterNaming 16102 @public 16103 */ 16104 useRouterNaming: function (parsedName) { 16105 parsedName.name = parsedName.name.replace(/\./g, '_'); 16106 if (parsedName.name === 'basic') { 16107 parsedName.name = ''; 16108 } 16109 }, 16110 /** 16111 Look up the template in Ember.TEMPLATES 16112 @protected 16113 @param {Object} parsedName a parseName object with the parsed 16114 fullName lookup string 16115 @method resolveTemplate 16116 @public 16117 */ 16118 resolveTemplate: function (parsedName) { 16119 var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); 16120 16121 return _emberHtmlbarsTemplate_registry.get(templateName) || _emberHtmlbarsTemplate_registry.get(_emberRuntimeSystemString.decamelize(templateName)); 16122 }, 16123 16124 /** 16125 Lookup the view using `resolveOther` 16126 @protected 16127 @param {Object} parsedName a parseName object with the parsed 16128 fullName lookup string 16129 @method resolveView 16130 @public 16131 */ 16132 resolveView: function (parsedName) { 16133 this.useRouterNaming(parsedName); 16134 return this.resolveOther(parsedName); 16135 }, 16136 16137 /** 16138 Lookup the controller using `resolveOther` 16139 @protected 16140 @param {Object} parsedName a parseName object with the parsed 16141 fullName lookup string
16142 @method resolveController 16143 @public 16144 */ 16145 resolveController: function (parsedName) { 16146 this.useRouterNaming(parsedName); 16147 return this.resolveOther(parsedName); 16148 }, 16149 /** 16150 Lookup the route using `resolveOther` 16151 @protected 16152 @param {Object} parsedName a parseName object with the parsed 16153 fullName lookup string 16154 @method resolveRoute 16155 @public 16156 */ 16157 resolveRoute: function (parsedName) { 16158 this.useRouterNaming(parsedName); 16159 return this.resolveOther(parsedName); 16160 }, 16161 16162 /** 16163 Lookup the model on the Application namespace 16164 @protected 16165 @param {Object} parsedName a parseName object with the parsed 16166 fullName lookup string 16167 @method resolveModel 16168 @public 16169 */ 16170 resolveModel: function (parsedName) { 16171 var className = _emberRuntimeSystemString.classify(parsedName.name); 16172 var factory = _emberMetalProperty_get.get(parsedName.root, className); 16173 16174 if (factory) { 16175 return factory; 16176 } 16177 }, 16178 /** 16179 Look up the specified object (from parsedName) on the appropriate 16180 namespace (usually on the Application) 16181 @protected 16182 @param {Object} parsedName a parseName object with the parsed 16183 fullName lookup string 16184 @method resolveHelper 16185 @public 16186 */ 16187 resolveHelper: function (parsedName) { 16188 return this.resolveOther(parsedName) || _emberHtmlbarsHelpers.default[parsedName.fullNameWithoutType]; 16189 }, 16190 /** 16191 Look up the specified object (from parsedName) on the appropriate 16192 namespace (usually on the Application) 16193 @protected 16194 @param {Object} parsedName a parseName object with the parsed 16195 fullName lookup string 16196 @method resolveOther 16197 @public 16198 */ 16199 resolveOther: function (parsedName) { 16200 var className = _emberRuntimeSystemString.classify(parsedName.name) + _emberRuntimeSystemString.classify(parsedName.type); 16201 var factory = _emberMetalProperty_get.get(parsedName.root, className); 16202 if (factory) { 16203 return factory; 16204 } 16205 }, 16206 16207 resolveMain: function (parsedName) { 16208 var className = _emberRuntimeSystemString.classify(parsedName.type); 16209 return _emberMetalProperty_get.get(parsedName.root, className); 16210 }, 16211 16212 /** 16213 @method _logLookup 16214 @param {Boolean} found 16215 @param {Object} parsedName 16216 @private 16217 */ 16218 _logLookup: function (found, parsedName) { 16219 var symbol, padding; 16220 16221 if (found) { 16222 symbol = '[â]'; 16223 } else { 16224 symbol = '[ ]'; 16225 } 16226 16227 if (parsedName.fullName.length > 60) { 16228 padding = '.'; 16229 } else { 16230 padding = new Array(60 - parsedName.fullName.length).join('.'); 16231 } 16232 16233 _emberMetalDebug.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); 16234 }, 16235 16236 /** 16237 Used to iterate all items of a given type. 16238 @method knownForType 16239 @param {String} type the type to search for 16240 @private 16241 */ 16242 knownForType: function (type) { 16243 var namespace = _emberMetalProperty_get.get(this, 'namespace'); 16244 var suffix = _emberRuntimeSystemString.classify(type); 16245 var typeRegexp = new RegExp(suffix + '$'); 16246 16247 var known = _emberMetalDictionary.default(null); 16248 var knownKeys = Object.keys(namespace); 16249 for (var index = 0, _length = knownKeys.length; index < _length; index++) { 16250 var _name = knownKeys[index]; 16251 16252 if (typeRegexp.test(_name)) { 16253 var containerName = this.translateToContainerFullname(type, _name); 16254 16255 known[containerName] = true; 16256 } 16257 } 16258 16259 return known; 16260 }, 16261 16262 /** 16263 Converts provided name from the backing namespace into a container lookup name. 16264 Examples: 16265 App.FooBarHelper -> helper:foo-bar 16266 App.THelper -> helper:t 16267 @method translateToContainerFullname 16268 @param {String} type 16269 @param {String} name 16270 @private 16271 */ 16272 16273 translateToContainerFullname: function (type, name) { 16274 var suffix = _emberRuntimeSystemString.classify(type);
16275 var namePrefix = name.slice(0, suffix.length * -1); 16276 var dasherizedName = _emberRuntimeSystemString.dasherize(namePrefix); 16277 16278 return type + ':' + dasherizedName; 16279 } 16280 }); 16281}); 16282enifed('ember-application/utils/validate-type', ['exports', 'ember-metal/debug'], function (exports, _emberMetalDebug) { 16283 /** 16284 @module ember 16285 @submodule ember-application 16286 */ 16287 16288 'use strict'; 16289 16290 exports.default = validateType; 16291 16292 var VALIDATED_TYPES = { 16293 route: ['assert', 'isRouteFactory', 'Ember.Route'], 16294 component: ['deprecate', 'isComponentFactory', 'Ember.Component'], 16295 view: ['deprecate', 'isViewFactory', 'Ember.View'], 16296 service: ['deprecate', 'isServiceFactory', 'Ember.Service'] 16297 }; 16298 16299 function validateType(resolvedType, parsedName) { 16300 var validationAttributes = VALIDATED_TYPES[parsedName.type]; 16301 16302 if (!validationAttributes) { 16303 return; 16304 } 16305 16306 var action = validationAttributes[0]; 16307 var factoryFlag = validationAttributes[1]; 16308 var expectedType = validationAttributes[2]; 16309 16310 if (action === 'deprecate') { 16311 _emberMetalDebug.deprecate('In Ember 2.0 ' + parsedName.type + ' factories must have an `' + factoryFlag + '` ' + ('property set to true. You registered ' + resolvedType + ' as a ' + parsedName.type + ' ') + ('factory. Either add the `' + factoryFlag + '` property to this factory or ') + ('extend from ' + expectedType + '.'), !!resolvedType[factoryFlag], { id: 'ember-application.validate-type', until: '3.0.0' }); 16312 } else { 16313 _emberMetalDebug.assert('Expected ' + parsedName.fullName + ' to resolve to an ' + expectedType + ' but ' + ('instead it was ' + resolvedType + '.'), !!resolvedType[factoryFlag]); 16314 } 16315 } 16316}); 16317enifed('ember-debug/deprecate', ['exports', 'ember-metal/core', 'ember-metal/error', 'ember-metal/logger', 'ember-debug/handlers'], function (exports, _emberMetalCore, _emberMetalError, _emberMetalLogger, _emberDebugHandlers) { 16318 /*global __fail__*/ 16319 16320 'use strict'; 16321 16322 var _slice = Array.prototype.slice; 16323 exports.registerHandler = registerHandler; 16324 exports.default = deprecate; 16325 16326 function registerHandler(handler) { 16327 _emberDebugHandlers.registerHandler('deprecate', handler); 16328 } 16329 16330 function formatMessage(_message, options) { 16331 var message = _message; 16332 16333 if (options && options.id) { 16334 message = message + (' [deprecation id: ' + options.id + ']'); 16335 } 16336 16337 if (options && options.url) { 16338 message += ' See ' + options.url + ' for more details.'; 16339 } 16340 16341 return message; 16342 } 16343 16344 registerHandler(function logDeprecationToConsole(message, options) { 16345 var updatedMessage = formatMessage(message, options); 16346 16347 _emberMetalLogger.default.warn('DEPRECATION: ' + updatedMessage); 16348 }); 16349 16350 registerHandler(function logDeprecationStackTrace(message, options, next) { 16351 if (_emberMetalCore.default.LOG_STACKTRACE_ON_DEPRECATION) { 16352 var stackStr = ''; 16353 var error = undefined, 16354 stack = undefined; 16355 16356 // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome 16357 try { 16358 __fail__.fail(); 16359 } catch (e) { 16360 error = e; 16361 } 16362 16363 if (error.stack) { 16364 if (error['arguments']) { 16365 // Chrome 16366 stack = error.stack.replace(/^\s+at\s+/gm, '').replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2').replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); 16367 stack.shift(); 16368 } else { 16369 // Firefox 16370 stack = error.stack.replace(/(?:\n@:0)?\s+$/m, '').replace(/^\(/gm, '{anonymous}(').split('\n'); 16371 } 16372 16373 stackStr = '\n ' + stack.slice(2).join('\n '); 16374 } 16375 16376 var updatedMessage = formatMessage(message, options); 16377 16378 _emberMetalLogger.default.warn('DEPRECATION: ' + updatedMessage + stackStr); 16379 } else { 16380 next.apply(undefined, arguments); 16381 } 16382 }); 16383 16384 registerHandler(function raiseOnDeprecation(message, options, next) { 16385 if (_emberMetalCore.default.ENV.RAISE_ON_DEPRECATION) { 16386 var updatedMessage = formatMessage(message); 16387 16388 throw new _emberMetalError.default(updatedMessage); 16389 } else { 16390 next.apply(undefined, arguments); 16391 } 16392 }); 16393 16394 var missingOptionsDeprecation = 'When calling `Ember.deprecate` you ' + 'must provide an `options` hash as the third parameter. ' + '`options` should include `id` and `until` properties.'; 16395 exports.missingOptionsDeprecation = missingOptionsDeprecation; 16396 var missingOptionsIdDeprecation = 'When calling `Ember.deprecate` you must provide `id` in options.'; 16397 exports.missingOptionsIdDeprecation = missingOptionsIdDeprecation; 16398 var missingOptionsUntilDeprecation = 'When calling `Ember.deprecate` you must provide `until` in options.'; 16399 16400 exports.missingOptionsUntilDeprecation = missingOptionsUntilDeprecation; 16401 /** 16402 @module ember 16403 @submodule ember-debug 16404 */ 16405 16406 /** 16407 Display a deprecation warning with the provided message and a stack trace 16408 (Chrome and Firefox only). 16409 16410 * In a production build, this method is defined as an empty function (NOP). 16411 Uses of this method in Ember itself are stripped from the ember.prod.js build. 16412 16413 @method deprecate 16414 @param {String} message A description of the deprecation. 16415 @param {Boolean} test A boolean. If falsy, the deprecation 16416 will be displayed. 16417 @param {Object} options An object that can be used to pass 16418 in a `url` to the transition guide on the emberjs.com website, and a unique 16419 `id` for this deprecation. The `id` can be used by Ember debugging tools 16420 to change the behavior (raise, log or silence) for that specific deprecation. 16421 The `id` should be namespaced by dots, e.g. "view.helper.select". 16422 @for Ember 16423 @public 16424 */ 16425 16426 function deprecate(message, test, options) { 16427 if (!options || !options.id && !options.until) { 16428 deprecate(missingOptionsDeprecation, false, { 16429 id: 'ember-debug.deprecate-options-missing', 16430 until: '3.0.0', 16431 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' 16432 }); 16433 } 16434 16435 if (options && !options.id) { 16436 deprecate(missingOptionsIdDeprecation, false, { 16437 id: 'ember-debug.deprecate-id-missing', 16438 until: '3.0.0', 16439 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' 16440 }); 16441 } 16442 16443 if (options && !options.until) { 16444 deprecate(missingOptionsUntilDeprecation, options && options.until, { 16445 id: 'ember-debug.deprecate-until-missing', 16446 until: '3.0.0', 16447 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' 16448 }); 16449 } 16450 16451 _emberDebugHandlers.invoke.apply(undefined, ['deprecate'].concat(_slice.call(arguments))); 16452 } 16453}); 16454enifed('ember-debug/handlers', ['exports', 'ember-debug/is-plain-function', 'ember-debug/deprecate'], function (exports, _emberDebugIsPlainFunction, _emberDebugDeprecate) { 16455 'use strict'; 16456 16457 exports.generateTestAsFunctionDeprecation = generateTestAsFunctionDeprecation; 16458 exports.registerHandler = registerHandler; 16459 exports.invoke = invoke; 16460 var HANDLERS = {}; 16461 16462 exports.HANDLERS = HANDLERS; 16463 16464 function generateTestAsFunctionDeprecation(source) { 16465 return 'Calling `' + source + '` with a function argument is deprecated. Please ' + 'use `!!Constructor` for constructors, or an `IIFE` to compute the test for deprecation. ' + 'In a future version, functions will be treated as truthy values instead of being executed.'; 16466 } 16467 16468 function normalizeTest(test, source) { 16469 if (_emberDebugIsPlainFunction.default(test)) { 16470 _emberDebugDeprecate.default(generateTestAsFunctionDeprecation(source), false, { id: 'ember-debug.deprecate-test-as-function', until: '2.5.0' }); 16471 16472 return test(); 16473 } 16474 16475 return test; 16476 } 16477 16478 function registerHandler(type, callback) { 16479 var nextHandler = HANDLERS[type] || function () {}; 16480 16481 HANDLERS[type] = function (message, options) { 16482 callback(message, options, nextHandler); 16483 }; 16484 } 16485 16486 function invoke(type, message, test, options) { 16487 if (normalizeTest(test, 'Ember.' + type)) { 16488 return; 16489 } 16490 16491 var handlerForType = HANDLERS[type]; 16492 16493 if (!handlerForType) { 16494 return; 16495 } 16496 16497 if (handlerForType) { 16498 handlerForType(message, options); 16499 } 16500 } 16501}); 16502enifed('ember-debug/index', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/error', 'ember-metal/logger', 'ember-metal/environment', 'ember-debug/deprecate', 'ember-debug/warn', 'ember-debug/is-plain-function', 'ember-debug/handlers'], function (exports, _emberMetalCore, _emberMetalDebug, _emberMetalFeatures, _emberMetalError, _emberMetalLogger, _emberMetalEnvironment, _emberDebugDeprecate, _emberDebugWarn, _emberDebugIsPlainFunction, _emberDebugHandlers) { 16503 'use strict'; 16504 16505 exports._warnIfUsingStrippedFeatureFlags = _warnIfUsingStrippedFeatureFlags; 16506 16507 /** 16508 @module ember 16509 @submodule ember-debug 16510 */ 16511 16512 /** 16513 @class Ember 16514 @public 16515 */ 16516 16517 /** 16518 Define an assertion that will throw an exception if the condition is not met. 16519 16520 * In a production build, this method is defined as an empty function (NOP). 16521 Uses of this method in Ember itself are stripped from the ember.prod.js build. 16522 16523 ```javascript 16524 // Test for truthiness 16525 Ember.assert('Must pass a valid object', obj); 16526 16527 // Fail unconditionally 16528 Ember.assert('This code path should never be run'); 16529 ``` 16530 16531 @method assert 16532 @param {String} desc A description of the assertion. This will become 16533 the text of the Error thrown if the assertion fails. 16534 @param {Boolean} test Must be truthy for the assertion to pass. If 16535 falsy, an exception will be thrown. 16536 @public 16537 */ 16538 _emberMetalDebug.setDebugFunction('assert', function assert(desc, test) { 16539 var throwAssertion = undefined; 16540 16541 if (_emberDebugIsPlainFunction.default(test)) { 16542 _emberMetalDebug.deprecate(_emberDebugHandlers.generateTestAsFunctionDeprecation('Ember.assert'), false, { id: 'ember-debug.deprecate-test-as-function', until: '2.5.0' }); 16543 16544 throwAssertion = !test(); 16545 } else { 16546 throwAssertion = !test; 16547 } 16548 16549 if (throwAssertion) { 16550 throw new _emberMetalError.default('Assertion Failed: ' + desc); 16551 } 16552 }); 16553 16554 /** 16555 Display a debug notice. 16556 16557 * In a production build, this method is defined as an empty function (NOP). 16558 Uses of this method in Ember itself are stripped from the ember.prod.js build. 16559 16560 ```javascript 16561 Ember.debug('I\'m a debug notice!'); 16562 ``` 16563 16564 @method debug 16565 @param {String} message A debug message to display. 16566 @public 16567 */ 16568 _emberMetalDebug.setDebugFunction('debug', function debug(message) { 16569 _emberMetalLogger.default.debug('DEBUG: ' + message); 16570 }); 16571 16572 /** 16573 Display an info notice. 16574 16575 * In a production build, this method is defined as an empty function (NOP). 16576 Uses of this method in Ember itself are stripped from the ember.prod.js build. 16577 16578 @method info 16579 @private 16580 */ 16581 _emberMetalDebug.setDebugFunction('info', function info() { 16582 _emberMetalLogger.default.info.apply(undefined, arguments); 16583 }); 16584 16585 /** 16586 Alias an old, deprecated method with its new counterpart. 16587 16588 Display a deprecation warning with the provided message and a stack trace 16589 (Chrome and Firefox only) when the assigned method is called. 16590 16591 * In a production build, this method is defined as an empty function (NOP). 16592 16593 ```javascript 16594 Ember.oldMethod = Ember.deprecateFunc('Please use the new, updated method', Ember.newMethod); 16595 ``` 16596 16597 @method deprecateFunc 16598 @param {String} message A description of the deprecation. 16599 @param {Object} [options] The options object for Ember.deprecate. 16600 @param {Function} func The new function called to replace its deprecated counterpart. 16601 @return {Function} A new function that wraps the original function with a deprecation warning 16602 @private 16603 */ 16604 _emberMetalDebug.setDebugFunction('deprecateFunc', function deprecateFunc() { 16605 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 16606 args[_key] = arguments[_key]; 16607 } 16608 16609 if (args.length === 3) { 16610 var _ret = (function () { 16611 var message = args[0]; 16612 var options = args[1]; 16613 var func = args[2]; 16614 16615 return { 16616 v: function () { 16617 _emberMetalDebug.deprecate(message, false, options); 16618 return func.apply(this, arguments); 16619 } 16620 }; 16621 })(); 16622 16623 if (typeof _ret === 'object') return _ret.v; 16624 } else { 16625 var _ret2 = (function () { 16626 var message = args[0]; 16627 var func = args[1]; 16628 16629 return { 16630 v: function () { 16631 _emberMetalDebug.deprecate(message); 16632 return func.apply(this, arguments); 16633 } 16634 }; 16635 })(); 16636 16637 if (typeof _ret2 === 'object') return _ret2.v; 16638 } 16639 }); 16640 16641 /** 16642 Run a function meant for debugging. 16643 16644 * In a production build, this method is defined as an empty function (NOP). 16645 Uses of this method in Ember itself are stripped from the ember.prod.js build. 16646 16647 ```javascript 16648 Ember.runInDebug(() => { 16649 Ember.Component.reopen({ 16650 didInsertElement() { 16651 console.log("I'm happy"); 16652 } 16653 }); 16654 }); 16655 ``` 16656 16657 @method runInDebug 16658 @param {Function} func The function to be executed. 16659 @since 1.5.0 16660 @public 16661 */ 16662 _emberMetalDebug.setDebugFunction('runInDebug', function runInDebug(func) { 16663 func(); 16664 }); 16665 16666 _emberMetalDebug.setDebugFunction('debugSeal', function debugSeal(obj) { 16667 Object.seal(obj); 16668 }); 16669 16670 _emberMetalDebug.setDebugFunction('deprecate', _emberDebugDeprecate.default); 16671 16672 _emberMetalDebug.setDebugFunction('warn', _emberDebugWarn.default); 16673 16674 /** 16675 Will call `Ember.warn()` if ENABLE_OPTIONAL_FEATURES or 16676 any specific FEATURES flag is truthy. 16677 16678 This method is called automatically in debug canary builds. 16679 16680 @private 16681 @method _warnIfUsingStrippedFeatureFlags 16682 @return {void} 16683 */ 16684 16685 function _warnIfUsingStrippedFeatureFlags(FEATURES, knownFeatures, featuresWereStripped) { 16686 if (featuresWereStripped) { 16687 _emberMetalDebug.warn('Ember.ENV.ENABLE_OPTIONAL_FEATURES is only available in canary builds.', !_emberMetalCore.default.ENV.ENABLE_OPTIONAL_FEATURES, { id: 'ember-debug.feature-flag-with-features-stripped' }); 16688 16689 var keys = Object.keys(FEATURES || {}); 16690 for (var i = 0; i < keys.length; i++) { 16691 var key = keys[i]; 16692 if (key === 'isEnabled' || !(key in knownFeatures)) { 16693 continue; 16694 } 16695 16696 _emberMetalDebug.warn('FEATURE["' + key + '"] is set as enabled, but FEATURE flags are only available in canary builds.', !FEATURES[key], { id: 'ember-debug.feature-flag-with-features-stripped' }); 16697 } 16698 } 16699 } 16700 16701 if (!_emberMetalCore.default.testing) { 16702 // Complain if they're using FEATURE flags in builds other than canary 16703 _emberMetalFeatures.FEATURES['features-stripped-test'] = true; 16704 var featuresWereStripped = true; 16705 16706 delete _emberMetalFeatures.FEATURES['features-stripped-test']; 16707 _warnIfUsingStrippedFeatureFlags(_emberMetalCore.default.ENV.FEATURES, _emberMetalFeatures.KNOWN_FEATURES, featuresWereStripped); 16708 16709 // Inform the developer about the Ember Inspector if not installed. 16710 var isFirefox = _emberMetalEnvironment.default.isFirefox; 16711 var isChrome = _emberMetalEnvironment.default.isChrome; 16712 16713 if (typeof window !== 'undefined' && (isFirefox || isChrome) && window.addEventListener) { 16714 window.addEventListener('load', function () { 16715 if (document.documentElement && document.documentElement.dataset && !document.documentElement.dataset.emberExtension) { 16716 var downloadURL; 16717 16718 if (isChrome) { 16719 downloadURL = 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'; 16720 } else if (isFirefox) { 16721 downloadURL = 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'; 16722 } 16723 16724 _emberMetalDebug.debug('For more advanced debugging, install the Ember Inspector from ' + downloadURL); 16725 } 16726 }, false); 16727 } 16728 } 16729 /** 16730 @public 16731 @class Ember.Debug 16732 */ 16733 _emberMetalCore.default.Debug = {}; 16734 16735 /** 16736 Allows for runtime registration of handler functions that override the default deprecation behavior. 16737 Deprecations are invoked by calls to [Ember.deprecate](http://emberjs.com/api/classes/Ember.html#method_deprecate). 16738 The following example
16738 demonstrates its usage by registering a handler that throws an error if the 16739 message contains the word "should", otherwise defers to the default handler. 16740 ```javascript 16741 Ember.Debug.registerDeprecationHandler((message, options, next) => { 16742 if (message.indexOf('should') !== -1) { 16743 throw new Error(`Deprecation message with should: ${message}`); 16744 } else { 16745 // defer to whatever handler was registered before this one 16746 next(message, options); 16747 } 16748 } 16749 ``` 16750 The handler function takes the following arguments: 16751 <ul> 16752 <li> <code>message</code> - The message received from the deprecation call.</li> 16753 <li> <code>options</code> - An object passed in with the deprecation call containing additional information including:</li> 16754 <ul> 16755 <li> <code>id</code> - An id of the deprecation in the form of <code>package-name.specific-deprecation</code>.</li> 16756 <li> <code>until</code> - The Ember version number the feature and deprecation will be removed in.</li> 16757 </ul> 16758 <li> <code>next</code> - A function that calls into the previously registered handler.</li> 16759 </ul> 16760 @public 16761 @static 16762 @method registerDeprecationHandler 16763 @param handler {Function} A function to handle deprecation calls. 16764 @since 2.1.0 16765 */ 16766 _emberMetalCore.default.Debug.registerDeprecationHandler = _emberDebugDeprecate.registerHandler; 16767 /** 16768 Allows for runtime registration of handler functions that override the default warning behavior. 16769 Warnings are invoked by calls made to [Ember.warn](http://emberjs.com/api/classes/Ember.html#method_warn). 16770 The following example demonstrates its usage by registering a handler that does nothing overriding Ember's 16771 default warning behavior. 16772 ```javascript 16773 // next is not called, so no warnings get the default behavior 16774 Ember.Debug.registerWarnHandler(() => {}); 16775 ``` 16776 The handler function takes the following arguments: 16777 <ul> 16778 <li> <code>message</code> - The message received from the warn call. </li> 16779 <li> <code>options</code> - An object passed in with the warn call containing additional information including:</li> 16780 <ul> 16781 <li> <code>id</code> - An id of the warning in the form of <code>package-name.specific-warning</code>.</li> 16782 </ul> 16783 <li> <code>next</code> - A function that calls into the previously registered handler.</li> 16784 </ul> 16785 @public 16786 @static 16787 @method registerWarnHandler 16788 @param handler {Function} A function to handle warnings. 16789 @since 2.1.0 16790 */ 16791 _emberMetalCore.default.Debug.registerWarnHandler = _emberDebugWarn.registerHandler; 16792 16793 /* 16794 We are transitioning away from `ember.js` to `ember.debug.js` to make 16795 it much clearer that it is only for local development purposes. 16796 16797 This flag value is changed by the tooling (by a simple string replacement) 16798 so that if `ember.js` (which must be output for backwards compat reasons) is 16799 used a nice helpful warning message will be printed out. 16800 */ 16801 var runningNonEmberDebugJS = false; 16802 exports.runningNonEmberDebugJS = runningNonEmberDebugJS; 16803 if (runningNonEmberDebugJS) { 16804 _emberMetalDebug.warn('Please use `ember.debug.js` instead of `ember.js` for development and debugging.'); 16805 } 16806}); 16807enifed('ember-debug/is-plain-function', ['exports'], function (exports) { 16808 'use strict'; 16809 16810 exports.default = isPlainFunction; 16811 16812 function isPlainFunction(test) { 16813 return typeof test === 'function' && test.PrototypeMixin === undefined; 16814 } 16815}); 16816enifed('ember-debug/warn', ['exports', 'ember-metal/logger', 'ember-metal/debug', 'ember-debug/handlers'], function (exports, _emberMetalLogger, _emberMetalDebug, _emberDebugHandlers) { 16817 'use strict'; 16818 16819 var _slice = Array.prototype.slice; 16820 exports.registerHandler = registerHandler; 16821 exports.default = warn; 16822 16823 function registerHandler(handler) { 16824 _emberDebugHandlers.registerHandler('warn', handler); 16825 } 16826 16827 registerHandler(function logWarning(message, options) { 16828 _emberMetalLogger.default.warn('WARNING: ' + message); 16829 if ('trace' in _emberMetalLogger.default) { 16830 _emberMetalLogger.default.trace(); 16831 } 16832 }); 16833 16834 var missingOptionsDeprecation = 'When calling `Ember.warn` you ' + 'must provide an `options` hash as the third parameter. ' + '`options` should include an `id` property.'; 16835 exports.missingOptionsDeprecation = missingOptionsDeprecation; 16836 var missingOptionsIdDeprecation = 'When calling `Ember.warn` you must provide `id` in options.'; 16837 16838 exports.missingOptionsIdDeprecation = missingOptionsIdDeprecation; 16839 /** 16840 @module ember 16841 @submodule ember-debug 16842 */ 16843 16844 /** 16845 Display a warning with the provided message. 16846 16847 * In a production build, this method is defined as an empty function (NOP). 16848 Uses of this method in Ember itself are stripped from the ember.prod.js build. 16849 16850 @method warn 16851 @param {String} message A warning to display. 16852 @param {Boolean} test An optional boolean. If falsy, the warning 16853 will be displayed. 16854 @param {Object} options An object that can be used to pass a unique 16855 `id` for this warning. The `id` can be used by Ember debugging tools 16856 to change the behavior (raise, log, or silence) for that specific warning. 16857 The `id` should be namespaced by dots, e.g. "ember-debug.feature-flag-with-features-stripped" 16858 @for Ember 16859 @public 16860 */ 16861 16862 function warn(message, test, options) { 16863 if (!options) { 16864 _emberMetalDebug.deprecate(missingOptionsDeprecation, false, { 16865 id: 'ember-debug.warn-options-missing', 16866 until: '3.0.0', 16867 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' 16868 }); 16869 } 16870 16871 if (options && !options.id) { 16872 _emberMetalDebug.deprecate(missingOptionsIdDeprecation, false, { 16873 id: 'ember-debug.warn-id-missing', 16874 until: '3.0.0', 16875 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-debug-function-options' 16876 }); 16877 } 16878 16879 _emberDebugHandlers.invoke.apply(undefined, ['warn'].concat(_slice.call(arguments))); 16880 } 16881}); 16882enifed('ember-extension-support/container_debug_adapter', ['exports', 'ember-metal/core', 'ember-runtime/system/native_array', 'ember-runtime/utils', 'ember-runtime/system/string', 'ember-runtime/system/namespace', 'ember-runtime/system/object'], function (exports, _emberMetalCore, _emberRuntimeSystemNative_array, _emberRuntimeUtils, _emberRuntimeSystemString, _emberRuntimeSystemNamespace, _emberRuntimeSystemObject) { 16883 'use strict'; 16884 16885 /** 16886 @module ember 16887 @submodule ember-extension-support 16888 */ 16889 16890 /** 16891 The `ContainerDebugAdapter` helps the container and resolver interface 16892 with tools that debug Ember such as the 16893 [Ember Extension](https://github.com/tildeio/ember-extension) 16894 for Chrome and Firefox. 16895 16896 This class can be extended by a custom resolver implementer 16897 to override some of the methods with library-specific code. 16898 16899 The methods likely to be overridden are: 16900 16901 * `canCatalogEntriesByType` 16902 * `catalogEntriesByType` 16903 16904 The adapter will need to be registered 16905 in the application's container as `container-debug-adapter:main`. 16906 16907 Example: 16908 16909 ```javascript 16910 Application.initializer({ 16911 name: "containerDebugAdapter", 16912 16913 initialize: function(application) { 16914 application.register('container-debug-adapter:main', require('app/container-debug-adapter')); 16915 } 16916 }); 16917 ``` 16918 16919 @class ContainerDebugAdapter 16920 @namespace Ember
16921 @extends Ember.Object 16922 @since 1.5.0 16923 @public 16924 */ 16925 exports.default = _emberRuntimeSystemObject.default.extend({ 16926 /** 16927 The resolver instance of the application 16928 being debugged. This property will be injected 16929 on creation. 16930 @property resolver 16931 @default null 16932 @public 16933 */ 16934 resolver: null, 16935 16936 /** 16937 Returns true if it is possible to catalog a list of available 16938 classes in the resolver for a given type. 16939 @method canCatalogEntriesByType 16940 @param {String} type The type. e.g. "model", "controller", "route". 16941 @return {boolean} whether a list is available for this type. 16942 @public 16943 */ 16944 canCatalogEntriesByType: function (type) { 16945 if (type === 'model' || type === 'template') { 16946 return false; 16947 } 16948 16949 return true; 16950 }, 16951 16952 /** 16953 Returns the available classes a given type. 16954 @method catalogEntriesByType 16955 @param {String} type The type. e.g. "model", "controller", "route". 16956 @return {Array} An array of strings. 16957 @public 16958 */ 16959 catalogEntriesByType: function (type) { 16960 var namespaces = _emberRuntimeSystemNative_array.A(_emberRuntimeSystemNamespace.default.NAMESPACES); 16961 var types = _emberRuntimeSystemNative_array.A(); 16962 var typeSuffixRegex = new RegExp(_emberRuntimeSystemString.classify(type) + '$'); 16963 16964 namespaces.forEach(function (namespace) { 16965 if (namespace !== _emberMetalCore.default) { 16966 for (var key in namespace) { 16967 if (!namespace.hasOwnProperty(key)) { 16968 continue; 16969 } 16970 if (typeSuffixRegex.test(key)) { 16971 var klass = namespace[key]; 16972 if (_emberRuntimeUtils.typeOf(klass) === 'class') { 16973 types.push(_emberRuntimeSystemString.dasherize(key.replace(typeSuffixRegex, ''))); 16974 } 16975 } 16976 } 16977 } 16978 }); 16979 return types; 16980 } 16981 }); 16982}); 16983enifed('ember-extension-support/data_adapter', ['exports', 'ember-metal/property_get', 'ember-metal/run_loop', 'ember-runtime/system/string', 'ember-runtime/system/namespace', 'ember-runtime/system/object', 'ember-runtime/system/native_array', 'ember-application/system/application', 'container/owner', 'ember-runtime/mixins/array'], function (exports, _emberMetalProperty_get, _emberMetalRun_loop, _emberRuntimeSystemString, _emberRuntimeSystemNamespace, _emberRuntimeSystemObject, _emberRuntimeSystemNative_array, _emberApplicationSystemApplication, _containerOwner, _emberRuntimeMixinsArray) { 16984 'use strict'; 16985 16986 /** 16987 @module ember 16988 @submodule ember-extension-support 16989 */ 16990 16991 /** 16992 The `DataAdapter` helps a data persistence library 16993 interface with tools that debug Ember such 16994 as the [Ember Extension](https://github.com/tildeio/ember-extension) 16995 for Chrome and Firefox. 16996 16997 This class will be extended by a persistence library 16998 which will override some of the methods with 16999 library-specific code. 17000 17001 The methods likely to be overridden are: 17002 17003 * `getFilters` 17004 * `detect` 17005 * `columnsForType` 17006 * `getRecords` 17007 * `getRecordColumnValues` 17008 * `getRecordKeywords` 17009 * `getRecordFilterValues` 17010 * `getRecordColor` 17011 * `observeRecord` 17012 17013 The adapter will need to be registered 17014 in the application's container as `dataAdapter:main`. 17015 17016 Example: 17017 17018 ```javascript 17019 Application.initializer({ 17020 name: "data-adapter", 17021 17022 initialize: function(application) { 17023 application.register('data-adapter:main', DS.DataAdapter); 17024 } 17025 }); 17026 ``` 17027 17028 @class DataAdapter 17029 @namespace Ember 17030 @extends EmberObject 17031 @public 17032 */ 17033 exports.default = _emberRuntimeSystemObject.default.extend({ 17034 init: function () { 17035 this._super.apply(this, arguments); 17036 this.releaseMethods = _emberRuntimeSystemNative_array.A(); 17037 }, 17038 17039 /** 17040 The container-debug-adapter which is used 17041 to list all models. 17042 @property containerDebugAdapter 17043 @default undefined 17044 @since 1.5.0 17045 @public 17046 **/ 17047 containerDebugAdapter: undefined, 17048 17049 /** 17050 The number of attributes to send 17051 as columns. (Enough to make the record 17052 identifiable). 17053 @private 17054 @property attributeLimit 17055 @default 3 17056 @since 1.3.0 17057 */ 17058 attributeLimit: 3, 17059 17060 /** 17061 Ember Data >
17061 v1.0.0-beta.18 17062 requires string model names to be passed 17063 around instead of the actual factories. 17064 This is a stamp for the Ember Inspector 17065 to differentiate between the versions 17066 to be able to support older versions too. 17067 @public 17068 @property acceptsModelName 17069 */ 17070 acceptsModelName: true, 17071 17072 /** 17073 Stores all methods that clear observers. 17074 These methods will be called on destruction. 17075 @private 17076 @property releaseMethods 17077 @since 1.3.0 17078 */ 17079 releaseMethods: _emberRuntimeSystemNative_array.A(), 17080 17081 /** 17082 Specifies how records can be filtered. 17083 Records returned will need to have a `filterValues` 17084 property with a key for every name in the returned array. 17085 @public 17086 @method getFilters 17087 @return {Array} List of objects defining filters. 17088 The object should have a `name` and `desc` property. 17089 */ 17090 getFilters: function () { 17091 return _emberRuntimeSystemNative_array.A(); 17092 }, 17093 17094 /** 17095 Fetch the model types and observe them for changes. 17096 @public 17097 @method watchModelTypes 17098 @param {Function} typesAdded Callback to call to add types. 17099 Takes an array of objects containing wrapped types (returned from `wrapModelType`). 17100 @param {Function} typesUpdated Callback to call when a type has changed. 17101 Takes an array of objects containing wrapped types. 17102 @return {Function} Method to call to remove all observers 17103 */ 17104 watchModelTypes: function (typesAdded, typesUpdated) { 17105 var _this = this; 17106 17107 var modelTypes = this.getModelTypes(); 17108 var releaseMethods = _emberRuntimeSystemNative_array.A(); 17109 var typesToSend; 17110 17111 typesToSend = modelTypes.map(function (type) { 17112 var klass = type.klass; 17113 var wrapped = _this.wrapModelType(klass, type.name); 17114 releaseMethods.push(_this.observeModelType(type.name, typesUpdated)); 17115 return wrapped; 17116 }); 17117 17118 typesAdded(typesToSend); 17119 17120 var release = function () { 17121 releaseMethods.forEach(function (fn) { 17122 return fn(); 17123 }); 17124 _this.releaseMethods.removeObject(release); 17125 }; 17126 this.releaseMethods.pushObject(release); 17127 return release; 17128 }, 17129 17130 _nameToClass: function (type) { 17131 if (typeof type === 'string') { 17132 type = _containerOwner.getOwner(this)._lookupFactory('model:' + type); 17133 } 17134 return type; 17135 }, 17136 17137 /** 17138 Fetch the records of a given type and observe them for changes. 17139 @public 17140 @method watchRecords 17141 @param {String} modelName The model name. 17142 @param {Function} recordsAdded Callback to call to add records. 17143 Takes an array of objects containing wrapped records. 17144 The object should have the following properties: 17145 columnValues: {Object} The key and value of a table cell. 17146 object: {Object} The actual record object. 17147 @param {Function} recordsUpdated Callback to call when a record has changed. 17148 Takes an array of objects containing wrapped records. 17149 @param {Function} recordsRemoved Callback to call when a record has removed. 17150 Takes the following parameters: 17151 index: The array index where the records were removed. 17152 count: The number of records removed. 17153 @return {Function} Method to call to remove all observers. 17154 */ 17155 watchRecords: function (modelName, recordsAdded, recordsUpdated, recordsRemoved) { 17156 var _this2 = this; 17157 17158 var releaseMethods = _emberRuntimeSystemNative_array.A(); 17159 var klass = this._nameToClass(modelName); 17160 var records = this.getRecords(klass, modelName); 17161 var release; 17162 17163 var recordUpdated = function (updatedRecord) { 17164 recordsUpdated([updatedRecord]); 17165 }; 17166 17167 var recordsToSend = records.map(function (record) { 17168 releaseMethods.push(_this2.observeRecord(record, recordUpdated)); 17169 return _this2.wrapRecord(record); 17170 }); 17171 17172 var contentDidChange = function (array, idx, removedCount, addedCount) { 17173 for (var i = idx; i < idx + addedCount; i++) { 17174 var record = _emberRuntimeMixinsArray.objectAt(array, i); 17175 var wrapped = _this2.wrapRecord(record); 17176 releaseMethods.push(_this2.observeRecord(record, recordUpdated)); 17177 recordsAdded([wrapped]); 17178 } 17179 17180 if (removedCount) { 17181 recordsRemoved(idx, removedCount); 17182 } 17183 }; 17184 17185 var observer = { didChange: contentDidChange, willChange: function () { 17186 return this; 17187 } }; 17188 _emberRuntimeMixinsArray.addArrayObserver(records, this, observer); 17189 17190 release = function () { 17191 releaseMethods.forEach(function (fn) { 17192 fn(); 17193 }); 17194 _emberRuntimeMixinsArray.removeArrayObserver(records, _this2, observer); 17195 _this2.releaseMethods.removeObject(release); 17196 }; 17197 17198 recordsAdded(recordsToSend); 17199 17200 this.releaseMethods.pushObject(release); 17201 return release; 17202 }, 17203 17204 /** 17205 Clear all observers before destruction 17206 @private 17207 @method willDestroy 17208 */ 17209 willDestroy: function () { 17210 this._super.apply(this, arguments); 17211 this.releaseMethods.forEach(function (fn) { 17212 fn(); 17213 }); 17214 }, 17215 17216 /** 17217 Detect whether a class is a model. 17218 Test that against the model class 17219 of your persistence library. 17220 @private 17221 @method detect 17222 @param {Class} klass The class to test. 17223 @return boolean Whether the class is a model class or not. 17224 */ 17225 detect: function (klass) { 17226 return false;
17227 }, 17228 17229 /** 17230 Get the columns for a given model type. 17231 @private 17232 @method columnsForType 17233 @param {Class} type The model type. 17234 @return {Array} An array of columns of the following format: 17235 name: {String} The name of the column. 17236 desc: {String} Humanized description (what would show in a table column name). 17237 */ 17238 columnsForType: function (type) { 17239 return _emberRuntimeSystemNative_array.A(); 17240 }, 17241 17242 /** 17243 Adds observers to a model type class. 17244 @private 17245 @method observeModelType 17246 @param {String} modelName The model type name. 17247 @param {Function} typesUpdated Called when a type is modified. 17248 @return {Function} The function to call to remove observers. 17249 */ 17250 17251 observeModelType: function (modelName, typesUpdated) { 17252 var _this3 = this; 17253 17254 var klass = this._nameToClass(modelName); 17255 var records = this.getRecords(klass, modelName); 17256 17257 var onChange = function () { 17258 typesUpdated([_this3.wrapModelType(klass, modelName)]); 17259 }; 17260 var observer = { 17261 didChange: function () { 17262 _emberMetalRun_loop.default.scheduleOnce('actions', this, onChange); 17263 }, 17264 willChange: function () { 17265 return this; 17266 } 17267 }; 17268 17269 _emberRuntimeMixinsArray.addArrayObserver(records, this, observer); 17270 17271 var release = function () { 17272 _emberRuntimeMixinsArray.removeArrayObserver(records, _this3, observer); 17273 }; 17274 17275 return release; 17276 }, 17277 17278 /** 17279 Wraps a given model type and observes changes to it. 17280 @private 17281 @method wrapModelType 17282 @param {Class} klass A model class. 17283 @param {String} modelName Name of the class. 17284 @return {Object} Contains the wrapped type and the function to remove observers 17285 Format: 17286 type: {Object} The wrapped type. 17287 The wrapped type has the following format: 17288 name: {String} The name of the type. 17289 count: {Integer} The number of records available. 17290 columns: {Columns} An array of columns to describe the record. 17291 object: {Class} The actual Model type class. 17292 release: {Function} The function to remove observers. 17293 */ 17294 wrapModelType: function (klass, name) { 17295 var records = this.getRecords(klass, name); 17296 var typeToSend; 17297 17298 typeToSend = { 17299 name: name, 17300 count: _emberMetalProperty_get.get(records, 'length'), 17301 columns: this.columnsForType(klass), 17302 object: klass 17303 }; 17304 17305 return typeToSend; 17306 }, 17307 17308 /** 17309 Fetches all models defined in the application. 17310 @private 17311 @method getModelTypes 17312 @return {Array} Array of model types. 17313 */ 17314 getModelTypes: function () { 17315 var _this4 = this; 17316 17317 var containerDebugAdapter = this.get('containerDebugAdapter'); 17318 var types; 17319 17320 if (containerDebugAdapter.canCatalogEntriesByType('model')) { 17321 types = containerDebugAdapter.catalogEntriesByType('model'); 17322 } else { 17323 types = this._getObjectsOnNamespaces(); 17324 } 17325 17326 // New adapters return strings instead of classes. 17327 types = _emberRuntimeSystemNative_array.A(types).map(function (name) { 17328 return { 17329 klass: _this4._nameToClass(name), 17330 name: name 17331 }; 17332 }); 17333 types = _emberRuntimeSystemNative_array.A(types).filter(function (type) { 17334 return _this4.detect(type.klass); 17335 }); 17336 17337 return _emberRuntimeSystemNative_array.A(types); 17338 }, 17339 17340 /** 17341 Loops over all namespaces and all objects 17342 attached to them. 17343 @private 17344 @method _getObjectsOnNamespaces 17345 @return {Array} Array of model type strings. 17346 */ 17347 _getObjectsOnNamespaces: function () { 17348 var _this5 = this; 17349 17350 var namespaces = _emberRuntimeSystemNative_array.A(_emberRuntimeSystemNamespace.default.NAMESPACES); 17351 var types = _emberRuntimeSystemNative_array.A(); 17352 17353 namespaces.forEach(function (namespace) { 17354 for (var key in namespace) { 17355 if (!namespace.hasOwnProperty(key)) { 17356 continue; 17357 } 17358 // Even though we will filter again in `getModelTypes`, 17359 // we should not call `lookupFactory` on non-models 17360 // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) 17361 if (!_this5.detect(namespace[key])) { 17362 continue; 17363 } 17364 var name = _emberRuntimeSystemString.dasherize(key); 17365 if (!(namespace instanceof _emberApplicationSystemApplication.default) && namespace.toString()) { 17366 name = namespace + '/' + name; 17367 } 17368 types.push(name); 17369 } 17370 }); 17371 return types; 17372 }, 17373 17374 /** 17375 Fetches all loaded records for a given type. 17376 @private 17377 @method getRecords 17378 @return {Array} An array of records. 17379 This array will be observed for changes, 17380 so it should update when new records are added/removed. 17381 */ 17382 getRecords: function (type) { 17383 return _emberRuntimeSystemNative_array.A(); 17384 }, 17385 17386 /** 17387 Wraps a record and observers changes to it. 17388 @private 17389 @method wrapRecord 17390 @param {Object}
17390 record The record instance. 17391 @return {Object} The wrapped record. Format: 17392 columnValues: {Array} 17393 searchKeywords: {Array} 17394 */ 17395 wrapRecord: function (record) { 17396 var recordToSend = { object: record }; 17397 17398 recordToSend.columnValues = this.getRecordColumnValues(record); 17399 recordToSend.searchKeywords = this.getRecordKeywords(record); 17400 recordToSend.filterValues = this.getRecordFilterValues(record); 17401 recordToSend.color = this.getRecordColor(record); 17402 17403 return recordToSend; 17404 }, 17405 17406 /** 17407 Gets the values for each column. 17408 @private 17409 @method getRecordColumnValues 17410 @return {Object} Keys should match column names defined 17411 by the model type. 17412 */ 17413 getRecordColumnValues: function (record) { 17414 return {}; 17415 }, 17416 17417 /** 17418 Returns keywords to match when searching records. 17419 @private 17420 @method getRecordKeywords 17421 @return {Array} Relevant keywords for search. 17422 */ 17423 getRecordKeywords: function (record) { 17424 return _emberRuntimeSystemNative_array.A(); 17425 }, 17426 17427 /** 17428 Returns the values of filters defined by `getFilters`. 17429 @private 17430 @method getRecordFilterValues 17431 @param {Object} record The record instance. 17432 @return {Object} The filter values. 17433 */ 17434 getRecordFilterValues: function (record) { 17435 return {}; 17436 }, 17437 17438 /** 17439 Each record can have a color that represents its state. 17440 @private 17441 @method getRecordColor 17442 @param {Object} record The record instance 17443 @return {String} The records color. 17444 Possible options: black, red, blue, green. 17445 */ 17446 getRecordColor: function (record) { 17447 return null; 17448 }, 17449 17450 /** 17451 Observes all relevant properties and re-sends the wrapped record 17452 when a change occurs. 17453 @private 17454 @method observerRecord 17455 @param {Object} record The record instance. 17456 @param {Function} recordUpdated The callback to call when a record is updated. 17457 @return {Function} The function to call to remove all observers. 17458 */ 17459 observeRecord: function (record, recordUpdated) { 17460 return function () {}; 17461 } 17462 }); 17463}); 17464enifed('ember-extension-support/index', ['exports', 'ember-metal/core', 'ember-extension-support/data_adapter', 'ember-extension-support/container_debug_adapter'], function (exports, _emberMetalCore, _emberExtensionSupportData_adapter, _emberExtensionSupportContainer_debug_adapter) { 17465 /** 17466 @module ember 17467 @submodule ember-extension-support 17468 */ 17469 17470 'use strict'; 17471 17472 _emberMetalCore.default.DataAdapter = _emberExtensionSupportData_adapter.default; 17473 _emberMetalCore.default.ContainerDebugAdapter = _emberExtensionSupportContainer_debug_adapter.default; 17474}); 17475enifed('ember-htmlbars/compat', ['exports', 'ember-metal/core', 'ember-htmlbars/utils/string'], function (exports, _emberMetalCore, _emberHtmlbarsUtilsString) { 17476 'use strict'; 17477 17478 var EmberHandlebars = _emberMetalCore.default.Handlebars = _emberMetalCore.default.Handlebars || {}; 17479 17480 EmberHandlebars.SafeString = _emberHtmlbarsUtilsString.SafeString; 17481 EmberHandlebars.Utils = { 17482 escapeExpression: _emberHtmlbarsUtilsString.escapeExpression 17483 }; 17484 17485 exports.default = EmberHandlebars; 17486}); 17487enifed('ember-htmlbars/env', ['exports', 'ember-metal', 'ember-metal/environment', 'htmlbars-runtime', 'ember-metal/assign', 'ember-htmlbars/hooks/subexpr', 'ember-htmlbars/hooks/concat', 'ember-htmlbars/hooks/link-render-node', 'ember-htmlbars/hooks/create-fresh-scope', 'ember-htmlbars/hooks/bind-shadow-scope', 'ember-htmlbars/hooks/bind-self', 'ember-htmlbars/hooks/bind-scope', 'ember-htmlbars/hooks/bind-local', 'ember-htmlbars/hooks/bind-block', 'ember-htmlbars/hooks/update-self', 'ember-htmlbars/hooks/get-root', 'ember-htmlbars/hooks/get-child', 'ember-htmlbars/hooks/get-block', 'ember-htmlbars/hooks/get-value', 'ember-htmlbars/hooks/get-cell-or-value', 'ember-htmlbars/hooks/cleanup-render-node', 'ember-htmlbars/hooks/destroy-render-node', 'ember-htmlbars/hooks/did-render-node', 'ember-htmlbars/hooks/will-cleanup-tree', 'ember-htmlbars/hooks/did-cleanup-tree', 'ember-htmlbars/hooks/classify', 'ember-htmlbars/hooks/component', 'ember-htmlbars/hooks/lookup-helper', 'ember-htmlbars/hooks/has-helper', 'ember-htmlbars/hooks/invoke-helper', 'ember-htmlbars/hooks/element', 'ember-htmlbars/helpers', 'ember-htmlbars/keywords', 'ember-htmlbars/system/dom-helper', 'ember-htmlbars/keywords/debugger', 'ember-htmlbars/keywords/with', 'ember-htmlbars/keywords/outlet', 'ember-htmlbars/keywords/unbound', 'ember-htmlbars/keywords/view', 'ember-htmlbars/keywords/component', 'ember-htmlbars/keywords/element-component', 'ember-htmlbars/keywords/partial', 'ember-htmlbars/keywords/input', 'ember-htmlbars/keywords/textarea', 'ember-htmlbars/keywords/collection', 'ember-htmlbars/keywords/yield', 'ember-htmlbars/keywords/legacy-yield', 'ember-htmlbars/keywords/mut', 'ember-htmlbars/keywords/each', 'ember-htmlbars/keywords/readonly', 'ember-htmlbars/keywords/get'], function (exports, _emberMetal, _emberMetalEnvironment, _htmlbarsRuntime, _emberMetalAssign, _emberHtmlbarsHooksSubexpr, _emberHtmlbarsHooksConcat, _emberHtmlbarsHooksLinkRenderNode, _emberHtmlbarsHooksCreateFreshScope, _emberHtmlbarsHooksBindShadowScope, _emberHtmlbarsHooksBindSelf, _emberHtmlbarsHooksBindScope, _emberHtmlbarsHooksBindLocal, _emberHtmlbarsHooksBindBlock, _emberHtmlbarsHooksUpdateSelf, _emberHtmlbarsHooksGetRoot, _emberHtmlbarsHooksGetChild, _emberHtmlbarsHooksGetBlock, _emberHtmlbarsHooksGetValue, _emberHtmlbarsHooksGetCellOrValue, _emberHtmlbarsHooksCleanupRenderNode, _emberHtmlbarsHooksDestroyRenderNode, _emberHtmlbarsHooksDidRenderNode, _emberHtmlbarsHooksWillCleanupTree, _emberHtmlbarsHooksDidCleanupTree, _emberHtmlbarsHooksClassify, _emberHtmlbarsHooksComponent, _emberHtmlbarsHooksLookupHelper, _emberHtmlbarsHooksHasHelper, _emberHtmlbarsHooksInvokeHelper, _emberHtmlbarsHooksElement, _emberHtmlbarsHelpers, _emberHtmlbarsKeywords, _emberHtmlbarsSystemDomHelper, _emberHtmlbarsKeywordsDebugger, _emberHtmlbarsKeywordsWith, _emberHtmlbarsKeywordsOutlet, _emberHtmlbarsKeywordsUnbound, _emberHtmlbarsKeywordsView, _emberHtmlbarsKeywordsComponent, _emberHtmlbarsKeywordsElementComponent, _emberHtmlbarsKeywordsPartial, _emberHtmlbarsKeywordsInput, _emberHtmlbarsKeywordsTextarea, _emberHtmlbarsKeywordsCollection, _emberHtmlbarsKeywordsYield, _emberHtmlbarsKeywordsLegacyYield, _emberHtmlbarsKeywordsMut, _emberHtmlbarsKeywordsEach, _emberHtmlbarsKeywordsReadonly, _emberHtmlbarsKeywordsGet) { 17488 'use strict'; 17489 17490 var emberHooks = _emberMetalAssign.default({}, _htmlbarsRuntime.hooks); 17491 emberHooks.keywords = _emberHtmlbarsKeywords.default; 17492 17493 _emberMetalAssign.default(emberHooks, { 17494 linkRenderNode: _emberHtmlbarsHooksLinkRenderNode.default, 17495 createFreshScope: _emberHtmlbarsHooksCreateFreshScope.default, 17496 createChildScope: _emberHtmlbarsHooksCreateFreshScope.createChildScope, 17497 bindShadowScope: _emberHtmlbarsHooksBindShadowScope.default, 17498 bindSelf: _emberHtmlbarsHooksBindSelf.default, 17499 bindScope: _emberHtmlbarsHooksBindScope.default, 17500 bindLocal: _emberHtmlbarsHooksBindLocal.default, 17501 bindBlock: _emberHtmlbarsHooksBindBlock.default, 17502 updateSelf: _emberHtmlbarsHooksUpdateSelf.default, 17503 getBlock: _emberHtmlbarsHooksGetBlock.default, 17504 getRoot: _emberHtmlbarsHooksGetRoot.default, 17505 getChild: _emberHtmlbarsHooksGetChild.default, 17506 getValue: _emberHtmlbarsHooksGetValue.default, 17507 getCellOrValue: _emberHtmlbarsHooksGetCellOrValue.default, 17508 subexpr: _emberHtmlbarsHooksSubexpr.default, 17509 concat: _emberHtmlbarsHooksConcat.default, 17510 cleanupRenderNode: _emberHtmlbarsHooksCleanupRenderNode.default, 17511 destroyRenderNode: _emberHtmlbarsHooksDestroyRenderNode.default, 17512 willCleanupTree: _emberHtmlbarsHooksWillCleanupTree.default, 17513 didCleanupTree: _emberHtmlbarsHooksDidCleanupTree.default, 17514 didRenderNode: _emberHtmlbarsHooksDidRenderNode.default, 17515 classify: _emberHtmlbarsHooksClassify.default, 17516 component: _emberHtmlbarsHooksComponent.default, 17517 lookupHelper: _emberHtmlbarsHooksLookupHelper.default, 17518 hasHelper: _emberHtmlbarsHooksHasHelper.default, 17519 invokeHelper: _emberHtmlbarsHooksInvokeHelper.default, 17520 element: _emberHtmlbarsHooksElement.default 17521 }); 17522 17523 _emberHtmlbarsKeywords.registerKeyword('debugger', _emberHtmlbarsKeywordsDebugger.default); 17524 _emberHtmlbarsKeywords.registerKeyword('with', _emberHtmlbarsKeywordsWith.default); 17525 _emberHtmlbarsKeywords.registerKeyword('outlet', _emberHtmlbarsKeywordsOutlet.default); 17526 _emberHtmlbarsKeywords.registerKeyword('unbound', _emberHtmlbarsKeywordsUnbound.default); 17527 _emberHtmlbarsKeywords.registerKeyword('component', _emberHtmlbarsKeywordsComponent.default);
17528 _emberHtmlbarsKeywords.registerKeyword('@element_component', _emberHtmlbarsKeywordsElementComponent.default); 17529 _emberHtmlbarsKeywords.registerKeyword('partial', _emberHtmlbarsKeywordsPartial.default); 17530 _emberHtmlbarsKeywords.registerKeyword('input', _emberHtmlbarsKeywordsInput.default); 17531 _emberHtmlbarsKeywords.registerKeyword('textarea', _emberHtmlbarsKeywordsTextarea.default); 17532 _emberHtmlbarsKeywords.registerKeyword('yield', _emberHtmlbarsKeywordsYield.default); 17533 _emberHtmlbarsKeywords.registerKeyword('legacy-yield', _emberHtmlbarsKeywordsLegacyYield.default); 17534 _emberHtmlbarsKeywords.registerKeyword('mut', _emberHtmlbarsKeywordsMut.default); 17535 _emberHtmlbarsKeywords.registerKeyword('@mut', _emberHtmlbarsKeywordsMut.privateMut); 17536 _emberHtmlbarsKeywords.registerKeyword('each', _emberHtmlbarsKeywordsEach.default); 17537 _emberHtmlbarsKeywords.registerKeyword('readonly', _emberHtmlbarsKeywordsReadonly.default); 17538 _emberHtmlbarsKeywords.registerKeyword('get', _emberHtmlbarsKeywordsGet.default); 17539 17540 if (_emberMetal.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 17541 _emberHtmlbarsKeywords.registerKeyword('collection', _emberHtmlbarsKeywordsCollection.default); 17542 _emberHtmlbarsKeywords.registerKeyword('view', _emberHtmlbarsKeywordsView.default); 17543 } 17544 17545 exports.default = { 17546 hooks: emberHooks, 17547 helpers: _emberHtmlbarsHelpers.default, 17548 useFragmentCache: true 17549 }; 17550 17551 var domHelper = _emberMetalEnvironment.default.hasDOM ? new _emberHtmlbarsSystemDomHelper.default() : null; 17552 17553 exports.domHelper = domHelper; 17554}); 17555enifed('ember-htmlbars/glimmer-component', ['exports', 'ember-views/views/core_view', 'ember-views/mixins/view_child_views_support', 'ember-views/mixins/view_state_support', 'ember-views/mixins/template_rendering_support', 'ember-views/mixins/class_names_support', 'ember-views/mixins/instrumentation_support', 'ember-views/mixins/aria_role_support', 'ember-views/mixins/view_support', 'ember-views/views/view'], function (exports, _emberViewsViewsCore_view, _emberViewsMixinsView_child_views_support, _emberViewsMixinsView_state_support, _emberViewsMixinsTemplate_rendering_support, _emberViewsMixinsClass_names_support, _emberViewsMixinsInstrumentation_support, _emberViewsMixinsAria_role_support, _emberViewsMixinsView_support, _emberViewsViewsView) { 17556 'use strict'; 17557 17558 exports.default = _emberViewsViewsCore_view.default.extend(_emberViewsMixinsView_child_views_support.default, _emberViewsMixinsView_state_support.default, _emberViewsMixinsTemplate_rendering_support.default, _emberViewsMixinsClass_names_support.default, _emberViewsMixinsInstrumentation_support.default, _emberViewsMixinsAria_role_support.default, _emberViewsMixinsView_support.default, { 17559 isComponent: true, 17560 isGlimmerComponent: true, 17561 17562 init: function () { 17563 this._super.apply(this, arguments); 17564 this._viewRegistry = this._viewRegistry || _emberViewsViewsView.default.views; 17565 } 17566 }); 17567}); 17568enifed('ember-htmlbars/helper', ['exports', 'ember-runtime/system/object'], function (exports, _emberRuntimeSystemObject) { 17569 /** 17570 @module ember 17571 @submodule ember-templates 17572 */ 17573 17574 'use strict'; 17575 17576 exports.helper = helper; 17577 17578 /** 17579 Ember Helpers are functions that can compute values, and are used in templates. 17580 For example, this code calls a helper named `format-currency`: 17581 17582 ```handlebars 17583 <div>{{format-currency cents currency="$"}}</div> 17584 ``` 17585 17586 Additionally, a helper can be called as a nested helper (sometimes called a 17587 subexpression). In this example, the computed value of a helper is passed 17588 to a component named `show-money`: 17589 17590 ```handlebars 17591 {{show-money amount=(format-currency cents currency="$")}} 17592 ``` 17593 17594 Helpers defined using a class must provide a `compute` function. For example: 17595 17596 ```js 17597 export default Ember.Helper.extend({ 17598 compute(params, hash) { 17599 let cents = params[0]; 17600 let currency = hash.currency; 17601 return `${currency}${cents * 0.01}`; 17602 } 17603 }); 17604 ``` 17605 17606 Each time the input to a helper changes, the `compute` function will be 17607 called again. 17608 17609 As instances, these helpers also have access to the container and will accept 17610 injected dependencies. 17611 17612 Additionally, class helpers can call `recompute` to force a new computation. 17613 17614 @class Ember.Helper 17615 @public 17616 @since 1.13.0 17617 */ 17618 var Helper = _emberRuntimeSystemObject.default.extend({ 17619 isHelperInstance: true, 17620 17621 /** 17622 On a class-based helper, it may be useful to force a recomputation of that 17623 helpers value. This is akin to `rerender` on a component. 17624 For example, this component will rerender when the `currentUser` on a 17625 session service changes: 17626 ```js 17627
17627// app/helpers/current-user-email.js 17628 export default Ember.Helper.extend({ 17629 session: Ember.inject.service(), 17630 onNewUser: Ember.observer('session.currentUser', function() { 17631 this.recompute(); 17632 }), 17633 compute() { 17634 return this.get('session.currentUser.email'); 17635 } 17636 }); 17637 ``` 17638 @method recompute 17639 @public 17640 @since 1.13.0 17641 */ 17642 recompute: function () { 17643 this._stream.notify(); 17644 } 17645 17646 /** 17647 Override this function when writing a class-based helper. 17648 @method compute 17649 @param {Array} params The positional arguments to the helper 17650 @param {Object} hash The named arguments to the helper 17651 @public 17652 @since 1.13.0 17653 */ 17654 }); 17655 17656 Helper.reopenClass({ 17657 isHelperFactory: true 17658 }); 17659 17660 /** 17661 In many cases, the ceremony of a full `Ember.Helper` class is not required. 17662 The `helper` method creates pure-function helpers without instances. For 17663 example: 17664 17665 ```js 17666
17666// app/helpers/format-currency.js 17667 export default Ember.Helper.helper(function(params, hash) { 17668 let cents = params[0]; 17669 let currency = hash.currency; 17670 return `${currency}${cents * 0.01}`; 17671 }); 17672 ``` 17673 17674 @static 17675 @param {Function} helper The helper function 17676 @method helper 17677 @public 17678 @since 1.13.0 17679 */ 17680 17681 function helper(helperFn) { 17682 return { 17683 isHelperInstance: true, 17684 compute: helperFn 17685 }; 17686 } 17687 17688 exports.default = Helper; 17689}); 17690enifed('ember-htmlbars/helpers/-html-safe', ['exports', 'htmlbars-util/safe-string'], function (exports, _htmlbarsUtilSafeString) { 17691 'use strict'; 17692 17693 exports.default = htmlSafeHelper; 17694 17695 /** 17696 This private helper is used internally to handle `isVisible: false` for 17697 Ember.View and Ember.Component. 17698 17699 @private 17700 */ 17701 17702 function htmlSafeHelper(_ref) { 17703 var value = _ref[0]; 17704 17705 return new _htmlbarsUtilSafeString.default(value); 17706 } 17707}); 17708enifed('ember-htmlbars/helpers/-join-classes', ['exports'], function (exports) { 17709 /* 17710 This private helper is used to join and compact a list of class names. 17711 17712 @private 17713 */ 17714 17715 'use strict'; 17716
17717 exports.default = joinClasses; 17718 17719 function joinClasses(classNames) { 17720 var result = []; 17721 17722 for (var i = 0, l = classNames.length; i < l; i++) { 17723 var className = classNames[i]; 17724 17725 if (className) { 17726 result.push(className); 17727 } 17728 } 17729 17730 return result.join(' '); 17731 } 17732}); 17733enifed('ember-htmlbars/helpers/-legacy-each-with-controller', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-htmlbars/utils/normalize-self', 'ember-htmlbars/utils/decode-each-key'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberHtmlbarsUtilsNormalizeSelf, _emberHtmlbarsUtilsDecodeEachKey) { 17734 'use strict'; 17735 17736 exports.default = legacyEachWithControllerHelper; 17737 17738 function legacyEachWithControllerHelper(params, hash, blocks) { 17739 var list = params[0]; 17740 var keyPath = hash.key; 17741 17742 // TODO: Correct falsy semantics. 17743 if (!list || _emberMetalProperty_get.get(list, 'length') === 0) { 17744 if (blocks.inverse.yield) { 17745 blocks.inverse.yield(); 17746 } 17747 return; 17748 } 17749 17750 list.forEach(function (item, i) { 17751 var self; 17752 17753 if (blocks.template.arity === 0) { 17754 _emberMetalDebug.deprecate(deprecation, false, { id: 'ember-htmlbars.each-with-controller-helper', until: '2.4.0' }); 17755 self = _emberHtmlbarsUtilsNormalizeSelf.default(item);
17756 self = bindController(self, true); 17757 } 17758 17759 var key = _emberHtmlbarsUtilsDecodeEachKey.default(item, keyPath, i); 17760 blocks.template.yieldItem(key, [item, i], self); 17761 }); 17762 } 17763 17764 function bindController(controller, isSelf) { 17765 return { 17766 controller: controller, 17767 hasBoundController: true, 17768 self: controller ? controller : undefined 17769 }; 17770 } 17771 17772 var deprecation = 'Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each items as |item|}}`) instead.'; 17773 exports.deprecation = deprecation; 17774}); 17775enifed('ember-htmlbars/helpers/-legacy-each-with-keyword', ['exports', 'ember-views/streams/should_display', 'ember-htmlbars/utils/decode-each-key'], function (exports, _emberViewsStreamsShould_display, _emberHtmlbarsUtilsDecodeEachKey) { 17776 'use strict'; 17777 17778 exports.default = legacyEachWithKeywordHelper; 17779 17780 function legacyEachWithKeywordHelper(params, hash, blocks) { 17781 var list = params[0]; 17782 var keyPath = hash.key; 17783 var legacyKeyword = hash['-legacy-keyword']; 17784 17785 if (_emberViewsStreamsShould_display.default(list)) { 17786 list.forEach(function (item, i) { 17787 var self; 17788 if (legacyKeyword) {
17789 self = bindKeyword(self, legacyKeyword, item); 17790 } 17791 17792 var key = _emberHtmlbarsUtilsDecodeEachKey.default(item, keyPath, i); 17793 blocks.template.yieldItem(key, [item, i], self); 17794 }); 17795 } else if (blocks.inverse.yield) { 17796 blocks.inverse.yield(); 17797 } 17798 } 17799 17800 function bindKeyword(self, keyword, item) { 17801 var _ref; 17802 17803 return _ref = { 17804 self: self 17805 }, _ref[keyword] = item, _ref; 17806 } 17807 17808 var deprecation = 'Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each items as |item|}}`) instead.'; 17809 exports.deprecation = deprecation; 17810}); 17811enifed('ember-htmlbars/helpers/-normalize-class', ['exports', 'ember-runtime/system/string', 'ember-metal/path_cache'], function (exports, _emberRuntimeSystemString, _emberMetalPath_cache) { 17812 'use strict'; 17813 17814 exports.default = normalizeClass; 17815 17816 /* 17817 This private helper is used by ComponentNode to convert the classNameBindings 17818 microsyntax into a class name. 17819 17820 When a component or view is created, we normalize class name bindings into a 17821 series of attribute nodes that use this helper. 17822 17823 @private 17824 */ 17825 17826 function normalizeClass(params, hash) { 17827 var propName = params[0]; 17828 var value = params[1]; 17829 var activeClass = hash.activeClass; 17830 var inactiveClass = hash.inactiveClass; 17831 17832 // When using the colon syntax, evaluate the truthiness or falsiness 17833 // of the value to determine which className to return. 17834 if (activeClass || inactiveClass) { 17835 if (!!value) { 17836 return activeClass; 17837 } else { 17838 return inactiveClass; 17839 } 17840 17841 // If value is a Boolean and true, return the dasherized property 17842 // name. 17843 } else if (value === true) { 17844 // Only apply to last segment in the path. 17845 if (propName && _emberMetalPath_cache.isPath(propName)) { 17846 var segments = propName.split('.'); 17847 propName = segments[segments.length - 1]; 17848 } 17849 17850 return _emberRuntimeSystemString.dasherize(propName); 17851 17852 // If the value is not false, undefined, or null, return the current 17853 // value of the property. 17854 } else if (value !== false && value != null) { 17855 return value; 17856 17857 // Nothing to display. Return null so that the old class is removed 17858 // but no new class is added. 17859 } else { 17860 return null; 17861 } 17862 } 17863}); 17864enifed('ember-htmlbars/helpers/concat', ['exports'], function (exports) { 17865 /** 17866 @module ember 17867 @submodule ember-templates 17868 */ 17869 17870 /** 17871 Concatenates the given arguments into a string. 17872 17873 Example: 17874 17875 ```handlebars 17876 {{some-component name=(concat firstName " " lastName)}} 17877 17878 {{! would pass name="<first name value> <last name value>" to the component}} 17879 ``` 17880 17881 @public 17882 @method concat 17883 @for Ember.Templates.helpers 17884 @since 1.13.0 17885 */ 17886 'use strict'; 17887 17888 exports.default = concat; 17889 17890 function concat(args) { 17891 return args.join(''); 17892 } 17893}); 17894enifed('ember-htmlbars/helpers/each-in', ['exports', 'ember-views/streams/should_display'], function (exports, _emberViewsStreamsShould_display) { 17895 /** 17896 @module ember 17897 @submodule ember-templates 17898 */ 17899 17900 'use strict'; 17901 17902 /** 17903 The `{{each-in}}` helper loops over properties on an object. It is unbound, 17904 in that new (or removed) properties added to the target object will not be 17905 rendered. 17906 17907 For example, given a `user` object that looks like: 17908 17909 ```javascript 17910 { 17911 "name": "Shelly Sails", 17912 "age": 42 17913 } 17914 ``` 17915 17916 This template would display all properties on the `user` 17917 object in a list: 17918 17919 ```handlebars 17920 <ul> 17921 {{#each-in user as |key value|}} 17922 <li>{{key}}: {{value}}</li> 17923 {{/each-in}} 17924 </ul> 17925 ``` 17926 17927 Outputting their name and age. 17928 17929 @method each-in 17930 @for Ember.Templates.helpers 17931 @public 17932 @since 2.1.0 17933 */ 17934 var eachInHelper = function (_ref, hash, blocks) { 17935 var object = _ref[0]; 17936 17937 var objKeys, prop, i; 17938 objKeys = object ? Object.keys(object) : []; 17939 if (_emberViewsStreamsShould_display.default(objKeys)) { 17940 for (i = 0; i < objKeys.length; i++) { 17941 prop = objKeys[i]; 17942 blocks.template.yieldItem(prop, [prop, object[prop]]); 17943 } 17944 } else if (blocks.inverse.yield) { 17945 blocks.inverse.yield(); 17946 } 17947 }; 17948 17949 exports.default = eachInHelper; 17950}); 17951enifed('ember-htmlbars/helpers/each', ['exports', 'ember-views/streams/should_display', 'ember-htmlbars/utils/decode-each-key'], function (exports, _emberViewsStream
17951sShould_display, _emberHtmlbarsUtilsDecodeEachKey) { 17952 /** 17953 @module ember 17954 @submodule ember-templates 17955 */ 17956 17957 'use strict'; 17958 17959 exports.default = eachHelper; 17960 17961 /** 17962 The `{{#each}}` helper loops over elements in a collection. It is an extension 17963 of the base Handlebars `{{#each}}` helper. 17964 17965 The default behavior of `{{#each}}` is to yield its inner block once for every 17966 item in an array passing the item as the first block parameter. 17967 17968 ```javascript 17969 var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; 17970 ``` 17971 17972 ```handlebars 17973 {{#each developers key="name" as |person|}} 17974 {{person.name}} 17975 {{! `this` is whatever it was outside the #each }} 17976 {{/each}} 17977 ``` 17978 17979 The same rules apply to arrays of primitives. 17980 17981 ```javascript 17982 var developerNames = ['Yehuda', 'Tom', 'Paul'] 17983 ``` 17984 17985 ```handlebars 17986 {{#each developerNames key="@index" as |name|}} 17987 {{name}} 17988 {{/each}} 17989 ``` 17990 17991 During iteration, the index of each item in the array is provided as a second block parameter. 17992 17993 ```handlebars 17994 <ul> 17995 {{#each people as |person index|}} 17996 <li>Hello, {{person.name}}! You're number {{index}} in line</li> 17997 {{/each}} 17998 </ul> 17999 ``` 18000 18001 ### Specifying Keys 18002 18003 The `key` option is used to tell Ember how to determine if the array being 18004 iterated over with `{{#each}}` has changed between renders. By helping Ember 18005 detect that some elements in the array are the same, DOM elements can be 18006 re-used, significantly improving rendering speed. 18007 18008 For example, here's the `{{#each}}` helper with its `key` set to `id`: 18009 18010 ```handlebars 18011 {{#each model key="id" as |item|}} 18012 {{/each}} 18013 ``` 18014 18015 When this `{{#each}}` re-renders, Ember will match up the previously rendered 18016 items (and reorder the generated DOM elements) based on each item's `id` 18017 property. 18018 18019 By default the item's own reference is used. 18020 18021 ### {{else}} condition 18022 18023 `{{#each}}` can have a matching `{{else}}`. The contents of this block will render 18024 if the collection is empty. 18025 18026 ```handlebars 18027 {{#each developers as |person|}} 18028 {{person.name}} 18029 {{else}} 18030 <p>Sorry, nobody is available for this task.</p> 18031 {{/each}} 18032 ``` 18033 18034 @method each 18035 @for Ember.Templates.helpers 18036 @public 18037 */ 18038 18039 function eachHelper(params, hash, blocks) { 18040 var list = params[0]; 18041 var keyPath = hash.key; 18042 18043 if (_emberViewsStreamsShould_display.default(list)) { 18044 forEach(list, function (item, i) { 18045 var key = _emberHtmlbarsUtilsDecodeEachKey.default(item, keyPath, i); 18046 18047 blocks.template.yieldItem(key, [item, i]); 18048 }); 18049 } else if (blocks.inverse.yield) { 18050 blocks.inverse.yield(); 18051 } 18052 } 18053 18054 function forEach(iterable, cb) { 18055 return iterable.forEach ? iterable.forEach(cb) : Array.prototype.forEach.call(iterable, cb); 18056 } 18057}); 18058enifed("ember-htmlbars/helpers/hash", ["exports"], function (exports) { 18059 /** 18060 @module ember 18061 @submodule ember-templates 18062 */ 18063 18064 /** 18065 Use the `{{hash}}` helper to create a hash to pass as an option to your 18066 components. This is specially useful for contextual components where you can 18067 just yield a hash: 18068 18069 ```handlebars 18070 {{yield (hash 18071 name='Sarah' 18072 title=office 18073 )}} 18074 ``` 18075 18076 Would result in an object such as: 18077 18078 ```js 18079 { name: 'Sarah', title: this.get('office') } 18080 ``` 18081 18082 Where the `title` is bound to updates of the `office` property. 18083 18084 @method hash 18085 @for Ember.Templates.helpers 18086 @param {Object} options 18087 @return {Object} Hash 18088 @public 18089 */ 18090 18091 "use strict"; 18092 18093 exports.default = hashHelper; 18094 18095 function hashHelper(params, hash, options) { 18096 return hash; 18097 } 18098}); 18099enifed('ember-htmlbars/helpers/if_unless', ['exports', 'ember-metal/debug', 'ember-views/streams/should_display'], function (exports, _emberMetalDebug, _emberViewsStreamsShould_display) { 18100 /** 18101 @module ember 18102 @submodule ember-templates 18103 */ 18104 18105 'use strict'; 18106 18107 /** 18108 Use the `if` block helper to conditionally render a block depending on a 18109 property. If the property is "falsey", for example: `false`, `undefined`, 18110 `null`, `""`, `0`, `NaN` or an empty array, the block will not be rendered. 18111 18112 ```handlebars 18113 {{! will not render if foo is falsey}} 18114 {{#if foo}} 18115 Welcome to the {{foo.bar}} 18116 {{/if}} 18117 ``` 18118 18119 You can also specify a template to show if the property is falsey by using 18120 the `else` helper. 18121 18122 ```handlebars 18123 {{! is it raining outside?}} 18124 {{#if isRaining}} 18125 Yes, grab an umbrella! 18126 {{else}} 18127 No, it's lovely outside! 18128 {{/if}} 18129 ``` 18130 18131 You are also able to combine `else` and `if` helpers to create more complex 18132 conditional logic. 18133 18134 ```handlebars 18135 {{#if isMorning}} 18136 Good morning 18137 {{else if isAfternoon}} 18138 Good afternoon 18139 {{else}} 18140 Good night 18141 {{/if}} 18142 ``` 18143 18144 You can use `if` inline to conditionally render a single property or string. 18145 This helper acts like a ternary operator. If the first property is truthy, 18146 the second argument will be displayed, if not, the third argument will be 18147 displayed 18148 18149 ```handlebars 18150 {{if useLongGreeting "Hello" "Hi"}} Dave 18151 ``` 18152 18153 Finally, you can use the `if` helper inside another helper as a subexpression. 18154
18155 ```handlebars 18156 {{some-component height=(if isBig "100" "10")}} 18157 ``` 18158 18159 @method if 18160 @for Ember.Templates.helpers 18161 @public 18162 */ 18163 function ifHelper(params, hash, options) { 18164 return ifUnless(params, hash, options, _emberViewsStreamsShould_display.default(params[0])); 18165 } 18166 18167 /** 18168 The `unless` helper is the inverse of the `if` helper. Its block will be 18169 rendered if the expression contains a falsey value. All forms of the `if` 18170 helper can also be used with `unless`. 18171 18172 @method unless 18173 @for Ember.Templates.helpers 18174 @public 18175 */ 18176 function unlessHelper(params, hash, options) { 18177 return ifUnless(params, hash, options, !_emberViewsStreamsShould_display.default(params[0])); 18178 } 18179 18180 function ifUnless(params, hash, options, truthy) { 18181 _emberMetalDebug.assert('The block form of the `if` and `unless` helpers expect exactly one ' + 'argument, e.g. `{{#if newMessages}} You have new messages. {{/if}}.`', !options.template.yield || params.length === 1); 18182 18183 _emberMetalDebug.assert('The inline form of the `if` and `unless` helpers expect two or ' + 'three arguments, e.g. `{{if trialExpired \'Expired\' expiryDate}}` ' + 'or `{{unless isFirstLogin \'Welcome back!\'}}`.', !!options.template.yield || params.length === 2 || params.length === 3); 18184 18185 if (truthy) { 18186 if (options.template.yield) { 18187 options.template.yield(); 18188 } else { 18189 return params[1]; 18190 } 18191 } else { 18192 if (options.inverse.yield) { 18193 options.inverse.yield(); 18194 } else { 18195 return params[2]; 18196 } 18197 } 18198 } 18199 18200 exports.ifHelper = ifHelper; 18201 exports.unlessHelper = unlessHelper; 18202}); 18203enifed('ember-htmlbars/helpers/loc', ['exports', 'ember-runtime/system/string'], function (exports, _emberRuntimeSystemString) { 18204 'use strict'; 18205 18206 exports.default = locHelper; 18207 18208 /** 18209 @module ember 18210 @submodule ember-templates 18211 */ 18212 18213 /** 18214 Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the 18215 provided string. This is a convenient way to localize text within a template. 18216 For example: 18217 18218 ```javascript 18219 Ember.STRINGS = { 18220 '_welcome_': 'Bonjour' 18221 }; 18222 ``` 18223 18224 ```handlebars 18225 <div class='message'> 18226 {{loc '_welcome_'}} 18227 </div> 18228 ``` 18229 18230 ```html 18231 <div class='message'> 18232 Bonjour 18233 </div> 18234 ``` 18235 18236 See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to 18237 set up localized string references. 18238 18239 @method loc 18240 @for Ember.Templates.helpers 18241 @param {String} str The string to format. 18242 @see {Ember.String#loc} 18243 @public 18244 */ 18245 18246 function locHelper(params) { 18247 return _emberRuntimeSystemString.loc.apply(null, params); 18248 } 18249}); 18250enifed('ember-htmlbars/helpers/log', ['exports', 'ember-metal/logger'], function (exports, _emberMetalLogger) { 18251 /** 18252 @module ember 18253 @submodule ember-templates 18254 */ 18255 18256 'use strict'; 18257 18258 exports.default = logHelper; 18259 18260 /** 18261 `log` allows you to output the value of variables in the current rendering 18262 context. `log` also accepts primitive types such as strings or numbers. 18263 18264 ```handlebars 18265 {{log "myVariable:" myVariable }} 18266 ``` 18267 18268 @method log 18269 @for Ember.Templates.helpers 18270 @param {*} values 18271 @public 18272 */ 18273 18274 function logHelper(values) { 18275 _emberMetalLogger.default.log.apply(null, values); 18276 } 18277}); 18278enifed('ember-htmlbars/helpers/with', ['exports', 'ember-views/streams/should_display'], function (exports, _emberViewsStreamsShould_display) { 18279 /** 18280 @module ember 18281 @submodule ember-templates 18282 */ 18283 18284 'use strict'; 18285 18286 exports.default = withHelper; 18287 18288 /** 18289 Use the `{{with}}` helper when you want to alias a property to a new name. This is helpful 18290 for semantic clarity as it allows you to retain default scope or to reference a property from another 18291 `{{with}}` block. 18292 18293 If the aliased property is "falsey", for example: `false`, `undefined` `null`, `""`, `0`, NaN or 18294 an empty array, the block will not be rendered. 18295 18296 ```handlebars 18297 {{! Will only render if user.posts contains items}} 18298 {{#with user.posts as |blogPosts|}} 18299 <div class="notice"> 18300 There are {{blogPosts.length}}
18300 blog posts written by {{user.name}}. 18301 </div> 18302 {{#each blogPosts as |post|}} 18303 <li>{{post.title}}</li> 18304 {{/each}} 18305 {{/with}} 18306 ``` 18307 18308 Without the `as` operator, it would be impossible to reference `user.name` in the example above. 18309 18310 NOTE: The alias should not reuse a name from the bound property path. 18311 For example: `{{#with foo.bar as |foo|}}` is not supported because it attempts to alias using 18312 the first part of the property path, `foo`. Instead, use `{{#with foo.bar as |baz|}}`. 18313 18314 @method with 18315 @for Ember.Templates.helpers 18316 @param {Object} options 18317 @return {String} HTML string 18318 @public 18319 */ 18320 18321 function withHelper(params, hash, options) { 18322 if (_emberViewsStreamsShould_display.default(params[0])) { 18323 options.template.yield([params[0]]); 18324 } else if (options.inverse && options.inverse.yield) { 18325 options.inverse.yield([]); 18326 } 18327 } 18328}); 18329enifed('ember-htmlbars/helpers', ['exports', 'ember-metal/empty_object'], function (exports, _emberMetalEmpty_object) { 18330 /** 18331 @module ember 18332 @submodule ember-htmlbars 18333 */ 18334 18335 /** 18336 @private 18337 @property helpers 18338 */ 18339 'use strict'; 18340 18341 exports.registerHelper = registerHelper; 18342 18343 var helpers = new _emberMetalEmpty_object.default(); 18344 18345 /** 18346 @module ember 18347 @submodule ember-htmlbars 18348 */ 18349 18350 /** 18351 @private 18352 @method _registerHelper 18353 @for Ember.HTMLBars 18354 @param {String} name 18355 @param {Object|Function} helperFunc The helper function to add. 18356 */ 18357 18358 function registerHelper(name, helperFunc) { 18359 helpers[name] = helperFunc; 18360 } 18361 18362 exports.default = helpers; 18363}); 18364enifed('ember-htmlbars/hooks/bind-block', ['exports'], function (exports) { 18365 'use strict'; 18366 18367 exports.default = bindBlock; 18368 18369 function bindBlock(env, scope, block) { 18370 var name = arguments.length <= 3 || arguments[3] === undefined ? 'default' : arguments[3]; 18371 18372 scope.bindBlock(name, block); 18373 } 18374}); 18375enifed('ember-htmlbars/hooks/bind-local', ['exports', 'ember-metal/streams/stream', 'ember-metal/streams/proxy-stream'], function (exports, _emberMetalStreamsStream, _emberMetalStreamsProxyStream) { 18376 /** 18377 @module ember 18378 @submodule ember-htmlbars 18379 */ 18380 18381 'use strict'; 18382 18383 exports.default = bindLocal; 18384 18385 function bindLocal(env, scope, key, value) { 18386 // TODO: What is the cause of these cases? 18387 if (scope.hasOwnLocal(key)) { 18388 var existing = scope.getLocal(key); 18389 if (existing !== value) { 18390 existing.setSource(value); 18391 } 18392 } else { 18393 var newValue = _emberMetalStreamsStream.wrap(value, _emberMetalStreamsProxyStream.default, key); 18394 scope.bindLocal(key, newValue); 18395 } 18396 } 18397}); 18398enifed("ember-htmlbars/hooks/bind-scope", ["exports"], function (exports) { 18399 "use strict"; 18400 18401 exports.default = bindScope; 18402 18403 function bindScope(env, scope) {} 18404}); 18405enifed('ember-htmlbars/hooks/bind-self', ['exports', 'ember-metal', 'ember-metal/streams/proxy-stream'], function (exports, _emberMetal, _emberMetalStreamsProxyStream) { 18406 /** 18407 @module ember 18408 @submodule ember-htmlbars 18409 */ 18410 18411 'use strict'; 18412 18413 exports.default = bindSelf; 18414 18415 function bindSelf(env, scope, _self) { 18416 var self = _self; 18417 18418 if (self && self.hasBoundController) { 18419 var _self2 = self; 18420 var controller = _self2.controller; 18421 18422 self = self.self; 18423 18424 if (!!_emberMetal.default.ENV._ENABLE_LEGACY_CONTROLLER_SUPPORT) { 18425 scope.bindLocal('controller', newStream(controller || self)); 18426 } 18427 } 18428 18429 if (self && self.isView) { 18430 if (!!_emberMetal.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 18431 scope.bindLocal('view', newStream(self, 'view')); 18432 } 18433 18434 if (!!_emberMetal.default.ENV._ENABLE_LEGACY_CONTROLLER_SUPPORT) { 18435 scope.bindLocal('controller', newStream(self, '').getKey('controller')); 18436 } 18437 18438 var _selfStream = newStream(self, ''); 18439 18440 if (self.isGlimmerComponent) { 18441 scope.bindSelf(_selfStream); 18442 } else { 18443 scope.bindSelf(newStream(_selfStream.getKey('context'), '')); 18444 } 18445 18446 return; 18447 } 18448 18449 var selfStream = newStream(self, ''); 18450 scope.bindSelf(selfStream); 18451 18452 if (!!_emberMetal.default.ENV._ENABLE_LEGACY_CONTROLLER_SUPPORT) { 18453 if (!scope.hasLocal('controller')) { 18454 scope.bindLocal('controller', selfStream); 18455 } 18456 } 18457 } 18458 18459 function newStream(newValue, key) { 18460 return new _emberMetalStreamsProxyStream.default(newValue, key); 18461 } 18462}); 18463enifed('ember-htmlbars/hooks/bind-shadow-scope', ['exports', 'ember-metal/stream
18463s/proxy-stream'], function (exports, _emberMetalStreamsProxyStream) { 18464 /** 18465 @module ember 18466 @submodule ember-htmlbars 18467 */ 18468 18469 'use strict'; 18470 18471 exports.default = bindShadowScope; 18472 18473 function bindShadowScope(env, parentScope, shadowScope, options) { 18474 if (!options) { 18475 return; 18476 } 18477 18478 var didOverrideController = false; 18479 18480 if (parentScope && parentScope.overrideController) { 18481 didOverrideController = true; 18482 shadowScope.bindLocal('controller', parentScope.getLocal('controller')); 18483 } 18484 18485 var view = options.view; 18486 if (view && !view.isComponent) { 18487 shadowScope.bindLocal('view', newStream(view, 'view')); 18488 18489 if (!didOverrideController) { 18490 shadowScope.bindLocal('controller', newStream(shadowScope.getLocal('view').getKey('controller'))); 18491 } 18492 18493 if (view.isView) { 18494 shadowScope.bindSelf(newStream(shadowScope.getLocal('view').getKey('context'), '')); 18495 } 18496 } 18497 18498 shadowScope.bindView(view); 18499 18500 if (view && options.attrs) { 18501 shadowScope.bindComponent(view); 18502 } 18503 18504 if ('attrs' in options) { 18505 shadowScope.bindAttrs(options.attrs); 18506 } 18507 18508 return shadowScope; 18509 } 18510 18511 function newStream(newValue, key) { 18512 return new _emberMetalStreamsProxyStream.default(newValue, key); 18513 } 18514}); 18515enifed('ember-htmlbars/hooks/classify', ['exports', 'ember-htmlbars/utils/is-component'], function (exports, _emberHtmlbarsUtilsIsComponent) { 18516 /** 18517 @module ember 18518 @submodule ember-htmlbars 18519 */ 18520 18521 'use strict'; 18522 18523 exports.default = classify; 18524 18525 function classify(env, scope, path) { 18526 if (_emberHtmlbarsUtilsIsComponent.default(env, scope, path)) { 18527 return 'component'; 18528 } 18529 18530 return null; 18531 } 18532}); 18533enifed("ember-htmlbars/hooks/cleanup-render-node", ["exports"], function (exports) { 18534 /** 18535 @module ember 18536 @submodule ember-htmlbars 18537 */ 18538 18539 "use strict"; 18540 18541 exports.default = cleanupRenderNode; 18542 18543 function cleanupRenderNode(renderNode) { 18544 if (renderNode.cleanup) { 18545 renderNode.cleanup(); 18546 } 18547 } 18548}); 18549enifed('ember-htmlbars/hooks/component', ['exports', 'ember-metal/features', 'ember-metal/debug', 'ember-htmlbars/node-managers/component-node-manager', 'ember-views/system/build-component-template', 'ember-htmlbars/utils/lookup-component', 'ember-metal/assign', 'ember-metal/empty_object', 'ember-metal/cache', 'ember-htmlbars/system/lookup-helper', 'ember-htmlbars/keywords/closure-component'], function (exports, _emberMetalFeatures, _emberMetalDebug, _emberHtmlbarsNodeManagersComponentNodeManager, _emberViewsSystemBuildComponentTemplate, _emberHtmlbarsUtilsLookupComponent, _emberMetalAssign, _emberMetalEmpty_object, _emberMetalCache, _emberHtmlbarsSystemLookupHelper, _emberHtmlbarsKeywordsClosureComponent) { 18550 'use strict'; 18551 18552 exports.default = componentHook; 18553 18554 var IS_ANGLE_CACHE = new _emberMetalCache.default(1000, function (key) { 18555 return key.match(/^(@?)<(.*)>$/); 18556 }); 18557 18558 function componentHook(renderNode, env, scope, _tagName, params, attrs, templates, visitor) { 18559 var state = renderNode.getState(); 18560 18561 var tagName = _tagName; 18562 if (_emberHtmlbarsSystemLookupHelper.CONTAINS_DOT_CACHE.get(tagName)) { 18563 var stream = env.hooks.get(env, scope, tagName); 18564 var componentCell = stream.value(); 18565 if (_emberHtmlbarsKeywordsClosureComponent.isComponentCell(componentCell)) { 18566 tagName = componentCell[_emberHtmlbarsKeywordsClosureComponent.COMPONENT_PATH]; 18567 18568 /* 18569 * Processing positional params before merging into a hash must be done 18570 * here to avoid problems with rest positional parameters rendered using 18571 * the dot notation. 18572 * 18573 * Closure components (for the contextual component feature) do not 18574 * actually keep the positional params, but process them at each level. 18575 * Therefore, when rendering a closure component with the component 18576 * helper we process the parameters and attributes and then merge those 18577 * on top of the closure component attributes. 18578 * 18579 */ 18580 var newAttrs = _emberMetalAssign.default(new _emberMetalEmpty_object.default(), attrs); 18581 _emberHtmlbarsKeywordsClosureComponent.processPositionalParamsFromCell(componentCell, params, newAttrs); 18582 params = []; 18583 attrs = _emberHtmlbarsKeywordsClosureComponent.mergeInNewHash(componentCell[_emberHtmlbarsKeywordsClosureComponent.COMPONENT_HASH], newAttrs); 18584 } 18585 } 18586 18587 // Determine if this is an initial render or a re-render. 18588 if (state.manager) { 18589 state.manager.rerender(env, attrs, visitor); 18590 return; 18591 } 18592 18593 var isAngleBracket = false;
18594 var isTopLevel = false; 18595 var isDasherized = false; 18596 18597 var angles = IS_ANGLE_CACHE.get(tagName); 18598 18599 if (angles) { 18600 tagName = angles[2]; 18601 isAngleBracket = true; 18602 isTopLevel = !!angles[1]; 18603 } 18604 18605 if (_emberHtmlbarsSystemLookupHelper.CONTAINS_DASH_CACHE.get(tagName)) { 18606 isDasherized = true; 18607 } 18608 18609 var parentView = env.view; 18610 18611 // | Top-level | Invocation: <foo-bar> | Invocation: {{foo-bar}} | 18612 // ---------------------------------------------------------------------- 18613 // | <div> | <div> is component el | no special semantics (a) | 18614 // | <foo-bar> | <foo-bar> is identity el | EWTF | 18615 // | <bar-baz> | recursive invocation | no special semantics | 18616 // | {{anything}} | EWTF | no special semantics | 18617 // 18618 // (a) needs to be implemented specially, because the usual semantics of 18619 // <div> are defined by the compiled template, and we need to emulate 18620 // those semantics. 18621 18622 var currentComponent = env.view; 18623 var isInvokedWithAngles = currentComponent && currentComponent._isAngleBracket; 18624 var isInvokedWithCurlies = currentComponent && !currentComponent._isAngleBracket; 18625 18626 // <div> at the top level of a <foo-bar> invocation. 18627 var isComponentHTMLElement = isAngleBracket && !isDasherized && isInvokedWithAngles; 18628 18629 // <foo-bar> at the top level of a <foo-bar> invocation. 18630 var isComponentIdentityElement = isAngleBracket && isTopLevel && tagName === env.view.tagName; 18631 18632 // <div> at the top level of a {{foo-bar}} invocation. 18633 var isNormalHTMLElement = isAngleBracket && !isDasherized && isInvokedWithCurlies; 18634 18635 var component = undefined, 18636 layout = undefined; 18637 if (isDasherized || !isAngleBracket) { 18638 var options = {}; 18639 18640 var moduleName = env.meta && env.meta.moduleName; 18641 18642 if (moduleName) { 18643 options.source = 'template:' + moduleName; 18644 } 18645 18646 var result = _emberHtmlbarsUtilsLookupComponent.default(env.owner, tagName, options); 18647 18648 component = result.component; 18649 layout = result.layout; 18650 18651 if (isAngleBracket && isDasherized && !component && !layout) { 18652 isComponentHTMLElement = true; 18653 } else { 18654 _emberMetalDebug.assert('HTMLBars error: Could not find component named "' + tagName + '" (no component or template with that name was found)', !!(component || layout)); 18655 } 18656 } 18657 18658 if (isComponentIdentityElement || isComponentHTMLElement) { 18659 // Inside the layout for <foo-bar> invoked with angles, this is the top-level element 18660 // for the component. It can either be `<foo-bar>` (the "identity element") or any 18661 // normal HTML element (non-dasherized). 18662 var templateOptions = { 18663 component: currentComponent, 18664 tagName: tagName, 18665 isAngleBracket: true, 18666 isComponentElement: true, 18667 outerAttrs: scope.getAttrs(), 18668 parentScope: scope 18669 }; 18670 18671 var contentOptions = { templates: templates, scope: scope }; 18672 18673 var _buildComponentTemplate = _emberViewsSystemBuildComponentTemplate.default(templateOptions, attrs, contentOptions); 18674 18675 var block = _buildComponentTemplate.block; 18676 18677 block.invoke(env, [], undefined, renderNode, scope, visitor); 18678 } else if (isNormalHTMLElement) { 18679 var block = _emberViewsSystemBuildComponentTemplate.buildHTMLTemplate(tagName, attrs, { templates: templates, scope: scope }); 18680 block.invoke(env, [], undefined, renderNode, scope, visitor); 18681 } else { 18682 // Invoking a component from the outside (either via <foo-bar> angle brackets 18683 // or {{foo-bar}} legacy curlies). 18684 18685 var manager = _emberHtmlbarsNodeManagersComponentNodeManager.default.create(renderNode, env, { 18686 tagName: tagName, 18687 params: params, 18688 attrs: attrs, 18689 parentView: parentView, 18690 templates: templates, 18691 isAngleBracket: isAngleBracket, 18692 isTopLevel: isTopLevel, 18693 component: component, 18694 layout: layout, 18695 parentScope: scope 18696 }); 18697 18698 state.manager = manager; 18699 manager.render(env, visitor); 18700 } 18701 } 18702}); 18703enifed('ember-htmlbars/hooks/concat', ['exports', 'ember-metal/stream
18703s/utils'], function (exports, _emberMetalStreamsUtils) { 18704 /** 18705 @module ember 18706 @submodule ember-htmlbars 18707 */ 18708 18709 'use strict'; 18710 18711 exports.default = concat; 18712 18713 function concat(env, parts) { 18714 return _emberMetalStreamsUtils.concat(parts, ''); 18715 } 18716}); 18717enifed('ember-htmlbars/hooks/create-fresh-scope', ['exports', 'ember-metal/streams/proxy-stream', 'ember-metal/empty_object'], function (exports, _emberMetalStreamsProxyStream, _emberMetalEmpty_object) { 18718 'use strict'; 18719 18720 exports.default = createFreshScope; 18721 exports.createChildScope = createChildScope; 18722 18723 /* 18724 Ember's implementation of HTMLBars creates an enriched scope. 18725 18726 * self: same as HTMLBars, this field represents the dynamic lookup 18727 of root keys that are not special keywords or block arguments. 18728 * blocks: same as HTMLBars, a bundle of named blocks the layout 18729 can yield to. 18730 * component: indicates that the scope is the layout of a component, 18731 which is used to trigger lifecycle hooks for the component when 18732 one of the streams in its layout fires. 18733 * attrs: a map of key-value attributes sent in by the invoker of 18734 a template, and available in the component's layout. 18735 * locals: a map of locals, produced by block params (`as |a b|`) 18736 * localPresent: a map of available locals to avoid expensive 18737 `hasOwnProperty` checks. 18738 18739 The `self` field has two special meanings: 18740 18741 * If `self` is a view (`isView`), the actual HTMLBars `self` becomes 18742 the view's `context`. This is legacy semantics; components always 18743 use the component itself as the `this`. 18744 * If `self` is a view, two special locals are created: `view` and 18745 `controller`. These locals are legacy semantics. 18746 * If self has a `hasBoundController` property, it is coming from 18747 a legacy form of #with or #each 18748 (`{{#with something controller=someController}}`). This has 18749 the special effect of giving the child scope the supplied 18750 `controller` keyword, with an unrelated `self`. This is 18751 legacy functionality, as both the `view` and `controller` 18752 keywords have been deprecated. 18753 18754 **IMPORTANT**: There are two places in Ember where the ambient 18755 controller is looked up. Both of those places use the presence 18756 of `scope.locals.view` to indicate that the controller lookup 18757 should be dynamic off of the ambient view. If `scope.locals.view` 18758 does not exist, the code assumes that it is inside of a top-level 18759 template (without a view) and uses the `self` itself as the 18760 controller. This means that if you remove `scope.locals.view` 18761 (perhaps because we are finally ready to shed the view keyword), 18762 there may be unexpected consequences on controller semantics. 18763 If this happens to you, I hope you find this comment. - YK & TD 18764 18765 In practice, this means that with the exceptions of top-level 18766 view-less templates and the legacy `controller=foo` semantics, 18767 the controller hierarchy is managed dynamically by looking at 18768 the current view's `controller`. 18769 */ 18770 18771 function Scope(parent) { 18772 this._self = undefined; 18773 this._blocks = undefined; 18774 this._component = undefined; 18775 this._view = undefined; 18776 this._attrs = undefined; 18777 this._locals = undefined; 18778 this._localPresent = undefined; 18779 this.overrideController = undefined; 18780 this.parent = parent; 18781 } 18782 18783 var proto = Scope.prototype; 18784 18785 proto.getSelf = function () { 18786 return this._self || this.parent.getSelf(); 18787 }; 18788 18789 proto.bindSelf = function (self) { 18790 this._self = self; 18791 }; 18792 18793 proto.updateSelf = function (self, key) { 18794 var existing = this._self; 18795 18796 if (existing) { 18797 existing.setSource(self); 18798 } else { 18799 this._self = new _emberMetalStreamsProxyStream.default(self, key); 18800 } 18801 }; 18802 18803 proto.getBlock = function (name) { 18804 if (!this._blocks) { 18805 return this.parent.getBlock(name); 18806 } 18807 return this._blocks[name] || this.parent.getBlock(name); 18808 }; 18809 18810 proto.hasBlock = function (name) { 18811 if (!this._blocks) { 18812 return this.parent.hasBlock(name); 18813 } 18814 return !!(this._blocks[name] || this.parent.hasBlock(name)); 18815 }; 18816 18817 proto.bindBlock = function (name, block) { 18818 if (!this._blocks) { 18819 this._blocks = new _emberMetalEmpty_object.default(); 18820 } 18821 this._blocks[name] = block; 18822 }; 18823 18824 proto.getComponent = function () { 18825 return this._component || this.parent.getComponent(); 18826 }; 18827 18828 proto.bindComponent = function (component) { 18829 this._component = component; 18830 }; 18831 18832 proto.getView = function () { 18833 return this._view || this.parent.getView(); 18834 }; 18835 18836 proto.bindView = function (view) { 18837 this._view = view; 18838 }; 18839 18840 proto.getAttrs = function () { 18841 return this._attrs || this.parent.getAttrs(); 18842 }; 18843 18844 proto.bindAttrs = function (attrs) { 18845 this._attrs = attrs; 18846 }; 18847 18848 proto.hasLocal = function (name) { 18849 if (!this._localPresent) { 18850 return this.parent.hasLocal(name); 18851 } 18852 return this._localPresent[name] || this.parent.hasLocal(name); 18853 }; 18854 18855 proto.hasOwnLocal = function (name) { 18856 return this._localPresent && this._localPresent[name]; 18857 }; 18858 18859 proto.getLocal = function (name) { 18860 if (!this._localPresent) { 18861 return this.parent.getLocal(name); 18862 } 18863 return this._localPresent[name] ? this._locals[name] : this.parent.getLocal(name); 18864 }; 18865 18866 proto.bindLocal = function (name, value) { 18867 if (!this._localPresent) { 18868 this._localPresent = new _emberMetalEmpty_object.default(); 18869 this._locals = new _emberMetalEmpty_object.default(); 18870 } 18871 18872 this._localPresent[name] = true; 18873 this._locals[name] = value; 18874 }; 18875 18876 var EMPTY = { 18877 _self: undefined, 18878 _blocks: undefined, 18879 _component: undefined, 18880 _view: undefined, 18881 _attrs: undefined, 18882 _locals: undefined, 18883 _localPresent: undefined, 18884 overrideController: undefined, 18885 18886 getSelf: function () { 18887 return null; 18888 }, 18889 bindSelf: function (self) { 18890 return null; 18891 }, 18892 updateSelf: function (self, key) { 18893 return null; 18894 }, 18895 getBlock: function (name) { 18896 return null; 18897 }, 18898 bindBlock: function (name, block) { 18899 return null; 18900 }, 18901 hasBlock: function (name) { 18902 return false;
18903 }, 18904 getComponent: function () { 18905 return null; 18906 }, 18907 bindComponent: function () { 18908 return null; 18909 }, 18910 getView: function () { 18911 return null; 18912 }, 18913 bindView: function (view) { 18914 return null; 18915 }, 18916 getAttrs: function () { 18917 return null; 18918 }, 18919 bindAttrs: function (attrs) { 18920 return null; 18921 }, 18922 hasLocal: function (name) { 18923 return false; 18924 }, 18925 hasOwnLocal: function (name) { 18926 return false; 18927 }, 18928 getLocal: function (name) { 18929 return null; 18930 }, 18931 bindLocal: function (name, value) { 18932 return null; 18933 } 18934 }; 18935 18936 function createFreshScope() { 18937 return new Scope(EMPTY); 18938 } 18939 18940 function createChildScope(parent) { 18941 return new Scope(parent); 18942 } 18943}); 18944enifed("ember-htmlbars/hooks/destroy-render-node", ["exports"], function (exports) { 18945 /** 18946 @module ember 18947 @submodule ember-htmlbars 18948 */ 18949 18950 "use strict"; 18951 18952 exports.default = destroyRenderNode; 18953 18954 function destroyRenderNode(renderNode) { 18955 if (renderNode.emberView) { 18956 renderNode.emberView.destroy(); 18957 } 18958 18959 var streamUnsubscribers = renderNode.streamUnsubscribers; 18960 if (streamUnsubscribers) { 18961 for (var i = 0, l = streamUnsubscribers.length; i < l; i++) { 18962 streamUnsubscribers[i](); 18963 } 18964 } 18965 } 18966}); 18967enifed("ember-htmlbars/hooks/did-cleanup-tree", ["exports"], function (exports) { 18968 "use strict"; 18969 18970 exports.default = didCleanupTree; 18971 18972 function didCleanupTree(env) { 18973 // Once we have finsihed cleaning up the render node and sub-nodes, reset 18974 // state tracking which view those render nodes belonged to. 18975 env.view.ownerView._destroyingSubtreeForView = null; 18976 } 18977}); 18978enifed("ember-htmlbars/hooks/did-render-node", ["exports"], function (exports) { 18979 "use strict"; 18980 18981 exports.default = didRenderNode; 18982 18983 function didRenderNode(morph, env) { 18984 env.renderedNodes.add(morph); 18985 } 18986}); 18987enifed('ember-htmlbars/hooks/element', ['exports', 'ember-htmlbars/system/lookup-helper', 'htmlbars-runtime/hooks', 'ember-htmlbars/system/invoke-helper'], function (exports, _emberHtmlbarsSystemLookupHelper, _htmlbarsRuntimeHooks, _emberHtmlbarsSystemInvokeHelper) { 18988 /** 18989 @module ember 18990 @submodule ember-htmlbars 18991 */ 18992 18993 'use strict'; 18994 18995 exports.default = emberElement; 18996 18997 function emberElement(morph, env, scope, path, params, hash, visitor) { 18998 if (_htmlbarsRuntimeHooks.handleRedirect(morph, env, scope, path, params, hash, null, null, visitor)) { 18999 return; 19000 } 19001 19002 var result; 19003 var helper = _emberHtmlbarsSystemLookupHelper.findHelper(path, scope.getSelf(), env); 19004 if (helper) { 19005 var helperStream = _emberHtmlbarsSystemInvokeHelper.buildHelperStream(helper, params, hash, { element: morph.element }, env, scope, path); 19006 result = helperStream.value(); 19007 } else { 19008 result = env.hooks.get(env, scope, path); 19009 } 19010 19011 env.hooks.getValue(result); 19012 } 19013}); 19014enifed("ember-htmlbars/hooks/get-block", ["exports"], function (exports) { 19015 "use strict"; 19016 19017 exports.default = getBlock; 19018 19019 function getBlock(scope, key) { 19020 return scope.getBlock(key); 19021 } 19022}); 19023enifed('ember-htmlbars/hooks/get-cell-or-value', ['exports', 'ember-metal/streams/utils', 'ember-htmlbars/keywords/mut'], function (exports, _emberMetalStreamsUtils, _emberHtmlbarsKeywordsMut) { 19024 'use strict'; 19025 19026 exports.default = getCellOrValue; 19027 19028 function getCellOrValue(ref) { 19029 if (ref && ref[_emberHtmlbarsKeywordsMut.MUTABLE_REFERENCE]) { 19030 // Reify the mutable reference into a mutable cell. 19031 return ref.cell(); 19032 } 19033 19034 // Get the value out of the reference. 19035 return _emberMetalStreamsUtils.read(ref); 19036 } 19037}); 19038enifed('ember-htmlbars/hooks/get-child', ['exports', 'ember-metal/streams/utils'], function (exports, _emberMetalStreamsUtils) { 19039 /** 19040 @module ember 19041 @submodule ember-htmlbars 19042 */ 19043 19044 'use strict'; 19045 19046 exports.default = getChild; 19047 19048 function getChild(parent, key) { 19049 if (_emberMetalStreamsUtils.isStream(parent)) { 19050 return parent.getKey(key); 19051 } 19052 19053 // This should only happen when we are looking at an `attrs` hash. 19054 // That might change if it is possible to pass object literals 19055 // through the templating system. 19056 return parent[key]; 19057 } 19058}); 19059enifed('ember-htmlbars/hooks/get-root', ['exports'], function (exports) { 19060 /** 19061 @module ember 19062 @submodule ember-htmlbars 19063 */ 19064 19065 'use strict'; 19066 19067 exports.default = getRoot; 19068 19069 function getRoot(scope, key) { 19070 if (key === 'this') { 19071 return [scope.getSelf()]; 19072 } else if (key === 'hasBlock') { 19073 return [!!scope.hasBlock('default')]; 19074 } else if (key === 'hasBlockParams') { 19075 var block = scope.getBlock('default'); 19076 return [!!block && block.arity]; 19077 } else if (scope.hasLocal(key)) { 19078 return [scope.getLocal(key)]; 19079 } else { 19080 return [getKey(scope, key)]; 19081 } 19082 } 19083 19084 function getKey(scope, key) { 19085 if (key === 'attrs') { 19086 var _attrs = scope.getAttrs(); 19087 if (_attrs) { 19088 return _attrs; 19089 } 19090 } 19091 19092 var self = scope.getSelf() || scope.getLocal('view'); 19093 19094 if (self) { 19095 return self.getKey(key); 19096 } 19097 19098 var attrs = scope.getAttrs(); 19099 if (attrs && key in attrs) { 19100 // TODO: attrs 19101 // deprecate("You accessed the `" + key + "` attribute directly. Please use `attrs." + key + "` instead."); 19102 return attrs[key]; 19103 } 19104 } 19105}); 19106enifed('ember-htmlbars/hooks/get-value', ['exports', 'ember-metal/stream
19106s/utils', 'ember-views/compat/attrs-proxy'], function (exports, _emberMetalStreamsUtils, _emberViewsCompatAttrsProxy) { 19107 /** 19108 @module ember 19109 @submodule ember-htmlbars 19110 */ 19111 19112 'use strict'; 19113 19114 exports.default = getValue; 19115 19116 function getValue(ref) { 19117 var value = _emberMetalStreamsUtils.read(ref); 19118 19119 if (value && value[_emberViewsCompatAttrsProxy.MUTABLE_CELL]) { 19120 return value.value; 19121 } 19122 19123 return value; 19124 } 19125}); 19126enifed('ember-htmlbars/hooks/has-helper', ['exports', 'ember-htmlbars/system/lookup-helper'], function (exports, _emberHtmlbarsSystemLookupHelper) { 19127 'use strict'; 19128 19129 exports.default = hasHelperHook; 19130 19131 function hasHelperHook(env, scope, helperName) { 19132 if (env.helpers[helperName]) { 19133 return true; 19134 } 19135 19136 var owner = env.owner; 19137 if (_emberHtmlbarsSystemLookupHelper.validateLazyHelperName(helperName, owner, env.hooks.keywords)) { 19138 var registrationName = 'helper:' + helperName; 19139 if (owner.hasRegistration(registrationName)) { 19140 return true; 19141 } 19142 19143 var options = {}; 19144 var moduleName = env.meta && env.meta.moduleName; 19145 if (moduleName) { 19146 options.source = 'template:' + moduleName; 19147 } 19148 19149 if (owner.hasRegistration(registrationName, options)) { 19150 return true; 19151 } 19152 } 19153 19154 return false; 19155 } 19156}); 19157enifed('ember-htmlbars/hooks/invoke-helper', ['exports', 'ember-htmlbars/system/invoke-helper', 'ember-htmlbars/utils/subscribe'], function (exports, _emberHtmlbarsSystemInvokeHelper, _emberHtmlbarsUtilsSubscribe) { 19158 'use strict'; 19159 19160 exports.default = invokeHelper; 19161 19162 function invokeHelper(morph, env, scope, visitor, params, hash, helper, templates, context) { 19163 var helperStream = _emberHtmlbarsSystemInvokeHelper.buildHelperStream(helper, params, hash, templates, env, scope); 19164 19165 // Ember.Helper helpers are pure values, thus linkable. 19166 if (helperStream.linkable) { 19167 if (morph) { 19168 // When processing an inline expression, the params and hash have already 19169 // been linked. Thus, HTMLBars will not link the returned helperStream. 19170 // We subscribe the morph to the helperStream here, and also subscribe 19171 // the helperStream to any params. 19172 var addedDependency = false; 19173 for (var i = 0, l = params.length; i < l; i++) { 19174 addedDependency = true; 19175 helperStream.addDependency(params[i]); 19176 } 19177 for (var key in hash) { 19178 addedDependency = true; 19179 helperStream.addDependency(hash[key]); 19180 } 19181 if (addedDependency) { 19182 _emberHtmlbarsUtilsSubscribe.default(morph, env, scope, helperStream); 19183 } 19184 } 19185 19186 return { link: true, value: helperStream }; 19187 } 19188 19189 // Built-in helpers are not linkable. They must run on every rerender. 19190 return { value: helperStream.value() }; 19191 } 19192}); 19193enifed('ember-htmlbars/hooks/link-render-node', ['exports', 'ember-htmlbars/utils/subscribe', 'ember-runtime/utils', 'ember-metal/streams/utils', 'ember-htmlbars/system/lookup-helper', 'ember-htmlbars/keywords/closure-component'], function (exports, _emberHtmlbarsUtilsSubscribe, _emberRuntimeUtils, _emberMetalStreamsUtils, _emberHtmlbarsSystemLookupHelper, _emberHtmlbarsKeywordsClosureComponent) { 19194 /** 19195 @module ember 19196 @submodule ember-htmlbars 19197 */ 19198 19199 'use strict'; 19200 19201 exports.default = linkRenderNode; 19202 19203 function linkRenderNode(renderNode, env, scope, path, params, hash) { 19204 if (renderNode.streamUnsubscribers) { 19205 return true; 19206 } 19207 19208 var keyword = env.hooks.keywords[path]; 19209 if (keyword && keyword.link) { 19210 keyword.link(renderNode.getState(), params, hash); 19211 } else { 19212 switch (path) { 19213 case 'unbound': 19214 return true; 19215 case 'unless': 19216 case 'if': 19217 params[0] = shouldDisplay(params[0], toBool);break; 19218 case 'each': 19219 params[0] = eachParam(params[0]);break; 19220 case 'with': 19221 params[0] = shouldDisplay(params[0], identity);break; 19222 } 19223 } 19224 19225 // If there is a dot in the path, we need to subscribe to the arguments in the 19226 // closure component as well. 19227 19228 if (_emberHtmlbarsSystemLookupHelper.CONTAINS_DOT_CACHE.get(path)) { 19229 var stream = env.hooks.get(env, scope, path); 19230 var componentCell = stream.value(); 19231 19232 if (_emberHtmlbarsKeywordsClosureComponent.isComponentCell(componentCell)) { 19233 var closureAttrs = _emberHtmlbarsKeywordsClosureComponent.mergeInNewHash(componentCell[_emberHtmlbarsKeywordsClosureComponent.COMPONENT_HASH], hash); 19234 19235 for (var key in closureAttrs) { 19236 _emberHtmlbarsUtilsSubscribe.default(renderNode, env, scope, closureAttrs[key]); 19237 } 19238 } 19239 } 19240 19241 if (params && params.length) { 19242 for (var i = 0; i < params.length; i++) { 19243 _emberHtmlbarsUtilsSubscribe.default(renderNode, env, scope, params[i]); 19244 } 19245 } 19246 19247 if (hash) { 19248 for (var key in hash) { 19249 _emberHtmlbarsUtilsSubscribe.default(renderNode, env, scope, hash[key]); 19250 } 19251 } 19252 19253 // The params and hash can be reused. They don't need to be 19254 // recomputed on subsequent re-renders because they are 19255 // streams. 19256 return true; 19257 } 19258 19259 function eachParam(list) { 19260 var listChange = getKey(list, '[]'); 19261 19262 var stream = _emberMetalStreamsUtils.chain(list, function () { 19263 _emberMetalStreamsUtils.read(listChange); 19264 return _emberMetalStreamsUtils.read(list); 19265 }, 'each'); 19266 19267 stream.addDependency(listChange); 19268 return stream; 19269 } 19270 19271 function shouldDisplay(predicate, coercer) { 19272 var length = getKey(predicate, 'length'); 19273 var isTruthy = getKey(predicate, 'isTruthy'); 19274 19275 var stream = _emberMetalStreamsUtils.chain(predicate, function () { 19276 var predicateVal = _emberMetalStreamsUtils.read(predicate); 19277 var lengthVal = _emberMetalStreamsUtils.read(length); 19278 var isTruthyVal = _emberMetalStreamsUtils.read(isTruthy); 19279 19280 if (_emberRuntimeUtils.isArray(predicateVal)) { 19281 return lengthVal > 0 ? coercer(predicateVal) : false;
19282 } 19283 19284 if (typeof isTruthyVal === 'boolean') { 19285 return isTruthyVal ? coercer(predicateVal) : false; 19286 } 19287 19288 return coercer(predicateVal); 19289 }, 'ShouldDisplay'); 19290 19291 _emberMetalStreamsUtils.addDependency(stream, length); 19292 _emberMetalStreamsUtils.addDependency(stream, isTruthy); 19293 19294 return stream; 19295 } 19296 19297 function toBool(value) { 19298 return !!value; 19299 } 19300 19301 function identity(value) { 19302 return value; 19303 } 19304 19305 function getKey(obj, key) { 19306 if (_emberMetalStreamsUtils.isStream(obj)) { 19307 return obj.getKey(key); 19308 } else { 19309 return obj && obj[key]; 19310 } 19311 } 19312}); 19313enifed('ember-htmlbars/hooks/lookup-helper', ['exports', 'ember-htmlbars/system/lookup-helper'], function (exports, _emberHtmlbarsSystemLookupHelper) { 19314 'use strict'; 19315 19316 exports.default = lookupHelperHook; 19317 19318 function lookupHelperHook(env, scope, helperName) { 19319 return _emberHtmlbarsSystemLookupHelper.default(helperName, scope.getSelf(), env); 19320 } 19321}); 19322enifed('ember-htmlbars/hooks/subexpr', ['exports', 'ember-htmlbars/system/lookup-helper', 'ember-htmlbars/system/invoke-helper', 'ember-metal/streams/utils'], function (exports, _emberHtmlbarsSystemLookupHelper, _emberHtmlbarsSystemInvokeHelper, _emberMetalStreamsUtils) { 19323 /** 19324 @module ember 19325 @submodule ember-htmlbars 19326 */ 19327 19328 'use strict'; 19329 19330 exports.default = subexpr; 19331 exports.labelForSubexpr = labelForSubexpr; 19332 19333 function subexpr(env, scope, helperName, params, hash) { 19334 // TODO: Keywords and helper invocation should be integrated into 19335 // the subexpr hook upstream in HTMLBars. 19336 var keyword = env.hooks.keywords[helperName]; 19337 if (keyword) { 19338 return keyword(null, env, scope, params, hash, null, null); 19339 } 19340 19341 var label = labelForSubexpr(params, hash, helperName); 19342 var helper = _emberHtmlbarsSystemLookupHelper.default(helperName, scope.getSelf(), env); 19343 19344 var helperStream = _emberHtmlbarsSystemInvokeHelper.buildHelperStream(helper, params, hash, null, env, scope, label); 19345 19346 for (var i = 0, l = params.length; i < l; i++) { 19347 helperStream.addDependency(params[i]); 19348 } 19349 19350 for (var key in hash) { 19351 helperStream.addDependency(hash[key]); 19352 } 19353 19354 return helperStream; 19355 } 19356 19357 function labelForSubexpr(params, hash, helperName) { 19358 var paramsLabels = labelsForParams(params); 19359 var hashLabels = labelsForHash(hash); 19360 var label = '(' + helperName; 19361 19362 if (paramsLabels) { 19363 label += ' ' + paramsLabels; 19364 } 19365 if (hashLabels) { 19366 label += ' ' + hashLabels; 19367 } 19368 19369 return label + ')'; 19370 } 19371 19372 function labelsForParams(params) { 19373 return _emberMetalStreamsUtils.labelsFor(params).join(' '); 19374 } 19375 19376 function labelsForHash(hash) { 19377 var out = []; 19378 19379 for (var prop in hash) { 19380 out.push(prop + '=' + _emberMetalStreamsUtils.labelFor(hash[prop])); 19381 } 19382 19383 return out.join(' '); 19384 } 19385}); 19386enifed('ember-htmlbars/hooks/update-self', ['exports', 'ember-metal/debug', 'ember-metal/property_get'], function (exports, _emberMetalDebug, _emberMetalProperty_get) { 19387 /** 19388 @module ember 19389 @submodule ember-htmlbars 19390 */ 19391 19392 'use strict'; 19393 19394 exports.default = updateSelf; 19395 19396 function updateSelf(env, scope, _self) { 19397 var self = _self; 19398 19399 if (self && self.hasBoundController) { 19400 var _self2 = self; 19401 var controller = _self2.controller; 19402 19403 self = self.self; 19404 19405 scope.updateLocal('controller', controller || self); 19406 } 19407 19408 _emberMetalDebug.assert('BUG: scope.attrs and self.isView should not both be true', !(scope.attrs && self.isView)); 19409 19410 if (self && self.isView) { 19411 scope.updateLocal('view', self); 19412 scope.updateSelf(_emberMetalProperty_get.get(self, 'context'), ''); 19413 return; 19414 } 19415 19416 scope.updateSelf(self); 19417 } 19418}); 19419enifed("ember-htmlbars/hooks/will-cleanup-tree", ["exports"], function (exports) { 19420 "use strict"; 19421 19422 exports.default = willCleanupTree; 19423 19424 function willCleanupTree(env) { 19425 var view = env.view; 19426 19427 // When we go to clean up the render node and all of its children, we may 19428 // encounter views/components associated with those nodes along the way. In 19429 // those cases, we need to sever the link between the 19430 // existing view hierarchy and those views. 19431 // 19432 // However, we do *not* need to remove the child views of child views, since 19433 // severing the connection to their parent effectively severs them from the 19434 // view graph. 19435 // 19436 // For example, imagine the following view graph: 19437 // 19438 // A 19439 // / \ 19440 // B C 19441 // / \ 19442 // D E 19443 // 19444 // If we are cleaning up the node for view C, we need to remove that view 19445 // from A's child views. However, we do not need to remove D and E from C's
19446 // child views, since removing C transitively removes D and E as well. 19447 // 19448 // To accomplish this, we track the nearest view to this render node on the 19449 // owner view, the root-most view in the graph (A in the example above). If 19450 // we detect a view that is a direct child of that view, we remove it from 19451 // the `childViews` array. Other parent/child view relationships are 19452 // untouched. This view is then cleared once cleanup is complete in 19453 // `didCleanupTree`. 19454 view.ownerView._destroyingSubtreeForView = view; 19455 } 19456}); 19457enifed('ember-htmlbars/index', ['exports', 'ember-metal/core', 'ember-metal/features', 'ember-template-compiler', 'ember-htmlbars/system/make_bound_helper', 'ember-htmlbars/helpers', 'ember-htmlbars/helpers/if_unless', 'ember-htmlbars/helpers/with', 'ember-htmlbars/helpers/loc', 'ember-htmlbars/helpers/log', 'ember-htmlbars/helpers/each', 'ember-htmlbars/helpers/each-in', 'ember-htmlbars/helpers/-normalize-class', 'ember-htmlbars/helpers/concat', 'ember-htmlbars/helpers/-join-classes', 'ember-htmlbars/helpers/-legacy-each-with-controller', 'ember-htmlbars/helpers/-legacy-each-with-keyword', 'ember-htmlbars/helpers/-html-safe', 'ember-htmlbars/helpers/hash', 'ember-htmlbars/system/dom-helper', 'ember-htmlbars/helper', 'ember-htmlbars/template_registry', 'ember-htmlbars/system/bootstrap', 'ember-htmlbars/compat'], function (exports, _emberMetalCore, _emberMetalFeatures, _emberTemplateCompiler, _emberHtmlbarsSystemMake_bound_helper, _emberHtmlbarsHelpers, _emberHtmlbarsHelpersIf_unless, _emberHtmlbarsHelpersWith, _emberHtmlbarsHelpersLoc, _emberHtmlbarsHelpersLog, _emberHtmlbarsHelpersEach, _emberHtmlbarsHelpersEachIn, _emberHtmlbarsHelpersNormalizeClass, _emberHtmlbarsHelpersConcat, _emberHtmlbarsHelpersJoinClasses, _emberHtmlbarsHelpersLegacyEachWithController, _emberHtmlbarsHelpersLegacyEachWithKeyword, _emberHtmlbarsHelpersHtmlSafe, _emberHtmlbarsHelpersHash, _emberHtmlbarsSystemDomHelper, _emberHtmlbarsHelper, _emberHtmlbarsTemplate_registry, _emberHtmlbarsSystemBootstrap, _emberHtmlbarsCompat) { 19458 /** 19459 Ember templates are executed by [HTMLBars](https://github.com/tildeio/htmlbars), 19460 an HTML-friendly version of [Handlebars](http://handlebarsjs.com/). Any valid Handlebars syntax is valid in an Ember template. 19461 19462 ### Showing a property 19463 19464 Templates manage the flow of an application's UI, and display state (through 19465 the DOM) to a user. For example, given a component with the property "name", 19466 that component's template can use the name in several ways: 19467 19468 ```javascript 19469
19469// app/components/person.js 19470 export default Ember.Component.extend({ 19471 name: 'Jill' 19472 }); 19473 ``` 19474 19475 ```handlebars 19476 {{! app/components/person.hbs }} 19477 {{name}} 19478 <div>{{name}}</div> 19479 <span data-name={{name}}></span> 19480 ``` 19481 19482 Any time the "name" property on the component changes, the DOM will be 19483 updated. 19484 19485 Properties can be chained as well: 19486 19487 ```handlebars 19488 {{aUserModel.name}} 19489 <div>{{listOfUsers.firstObject.name}}</div> 19490 ``` 19491 19492 ### Using Ember helpers 19493 19494 When content is passed in mustaches `{{}}`, Ember will first try to find a helper 19495 or component with that name. For example, the `if` helper: 19496 19497 ```handlebars 19498 {{if name "I have a name" "I have no name"}} 19499 <span data-has-name={{if name true}}></span> 19500 ``` 19501 19502 The returned value is placed where the `{{}}` is called. The above style is 19503 called "inline". A second style of helper usage is called "block". For example: 19504 19505 ```handlebars 19506 {{#if name}} 19507 I have a name 19508 {{else}} 19509 I have no name 19510 {{/if}} 19511 ``` 19512 19513 The block form of helpers allows you to control how the UI is created based 19514 on the values of properties. 19515 19516 A third form of helper is called "nested". For example here the concat 19517 helper will add " Doe" to a displayed name if the person has no last name: 19518 19519 ```handlebars 19520 <span data-name={{concat firstName ( 19521 if lastName (concat " " lastName) "Doe" 19522 )}}></span> 19523 ``` 19524 19525 Ember's built-in helpers are described under the [Ember.Templates.helpers](/api/classes/Ember.Templates.helpers.html) 19526 namespace. Documentation on creating custom helpers can be found under 19527 [Ember.Helper](/api/classes/Ember.Helper.html). 19528 19529 ### Invoking a Component 19530 19531 Ember components represent state to the UI of an application. Further 19532 reading on components can be found under [Ember.Component](/api/classes/Ember.Component.html). 19533 19534 @module ember 19535 @submodule ember-templates 19536 @main ember-templates 19537 @public 19538 */ 19539 19540 /** 19541 19542 [HTMLBars](https://github.com/tildeio/htmlbars) is a [Handlebars](http://handlebarsjs.com/) 19543 compatible templating engine used by Ember.js. The classes and namespaces 19544 covered by this documentation attempt to focus on APIs for interacting 19545 with HTMLBars itself. For more general guidance on Ember.js templates and 19546 helpers, please see the [ember-templates](/api/modules/ember-templates.html) 19547 package. 19548 19549 @module ember 19550 @submodule ember-htmlbars 19551 @main ember-htmlbars 19552 @public 19553 */ 19554 'use strict'; 19555 19556 _emberHtmlbarsHelpers.registerHelper('if', _emberHtmlbarsHelpersIf_unless.ifHelper); 19557 _emberHtmlbarsHelpers.registerHelper('unless', _emberHtmlbarsHelpersIf_unless.unlessHelper); 19558 _emberHtmlbarsHelpers.registerHelper('with', _emberHtmlbarsHelpersWith.default); 19559 _emberHtmlbarsHelpers.registerHelper('loc', _emberHtmlbarsHelpersLoc.default); 19560 _emberHtmlbarsHelpers.registerHelper('log', _emberHtmlbarsHelpersLog.default); 19561 _emberHtmlbarsHelpers.registerHelper('each', _emberHtmlbarsHelpersEach.default); 19562 _emberHtmlbarsHelpers.registerHelper('each-in', _emberHtmlbarsHelpersEachIn.default); 19563 _emberHtmlbarsHelpers.registerHelper('-normalize-class', _emberHtmlbarsHelpersNormalizeClass.default); 19564 _emberHtmlbarsHelpers.registerHelper('concat', _emberHtmlbarsHelpersConcat.default); 19565 _emberHtmlbarsHelpers.registerHelper('-join-classes', _emberHtmlbarsHelpersJoinClasses.default); 19566 _emberHtmlbarsHelpers.registerHelper('-html-safe', _emberHtmlbarsHelpersHtmlSafe.default); 19567 19568 _emberHtmlbarsHelpers.registerHelper('hash', _emberHtmlbarsHelpersHash.default); 19569 19570 if (_emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 19571 _emberHtmlbarsHelpers.registerHelper('-legacy-each-with-controller', _emberHtmlbarsHelpersLegacyEachWithController.default); 19572 _emberHtmlbarsHelpers.registerHelper('-legacy-each-with-keyword', _emberHtmlbarsHelpersLegacyEachWithKeyword.default); 19573 } 19574 19575 _emberMetalCore.default.HTMLBars = { 19576 template: _emberTemplateCompiler.template, 19577 compile: _emberTemplateCompiler.compile, 19578 precompile: _emberTemplateCompiler.precompile, 19579 makeBoundHelper: _emberHtmlbarsSystemMake_bound_helper.default, 19580 registerPlugin: _emberTemplateCompiler.registerPlugin, 19581 DOMHelper: _emberHtmlbarsSystemDomHelper.default 19582 }; 19583 19584 _emberHtmlbarsHelper.default.helper = _emberHtmlbarsHelper.helper; 19585 _emberMetalCore.default.Helper = _emberHtmlbarsHelper.default; 19586 19587 /** 19588 Global hash of shared templates. This will automatically be populated 19589 by the build tools so that you can store your Handlebars templates in 19590 separate files that get loaded into JavaScript at buildtime. 19591 19592 @property TEMPLATES 19593 @for Ember 19594 @type Object 19595 @private 19596 */ 19597 Object.defineProperty(_emberMetalCore.default, 'TEMPLATES', { 19598 configurable: false, 19599 get: _emberHtmlbarsTemplate_registry.getTemplates, 19600 set: _emberHtmlbarsTemplate_registry.setTemplates 19601 }); 19602}); 19603 19604// Importing adds template bootstrapping 19605// initializer to enable embedded templates. 19606 19607// Importing ember-htmlbars/compat updates the 19608// Ember.Handlebars global if htmlbars is enabled. 19609enifed('ember-htmlbars/keywords/closure-component', ['exports', 'ember-metal/debug', 'ember-metal/is_none', 'ember-metal/symbol', 'ember-metal/stream
19609s/stream', 'ember-metal/empty_object', 'ember-metal/streams/utils', 'ember-htmlbars/hooks/subexpr', 'ember-metal/assign', 'ember-htmlbars/utils/extract-positional-params', 'ember-htmlbars/utils/lookup-component'], function (exports, _emberMetalDebug, _emberMetalIs_none, _emberMetalSymbol, _emberMetalStreamsStream, _emberMetalEmpty_object, _emberMetalStreamsUtils, _emberHtmlbarsHooksSubexpr, _emberMetalAssign, _emberHtmlbarsUtilsExtractPositionalParams, _emberHtmlbarsUtilsLookupComponent) { 19610 /** 19611 @module ember 19612 @submodule ember-templates 19613 */ 19614 19615 'use strict'; 19616 19617 exports.default = closureComponent; 19618 exports.isComponentCell = isComponentCell; 19619 exports.processPositionalParamsFromCell = processPositionalParamsFromCell; 19620 exports.mergeInNewHash = mergeInNewHash; 19621 var COMPONENT_REFERENCE = _emberMetalSymbol.default('COMPONENT_REFERENCE'); 19622 exports.COMPONENT_REFERENCE = COMPONENT_REFERENCE; 19623 var COMPONENT_CELL = _emberMetalSymbol.default('COMPONENT_CELL'); 19624 exports.COMPONENT_CELL = COMPONENT_CELL; 19625 var COMPONENT_PATH = _emberMetalSymbol.default('COMPONENT_PATH'); 19626 exports.COMPONENT_PATH = COMPONENT_PATH; 19627 var COMPONENT_POSITIONAL_PARAMS = _emberMetalSymbol.default('COMPONENT_POSITIONAL_PARAMS'); 19628 exports.COMPONENT_POSITIONAL_PARAMS = COMPONENT_POSITIONAL_PARAMS; 19629 var COMPONENT_HASH = _emberMetalSymbol.default('COMPONENT_HASH'); 19630 19631 exports.COMPONENT_HASH = COMPONENT_HASH; 19632 var ClosureComponentStream = _emberMetalStreamsStream.default.extend({ 19633 init: function (env, path, params, hash) { 19634 this._env = env; 19635 this._path = path; 19636 this._params = params; 19637 this._hash = hash; 19638 this.label = _emberHtmlbarsHooksSubexpr.labelForSubexpr([path].concat(params), hash, 'component'); 19639 this[COMPONENT_REFERENCE] = true; 19640 }, 19641 compute: function () { 19642 return createClosureComponentCell(this._env, this._path, this._params, this._hash, this.label); 19643 } 19644 }); 19645 19646 function closureComponent(env, _ref3, hash) { 19647 var path = _ref3[0]; 19648 19649 var params = _ref3.slice(1); 19650 19651 var s = new ClosureComponentStream(env, path, params, hash); 19652 19653 s.addDependency(path); 19654 19655 // FIXME: If the stream invalidates on every params or hash change, then 19656 // the {{component helper will be forced to re-render the whole component 19657 // each time. Instead, these dependencies should not be required and the 19658 // element component keyword should add the params and hash as dependencies. 19659 params.forEach(function (item) { 19660 return s.addDependency(item); 19661 }); 19662 Object.keys(hash).forEach(function (key) { 19663 return s.addDependency(hash[key]); 19664 }); 19665 19666 return s; 19667 } 19668 19669 function createClosureComponentCell(env, originalComponentPath, params, hash, label) { 19670 var componentPath = _emberMetalStreamsUtils.read(originalComponentPath); 19671 19672 _emberMetalDebug.assert('Component path cannot be null in ' + label, !_emberMetalIs_none.default(componentPath)); 19673 19674 var newHash = _emberMetalAssign.default(new _emberMetalEmpty_object.default(), hash); 19675 19676 if (isComponentCell(componentPath)) { 19677 return createNestedClosureComponentCell(componentPath, params, newHash); 19678 } else { 19679 _emberMetalDebug.assert('The component helper cannot be used without a valid component name. You used "' + componentPath + '" via ' + label, isValidComponentPath(env, componentPath)); 19680 return createNewClosureComponentCell(env, componentPath, params, newHash); 19681 } 19682 } 19683 19684 function isValidComponentPath(env, path) { 19685 var result = _emberHtmlbarsUtilsLookupComponent.default(env.owner, path); 19686 19687 return !!(result.component || result.layout); 19688 } 19689 19690 function isComponentCell(component) { 19691 return component && component[COMPONENT_CELL]; 19692 } 19693 19694 function createNestedClosureComponentCell(componentCell, params, hash) { 19695 var _ref; 19696 19697 // This needs to be done in each nesting level to avoid raising assertions. 19698 processPositionalParamsFromCell(componentCell, params, hash); 19699 19700 return _ref = {}, _ref[COMPONENT_PATH] = componentCell[COMPONENT_PATH], _ref[COMPONENT_HASH] = mergeInNewHash(componentCell[COMPONENT_HASH], hash), _ref[COMPONENT_POSITIONAL_PARAMS] = componentCell[COMPONENT_POSITIONAL_PARAMS], _ref[COMPONENT_CELL] = true, _ref; 19701 } 19702 19703 function processPositionalParamsFromCell(componentCell, params, hash) { 19704 var positionalParams = componentCell[COMPONENT_POSITIONAL_PARAMS]; 19705 19706 _emberHtmlbarsUtilsExtractPositionalParams.processPositionalParams(null, positionalParams, params, hash); 19707 } 19708 19709 function createNewClosureComponentCell(env, componentPath, params, hash) { 19710 var _ref2; 19711 19712 var positionalParams = getPositionalParams(env.owner, componentPath); 19713 19714 // This needs to be done in each nesting level to avoid raising assertions.
19715 _emberHtmlbarsUtilsExtractPositionalParams.processPositionalParams(null, positionalParams, params, hash); 19716 19717 return _ref2 = {}, _ref2[COMPONENT_PATH] = componentPath, _ref2[COMPONENT_HASH] = hash, _ref2[COMPONENT_POSITIONAL_PARAMS] = positionalParams, _ref2[COMPONENT_CELL] = true, _ref2; 19718 } 19719 19720 /* 19721 Returns the positional parameters for component `componentPath`. 19722 If it has no positional parameters, it returns the empty array. 19723 */ 19724 function getPositionalParams(container, componentPath) { 19725 if (!componentPath) { 19726 return []; 19727 } 19728 var result = _emberHtmlbarsUtilsLookupComponent.default(container, componentPath); 19729 var component = result.component; 19730 19731 if (component && component.positionalParams) { 19732 return component.positionalParams; 19733 } else { 19734 return []; 19735 } 19736 } 19737 19738 function mergeInNewHash(original, updates) { 19739 return _emberMetalAssign.default({}, original, updates); 19740 } 19741}); 19742enifed('ember-htmlbars/keywords/collection', ['exports', 'ember-views/streams/utils', 'ember-views/views/collection_view', 'ember-htmlbars/node-managers/view-node-manager', 'ember-metal/assign'], function (exports, _emberViewsStreamsUtils, _emberViewsViewsCollection_view, _emberHtmlbarsNodeManagersViewNodeManager, _emberMetalAssign) { 19743 /** 19744 @module ember 19745 @submodule ember-templates 19746 */ 19747 19748 'use strict'; 19749 19750 /** 19751 `{{collection}}` is a template helper for adding instances of 19752 `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) 19753 for additional information on how a `CollectionView` functions. 19754 19755 `{{collection}}`'s primary use is as a block helper with a `contentBinding` 19756 option pointing towards an `Ember.Array`-compatible object. An `Ember.View` 19757 instance will be created for each item in its `content` property. Each view 19758 will have its own `content` property set to the appropriate item in the 19759 collection. 19760 19761 The provided block will be applied as the template for each item's view. 19762 19763 Given an empty `<body>` the following template: 19764 19765 ```handlebars 19766 {{! application.hbs }} 19767 {{#collection content=model}} 19768 Hi {{view.content.name}} 19769 {{/collection}} 19770 ``` 19771 19772 And the following application code 19773 19774 ```javascript 19775 App = Ember.Application.create(); 19776 App.ApplicationRoute = Ember.Route.extend({ 19777 model() { 19778 return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; 19779 } 19780 }); 19781 ``` 19782 19783 The following HTML will result: 19784 19785 ```html 19786 <div class="ember-view"> 19787 <div class="ember-view">Hi Yehuda</div> 19788 <div class="ember-view">Hi Tom</div> 19789 <div class="ember-view">Hi Peter</div> 19790 </div> 19791 ``` 19792 19793 ### Non-block version of collection 19794 19795 If you provide an `itemViewClass` option that has its own `template`, 19796 then you may omit the block. 19797 19798 The following template: 19799 19800 ```handlebars 19801 {{! application.hbs }} 19802 {{collection content=model itemViewClass="an-item"}} 19803 ``` 19804 19805 And application code 19806 19807 ```javascript 19808 App = Ember.Application.create(); 19809 App.ApplicationRoute = Ember.Route.extend({ 19810 model() { 19811 return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; 19812 } 19813 }); 19814 19815 App.AnItemView = Ember.View.extend({ 19816 template: Ember.Handlebars.compile("Greetings {{view.content.name}}") 19817 }); 19818 ``` 19819 19820 Will result in the HTML structure below 19821 19822 ```html 19823 <div class="ember-view"> 19824 <div class="ember-view">Greetings Yehuda</div> 19825 <div class="ember-view">Greetings Tom</div> 19826 <div class="ember-view">Greetings Peter</div> 19827 </div> 19828 ``` 19829 19830 ### Specifying a CollectionView subclass 19831 19832 By default the `{{collection}}` helper will create an instance of 19833 `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to 19834 the helper by passing it as the first argument: 19835 19836 ```handlebars 19837 {{#collection "my-custom-collection" content=model}} 19838 Hi {{view.content.name}} 19839 {{/collection}} 19840 ``` 19841 19842 This example would look for the class `App.MyCustomCollection`. 19843 19844 ### Forwarded `item.*`-named Options 19845 19846 As with the `{{view}}`, helper options passed to the `{{collection}}` will be 19847 set on the resulting `Ember.CollectionView` as properties. Additionally, 19848 options prefixed with `item` will be applied to the views rendered for each 19849 item (note the camelcasing): 19850 19851 ```handlebars 19852 {{#collection content=model 19853 itemTagName="p" 19854 itemClassNames="greeting"}} 19855 Howdy {{view.content.name}} 19856 {{/collection}} 19857 ``` 19858 19859 Will result in the following HTML structure: 19860 19861 ```html 19862 <div class="ember-view"> 19863 <p class="ember-view greeting">Howdy Yehuda</p> 19864 <p class="ember-view greeting">Howdy Tom</p> 19865 <p class="ember-view greeting">Howdy Peter</p> 19866 </div> 19867 ``` 19868 19869 @method collection 19870 @for Ember.Templates.helpers 19871 @deprecated Use `{{each}}` helper instead. 19872 @public 19873 */ 19874 exports.default = { 19875 setupState: function (state, env, scope, params, hash) { 19876 var read = env.hooks.getValue; 19877 19878 return _emberMetalAssign.default({}, state, { 19879 parentView: env.view, 19880 viewClassOrInstance: getView(read(params[0]), env.owner) 19881 }); 19882 }, 19883 19884 rerender: function (morph, env, scope, params, hash, template, inverse, visitor) { 19885 // If the hash is empty, the component cannot have extracted a part 19886 // of a mutable param and used it in its layout, because there are 19887 // no params at all. 19888 if (Object.keys(hash).length) { 19889 return morph.getState().manager.rerender(env, hash, visitor, true); 19890 } 19891 }, 19892 19893 render: function (node, env, scope, params, hash, template, inverse, visitor) { 19894 var state = node.getState(); 19895 var parentView = state.parentView; 19896 19897 var options = { component: state.viewClassOrInstance, layout: null }; 19898 if (template) { 19899 options.createOptions = { 19900 _itemViewTemplate: template && { raw: template }, 19901 _itemViewInverse: inverse && { raw: inverse } 19902 }; 19903 } 19904 19905 if (hash.itemView) { 19906 hash.itemViewClass = hash.itemView; 19907 } 19908 19909 if (hash.emptyView) { 19910 hash.emptyViewClass = hash.emptyView; 19911 } 19912 19913 var nodeManager = _emberHtmlbarsNodeManagersViewNodeManager.default.create(node, env, hash, options, parentView, null, scope, template); 19914 state.manager = nodeManager; 19915 19916 nodeManager.render(env, hash, visitor); 19917 } 19918 }; 19919 19920 function getView(viewPath, container) { 19921 var viewClassOrInstance; 19922 19923 if (!viewPath) { 19924 viewClassOrInstance = _emberViewsViewsCollection_view.default; 19925 } else {
19926 viewClassOrInstance = _emberViewsStreamsUtils.readViewFactory(viewPath, container); 19927 } 19928 19929 return viewClassOrInstance; 19930 } 19931}); 19932enifed('ember-htmlbars/keywords/component', ['exports', 'htmlbars-runtime/hooks', 'ember-htmlbars/keywords/closure-component', 'ember-metal/features', 'ember-metal/empty_object', 'ember-metal/assign'], function (exports, _htmlbarsRuntimeHooks, _emberHtmlbarsKeywordsClosureComponent, _emberMetalFeatures, _emberMetalEmpty_object, _emberMetalAssign) { 19933 /** 19934 @module ember 19935 @submodule ember-templates 19936 @public 19937 */ 19938 'use strict'; 19939 19940 /** 19941 The `{{component}}` helper lets you add instances of `Ember.Component` to a 19942 template. See [Ember.Component](/api/classes/Ember.Component.html) for 19943 additional information on how a `Component` functions. 19944 `{{component}}`'s primary use is for cases where you want to dynamically 19945 change which type of component is rendered as the state of your application 19946 changes. The provided block will be applied as the template for the component. 19947 Given an empty `<body>` the following template: 19948 19949 ```handlebars 19950 {{! application.hbs }} 19951 {{component infographicComponentName}} 19952 ``` 19953 19954 And the following application code: 19955 19956 ```javascript 19957 export default Ember.Controller.extend({ 19958 infographicComponentName: computed('isMarketOpen', { 19959 get() { 19960 if (this.get('isMarketOpen')) { 19961 return 'live-updating-chart'; 19962 } else { 19963 return 'market-close-summary'; 19964 } 19965 } 19966 }) 19967 }); 19968 ``` 19969 19970 The `live-updating-chart` component will be appended when `isMarketOpen` is 19971 `true`, and the `market-close-summary` component will be appended when 19972 `isMarketOpen` is `false`. If the value changes while the app is running, 19973 the component will be automatically swapped out accordingly. 19974 Note: You should not use this helper when you are consistently rendering the same 19975 component. In that case, use standard component syntax, for example: 19976 19977 ```handlebars 19978 {{! application.hbs }} 19979 {{live-updating-chart}} 19980 ``` 19981 19982 ## Nested Usage 19983 19984 The `component` helper can be used to package a component path with initial attrs. 19985 The included attrs can then be merged during the final invocation. 19986 19987 For example, given a `person-form` component with the following template: 19988 19989 ```handlebars 19990 {{yield (hash 19991 nameInput=(component "my-input-component" value=model.name placeholder="First Name"))}} 19992 ``` 19993 19994 The following snippet: 19995 19996 ``` 19997 {{#person-form as |form|}} 19998 {{component form.nameInput placeholder="Username"}} 19999 {{/person-form}} 20000 ``` 20001 20002 would output an input whose value is already bound to `model.name` and `placeholder` 20003 is "Username". 20004 20005 @method component 20006 @since 1.11.0 20007 @for Ember.Templates.helpers 20008 @public 20009 */ 20010 20011 exports.default = function (morph, env, scope, params, hash, template, inverse, visitor) { 20012 if (!morph) { 20013 return _emberHtmlbarsKeywordsClosureComponent.default(env, params, hash); 20014 } 20015 20016 var newHash = _emberMetalAssign.default(new _emberMetalEmpty_object.default(), hash); 20017 20018 _htmlbarsRuntimeHooks.keyword('@element_component', morph, env, scope, params, newHash, template, inverse, visitor); 20019 return true; 20020 }; 20021}); 20022enifed('ember-htmlbars/keywords/debugger', ['exports', 'ember-metal/debug'], function (exports, _emberMetalDebug) { 20023 /*jshint debug:true*/ 20024 20025 /** 20026 @module ember 20027 @submodule ember-htmlbars 20028 */ 20029 20030 'use strict'; 20031 20032 exports.default = debuggerKeyword; 20033 20034 /** 20035 Execute the `debugger` statement in the current template's context. 20036 20037 ```handlebars 20038 {{debugger}} 20039 ``` 20040 20041 When using the debugger helper you will have access to a `get` function. This 20042 function retrieves values available in the context of the template. 20043 For example, if you're wondering why a value `{{foo}}` isn't rendering as 20044 expected within a template, you could place a `{{debugger}}` statement and, 20045 when the `debugger;` breakpoint is hit, you can attempt to retrieve this value: 20046 20047 ``` 20048 > get('foo') 20049 ``` 20050 20051 `get` is also aware of keywords. So in this situation 20052 20053 ```handlebars 20054 {{#each items as |item|}} 20055 {{debugger}} 20056 {{/each}} 20057 ``` 20058 20059 You'll be able to get values from the current item: 20060 20061 ``` 20062 > get('item.name') 20063 ``` 20064 20065 You can also access the context of the view to make sure it is the object that 20066 you expect: 20067 20068 ``` 20069 > context 20070 ``` 20071 20072 @method debugger 20073 @for Ember.Templates.helpers 20074 @public 20075 */ 20076 20077 function debuggerKeyword(morph, env, scope) { 20078 /* jshint unused: false, debug: true */ 20079 20080 var view = env.hooks.getValue(scope.getLocal('view')); 20081 var context = env.hooks.getValue(scope.getSelf()); 20082 20083 function get(path) { 20084 return env.hooks.getValue(env.hooks.get(env, scope, path)); 20085 } 20086 20087 _emberMetalDebug.info('Use `view`, `context`, and `get(<path>)` to debug this template.'); 20088 20089 debugger; 20090 20091 return true; 20092 } 20093}); 20094enifed('ember-htmlbars/keywords/each', ['exports'], function (exports) { 20095 /** 20096 @module ember 20097 @submodule ember-htmlbars 20098 */ 20099 20100 'use strict'; 20101 20102 exports.default = each; 20103 20104 function each(morph, env, scope, params, hash, template, inverse, visitor) { 20105 var getValue = env.hooks.getValue; 20106 var keyword = hash['-legacy-keyword'] && getValue(hash['-legacy-keyword']); 20107 20108 /* START: Support of legacy ArrayController. TODO: Remove after 1st 2.0 TLS release */ 20109 var firstParam = params[0] && getValue(params[0]); 20110 if (firstParam && firstParam._isArrayController) { 20111 env.hooks.block(morph, env, scope, '-legacy-each-with-controller', params, hash, template, inverse, visitor); 20112 return true; 20113 } 20114 /* END: Support of legacy ArrayController */ 20115 20116 if (keyword) { 20117 env.hooks.block(morph, env, scope, '-legacy-each-with-keyword', params, hash, template, inverse, visitor); 20118 return true; 20119 } 20120 20121 return false;
20122 } 20123}); 20124enifed('ember-htmlbars/keywords/element-component', ['exports', 'ember-metal/assign', 'ember-htmlbars/keywords/closure-component', 'ember-htmlbars/utils/lookup-component', 'ember-htmlbars/utils/extract-positional-params'], function (exports, _emberMetalAssign, _emberHtmlbarsKeywordsClosureComponent, _emberHtmlbarsUtilsLookupComponent, _emberHtmlbarsUtilsExtractPositionalParams) { 20125 'use strict'; 20126 20127 exports.default = { 20128 setupState: function (lastState, env, scope, params, hash) { 20129 var componentPath = getComponentPath(params[0], env); 20130 return _emberMetalAssign.default({}, lastState, { 20131 componentPath: componentPath, 20132 isComponentHelper: true 20133 }); 20134 }, 20135 20136 render: function (morph) { 20137 var state = morph.getState(); 20138 20139 if (state.manager) { 20140 state.manager.destroy(); 20141 } 20142 20143 // Force the component hook to treat this as a first-time render, 20144 // because normal components (`<foo-bar>`) cannot change at runtime, 20145 // but the `{{component}}` helper can. 20146 state.manager = null; 20147 20148 for (var _len = arguments.length, rest = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 20149 rest[_key - 1] = arguments[_key]; 20150 } 20151 20152 render.apply(undefined, [morph].concat(rest)); 20153 }, 20154 20155 rerender: render 20156 }; 20157 20158 function getComponentPath(param, env) { 20159 var path = env.hooks.getValue(param); 20160 if (_emberHtmlbarsKeywordsClosureComponent.isComponentCell(path)) { 20161 path = path[_emberHtmlbarsKeywordsClosureComponent.COMPONENT_PATH]; 20162 } 20163 return path; 20164 } 20165 20166 function render(morph, env, scope, _ref, hash, template, inverse, visitor) { 20167 var path = _ref[0]; 20168 20169 var params = _ref.slice(1); 20170 20171 var isRerender = arguments.length <= 8 || arguments[8] === undefined ? false : arguments[8]; 20172 20173 var _morph$getState = morph.getState(); 20174 20175 var componentPath = _morph$getState.componentPath; 20176 20177 // If the value passed to the {{component}} helper is undefined or null, 20178 // don't create a new ComponentNode. 20179 if (componentPath === undefined || componentPath === null) { 20180 return; 20181 } 20182 20183 path = env.hooks.getValue(path); 20184 20185 if (isRerender) { 20186 var result = _emberHtmlbarsUtilsLookupComponent.default(env.owner, componentPath); 20187 var component = result.component; 20188 20189 _emberHtmlbarsUtilsExtractPositionalParams.default(null, component, params, hash); 20190 } 20191 20192 if (_emberHtmlbarsKeywordsClosureComponent.isComponentCell(path)) { 20193 var closureComponent = env.hooks.getValue(path); 20194 20195 // This needs to be done in each nesting level to avoid raising assertions 20196 _emberHtmlbarsKeywordsClosureComponent.processPositionalParamsFromCell(closureComponent, params, hash); 20197 params = []; 20198 hash = _emberHtmlbarsKeywordsClosureComponent.mergeInNewHash(closureComponent[_emberHtmlbarsKeywordsClosureComponent.COMPONENT_HASH], hash); 20199 } 20200 20201 var templates = { default: template, inverse: inverse }; 20202 env.hooks.component(morph, env, scope, componentPath, params, hash, templates, visitor); 20203 } 20204}); 20205enifed('ember-htmlbars/keywords/get', ['exports', 'ember-metal/debug', 'ember-metal/streams/stream', 'ember-metal/streams/utils', 'ember-htmlbars/utils/subscribe', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/observer'], function (exports, _emberMetalDebug, _emberMetalStreamsStream, _emberMetalStreamsUtils, _emberHtmlbarsUtilsSubscribe, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalObserver) { 20206 /** 20207 @module ember 20208 @submodule ember-templates 20209 */ 20210 20211 'use strict'; 20212 20213 function labelFor(source, key) { 20214 var sourceLabel = source.label ? source.label : ''; 20215 var keyLabel = key.label ? key.label : ''; 20216 return '(get ' + sourceLabel + ' ' + keyLabel + ')'; 20217 } 20218 20219 var DynamicKeyStream = _emberMetalStreamsStream.default.extend({ 20220 init: function (source, keySource) { 20221 // Used to get the original path for debugging purposes. 20222 var label = labelFor(source, keySource); 20223 20224 this.label = label; 20225 this.path = label; 20226 this.sourceDep = this.addMutableDependency(source); 20227 this.keyDep = this.addMutableDependency(keySource); 20228 this.observedObject = null; 20229 this.observedKey = null; 20230 }, 20231 20232 key: function () { 20233 var key = this.keyDep.getValue(); 20234 if (typeof key === 'string') { 20235 return key; 20236 } 20237 }, 20238 20239 compute: function () { 20240 var object = this.sourceDep.getValue(); 20241 var key = this.key(); 20242 if (object && key) { 20243 return _emberMetalProperty_get.get(object, key); 20244 } 20245 }, 20246 20247 setValue: function (value) { 20248 var object = this.sourceDep.getValue(); 20249 var key = this.key(); 20250 if (object) { 20251 _emberMetalProperty_set.set(object, key, value); 20252 } 20253 }, 20254 20255 _super$revalidate: _emberMetalStreamsStream.default.prototype.revalidate, 20256 20257 revalidate: function (value) { 20258 this._super$revalidate(value); 20259 20260 var object = this.sourceDep.getValue(); 20261 var key = this.key(); 20262 if (object !== this.observedObject || key !== this.observedKey) { 20263 this._clearObservedObject(); 20264 20265 if (object && typeof object === 'object' && key) { 20266 _emberMetalObserver.addObserver(object, key, this, this.notify); 20267 this.observedObject = object; 20268 this.observedKey = key; 20269 } 20270 } 20271 }, 20272 20273 _clearObservedObject: function () { 20274 if (this.observedObject) { 20275 _emberMetalObserver.removeObserver(this.observedObject, this.observedKey, this, this.notify); 20276 this.observedObject = null; 20277 this.observedKey = null; 20278 } 20279 } 20280 }); 20281 20282 var buildStream = function buildStream(params) { 20283 var objRef = params[0]; 20284 var pathRef = params[1]; 20285 20286 _emberMetalDebug.assert('The first argument to {{get}} must be a stream', _emberMetalStreamsUtils.isStream(objRef)); 20287 _emberMetalDebug.assert('{{get}} requires at least two arguments', params.length > 1); 20288 20289 var stream = buildDynamicKeyStream(objRef, pathRef); 20290 20291 return stream; 20292 }; 20293 20294 function buildDynamicKeyStream(source, keySource) { 20295 if (!_emberMetalStreamsUtils.isStream(keySource)) { 20296 return source.get(keySource); 20297 } else { 20298 return new DynamicKeyStream(source, keySource); 20299 } 20300 } 20301 20302 /** 20303 Dynamically look up a property on an object. The second argument to `{{get}}` 20304 should have a string value, although it can be bound. 20305 20306 For example, these two usages are equivilent: 20307 20308 ```handlebars 20309 {{person.height}} 20310 {{get person "height"}} 20311 ``` 20312 20313 If there were several facts about a person, the `{{get}}` helper can dynamically 20314 pick one: 20315 20316 ```handlebars 20317 {{get person factName}} 20318 ``` 20319 20320 For a more complex example, this template would allow the user to switch 20321 between showing the user's height and weight with a click: 20322 20323 ```handlebars 20324 {{get person factName}} 20325 <button {{action (mut factName) "height"}}>Show height</button> 20326 <button {{action (mut factName) "weight"}}>Show weight</button> 20327 ``` 20328 20329 The `{{get}}` helper can also respect mutable values itself. For example: 20330 20331 ```handlebars 20332 {{input value=(mut (get person factName)) type="text"}} 20333 <button {{action (mut factName) "height"}}>Show height</button> 20334 <button {{action (mut factName) "weight"}}>Show weight</button> 20335 ``` 20336 20337 Would allow the user to swap what fact is being displayed, and also edit 20338 that fact via a two-way mutable binding. 20339 20340 @public 20341 @method get 20342 @for Ember.Templates.helpers 20343 @since 2.1.0 20344 */ 20345 function getKeyword(morph, env, scope, params, hash, template, inverse, visitor) { 20346 if (morph === null) { 20347 return buildStream(params); 20348 } else { 20349 var stream = undefined; 20350 if (morph.linkedResult) { 20351 stream = morph.linkedResult; 20352 } else { 20353 stream = buildStream(params); 20354 20355 _emberHtmlbarsUtilsSubscribe.default(morph, env, scope, stream); 20356 env.hooks.linkRenderNode(morph, env, scope, null, params, hash); 20357 20358 morph.linkedResult = stream; 20359 } 20360 env.hooks.range(morph, env, scope, null, stream, visitor); 20361 } 20362 20363 return true; 20364 } 20365 20366 exports.default = getKeyword; 20367}); 20368enifed('ember-htmlbars/keywords/input', ['exports', 'ember-metal/debug', 'ember-metal/assign'], function (exports, _emberMetalDebug, _emberMetalAssign) { 20369 /** 20370 @module ember 20371 @submodule ember-templates 20372 */ 20373 'use strict'; 20374 20375 /** 20376 The `{{input}}` helper lets you create an HTML `<input />` component.
20377 It causes an `Ember.TextField` component to be rendered. For more info, 20378 see the [Ember.TextField](/api/classes/Ember.TextField.html) docs and 20379 the [templates guide](http://emberjs.com/guides/templates/input-helpers/). 20380 20381 ```handlebars 20382 {{input value="987"}} 20383 ``` 20384 20385 renders as: 20386 20387 ```HTML 20388 <input type="text" value="987" /> 20389 ``` 20390 20391 ### Text field 20392 20393 If no `type` option is specified, a default of type 'text' is used. 20394 20395 Many of the standard HTML attributes may be passed to this helper. 20396 20397 <table> 20398 <tr><td>`readonly`</td><td>`required`</td><td>`autofocus`</td></tr> 20399 <tr><td>`value`</td><td>`placeholder`</td><td>`disabled`</td></tr> 20400 <tr><td>`size`</td><td>`tabindex`</td><td>`maxlength`</td></tr> 20401 <tr><td>`name`</td><td>`min`</td><td>`max`</td></tr> 20402 <tr><td>`pattern`</td><td>`accept`</td><td>`autocomplete`</td></tr> 20403 <tr><td>`autosave`</td><td>`formaction`</td><td>`formenctype`</td></tr> 20404 <tr><td>`formmethod`</td><td>`formnovalidate`</td><td>`formtarget`</td></tr> 20405 <tr><td>`height`</td><td>`inputmode`</td><td>`multiple`</td></tr> 20406 <tr><td>`step`</td><td>`width`</td><td>`form`</td></tr> 20407 <tr><td>`selectionDirection`</td><td>`spellcheck`</td><td> </td></tr> 20408 </table> 20409 20410 20411 When set to a quoted string, these values will be directly applied to the HTML 20412 element. When left unquoted, these values will be bound to a property on the 20413 template's current rendering context (most typically a controller instance). 20414 20415 20416 A very common use of this helper is to bind the `value` of an input to an Object's attribute: 20417 20418 ```handlebars 20419 Search: 20420 {{input value=searchWord}} 20421 ``` 20422 20423 In this example, the inital value in the `<input />` will be set to the value of `searchWord`. 20424 If the user changes the text, the value of `searchWord` will also be updated. 20425 20426 ### Actions 20427 The helper can send multiple actions based on user events. 20428 The action property defines the action which is sent when 20429 the user presses the return key. 20430 20431 ```handlebars 20432 {{input action="submit"}} 20433 ``` 20434 20435 The helper allows some user events to send actions. 20436 20437 * `enter` 20438 * `insert-newline` 20439 * `escape-press` 20440 * `focus-in` 20441 * `focus-out` 20442 * `key-press` 20443 * `key-up` 20444 20445 20446 For example, if you desire an action to be sent when the input is blurred, 20447 you only need to setup the action name to the event name property. 20448 20449 ```handlebars 20450 {{input focus-out="alertMessage"}} 20451 ``` 20452 20453 See more about [Text Support Actions](/api/classes/Ember.TextField.html) 20454 20455 20456 ### Extending `Ember.TextField` 20457 20458 Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing 20459 arguments from the helper to `Ember.TextField`'s `create` method. You can extend the 20460 capabilities of text inputs in your applications by reopening this class. For example, 20461 if you are building a Bootstrap project where `data-*` attributes are used, you 20462 can add one to the `TextField`'s `attributeBindings` property: 20463 20464 20465 ```javascript 20466 Ember.TextField.reopen({ 20467 attributeBindings: ['data-error'] 20468 }); 20469 ``` 20470 20471 Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` 20472 itself extends `Ember.Component`. Expect isolated component semantics, not 20473 legacy 1.x view semantics (like `controller` being present). 20474 20475 See more about [Ember components](/api/classes/Ember.Component.html) 20476 20477 20478 ### Checkbox 20479 20480 Checkboxes are special forms of the `{{input}}` helper. To create a `<checkbox />`: 20481 20482 ```handlebars 20483 Emberize Everything: 20484 {{input type="checkbox" name="isEmberized" checked=isEmberized}} 20485 ``` 20486 20487 This will bind checked state of this checkbox to the value of `isEmberized` -- if either one changes, 20488 it will be reflected in the other. 20489 20490 20491 The following HTML attributes can be set via the helper: 20492 20493 * `checked` 20494 * `disabled` 20495 * `tabindex` 20496 * `indeterminate` 20497 * `name` 20498 * `autofocus` 20499 * `form` 20500 20501 20502 ### Extending `Ember.Checkbox` 20503 20504 Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing 20505 arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the 20506 capablilties of checkbox inputs in your applications by reopening this class. For example, 20507 if you wanted to add a css class to all checkboxes in your application: 20508 20509 ```javascript 20510 Ember.Checkbox.reopen({ 20511 classNames: ['my-app-checkbox'] 20512 }); 20513 ``` 20514 20515 20516 @method input 20517 @for Ember.Templates.helpers 20518 @param {Hash} options 20519 @public 20520 */ 20521 exports.default = { 20522 setupState: function (lastState, env, scope, params, hash) { 20523 var type = env.hooks.getValue(hash.type); 20524 var componentName = componentNameMap[type] || defaultComponentName; 20525 20526 _emberMetalDebug.assert('{{input type=\'checkbox\'}} does not support setting `value=someBooleanValue`; ' + 'you must use `checked=someBooleanValue` instead.', !(type === 'checkbox' && hash.hasOwnProperty('value'))); 20527 20528 return _emberMetalAssign.default({}, lastState, { componentName: componentName }); 20529 }, 20530 20531 render: function (morph, env, scope, params, hash, template, inverse, visitor) { 20532 env.hooks.component(morph, env, scope, morph.getState().componentName, params, hash, { default: template, inverse: inverse }, visitor); 20533 }, 20534 20535 rerender: function () { 20536 this.render.apply(this, arguments); 20537 } 20538 }; 20539 20540 var defaultComponentName = '-text-field'; 20541 20542 var componentNameMap = { 20543 'checkbox': '-checkbox' 20544 }; 20545}); 20546enifed('ember-htmlbars/keywords/legacy-yield', ['exports', 'ember-metal/stream
20546s/proxy-stream'], function (exports, _emberMetalStreamsProxyStream) { 20547 'use strict'; 20548 20549 exports.default = legacyYield; 20550 20551 function legacyYield(morph, env, _scope, params, hash, template, inverse, visitor) { 20552 var scope = _scope; 20553 var block = scope.getBlock('default'); 20554 20555 if (block.arity === 0) { 20556 // Typically, the `controller` local persists through lexical scope. 20557 // However, in this case, the `{{legacy-yield}}` in the legacy each view 20558 // needs to override the controller local for the template it is yielding. 20559 // This megahaxx allows us to override the controller, and most importantly, 20560 // prevents the downstream scope from attempting to bind the `controller` local. 20561 if (hash.controller) { 20562 scope = env.hooks.createChildScope(scope); 20563 scope.bindLocal('controller', new _emberMetalStreamsProxyStream.default(hash.controller, 'controller')); 20564 scope.overrideController = true; 20565 } 20566 block.invoke(env, [], params[0], morph, scope, visitor); 20567 } else { 20568 block.invoke(env, params, undefined, morph, scope, visitor); 20569 } 20570 20571 return true; 20572 } 20573}); 20574enifed('ember-htmlbars/keywords/mut', ['exports', 'ember-metal/debug', 'ember-metal/symbol', 'ember-metal/streams/proxy-stream', 'ember-metal/streams/stream', 'ember-metal/streams/utils', 'ember-views/compat/attrs-proxy', 'ember-routing-htmlbars/keywords/closure-action'], function (exports, _emberMetalDebug, _emberMetalSymbol, _emberMetalStreamsProxyStream, _emberMetalStreamsStream, _emberMetalStreamsUtils, _emberViewsCompatAttrsProxy, _emberRoutingHtmlbarsKeywordsClosureAction) { 20575 /** 20576 @module ember 20577 @submodule ember-templates 20578 */ 20579 20580 'use strict'; 20581 20582 var _ProxyStream$extend; 20583 20584 exports.default = mut; 20585 exports.privateMut = privateMut; 20586 var MUTABLE_REFERENCE = _emberMetalSymbol.default('MUTABLE_REFERENCE'); 20587 20588 exports.MUTABLE_REFERENCE = MUTABLE_REFERENCE; 20589 var MutStream = _emberMetalStreamsProxyStream.default.extend((_ProxyStream$extend = { 20590 init: function (stream) { 20591 this.label = '(mut ' + stream.label + ')'; 20592 this.path = stream.path; 20593 this.sourceDep = this.addMutableDependency(stream); 20594 this[MUTABLE_REFERENCE] = true; 20595 }, 20596 20597 cell: function () { 20598 var source = this; 20599 var value = source.value(); 20600 20601 if (value && value[_emberRoutingHtmlbarsKeywordsClosureAction.ACTION]) { 20602 return value; 20603 } 20604 20605 var val = { 20606 value: value, 20607 update: function (val) { 20608 source.setValue(val); 20609 } 20610 }; 20611 20612 val[_emberViewsCompatAttrsProxy.MUTABLE_CELL] = true; 20613 return val; 20614 } 20615 }, _ProxyStream$extend[_emberRoutingHtmlbarsKeywordsClosureAction.INVOKE] = function (val) { 20616 this.setValue(val); 20617 }, _ProxyStream$extend)); 20618 20619 /** 20620 The `mut` helper lets you __clearly specify__ that a child `Component` can update the 20621 (mutable) value passed to it, which will __change the value of the parent component__. 20622 20623 This is very helpful for passing mutable values to a `Component` of any size, but 20624 critical to understanding the logic of a large/complex `Component`. 20625 20626 To specify that a parameter is mutable, when invoking the child `Component`: 20627 20628 ```handlebars 20629 {{my-child childClickCount=(mut totalClicks)}} 20630 ``` 20631 20632 The child `Component` can then modify the parent's value as needed: 20633 20634 ```javascript 20635 // my-child.js 20636 export default Component.extend({ 20637 click() { 20638 this.get('childClickCount').update(this.get('childClickCount').value + 1); 20639 } 20640 }); 20641 ``` 20642 20643 Additionally, the `mut` helper can be combined with the `action` helper to 20644 mutate a value. For example: 20645 20646 ```handlebars 20647 {{my-child childClickCount=totalClicks click-count-change=(action (mut "totalClicks"))}} 20648 ``` 20649 20650 The child `Component` would invoke the action with the new click value: 20651 20652 ```javascript 20653 // my-child.js 20654 export default Component.extend({ 20655 click() { 20656 this.get('clickCountChange')(this.get('childClickCount') + 1); 20657 } 20658 }); 20659 ``` 20660 20661 The `mut` helper changes the `totalClicks` value to what was provided as the action argument. 20662 20663 See a [2.0 blog post](http://emberjs.com/blog/2015/05/10/run-up-to-two-oh.html#toc_the-code-mut-code-helper) for 20664 additional information on using `{{mut}}`. 20665 20666 @public 20667 @method mut 20668 @param {Object} [attr] the "two-way" attribute that can be modified. 20669 @for Ember.Templates.helpers 20670 @public 20671 */ 20672 20673 function mut(morph, env, scope, originalParams, hash, template, inverse) { 20674 // If `morph` is `null` the keyword is being invoked as a subexpression. 20675 if (morph === null) { 20676 var valueStream = originalParams[0]; 20677 return mutParam(env.hooks.getValue, valueStream); 20678 } 20679 20680 return true; 20681 } 20682 20683 function privateMut(morph, env, scope, originalParams, hash, template, inverse) { 20684 // If `morph` is `null` the keyword is being invoked as a subexpression. 20685 if (morph === null) { 20686 var valueStream = originalParams[0]; 20687 return mutParam(env.hooks.getValue, valueStream, true); 20688 } 20689 20690 return true; 20691 } 20692 20693 var LiteralStream = _emberMetalStreamsStream.default.extend({ 20694 init: function (literal) { 20695 this.literal = literal; 20696 this.label = '(literal ' + literal + ')'; 20697 }, 20698 20699 compute: function () { 20700 return this.literal; 20701 }, 20702 20703 setValue: function (val) { 20704 this.literal = val; 20705 this.notify(); 20706 } 20707 }); 20708 20709 function mutParam(read, stream, internal) { 20710 if (internal) { 20711 if (!_emberMetalStreamsUtils.isStream(stream)) { 20712 var literal = stream; 20713 stream = new LiteralStream(literal); 20714 } 20715 } else { 20716 _emberMetalDebug.assert('You can only pass a path to mut', _emberMetalStreamsUtils.isStream(stream)); 20717 } 20718 20719 if (stream[MUTABLE_REFERENCE]) { 20720 return stream; 20721 } 20722 20723 return new MutStream(stream); 20724 } 20725}); 20726enifed('ember-htmlbars/keywords/outlet', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-htmlbars/node-managers/view-node-manager', 'ember-htmlbars/templates/top-level-view', 'ember-metal/features'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberHtmlbarsNodeManagersViewNodeManager, _emberHtmlbarsTemplatesTopLevelView, _emberMetalFeatures) { 20727 /** 20728 @module ember 20729 @submodule ember-templates 20730 */ 20731 20732 'use strict'; 20733 20734 _emberHtmlbarsTemplatesTopLevelView.default.meta.revision = '[email protected]'; 20735 20736 /** 20737 The `{{outlet}}` helper lets you specify where a child route will render in 20738 your template. An important use of the `{{outlet}}` helper is in your 20739 application's `application.hbs` file: 20740 20741 ```handlebars 20742 {{! app/templates/application.hbs }} 20743 20744 <!-- header content goes here, and will always display --> 20745 {{my-header}} 20746 20747 <div class="my-dynamic-content"> 20748 <!-- this content will change based on the current route, which depen
20748ds on the current URL --> 20749 {{outlet}} 20750 </div> 20751 20752 <!-- footer content goes here, and will always display --> 20753 {{my-footer}} 20754 ``` 20755 20756 See [templates guide](http://emberjs.com/guides/templates/the-application-template/) for 20757 additional information on using `{{outlet}}` in `application.hbs`. 20758 20759 You may also specify a name for the `{{outlet}}`, which is useful when using more than one 20760 `{{outlet}}` in a template: 20761 20762 ```handlebars 20763 {{outlet "menu"}} 20764 {{outlet "sidebar"}} 20765 {{outlet "main"}} 20766 ``` 20767 20768 Your routes can then render into a specific one of these `outlet`s by specifying the `outlet` 20769 attribute in your `renderTemplate` function: 20770 20771 ```javascript 20772
20772// app/routes/menu.js 20773 20774 export default Ember.Route.extend({ 20775 renderTemplate() { 20776 this.render({ outlet: 'menu' }); 20777 } 20778 }); 20779 ``` 20780 20781 See the [routing guide](http://emberjs.com/guides/routing/rendering-a-template/) for more 20782 information on how your `route` interacts with the `{{outlet}}` helper. 20783 20784 Note: Your content __will not render__ if there isn't an `{{outlet}}` for it. 20785 20786 @public 20787 @method outlet 20788 @param {String} [name] 20789 @for Ember.Templates.helpers 20790 @public 20791 */ 20792 exports.default = { 20793 willRender: function (renderNode, env) { 20794 env.view.ownerView._outlets.push(renderNode); 20795 }, 20796 20797 setupState: function (state, env, scope, params, hash) { 20798 var outletState = env.outletState; 20799 var read = env.hooks.getValue; 20800 var outletName = read(params[0]) || 'main'; 20801 var selectedOutletState = outletState[outletName]; 20802 20803 var toRender = selectedOutletState && selectedOutletState.render; 20804 if (toRender && !toRender.template && !toRender.ViewClass) { 20805 toRender.template = _emberHtmlbarsTemplatesTopLevelView.default; 20806 } 20807 20808 return { 20809 outletState: selectedOutletState, 20810 hasParentOutlet: env.hasParentOutlet, 20811 manager: state.manager 20812 }; 20813 }, 20814 20815 childEnv: function (state, env) { 20816 var outletState = state.outletState; 20817 var toRender = outletState && outletState.render; 20818 var meta = toRender && toRender.template && toRender.template.meta; 20819 20820 return env.childWithOutletState(outletState && outletState.outlets, true, meta); 20821 }, 20822 20823 isStable: function (lastState, nextState) { 20824 return isStable(lastState.outletState, nextState.outletState); 20825 }, 20826 20827 isEmpty: function (state) { 20828 return isEmpty(state.outletState); 20829 }, 20830 20831 render: function (renderNode, env, scope, params, hash, template, inverse, visitor) { 20832 var state = renderNode.getState(); 20833 var parentView = env.view; 20834 var outletState = state.outletState; 20835 var toRender = outletState.render; 20836 var namespace = env.owner.lookup('application:main'); 20837 var LOG_VIEW_LOOKUPS = _emberMetalProperty_get.get(namespace, 'LOG_VIEW_LOOKUPS'); 20838 20839 var ViewClass = outletState.render.ViewClass; 20840 20841 if (!state.hasParentOutlet && !ViewClass) { 20842 ViewClass = env.owner._lookupFactory('view:toplevel'); 20843 } 20844 20845 var Component; 20846 20847 var options; 20848 var attrs = {}; 20849 if (Component) { 20850 options = { 20851 component: Component 20852 }; 20853 attrs = toRender.attrs; 20854 } else { 20855 options = { 20856 component: ViewClass, 20857 self: toRender.controller, 20858 createOptions: { 20859 controller: toRender.controller 20860 } 20861 }; 20862 20863 template = template || toRender.template && toRender.template.raw; 20864 20865 if (LOG_VIEW_LOOKUPS && ViewClass) { 20866 _emberMetalDebug.info('Rendering ' + toRender.name + ' with ' + ViewClass, { fullName: 'view:' + toRender.name }); 20867 } 20868 } 20869 20870 if (state.manager) { 20871 state.manager.destroy(); 20872 state.manager = null; 20873 } 20874 20875 var nodeManager = _emberHtmlbarsNodeManagersViewNodeManager.default.create(renderNode, env, attrs, options, parentView, null, null, template); 20876 state.manager = nodeManager; 20877 20878 nodeManager.render(env, hash, visitor); 20879 } 20880 }; 20881 20882 function isEmpty(outletState) { 20883 return !outletState || !outletState.render.ViewClass && !outletState.render.template; 20884 } 20885 20886 function isStable(a, b) { 20887 if (!a && !b) { 20888 return true; 20889 } 20890 if (!a || !b) { 20891 return false; 20892 } 20893 a = a.render; 20894 b = b.render; 20895 for (var key in a) { 20896 if (a.hasOwnProperty(key)) { 20897 // Name is only here for logging & debugging. If two different 20898 // names result in otherwise identical states, they're still 20899 // identical. 20900 if (a[key] !== b[key] && key !== 'name') { 20901 return false; 20902 } 20903 } 20904 } 20905 return true; 20906 } 20907}); 20908enifed('ember-htmlbars/keywords/partial', ['exports', 'ember-views/system/lookup_partial', 'htmlbars-runtime'], function (exports, _emberViewsSystemLookup_partial, _htmlbarsRuntime) { 20909 /** 20910 @module ember 20911 @submodule ember-templates 20912 */ 20913 20914 'use strict'; 20915 20916 /** 20917 The `partial` helper renders another template without 20918 changing the template context: 20919 20920 ```handlebars 20921 {{foo}} 20922 {{partial "nav"}} 20923 ``` 20924 20925 The above example template will render a template named 20926 "_nav", which has the same context as the parent template 20927 it's rendered into, so if the "_nav" template also referenced 20928 `{{foo}}`, it would print the same thing as the `{{foo}}` 20929 in the above example. 20930 20931 If a "_nav" template isn't found, the `partial` helper will 20932 fall back to a template named "nav". 20933 20934 ### Bound template names 20935 20936 The parameter supplied to `partial` can also be a path 20937 to a property containing a template name, e.g.: 20938 20939 ```handlebars 20940 {{partial someTemplateName}} 20941 ``` 20942 20943 The above example will look up the value of `someTemplateName` 20944 on the template context (e.g. a controller) and use that 20945 value as the name of the template to render. If the resolved 20946 value is falsy, nothing will be rendered. If `someTemplateName` 20947 changes, the partial will be re-rendered using the new template 20948 name. 20949 20950 20951 @method partial 20952 @for Ember.Templates.helpers 20953 @param {String} partialName The name of the template to render minus the leading underscore. 20954 @public 20955 */ 20956 20957 exports.default = { 20958 setupState: function (state, env, scope, params, hash) { 20959 return { partialName: env.hooks.getValue(params[0]) }; 20960 }, 20961 20962 render: function (renderNode, env, scope, params, hash, template, inverse, visitor) { 20963 var state = renderNode.getState(); 20964 if (!state.partialName) { 20965 return true; 20966 } 20967 var found = _emberViewsSystemLookup_partial.default(env, state.partialName); 20968 if (!found) { 20969 return true; 20970 } 20971 20972 _htmlbarsRuntime.internal.hostBlock(renderNode, env, scope, found.raw, null, null, visitor, function (options) { 20973 options.templates.template.yield(); 20974 }); 20975 } 20976 }; 20977}); 20978enifed('ember-htmlbars/keywords/readonly', ['exports', 'ember-htmlbars/keywords/mut'], function (exports, _emberHtmlbarsKeywordsMut) { 20979 /** 20980 @module ember 20981 @submodule ember-templates 20982 */ 20983 20984 'use strict'; 20985 20986 exports.default = readonly; 20987 20988 function readonly(morph, env, scope, originalParams, hash, template, inverse) { 20989 // If `morph` is `null` the keyword is being invoked as a subexpression. 20990 if (morph === null) { 20991 var stream = originalParams[0]; 20992 if (stream && stream[_emberHtmlbarsKeywordsMut.MUTABLE_REFERENCE]) { 20993 return stream.sourceDep.dependee; 20994 } 20995 return stream; 20996 } 20997 20998 return true; 20999 } 21000}); 21001enifed('ember-htmlbars/keywords/textarea', ['exports'], function (exports) { 21002 /** 21003 @module ember 21004 @submodule ember-templates 21005 */ 21006 21007 /** 21008 `{{textarea}}` inserts a new instance of `<textarea>` tag into the template. 21009 The attributes of `{{textarea}}` match those of the native HTML tags as 21010 closely as possible. 21011 21012 The following HTML attributes can be set: 21013 21014 * `value` 21015 * `name` 21016 * `rows` 21017 * `cols` 21018 * `placeholder` 21019 * `disabled` 21020 * `maxlength` 21021 * `tabindex` 21022 * `selectionEnd` 21023 * `selectionStart` 21024 * `selectionDirection` 21025 * `wrap` 21026 * `readonly` 21027 * `autofocus` 21028 * `form` 21029 * `spellcheck` 21030 * `required` 21031 21032 When set to a quoted string, these value will be directly applied to the HTML 21033 element. When left unquoted, these values will be bound to a property on the 21034 template's current rendering context (most typically a controller instance). 21035 21036 Unbound: 21037 21038 ```handlebars 21039 {{textarea value="Lots of static text that ISN'T bound"}} 21040 ``` 21041 21042 Would result in the following HTML: 21043 21044 ```html 21045 <textarea class="ember-text-area"> 21046 Lots of static text that ISN'T bound 21047 </textarea> 21048 ``` 21049 21050 Bound: 21051 21052 In the following example, the `writtenWords` property on `App.ApplicationController` 21053 will be updated live as the user types 'Lots of text that IS bound' into 21054 the text area of their browser's window. 21055 21056 ```javascript 21057 App.ApplicationController = Ember.Controller.extend({
21058 writtenWords: "Lots of text that IS bound" 21059 }); 21060 ``` 21061 21062 ```handlebars 21063 {{textarea value=writtenWords}} 21064 ``` 21065 21066 Would result in the following HTML: 21067 21068 ```html 21069 <textarea class="ember-text-area"> 21070 Lots of text that IS bound 21071 </textarea> 21072 ``` 21073 21074 If you wanted a one way binding between the text area and a div tag 21075 somewhere else on your screen, you could use `Ember.computed.oneWay`: 21076 21077 ```javascript 21078 App.ApplicationController = Ember.Controller.extend({ 21079 writtenWords: "Lots of text that IS bound", 21080 outputWrittenWords: Ember.computed.oneWay("writtenWords") 21081 }); 21082 ``` 21083 21084 ```handlebars 21085 {{textarea value=writtenWords}} 21086 21087 <div> 21088 {{outputWrittenWords}} 21089 </div> 21090 ``` 21091 21092 Would result in the following HTML: 21093 21094 ```html 21095 <textarea class="ember-text-area"> 21096 Lots of text that IS bound 21097 </textarea> 21098 21099 <-- the following div will be updated in real time as you type --> 21100 21101 <div> 21102 Lots of text that IS bound 21103 </div> 21104 ``` 21105 21106 Finally, this example really shows the power and ease of Ember when two 21107 properties are bound to eachother via `Ember.computed.alias`. Type into 21108 either text area box and they'll both stay in sync. Note that 21109 `Ember.computed.alias` costs more in terms of performance, so only use it when 21110 your really binding in both directions: 21111 21112 ```javascript 21113 App.ApplicationController = Ember.Controller.extend({ 21114 writtenWords: "Lots of text that IS bound", 21115 twoWayWrittenWords: Ember.computed.alias("writtenWords") 21116 }); 21117 ``` 21118 21119 ```handlebars 21120 {{textarea value=writtenWords}} 21121 {{textarea value=twoWayWrittenWords}} 21122 ``` 21123 21124 ```html 21125 <textarea id="ember1" class="ember-text-area"> 21126 Lots of text that IS bound 21127 </textarea> 21128 21129 <-- both updated in real time --> 21130 21131 <textarea id="ember2" class="ember-text-area"> 21132 Lots of text that IS bound 21133 </textarea> 21134 ``` 21135 21136 ### Actions 21137 21138 The helper can send multiple actions based on user events. 21139 21140 The action property defines the action which is send when 21141 the user presses the return key. 21142 21143 ```handlebars 21144 {{input action="submit"}} 21145 ``` 21146 21147 The helper allows some user events to send actions. 21148 21149 * `enter` 21150 * `insert-newline` 21151 * `escape-press` 21152 * `focus-in` 21153 * `focus-out` 21154 * `key-press` 21155 21156 For example, if you desire an action to be sent when the input is blurred, 21157 you only need to setup the action name to the event name property. 21158 21159 ```handlebars 21160 {{textarea focus-in="alertMessage"}} 21161 ``` 21162 21163 See more about [Text Support Actions](/api/classes/Ember.TextArea.html) 21164 21165 ### Extension 21166 21167 Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing 21168 arguments from the helper to `Ember.TextArea`'s `create` method. You can 21169 extend the capabilities of text areas in your application by reopening this 21170 class. For example, if you are building a Bootstrap project where `data-*` 21171 attributes are used, you can globally add support for a `data-*` attribute 21172 on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or 21173 `Ember.TextSupport` and adding it to the `attributeBindings` concatenated 21174 property: 21175 21176 ```javascript 21177 Ember.TextArea.reopen({ 21178 attributeBindings: ['data-error'] 21179 }); 21180 ``` 21181 21182 Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` 21183 itself extends `Ember.Component`. Expect isolated component semantics, not 21184 legacy 1.x view semantics (like `controller` being present). 21185 21186 See more about [Ember components](/api/classes/Ember.Component.html) 21187 21188 @method textarea 21189 @for Ember.Templates.helpers 21190 @param {Hash} options 21191 @public 21192 */ 21193 'use strict'; 21194 21195 exports.default = textarea; 21196 21197 function textarea(morph, env, scope, originalParams, hash, template, inverse, visitor) { 21198 env.hooks.component(morph, env, scope, '-text-area', originalParams, hash, { default: template, inverse: inverse }, visitor); 21199 return true; 21200 } 21201}); 21202enifed('ember-htmlbars/keywords/unbound', ['exports', 'ember-metal/debug', 'ember-metal/stream
21202s/stream', 'ember-metal/streams/utils'], function (exports, _emberMetalDebug, _emberMetalStreamsStream, _emberMetalStreamsUtils) { 21203 /** 21204 @module ember 21205 @submodule ember-templates 21206 */ 21207 21208 'use strict'; 21209 21210 exports.default = unbound; 21211 21212 /** 21213 The `{{unbound}}` helper disconnects the one-way binding of a property, 21214 essentially freezing its value at the moment of rendering. For example, 21215 in this example the display of the variable `name` will not change even 21216 if it is set with a new value: 21217 21218 ```handlebars 21219 {{unbound name}} 21220 ``` 21221 21222 Like any helper, the `unbound` helper can accept a nested helper expression. 21223 This allows for custom helpers to be rendered unbound: 21224 21225 ```handlebars 21226 {{unbound (some-custom-helper)}} 21227 {{unbound (capitalize name)}} 21228 {{! You can use any helper, including unbound, in a nested expression }} 21229 {{capitalize (unbound name)}} 21230 ``` 21231 21232 The `unbound` helper only accepts a single argument, and it return an 21233 unbound value. 21234 21235 @method unbound 21236 @for Ember.Templates.helpers 21237 @public 21238 */ 21239 21240 var VolatileStream = _emberMetalStreamsStream.default.extend({ 21241 init: function (source) { 21242 this.label = '(volatile ' + source.label + ')'; 21243 this.source = source; 21244 this.addDependency(source); 21245 }, 21246 21247 value: function () { 21248 return _emberMetalStreamsUtils.read(this.source); 21249 }, 21250 21251 notify: function () {} 21252 }); 21253 21254 function unbound(morph, env, scope, params, hash, template, inverse, visitor) { 21255 _emberMetalDebug.assert('unbound helper cannot be called with multiple params or hash params', params.length === 1 && Object.keys(hash).length === 0); 21256 _emberMetalDebug.assert('unbound helper cannot be called as a block', !template); 21257 21258 if (morph === null) { 21259 return new VolatileStream(params[0]); 21260 } 21261 21262 var stream = undefined; 21263 if (morph.linkedResult) { 21264 stream = morph.linkedResult; 21265 } else { 21266 stream = new VolatileStream(params[0]); 21267 morph.linkedResult = stream; 21268 } 21269 env.hooks.range(morph, env, scope, null, stream, visitor); 21270 return true; 21271 } 21272}); 21273enifed('ember-htmlbars/keywords/view', ['exports', 'ember-views/streams/utils', 'ember-views/views/view', 'ember-htmlbars/node-managers/view-node-manager'], function (exports, _emberViewsStreamsUtils, _emberViewsViewsView, _emberHtmlbarsNodeManagersViewNodeManager) { 21274 /** 21275 @module ember 21276 @submodule ember-templates 21277 */ 21278 21279 'use strict'; 21280 21281 /** 21282 `{{view}}` inserts a new instance of an `Ember.View` into a template passing its 21283 options to the `Ember.View`'s `create` method and using the supplied block as 21284 the view's own template. 21285 21286 An empty `<body>` and the following template: 21287 21288 ```handlebars 21289 A span: 21290 {{#view tagName="span"}} 21291 hello. 21292 {{/view}} 21293 ``` 21294 21295 Will result in HTML structure: 21296 21297 ```html 21298 <body> 21299 <!-- Note: the handlebars template script 21300 also results in a rendered Ember.View 21301 which is the outer <div> here --> 21302 21303 <div class="ember-view"> 21304 A span: 21305 <span id="ember1" class="ember-view"> 21306 Hello. 21307 </span> 21308 </div> 21309 </body> 21310 ``` 21311 21312 ### `parentView` setting 21313 21314 The `parentView` property of the new `Ember.View` instance created through 21315 `{{view}}` will be set to the `Ember.View` instance of the template where 21316 `{{view}}` was called. 21317 21318 ```javascript 21319 aView = Ember.View.create({ 21320 template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") 21321 }); 21322 21323 aView.appendTo('body'); 21324 ``` 21325 21326 Will result in HTML structure: 21327 21328 ```html 21329 <div id="ember1" class="ember-view"> 21330 <div id="ember2" class="ember-view"> 21331 my parent: ember1 21332 </div> 21333 </div> 21334 ``` 21335 21336 ### Setting CSS id and class attributes 21337 21338 The HTML `id` attribute can be set on the `{{view}}`'s resulting element with 21339 the `id` option. This option will _not_ be passed to `Ember.View.create`. 21340 21341 ```handlebars 21342 {{#view tagName="span" id="a-custom-id"}} 21343 hello. 21344 {{/view}} 21345 ``` 21346 21347 Results in the following HTML structure: 21348 21349 ```html 21350 <div class="ember-view">
21351 <span id="a-custom-id" class="ember-view"> 21352 hello. 21353 </span> 21354 </div> 21355 ``` 21356 21357 The HTML `class` attribute can be set on the `{{view}}`'s resulting element 21358 with the `class` or `classNameBindings` options. The `class` option will 21359 directly set the CSS `class` attribute and will not be passed to 21360 `Ember.View.create`. `classNameBindings` will be passed to `create` and use 21361 `Ember.View`'s class name binding functionality: 21362 21363 ```handlebars 21364 {{#view tagName="span" class="a-custom-class"}} 21365 hello. 21366 {{/view}} 21367 ``` 21368 21369 Results in the following HTML structure: 21370 21371 ```html 21372 <div class="ember-view"> 21373 <span id="ember2" class="ember-view a-custom-class"> 21374 hello. 21375 </span> 21376 </div> 21377 ``` 21378 21379 ### Supplying a different view class 21380 21381 `{{view}}` can take an optional first argument before its supplied options to 21382 specify a path to a custom view class. 21383 21384 ```handlebars 21385 {{#view "custom"}}{{! will look up App.CustomView }} 21386 hello. 21387 {{/view}} 21388 ``` 21389 21390 The first argument can also be a relative path accessible from the current 21391 context. 21392 21393 ```javascript 21394 MyApp = Ember.Application.create({}); 21395 MyApp.OuterView = Ember.View.extend({ 21396 innerViewClass: Ember.View.extend({ 21397 classNames: ['a-custom-view-class-as-property'] 21398 }), 21399 template: Ember.Handlebars.compile('{{#view view.innerViewClass}} hi {{/view}}') 21400 }); 21401 21402 MyApp.OuterView.create().appendTo('body'); 21403 ``` 21404 21405 Will result in the following HTML: 21406 21407 ```html 21408 <div id="ember1" class="ember-view"> 21409 <div id="ember2" class="ember-view a-custom-view-class-as-property"> 21410 hi 21411 </div> 21412 </div> 21413 ``` 21414 21415 ### Blockless use 21416 21417 If you supply a custom `Ember.View` subclass that specifies its own template 21418 or provide a `templateName` option to `{{view}}` it can be used without 21419 supplying a block. Attempts to use both a `templateName` option and supply a 21420 block will throw an error. 21421 21422 ```javascript 21423 var App = Ember.Application.create(); 21424 App.WithTemplateDefinedView = Ember.View.extend({ 21425 templateName: 'defined-template' 21426 }); 21427 ``` 21428 21429 ```handlebars 21430 {{! application.hbs }} 21431 {{view 'with-template-defined'}} 21432 ``` 21433 21434 ```handlebars 21435 {{! defined-template.hbs }} 21436 Some content for the defined template view. 21437 ``` 21438 21439 ### `viewName` property 21440 21441 You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance 21442 will be referenced as a property of its parent view by this name. 21443 21444 ```javascript 21445 aView = Ember.View.create({ 21446 template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') 21447 }); 21448 21449 aView.appendTo('body'); 21450 aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper 21451 ``` 21452 21453 @method view 21454 @for Ember.Templates.helpers 21455 @public 21456 @deprecated 21457 */ 21458 21459 exports.default = { 21460 setupState: function (state, env, scope, params, hash) { 21461 var read = env.hooks.getValue; 21462 var targetObject = read(scope.getSelf()); 21463 var viewClassOrInstance = state.viewClassOrInstance; 21464 if (!viewClassOrInstance) { 21465 viewClassOrInstance = getView(read(params[0]), env.owner); 21466 } 21467 21468 // if parentView exists, use its controller (the default 21469 // behavior), otherwise use `scope.self` as the controller 21470 var controller = scope.hasLocal('view') ? null : read(scope.getSelf()); 21471 21472 return { 21473 manager: state.manager, 21474 parentView: env.view, 21475 controller: controller, 21476 targetObject: targetObject, 21477 viewClassOrInstance: viewClassOrInstance 21478 }; 21479 }, 21480 21481 rerender: function (morph, env, scope, params, hash, template, inverse, visitor) { 21482 // If the hash is empty, the component cannot have extracted a part 21483 // of a mutable param and used it in its layout, because there are 21484 // no params at all. 21485 if (Object.keys(hash).length) { 21486 return morph.getState().manager.rerender(env, hash, visitor, true); 21487 } 21488 }, 21489 21490 render: function (node, env, scope, params, hash, template, inverse, visitor) { 21491 if (hash.tag) { 21492 hash = swapKey(hash, 'tag', 'tagName'); 21493 } 21494 21495 if (hash.classNameBindings) { 21496 hash.classNameBindings = hash.classNameBindings.split(' '); 21497 } 21498 21499 var state = node.getState(); 21500 var parentView = state.parentView; 21501 21502 var options = { 21503 component: state.viewClassOrInstance, 21504 layout: null 21505 }; 21506 21507 options.createOptions = {}; 21508 if (state.controller) { 21509 // Use `_controller` to avoid stomping on a CP 21510 // that exists in the target view/component 21511 options.createOptions._controller = state.controller; 21512 } 21513 21514 if (state.targetObject) { 21515 // Use `_targetObject` to avoid stomping on a CP 21516 // that exists in the target view/component 21517 options.createOptions._targetObject = state.targetObject; 21518 } 21519 21520 if (state.manager) { 21521 state.manager.destroy(); 21522 state.manager = null; 21523 } 21524 21525 var nodeManager = _emberHtmlbarsNodeManagersViewNodeManager.default.create(node, env, hash, options, parentView, null, scope, template); 21526 state.manager = nodeManager; 21527 21528 nodeManager.render(env, hash, visitor); 21529 } 21530 }; 21531 21532 function getView(viewPath, owner) { 21533 var viewClassOrInstance; 21534 21535 if (!viewPath) { 21536 if (owner) { 21537 viewClassOrInstance = owner._lookupFactory('view:toplevel'); 21538 } else { 21539 viewClassOrInstance = _emberViewsViewsView.default; 21540 } 21541 } else {
21542 viewClassOrInstance = _emberViewsStreamsUtils.readViewFactory(viewPath, owner); 21543 } 21544 21545 return viewClassOrInstance; 21546 } 21547 21548 function swapKey(hash, original, update) { 21549 var newHash = {}; 21550 21551 for (var prop in hash) { 21552 if (prop === original) { 21553 newHash[update] = hash[prop]; 21554 } else { 21555 newHash[prop] = hash[prop]; 21556 } 21557 } 21558 21559 return newHash; 21560 } 21561}); 21562enifed('ember-htmlbars/keywords/with', ['exports', 'ember-metal/debug', 'htmlbars-runtime'], function (exports, _emberMetalDebug, _htmlbarsRuntime) { 21563 /** 21564 @module ember 21565 @submodule ember-templates 21566 */ 21567 21568 'use strict'; 21569 21570 exports.default = { 21571 isStable: function () { 21572 return true; 21573 }, 21574 21575 isEmpty: function (state) { 21576 return false; 21577 }, 21578 21579 render: function (morph, env, scope, params, hash, template, inverse, visitor) { 21580 _emberMetalDebug.assert('{{#with foo}} must be called with a single argument or the use the ' + '{{#with foo as |bar|}} syntax', params.length === 1); 21581 21582 _emberMetalDebug.assert('The {{#with}} helper must be called with a block', !!template); 21583 21584 _htmlbarsRuntime.internal.continueBlock(morph, env, scope, 'with', params, hash, template, inverse, visitor); 21585 }, 21586 21587 rerender: function (morph, env, scope, params, hash, template, inverse, visitor) { 21588 _htmlbarsRuntime.internal.continueBlock(morph, env, scope, 'with', params, hash, template, inverse, visitor); 21589 } 21590 }; 21591}); 21592enifed('ember-htmlbars/keywords/yield', ['exports'], function (exports) { 21593 'use strict'; 21594 21595 exports.default = yieldKeyword; 21596 21597 function yieldKeyword(morph, env, scope, params, hash, template, inverse, visitor) { 21598 var to = env.hooks.getValue(hash.to) || 'default'; 21599 var block = scope.getBlock(to); 21600 21601 if (block) { 21602 block.invoke(env, params, hash.self, morph, scope, visitor); 21603 } 21604 21605 return true; 21606 } 21607}); 21608enifed('ember-htmlbars/keywords', ['exports', 'htmlbars-runtime'], function (exports, _htmlbarsRuntime) { 21609 /** 21610 @module ember 21611 @submodule ember-htmlbars 21612 */ 21613 21614 'use strict'; 21615 21616 exports.registerKeyword = registerKeyword; 21617 21618 /** 21619 @private 21620 @property helpers 21621 */ 21622 var keywords = Object.create(_htmlbarsRuntime.hooks.keywords); 21623 21624 /** 21625 @module ember 21626 @submodule ember-htmlbars 21627 */ 21628 21629 /** 21630 @private 21631 @method _registerHelper 21632 @for Ember.HTMLBars 21633 @param {String} name 21634 @param {Object|Function} keyword The keyword to add. 21635 */ 21636 21637 function registerKeyword(name, keyword) { 21638 keywords[name] = keyword; 21639 } 21640 21641 exports.default = keywords; 21642}); 21643enifed('ember-htmlbars/morphs/attr-morph', ['exports', 'ember-metal/debug', 'dom-helper', 'ember-metal/is_none'], function (exports, _emberMetalDebug, _domHelper, _emberMetalIs_none) { 21644 'use strict'; 21645 21646 var HTMLBarsAttrMorph = _domHelper.default.prototype.AttrMorphClass; 21647 21648 var styleWarning = '' + 'Binding style attributes may introduce cross-site scripting vulnerabilities; ' + 'please ensure that values being bound are properly escaped. For more information, ' + 'including how to disable this warning, see ' + 'http://emberjs.com/deprecations/v1.x/#toc_binding-style-attributes.'; 21649 21650 exports.styleWarning = styleWarning; 21651 var proto = HTMLBarsAttrMorph.prototype; 21652 21653 proto.didInit = function () { 21654 this.streamUnsubscribers = null; 21655 21656 _emberMetalDebug.debugSeal(this); 21657 }; 21658 21659 function deprecateEscapedStyle(morph, value) { 21660 _emberMetalDebug.warn(styleWarning, (function (name, value, escaped) { 21661 // SafeString 21662 if (_emberMetalIs_none.default(value) || value && value.toHTML) { 21663 return true; 21664 } 21665 21666 if (name !== 'style') { 21667 return true; 21668 } 21669 21670 return !escaped; 21671 })(morph.attrName, value, morph.escaped), { id: 'ember-htmlbars.style-xss-warning' }); 21672 } 21673 21674 proto.willSetContent = function (value) { 21675 deprecateEscapedStyle(this, value); 21676 }; 21677 21678 exports.default = HTMLBarsAttrMorph; 21679}); 21680enifed('ember-htmlbars/morphs/morph', ['exports', 'dom-helper', 'ember-metal/debug'], function (exports, _domHelper, _emberMetalDebug) { 21681 'use strict'; 21682 21683 var HTMLBarsMorph = _domHelper.default.prototype.MorphClass; 21684 var guid = 1; 21685 21686 function EmberMorph(DOMHelper, contextualElement) { 21687 this.HTMLBarsMorph$constructor(DOMHelper, contextualElement); 21688 21689 this.emberView = null; 21690 this.emberToDestroy = null; 21691 this.streamUnsubscribers = null; 21692 this.guid = guid++; 21693 21694 // A component can become dirty either because one of its 21695 // attributes changed, or because it was re-rendered. If any part 21696 // of the component's template changes through observation, it has 21697 // re-rendered from the perpsective of the programming model. This 21698 // flag is set to true whenever a component becomes dirty because 21699 // one of its attributes changed, which also triggers the attribute 21700 // update flag (didUpdateAttrs). 21701 this.shouldReceiveAttrs = false;
21702 21703 _emberMetalDebug.debugSeal(this); 21704 } 21705 21706 var proto = EmberMorph.prototype = Object.create(HTMLBarsMorph.prototype); 21707 proto.HTMLBarsMorph$constructor = HTMLBarsMorph; 21708 proto.HTMLBarsMorph$clear = HTMLBarsMorph.prototype.clear; 21709 21710 proto.addDestruction = function (toDestroy) { 21711 this.emberToDestroy = this.emberToDestroy || []; 21712 this.emberToDestroy.push(toDestroy); 21713 }; 21714 21715 proto.cleanup = function () { 21716 var view = this.emberView; 21717 21718 if (view) { 21719 var parentView = view.parentView; 21720 21721 if (parentView && view.ownerView._destroyingSubtreeForView === parentView) { 21722 parentView.removeChild(view); 21723 } 21724 } 21725 21726 var toDestroy = this.emberToDestroy; 21727 21728 if (toDestroy) { 21729 for (var i = 0, l = toDestroy.length; i < l; i++) { 21730 toDestroy[i].destroy(); 21731 } 21732 21733 this.emberToDestroy = null; 21734 } 21735 }; 21736 21737 proto.didRender = function (env, scope) { 21738 env.renderedNodes.add(this); 21739 }; 21740 21741 exports.default = EmberMorph; 21742}); 21743enifed('ember-htmlbars/node-managers/component-node-manager', ['exports', 'ember-metal/debug', 'ember-views/system/build-component-template', 'ember-htmlbars/hooks/get-cell-or-value', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-views/compat/attrs-proxy', 'ember-htmlbars/system/instrumentation-support', 'ember-views/components/component', 'ember-htmlbars/glimmer-component', 'ember-htmlbars/utils/extract-positional-params', 'ember-metal/symbol', 'container/owner', 'ember-htmlbars/hooks/get-value'], function (exports, _emberMetalDebug, _emberViewsSystemBuildComponentTemplate, _emberHtmlbarsHooksGetCellOrValue, _emberMetalProperty_get, _emberMetalProperty_set, _emberViewsCompatAttrsProxy, _emberHtmlbarsSystemInstrumentationSupport, _emberViewsComponentsComponent, _emberHtmlbarsGlimmerComponent, _emberHtmlbarsUtilsExtractPositionalParams, _emberMetalSymbol, _containerOwner, _emberHtmlbarsHooksGetValue) { 21744 'use strict'; 21745 21746 exports.createComponent = createComponent; 21747 exports.takeLegacySnapshot = takeLegacySnapshot; 21748 21749 // These symbols will be used to limit link-to's public API surface area. 21750 var HAS_BLOCK = _emberMetalSymbol.default('HAS_BLOCK'); 21751 21752 exports.HAS_BLOCK = HAS_BLOCK; 21753 // In theory this should come through the env, but it should 21754 // be safe to import this until we make the hook system public 21755 // and it gets actively used in addons or other downstream 21756 // libraries. 21757 21758 function ComponentNodeManager(component, isAngleBracket, scope, renderNode, attrs, block, expectElement) { 21759 this.component = component; 21760 this.isAngleBracket = isAngleBracket; 21761 this.scope = scope; 21762 this.renderNode = renderNode; 21763 this.attrs = attrs; 21764 this.block = block; 21765 this.expectElement = expectElement; 21766 } 21767 21768 exports.default = ComponentNodeManager; 21769 21770 ComponentNodeManager.create = function ComponentNodeManager_create(renderNode, env, options) { 21771 var _createOptions; 21772 21773 var tagName = options.tagName; 21774 var params = options.params; 21775 var _options$attrs = options.attrs; 21776 var attrs = _options$attrs === undefined ? {} : _options$attrs; 21777 var parentView = options.parentView; 21778 var parentScope = options.parentScope; 21779 var isAngleBracket = options.isAngleBracket; 21780 var component = options.component; 21781 var layout = options.layout; 21782 var templates = options.templates; 21783 21784 component = component || (isAngleBracket ? _emberHtmlbarsGlimmerComponent.default : _emberViewsComponentsComponent.default); 21785 21786 var createOptions = (_createOptions = { 21787 parentView: parentView 21788 }, _createOptions[HAS_BLOCK] = !!templates.default, _createOptions); 21789 21790 configureTagName(attrs, tagName, component, isAngleBracket, createOptions); 21791 21792 // Map passed attributes (e.g. <my-component id="foo">) to component 21793 // properties ({ id: "foo" }). 21794 configureCreateOptions(attrs, createOptions); 21795 21796 // If there is a controller on the scope, pluck it off and save it on the 21797 // component. This allows the component to target actions sent via 21798 // `sendAction` correctly. 21799 if (parentScope.hasLocal('controller')) { 21800 createOptions._controller = _emberHtmlbarsHooksGetValue.default(parentScope.getLocal('controller')); 21801 } else { 21802 createOptions._targetObject = _emberHtmlbarsHooksGetValue.default(parentScope.getSelf()); 21803 } 21804 21805 _emberHtmlbarsUtilsExtractPositionalParams.default(renderNode, component, params, attrs); 21806 21807 // Instantiate the component 21808 component = createComponent(component, isAngleBracket, createOptions, renderNode, env, attrs); 21809 21810 // If the component specifies its layout via the `layout` property 21811 // instead of using the template looked up in the container, get it 21812 // now that we have the component instance. 21813 if (!layout) { 21814 layout = _emberMetalProperty_get.get(component, 'layout'); 21815 } 21816 21817 _emberMetalDebug.runInDebug(function () { 21818 if (isAngleBracket) { 21819 _emberMetalDebug.assert('You cannot invoke the \'' + tagName + '\' component with angle brackets, because it\'s a subclass of Component. Please upgrade to GlimmerComponent. Alternatively, you can invoke as \'{{' + tagName + '}}\'.', component.isGlimmerComponent); 21820 } else { 21821 _emberMetalDebug.assert('You cannot invoke the \'' + tagName + '\' component with curly braces, because it\'s a subclass of GlimmerComponent. Please invoke it as \'<' + tagName + '>\' instead.', !component.isGlimmerComponent); 21822 } 21823 21824 if (!layout) { 21825 return; 21826 } 21827 21828 var fragmentReason = layout.meta.fragmentReason; 21829 if (isAngleBracket && fragmentReason) { 21830 switch (fragmentReason.name) { 21831 case 'missing-wrapper': 21832 _emberMetalDebug.assert('The <' + tagName + '> template must have a single top-level element because it is a GlimmerComponent.'); 21833 break; 21834 case 'modifiers': 21835 var modifiers = fragmentReason.modifiers.map(function (m) { 21836 return '{{' + m + ' ...}}'; 21837 }); 21838 _emberMetalDebug.assert('You cannot use ' + modifiers.join(', ') + ' in the top-level element of the <' + tagName + '> template because it is a GlimmerComponent.'); 21839 break; 21840 case 'triple-curlies': 21841 _emberMetalDebug.assert('You cannot use triple curlies (e.g. style={{{ ... }}}) in the top-level element of the <' + tagName + '> template because it is a GlimmerComponent.'); 21842 break; 21843 } 21844 } 21845 }); 21846 21847 var results = _emberViewsSystemBuildComponentTemplate.default({ layout: layout, component: component, isAngleBracket: isAngleBracket }, attrs, { templates: templates, scope: parentScope }); 21848 21849 return new ComponentNodeManager(component, isAngleBracket, parentScope, renderNode, attrs, results.block, results.createdElement); 21850 }; 21851 21852 function configureTagName(attrs, tagName, component, isAngleBracket, createOptions) { 21853 if (isAngleBracket) { 21854 createOptions.tagName = tagName; 21855 } else if (attrs.tagName) { 21856 createOptions.tagName = _emberHtmlbarsHooksGetValue.default(attrs.tagName); 21857 } 21858 } 21859 21860 function configureCreateOptions(attrs, createOptions) { 21861 // Some attrs are special and need to be set as properties on the component 21862 // instance. Make sure we use getValue() to get them from `attrs` since 21863 // they are still streams. 21864 if (attrs.id) { 21865 createOptions.elementId = _emberHtmlbarsHooksGetValue.default(attrs.id); 21866 } 21867 if (attrs._defaultTagName) { 21868 createOptions._defaultTagName = _emberHtmlbarsHooksGetValue.default(attrs._defaultTagName); 21869 } 21870 if (attrs.viewName) { 21871 createOptions.viewName = _emberHtmlbarsHooksGetValue.default(attrs.viewName); 21872 } 21873 } 21874 21875 ComponentNodeManager.prototype.render = function ComponentNodeManager_render(_env, visitor) { 21876 var component = this.component; 21877 21878 return _emberHtmlbarsSystemInstrumentationSupport.instrument(component, function ComponentNodeManager_render_instrument() { 21879 var meta = this.block && this.block.template.meta; 21880 var env = _env.childWithView(component, meta); 21881 21882 env.renderer.componentWillRender(component); 21883 env.renderedViews.push(component.elementId); 21884 21885 if (this.block) { 21886 this.block.invoke(env, [], undefined, this.renderNode, this.scope, visitor); 21887 } 21888 21889 var element = undefined; 21890 if (this.expectElement || component.isGlimmerComponent) { 21891 // This code assumes that Glimmer components are never fragments. When 21892 // Glimmer components gain fragment powers, we will need to communicate 21893 // whether the layout produced a single top-level node or fragment 21894 // somehow (either via static information on the template/component, or 21895 // dynamically as the layout is being rendered). 21896 element = this.renderNode.firstNode; 21897 21898 // Glimmer components may have whitespace or boundary nodes around the 21899 // top-level element. 21900 if (element && element.nodeType !== 1) { 21901 element = nextElementSibling(element); 21902 } 21903 } 21904 21905 // In environments like FastBoot, disable any hooks that would cause the component 21906 // to access the DOM directly. 21907 if (env.destinedForDOM) { 21908 env.renderer.didCreateElement(component, element); 21909 env.renderer.willInsertElement(component, element); 21910 21911 env.lifecycleHooks.push({ type: 'didInsertElement', view: component }); 21912 } 21913 }, this); 21914 }; 21915 21916 function nextElementSibling(node) { 21917 var current = node; 21918 21919 while (current) { 21920 if (current.nodeType === 1) { 21921 return current; 21922 } 21923 current = node.nextSibling; 21924 } 21925 } 21926 21927 ComponentNodeManager.prototype.rerender = function ComponentNodeManager_rerender(_env, attrs, visitor) { 21928 var component = this.component; 21929 21930 return _emberHtmlbarsSystemInstrumentationSupport.instrument(component, function ComponentNodeManager_rerender_instrument() { 21931 var env = _env.childWithView(component); 21932 21933 var snapshot = takeSnapshot(attrs); 21934 21935 if (component._renderNode.shouldReceiveAttrs) { 21936 if (component._propagateAttrsToThis) { 21937 component._propagateAttrsToThis(takeLegacySnapshot(attrs)); 21938 } 21939 21940 env.renderer.componentUpdateAttrs(component, snapshot); 21941 component._renderNode.shouldReceiveAttrs = false;
21942 } 21943 21944 // Notify component that it has become dirty and is about to change. 21945 env.renderer.componentWillUpdate(component, snapshot); 21946 env.renderer.componentWillRender(component); 21947 21948 env.renderedViews.push(component.elementId); 21949 21950 if (this.block) { 21951 this.block.invoke(env, [], undefined, this.renderNode, this.scope, visitor); 21952 } 21953 21954 env.lifecycleHooks.push({ type: 'didUpdate', view: component }); 21955 21956 return env; 21957 }, this); 21958 }; 21959 21960 ComponentNodeManager.prototype.destroy = function ComponentNodeManager_destroy() { 21961 var component = this.component; 21962 21963 // Clear component's render node. Normally this gets cleared 21964 // during view destruction, but in this case we're re-assigning the 21965 // node to a different view and it will get cleaned up automatically. 21966 component._renderNode = null; 21967 component.destroy(); 21968 }; 21969 21970 function createComponent(_component, isAngleBracket, props, renderNode, env) { 21971 var attrs = arguments.length <= 5 || arguments[5] === undefined ? {} : arguments[5]; 21972 21973 if (!isAngleBracket) { 21974 _emberMetalDebug.assert('controller= is no longer supported', !('controller' in attrs)); 21975 21976 snapshotAndUpdateTarget(attrs, props); 21977 } else { 21978 props.attrs = takeSnapshot(attrs); 21979 21980 props._isAngleBracket = true; 21981 } 21982 21983 _containerOwner.setOwner(props, env.owner); 21984 props.renderer = props.parentView ? props.parentView.renderer : env.owner.lookup('renderer:-dom'); 21985 props._viewRegistry = props.parentView ? props.parentView._viewRegistry : env.owner.lookup('-view-registry:main'); 21986 21987 var component = _component.create(props); 21988 21989 if (props.parentView) { 21990 props.parentView.appendChild(component); 21991 21992 if (props.viewName) { 21993 _emberMetalProperty_set.set(props.parentView, props.viewName, component); 21994 } 21995 } 21996 21997 component._renderNode = renderNode; 21998 renderNode.emberView = component; 21999 renderNode.buildChildEnv = buildChildEnv; 22000 return component; 22001 } 22002 22003 function takeSnapshot(attrs) { 22004 var hash = {}; 22005 22006 for (var prop in attrs) { 22007 hash[prop] = _emberHtmlbarsHooksGetCellOrValue.default(attrs[prop]); 22008 } 22009 22010 return hash; 22011 } 22012 22013 function takeLegacySnapshot(attrs) { 22014 var hash = {}; 22015 22016 for (var prop in attrs) { 22017 hash[prop] = _emberHtmlbarsHooksGetValue.default(attrs[prop]); 22018 } 22019 22020 return hash; 22021 } 22022 22023 function snapshotAndUpdateTarget(rawAttrs, target) { 22024 var attrs = {}; 22025 22026 for (var prop in rawAttrs) { 22027 var value = _emberHtmlbarsHooksGetCellOrValue.default(rawAttrs[prop]); 22028 attrs[prop] = value; 22029 22030 // when `attrs` is an actual value being set in the 22031 // attrs hash (`{{foo-bar attrs="blah"}}`) we cannot 22032 // set `"blah"` to the root of the target because 22033 // that would replace all attrs with `attrs.attrs` 22034 if (prop === 'attrs') { 22035 _emberMetalDebug.warn('Invoking a component with a hash attribute named `attrs` is not supported. Please refactor usage of ' + target + ' to avoid passing `attrs` as a hash parameter.', false, { id: 'ember-htmlbars.component-unsupported-attrs' }); 22036 continue; 22037 } 22038 22039 if (value && value[_emberViewsCompatAttrsProxy.MUTABLE_CELL]) { 22040 value = value.value; 22041 } 22042 22043 target[prop] = value; 22044 } 22045 22046 return target.attrs = attrs; 22047 } 22048 22049 function buildChildEnv(state, env) { 22050 return env.childWithView(this.emberView); 22051 } 22052}); 22053enifed('ember-htmlbars/node-managers/view-node-manager', ['exports', 'ember-metal/assign', 'ember-metal/debug', 'ember-views/system/build-component-template', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/set_properties', 'ember-views/views/view', 'ember-views/compat/attrs-proxy', 'ember-htmlbars/hooks/get-cell-or-value', 'ember-htmlbars/system/instrumentation-support', 'ember-htmlbars/node-managers/component-node-manager', 'container/owner', 'ember-htmlbars/hooks/get-value'], function (exports, _emberMetalAssign, _emberMetalDebug, _emberViewsSystemBuildComponentTemplate, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalSet_properties, _emberViewsViewsView, _emberViewsCompatAttrsProxy, _emberHtmlbarsHooksGetCellOrValue, _emberHtmlbarsSystemInstrumentationSupport, _emberHtmlbarsNodeManagersComponentNodeManager, _containerOwner, _emberHtmlbarsHooksGetValue) { 22054 'use strict'; 22055 22056 exports.createOrUpdateComponent = createOrUpdateComponent; 22057 22058 function ViewNodeManager(component, scope, renderNode, block, expectElement) { 22059 this.component = component; 22060 this.scope = scope; 22061 this.renderNode = renderNode;
22062 this.block = block; 22063 this.expectElement = expectElement; 22064 } 22065 22066 exports.default = ViewNodeManager; 22067 22068 ViewNodeManager.create = function ViewNodeManager_create(renderNode, env, attrs, found, parentView, path, contentScope, contentTemplate) { 22069 _emberMetalDebug.assert('HTMLBars error: Could not find component named "' + path + '" (no component or template with that name was found)', !!(function () { 22070 if (path) { 22071 return found.component || found.layout; 22072 } else { 22073 return found.component || found.layout || contentTemplate; 22074 } 22075 })()); 22076 22077 var component; 22078 var componentInfo = { layout: found.layout }; 22079 22080 if (found.component) { 22081 var options = { parentView: parentView }; 22082 22083 if (attrs && attrs.id) { 22084 options.elementId = _emberHtmlbarsHooksGetValue.default(attrs.id); 22085 } 22086 if (attrs && attrs.tagName) { 22087 options.tagName = _emberHtmlbarsHooksGetValue.default(attrs.tagName); 22088 } 22089 if (attrs && attrs._defaultTagName) { 22090 options._defaultTagName = _emberHtmlbarsHooksGetValue.default(attrs._defaultTagName); 22091 } 22092 if (attrs && attrs.viewName) { 22093 options.viewName = _emberHtmlbarsHooksGetValue.default(attrs.viewName); 22094 } 22095 22096 if (found.component.create && contentScope) { 22097 var _self = contentScope.getSelf(); 22098 if (_self) { 22099 options._context = _emberHtmlbarsHooksGetValue.default(contentScope.getSelf()); 22100 } 22101 } 22102 22103 if (found.self) { 22104 options._context = _emberHtmlbarsHooksGetValue.default(found.self); 22105 } 22106 22107 component = componentInfo.component = createOrUpdateComponent(found.component, options, found.createOptions, renderNode, env, attrs); 22108 22109 var layout = _emberMetalProperty_get.get(component, 'layout'); 22110 if (layout) { 22111 componentInfo.layout = layout; 22112 } else { 22113 componentInfo.layout = getTemplate(component) || componentInfo.layout; 22114 } 22115 22116 renderNode.emberView = component; 22117 } 22118 22119 _emberMetalDebug.assert('BUG: ViewNodeManager.create can take a scope or a self, but not both', !(contentScope && found.self)); 22120 22121 var results = _emberViewsSystemBuildComponentTemplate.default(componentInfo, attrs, { 22122 templates: { default: contentTemplate }, 22123 scope: contentScope, 22124 self: found.self 22125 }); 22126 22127 return new ViewNodeManager(component, contentScope, renderNode, results.block, results.createdElement); 22128 }; 22129 22130 ViewNodeManager.prototype.render = function ViewNodeManager_render(env, attrs, visitor) { 22131 var component = this.component; 22132 22133 return _emberHtmlbarsSystemInstrumentationSupport.instrument(component, function ViewNodeManager_render_instrument() { 22134 var newEnv = env; 22135 if (component) { 22136 newEnv = env.childWithView(component); 22137 } else { 22138 var meta = this.block && this.block.template.meta; 22139 22140 newEnv = env.childWithMeta(meta); 22141 } 22142 22143 if (component) { 22144 env.renderer.willRender(component); 22145 env.renderedViews.push(component.elementId); 22146 } 22147 22148 if (this.block) { 22149 this.block.invoke(newEnv, [], undefined, this.renderNode, this.scope, visitor); 22150 } 22151 22152 if (component) { 22153 var element = this.expectElement && this.renderNode.firstNode; 22154 22155 // In environments like FastBoot, disable any hooks that would cause the component 22156 // to access the DOM directly. 22157 if (env.destinedForDOM) { 22158 env.renderer.didCreateElement(component, element); 22159 env.renderer.willInsertElement(component, element); 22160 env.lifecycleHooks.push({ type: 'didInsertElement', view: component }); 22161 } 22162 } 22163 }, this); 22164 }; 22165 22166 ViewNodeManager.prototype.rerender = function ViewNodeManager_rerender(env, attrs, visitor) { 22167 var component = this.component; 22168 22169 return _emberHtmlbarsSystemInstrumentationSupport.instrument(component, function ViewNodeManager_rerender_instrument() { 22170 var newEnv = env; 22171 if (component) { 22172 newEnv = env.childWithView(component); 22173 22174 var snapshot = takeSnapshot(attrs); 22175 22176 // Notify component that it has become dirty and is about to change. 22177 env.renderer.willUpdate(component, snapshot); 22178 22179 if (component._renderNode.shouldReceiveAttrs) { 22180 if (component._propagateAttrsToThis) { 22181 component._propagateAttrsToThis(_emberHtmlbarsNodeManagersComponentNodeManager.takeLegacySnapshot(attrs)); 22182 } 22183 22184 env.renderer.componentUpdateAttrs(component, snapshot); 22185 component._renderNode.shouldReceiveAttrs = false;
22186 } 22187 22188 env.renderer.willRender(component); 22189 22190 env.renderedViews.push(component.elementId); 22191 } else { 22192 var meta = this.block && this.block.template.meta; 22193 22194 newEnv = env.childWithMeta(meta); 22195 } 22196 22197 if (this.block) { 22198 this.block.invoke(newEnv, [], undefined, this.renderNode, this.scope, visitor); 22199 } 22200 22201 return newEnv; 22202 }, this); 22203 }; 22204 22205 ViewNodeManager.prototype.destroy = function ViewNodeManager_destroy() { 22206 if (this.component) { 22207 this.component.destroy(); 22208 this.component = null; 22209 } 22210 }; 22211 22212 function getTemplate(componentOrView) { 22213 if (!componentOrView.isComponent) { 22214 return _emberMetalProperty_get.get(componentOrView, 'template'); 22215 } 22216 22217 return null; 22218 } 22219 22220 function createOrUpdateComponent(component, options, createOptions, renderNode, env) { 22221 var attrs = arguments.length <= 5 || arguments[5] === undefined ? {} : arguments[5]; 22222 22223 var snapshot = takeSnapshot(attrs); 22224 var props = _emberMetalAssign.default({}, options); 22225 var defaultController = _emberViewsViewsView.default.proto().controller; 22226 var hasSuppliedController = 'controller' in attrs || 'controller' in props; 22227 22228 if (!props.ownerView && options.parentView) { 22229 props.ownerView = options.parentView.ownerView; 22230 } 22231 22232 props.attrs = snapshot; 22233 if (component.create) { 22234 var proto = component.proto(); 22235 22236 if (createOptions) { 22237 _emberMetalAssign.default(props, createOptions); 22238 } 22239 22240 mergeBindings(props, snapshot); 22241 22242 var owner = env.owner; 22243 22244 _containerOwner.setOwner(props, owner); 22245 props.renderer = options.parentView ? options.parentView.renderer : owner && owner.lookup('renderer:-dom'); 22246 props._viewRegistry = options.parentView ? options.parentView._viewRegistry : owner && owner.lookup('-view-registry:main'); 22247 22248 if (proto.controller !== defaultController || hasSuppliedController) { 22249 delete props._context; 22250 } 22251 22252 component = component.create(props); 22253 } else { 22254 env.renderer.componentUpdateAttrs(component, snapshot); 22255 _emberMetalSet_properties.default(component, props); 22256 22257 if (component._propagateAttrsToThis) { 22258 component._propagateAttrsToThis(_emberHtmlbarsNodeManagersComponentNodeManager.takeLegacySnapshot(attrs)); 22259 } 22260 } 22261 22262 if (options.parentView) { 22263 options.parentView.appendChild(component); 22264 22265 if (options.viewName) { 22266 _emberMetalProperty_set.set(options.parentView, options.viewName, component); 22267 } 22268 } 22269 22270 component._renderNode = renderNode; 22271 22272 renderNode.emberView = component; 22273 return component; 22274 } 22275 22276 function takeSnapshot(attrs) { 22277 var hash = {}; 22278 22279 for (var prop in attrs) { 22280 hash[prop] = _emberHtmlbarsHooksGetCellOrValue.default(attrs[prop]); 22281 } 22282 22283 return hash; 22284 } 22285 22286 function mergeBindings(target, attrs) { 22287 for (var prop in attrs) { 22288 if (!attrs.hasOwnProperty(prop)) { 22289 continue; 22290 } 22291 // when `attrs` is an actual value being set in the 22292 // attrs hash (`{{foo-bar attrs="blah"}}`) we cannot 22293 // set `"blah"` to the root of the target because 22294 // that would replace all attrs with `attrs.attrs` 22295 if (prop === 'attrs') { 22296 _emberMetalDebug.warn('Invoking a component with a hash attribute named `attrs` is not supported. Please refactor usage of ' + target + ' to avoid passing `attrs` as a hash parameter.', false, { id: 'ember-htmlbars.view-unsupported-attrs' }); 22297 continue; 22298 } 22299 var value = attrs[prop]; 22300 22301 if (value && value[_emberViewsCompatAttrsProxy.MUTABLE_CELL]) { 22302 target[prop] = value.value; 22303 } else { 22304 target[prop] = value; 22305 } 22306 } 22307 22308 return target; 22309 } 22310}); 22311 22312// In theory this should come through the env, but it should 22313// be safe to import this until we make the hook system public 22314// and it gets actively used in addons or other downstream 22315// libraries. 22316enifed('ember-htmlbars/streams/built-in-helper', ['exports', 'ember-metal/streams/stream', 'ember-htmlbars/streams/utils'], function (exports, _emberMetalStreamsStream, _emberHtmlbarsStreamsUtils) { 22317 'use strict'; 22318 22319 var BuiltInHelperStream = _emberMetalStreamsStream.default.extend({ 22320 init: function (helper, params, hash, templates, env, scope, label) { 22321 this.helper = helper; 22322 this.params = params; 22323 this.templates = templates; 22324 this.env = env; 22325 this.scope = scope; 22326 this.hash = hash; 22327 this.label = label; 22328 }, 22329 22330 compute: function () { 22331 return this.helper(_emberHtmlbarsStreamsUtils.getArrayValues(this.params), _emberHtmlbarsStreamsUtils.getHashValues(this.hash), this.templates, this.env, this.scope); 22332 } 22333 }); 22334 22335 exports.default = BuiltInHelperStream; 22336}); 22337enifed('ember-htmlbars/streams/helper-factory', ['exports', 'ember-metal/stream
22337s/stream', 'ember-htmlbars/streams/utils'], function (exports, _emberMetalStreamsStream, _emberHtmlbarsStreamsUtils) { 22338 'use strict'; 22339 22340 var HelperFactoryStream = _emberMetalStreamsStream.default.extend({ 22341 init: function (helperFactory, params, hash, label) { 22342 this.helperFactory = helperFactory; 22343 this.params = params; 22344 this.hash = hash; 22345 this.linkable = true; 22346 this.helper = null; 22347 this.label = label; 22348 }, 22349 22350 compute: function () { 22351 if (!this.helper) { 22352 this.helper = this.helperFactory.create({ _stream: this }); 22353 } 22354 return this.helper.compute(_emberHtmlbarsStreamsUtils.getArrayValues(this.params), _emberHtmlbarsStreamsUtils.getHashValues(this.hash)); 22355 }, 22356 22357 deactivate: function () { 22358 this.super$deactivate(); 22359 if (this.helper) { 22360 this.helper.destroy(); 22361 this.helper = null; 22362 } 22363 }, 22364 super$deactivate: _emberMetalStreamsStream.default.prototype.deactivate 22365 }); 22366 22367 exports.default = HelperFactoryStream; 22368}); 22369enifed('ember-htmlbars/streams/helper-instance', ['exports', 'ember-metal/streams/stream', 'ember-htmlbars/streams/utils'], function (exports, _emberMetalStreamsStream, _emberHtmlbarsStreamsUtils) { 22370 'use strict'; 22371 22372 var HelperInstanceStream = _emberMetalStreamsStream.default.extend({ 22373 init: function (helper, params, hash, label) { 22374 this.helper = helper; 22375 this.params = params; 22376 this.hash = hash; 22377 this.linkable = true; 22378 this.label = label; 22379 }, 22380 22381 compute: function () { 22382 return this.helper.compute(_emberHtmlbarsStreamsUtils.getArrayValues(this.params), _emberHtmlbarsStreamsUtils.getHashValues(this.hash)); 22383 } 22384 }); 22385 22386 exports.default = HelperInstanceStream; 22387}); 22388enifed('ember-htmlbars/streams/utils', ['exports', 'ember-htmlbars/hooks/get-value'], function (exports, _emberHtmlbarsHooksGetValue) { 22389 'use strict'; 22390 22391 exports.getArrayValues = getArrayValues; 22392 exports.getHashValues = getHashValues; 22393 22394 // We don't want to leak mutable cells into helpers, which 22395 // are pure functions that can only work with values. 22396 22397 function getArrayValues(params) { 22398 var l = params.length; 22399 var out = new Array(l); 22400 22401 for (var i = 0; i < l; i++) { 22402 out[i] = _emberHtmlbarsHooksGetValue.default(params[i]); 22403 } 22404 22405 return out; 22406 } 22407 22408 function getHashValues(hash) { 22409 var out = {}; 22410 22411 for (var prop in hash) { 22412 out[prop] = _emberHtmlbarsHooksGetValue.default(hash[prop]); 22413 } 22414 22415 return out; 22416 } 22417}); 22418enifed('ember-htmlbars/system/append-templated-view', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-views/views/view'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberViewsViewsView) { 22419 /** 22420 @module ember 22421 @submodule ember-htmlbars 22422 */ 22423 22424 'use strict'; 22425 22426 exports.default = appendTemplatedView; 22427 22428 function appendTemplatedView(parentView, morph, viewClassOrInstance, props) { 22429 var viewProto; 22430 if (_emberViewsViewsView.default.detectInstance(viewClassOrInstance)) { 22431 viewProto = viewClassOrInstance; 22432 } else { 22433 viewProto = viewClassOrInstance.proto(); 22434 } 22435 22436 _emberMetalDebug.assert('You cannot provide a template block if you also specified a templateName', !props.template || !_emberMetalProperty_get.get(props, 'templateName') && !_emberMetalProperty_get.get(viewProto, 'templateName')); 22437 22438 // We only want to override the `_context` computed property if there is 22439 // no specified controller. See View#_context for more information. 22440 var noControllerInProto = !viewProto.controller; 22441 if (viewProto.controller && viewProto.controller.isDescriptor) { 22442 noControllerInProto = true; 22443 } 22444 if (noControllerInProto && !viewProto.controllerBinding && !props.controller && !props.controllerBinding) { 22445 props._context = _emberMetalProperty_get.get(parentView, 'context'); // TODO: is this right?! 22446 } 22447 22448 props._morph = morph; 22449 22450 return parentView.appendChild(viewClassOrInstance, props); 22451 } 22452}); 22453enifed('ember-htmlbars/system/bootstrap', ['exports', 'ember-views/component_lookup', 'ember-views/system/jquery', 'ember-metal/error', 'ember-runtime/system/lazy_load', 'ember-template-compiler/system/compile', 'ember-metal/environment', 'ember-htmlbars/template_registry'], function (exports, _emberViewsComponent_lookup, _emberViewsSystemJquery, _emberMetalError, _emberRuntimeSystemLazy_load, _emberTemplateCompilerSystemCompile, _emberMetalEnvironment, _emberHtmlbarsTemplate_registry) { 22454 /*globals Handlebars */ 22455 22456 /** 22457 @module ember 22458 @submodule ember-htmlbars 22459 */ 22460 22461 'use strict'; 22462 22463 /** 22464 @module ember 22465 @submodule ember-htmlbars 22466 */ 22467 22468 /** 22469 Find templates stored in the head tag as script tags and make them available 22470 to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run 22471 as a jQuery DOM-ready callback. 22472
22473 Script tags with `text/x-handlebars` will be compiled 22474 with Ember's template compiler and are suitable for use as a view's template. 22475 Those with type `text/x-raw-handlebars` will be compiled with regular 22476 Handlebars and are suitable for use in views' computed properties. 22477 22478 @private 22479 @method bootstrap 22480 @for Ember.HTMLBars 22481 @static 22482 @param ctx 22483 */ 22484 function bootstrap(ctx) { 22485 var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; 22486 22487 _emberViewsSystemJquery.default(selectors, ctx).each(function () { 22488 // Get a reference to the script tag. 22489 var script = _emberViewsSystemJquery.default(this); 22490 22491 // Get the name of the script, used by Ember.View's templateName property. 22492 // First look for data-template-name attribute, then fall back to its 22493 // id if no name is found. 22494 var templateName = script.attr('data-template-name') || script.attr('id') || 'application'; 22495 var template, compile; 22496 22497 if (script.attr('type') === 'text/x-raw-handlebars') { 22498 compile = _emberViewsSystemJquery.default.proxy(Handlebars.compile, Handlebars); 22499 template = compile(script.html()); 22500 } else { 22501 template = _emberTemplateCompilerSystemCompile.default(script.html(), { 22502 moduleName: templateName 22503 }); 22504 } 22505 22506 // Check if template of same name already exists. 22507 if (_emberHtmlbarsTemplate_registry.has(templateName)) { 22508 throw new _emberMetalError.default('Template named "' + templateName + '" already exists.'); 22509 } 22510 22511 // For templates which have a name, we save them and then remove them from the DOM. 22512 _emberHtmlbarsTemplate_registry.set(templateName, template); 22513 22514 // Remove script tag from DOM. 22515 script.remove(); 22516 }); 22517 } 22518 22519 function _bootstrap() { 22520 bootstrap(_emberViewsSystemJquery.default(document)); 22521 } 22522 22523 function registerComponentLookup(app) { 22524 app.register('component-lookup:main', _emberViewsComponent_lookup.default); 22525 } 22526 22527 /* 22528 We tie this to application.load to ensure that we've at least 22529 attempted to bootstrap at the point that the application is loaded. 22530 22531 We also tie this to document ready since we're guaranteed that all 22532 the inline templates are present at this point. 22533 22534 There's no harm to running this twice, since we remove the templates 22535 from the DOM after processing. 22536 */ 22537 22538 _emberRuntimeSystemLazy_load.onLoad('Ember.Application', function (Application) { 22539 Application.initializer({ 22540 name: 'domTemplates', 22541 initialize: _emberMetalEnvironment.default.hasDOM ? _bootstrap : function () {} 22542 }); 22543 22544 Application.instanceInitializer({ 22545 name: 'registerComponentLookup', 22546 initialize: registerComponentLookup 22547 }); 22548 }); 22549 22550 exports.default = bootstrap; 22551}); 22552enifed('ember-htmlbars/system/dom-helper', ['exports', 'dom-helper', 'ember-htmlbars/morphs/morph', 'ember-htmlbars/morphs/attr-morph'], function (exports, _domHelper, _emberHtmlbarsMorphsMorph, _emberHtmlbarsMorphsAttrMorph) { 22553 'use strict'; 22554 22555 function EmberDOMHelper(_document) { 22556 _domHelper.default.call(this, _document); 22557 } 22558 22559 var proto = EmberDOMHelper.prototype = Object.create(_domHelper.default.prototype); 22560 proto.MorphClass = _emberHtmlbarsMorphsMorph.default; 22561 proto.AttrMorphClass = _emberHtmlbarsMorphsAttrMorph.default; 22562 22563 exports.default = EmberDOMHelper; 22564}); 22565enifed('ember-htmlbars/system/instrumentation-support', ['exports', 'ember-metal/instrumentation'], function (exports, _emberMetalInstrumentation) { 22566 'use strict'; 22567 22568 exports.instrument = instrument; 22569 22570 /** 22571 Provides instrumentation for node managers. 22572 22573 Wrap your node manager's render and re-render methods 22574 with this function. 22575 22576 @param {Object} component Component or View instance (optional). 22577 @param {Function} callback The function to instrument. 22578 @param {Object} context The context to call the function with. 22579 @return {Object} Return value from the invoked callback. 22580 @private 22581 */ 22582 22583 function instrument(component, callback, context) { 22584 var instrumentName, val, details, end; 22585 // Only instrument if there's at least one subscriber. 22586 if (_emberMetalInstrumentation.subscribers.length) { 22587 if (component) { 22588 instrumentName = component.instrumentName; 22589 } else { 22590 instrumentName = 'node'; 22591 } 22592 details = {}; 22593 if (component) {
22594 component.instrumentDetails(details); 22595 } 22596 end = _emberMetalInstrumentation._instrumentStart('render.' + instrumentName, function viewInstrumentDetails() { 22597 return details; 22598 }); 22599 val = callback.call(context); 22600 if (end) { 22601 end(); 22602 } 22603 return val; 22604 } else { 22605 return callback.call(context); 22606 } 22607 } 22608}); 22609enifed('ember-htmlbars/system/invoke-helper', ['exports', 'ember-metal/debug', 'ember-htmlbars/streams/helper-instance', 'ember-htmlbars/streams/helper-factory', 'ember-htmlbars/streams/built-in-helper'], function (exports, _emberMetalDebug, _emberHtmlbarsStreamsHelperInstance, _emberHtmlbarsStreamsHelperFactory, _emberHtmlbarsStreamsBuiltInHelper) { 22610 'use strict'; 22611 22612 exports.buildHelperStream = buildHelperStream; 22613 22614 function buildHelperStream(helper, params, hash, templates, env, scope, label) { 22615 var isAnyKindOfHelper = helper.isHelperInstance || helper.isHelperFactory; 22616 _emberMetalDebug.assert('Helpers may not be used in the block form, for example {{#my-helper}}{{/my-helper}}. Please use a component, or alternatively use the helper in combination with a built-in Ember helper, for example {{#if (my-helper)}}{{/if}}.', !(isAnyKindOfHelper && templates && templates.template && templates.template.meta)); 22617 _emberMetalDebug.assert('Helpers may not be used in the element form, for example <div {{my-helper}}>.', !(isAnyKindOfHelper && templates && templates.element)); 22618 if (helper.isHelperFactory) { 22619 return new _emberHtmlbarsStreamsHelperFactory.default(helper, params, hash, label); 22620 } else if (helper.isHelperInstance) { 22621 return new _emberHtmlbarsStreamsHelperInstance.default(helper, params, hash, label); 22622 } else { 22623 templates = templates || { template: {}, inverse: {} }; 22624 return new _emberHtmlbarsStreamsBuiltInHelper.default(helper, params, hash, templates, env, scope, label); 22625 } 22626 } 22627}); 22628enifed('ember-htmlbars/system/lookup-helper', ['exports', 'ember-metal/debug', 'ember-metal/cache'], function (exports, _emberMetalDebug, _emberMetalCache) { 22629 /** 22630 @module ember 22631 @submodule ember-htmlbars 22632 */ 22633 22634 'use strict'; 22635 22636 exports.validateLazyHelperName = validateLazyHelperName; 22637 exports.findHelper = findHelper; 22638 exports.default = lookupHelper; 22639 var CONTAINS_DASH_CACHE = new _emberMetalCache.default(1000, function (key) { 22640 return key.indexOf('-') !== -1; 22641 }); 22642 22643 exports.CONTAINS_DASH_CACHE = CONTAINS_DASH_CACHE; 22644 var CONTAINS_DOT_CACHE = new _emberMetalCache.default(1000, function (key) { 22645 return key.indexOf('.') !== -1; 22646 }); 22647 22648 exports.CONTAINS_DOT_CACHE = CONTAINS_DOT_CACHE; 22649 22650 function validateLazyHelperName(helperName, container, keywords) { 22651 return container && !(helperName in keywords); 22652 } 22653 22654 /** 22655 Used to lookup/resolve handlebars helpers. The lookup order is: 22656 22657 * Look for a registered helper 22658 * If a dash exists in the name: 22659 * Look for a helper registed in the container. 22660 * Use Ember.ComponentLookup to find an Ember.Component that resolves 22661 to the given name. 22662 22663 @private 22664 @method resolveHelper 22665 @param {String} name The name of the helper to lookup. 22666 @return {Helper} 22667 */ 22668 function _findHelper(name, view, env, options) { 22669 var helper = env.helpers[name]; 22670 22671 if (!helper) { 22672 var owner = env.owner; 22673 if (validateLazyHelperName(name, owner, env.hooks.keywords)) { 22674 var helperName = 'helper:' + name; 22675 // See https://github.com/emberjs/ember.js/issues/13071 22676 // See https://bugs.chromium.org/p/v8/issues/detail?id=4839 22677 var registered = owner.hasRegistration(helperName, options); 22678 if (registered) { 22679 helper = owner._lookupFactory(helperName, options); 22680 _emberMetalDebug.assert('Expected to find an Ember.Helper with the name ' + helperName + ', but found an object of type ' + typeof helper + ' instead.', helper.isHelperFactory || helper.isHelperInstance); 22681 } 22682 } 22683 } 22684 22685 return helper; 22686 } 22687 22688 function findHelper(name, view, env) { 22689 var options = {}; 22690 var moduleName = env.meta && env.meta.moduleName; 22691 if (moduleName) { 22692 options.source = 'template:' + moduleName; 22693 } 22694 22695 var localHelper = _findHelper(name, view, env, options); 22696 22697 // Local match found, use it. 22698 if (localHelper) { 22699 return localHelper; 22700 } 22701 22702 // Fall back to global. 22703 return _findHelper(name, view, env); 22704 } 22705 22706 function lookupHelper(name, view, env) { 22707 var helper = findHelper(name, view, env); 22708 22709 _emberMetalDebug.assert('A helper named \'' + name + '\' could not be found', !!
22709helper); 22710 22711 return helper; 22712 } 22713}); 22714enifed('ember-htmlbars/system/make_bound_helper', ['exports', 'ember-metal/debug', 'ember-htmlbars/helper'], function (exports, _emberMetalDebug, _emberHtmlbarsHelper) { 22715 /** 22716 @module ember 22717 @submodule ember-htmlbars 22718 */ 22719 'use strict'; 22720 22721 exports.default = makeBoundHelper; 22722 22723 /** 22724 Create a bound helper. Accepts a function that receives the ordered and hash parameters 22725 from the template. If a bound property was provided in the template, it will be resolved to its 22726 value and any changes to the bound property cause the helper function to be re-run with the updated 22727 values. 22728 22729 * `params` - An array of resolved ordered parameters. 22730 * `hash` - An object containing the hash parameters. 22731 22732 For example: 22733 22734 * With an unquoted ordered parameter: 22735 22736 ```javascript 22737 {{x-capitalize foo}} 22738 ``` 22739 22740 Assuming `foo` was set to `"bar"`, the bound helper would receive `["bar"]` as its first argument, and 22741 an empty hash as its second. 22742 22743 * With a quoted ordered parameter: 22744 22745 ```javascript 22746 {{x-capitalize "foo"}} 22747 ``` 22748 22749 The bound helper would receive `["foo"]` as its first argument, and an empty hash as its second. 22750 22751 * With an unquoted hash parameter: 22752 22753 ```javascript 22754 {{x-repeat "foo" count=repeatCount}} 22755 ``` 22756 22757 Assuming that `repeatCount` resolved to 2, the bound helper would receive `["foo"]` as its first argument, 22758 and { count: 2 } as its second. 22759 22760 @private 22761 @method makeBoundHelper 22762 @for Ember.HTMLBars 22763 @param {Function} fn 22764 @since 1.10.0 22765 */ 22766 22767 function makeBoundHelper(fn) { 22768 _emberMetalDebug.deprecate('Using `Ember.HTMLBars.makeBoundHelper` is deprecated. Please refactor to use `Ember.Helper` or `Ember.Helper.helper`.', false, { id: 'ember-htmlbars.make-bound-helper', until: '3.0.0' }); 22769 return _emberHtmlbarsHelper.helper(fn); 22770 } 22771}); 22772enifed('ember-htmlbars/system/render-env', ['exports', 'ember-htmlbars/env', 'ember-metal-views', 'container/owner'], function (exports, _emberHtmlbarsEnv, _emberMetalViews, _containerOwner) { 22773 'use strict'; 22774 22775 exports.default = RenderEnv; 22776
22777 function RenderEnv(options) { 22778 this.lifecycleHooks = options.lifecycleHooks || []; 22779 this.renderedViews = options.renderedViews || []; 22780 this.renderedNodes = options.renderedNodes || new _emberMetalViews.MorphSet(); 22781 this.hasParentOutlet = options.hasParentOutlet || false; 22782 22783 this.view = options.view; 22784 this.outletState = options.outletState; 22785 this.owner = options.owner; 22786 this.renderer = options.renderer; 22787 this.dom = options.dom; 22788 this.meta = options.meta; 22789 22790 this.hooks = _emberHtmlbarsEnv.default.hooks; 22791 this.helpers = _emberHtmlbarsEnv.default.helpers; 22792 this.useFragmentCache = _emberHtmlbarsEnv.default.useFragmentCache; 22793 this.destinedForDOM = this.renderer._destinedForDOM; 22794 } 22795 22796 RenderEnv.build = function (view, meta) { 22797 return new RenderEnv({ 22798 view: view, 22799 outletState: view.outletState, 22800 owner: _containerOwner.getOwner(view), 22801 renderer: view.renderer, 22802 dom: view.renderer._dom, 22803 meta: meta 22804 }); 22805 }; 22806 22807 RenderEnv.prototype.childWithMeta = function (meta) { 22808 return new RenderEnv({ 22809 view: this.view, 22810 outletState: this.outletState, 22811 owner: this.owner, 22812 renderer: this.renderer, 22813 dom: this.dom, 22814 lifecycleHooks: this.lifecycleHooks, 22815 renderedViews: this.renderedViews, 22816 renderedNodes: this.renderedNodes, 22817 hasParentOutlet: this.hasParentOutlet, 22818 meta: meta 22819 }); 22820 }; 22821 22822 RenderEnv.prototype.childWithView = function (view) { 22823 var meta = arguments.length <= 1 || arguments[1] === undefined ? this.meta : arguments[1]; 22824 22825 return new RenderEnv({ 22826 view: view, 22827 outletState: this.outletState, 22828 owner: this.owner, 22829 renderer: this.renderer, 22830 dom: this.dom, 22831 lifecycleHooks: this.lifecycleHooks, 22832 renderedViews: this.renderedViews, 22833 renderedNodes: this.renderedNodes, 22834 hasParentOutlet: this.hasParentOutlet, 22835 meta: meta 22836 }); 22837 }; 22838 22839 RenderEnv.prototype.childWithOutletState = function (outletState) { 22840 var hasParentOutlet = arguments.length <= 1 || arguments[1] === undefined ? this.hasParentOutlet : arguments[1]; 22841 var meta = arguments.length <= 2 || arguments[2] === undefined ? this.meta : arguments[2]; 22842 22843 return new RenderEnv({ 22844 view: this.view, 22845 outletState: outletState, 22846 owner: this.owner, 22847 renderer: this.renderer, 22848 dom: this.dom, 22849 lifecycleHooks: this.lifecycleHooks, 22850 renderedViews: this.renderedViews, 22851 renderedNodes: this.renderedNodes, 22852 hasParentOutlet: hasParentOutlet, 22853 meta: meta 22854 }); 22855 }; 22856}); 22857enifed('ember-htmlbars/system/render-view', ['exports', 'ember-htmlbars/node-managers/view-node-manager', 'ember-htmlbars/system/render-env'], function (exports, _emberHtmlbarsNodeManagersViewNodeManager, _emberHtmlbarsSystemRenderEnv) { 22858 'use strict'; 22859 22860 exports.renderHTMLBarsBlock = renderHTMLBarsBlock; 22861 22862 // This function only gets called once per render of a "root view" (`appendTo`). Otherwise, 22863 // HTMLBars propagates the existing env and renders templates for a given render node. 22864 22865 function renderHTMLBarsBlock(view, block, renderNode) { 22866 var meta = block && block.template && block.template.meta; 22867 var env = _emberHtmlbarsSystemRenderEnv.default.build(view, meta); 22868 22869 view.env = env; 22870 _emberHtmlbarsNodeManagersViewNodeManager.createOrUpdateComponent(view, {}, null, renderNode, env); 22871 var nodeManager = new _emberHtmlbarsNodeManagersViewNodeManager.default(view, null, renderNode, block, view.tagName !== ''); 22872 22873 nodeManager.render(env, {}); 22874 } 22875}); 22876enifed("ember-htmlbars/template_registry", ["exports"], function (exports) { 22877 // STATE within a module is frowned apon, this exists 22878 // to support Ember.TEMPLATES but shield ember internals from this legacy 22879 // global API. 22880 "use strict"; 22881 22882 exports.setTemplates = setTemplates; 22883 exports.getTemplates = getTemplates; 22884 exports.get = get; 22885 exports.has = has; 22886 exports.set = set; 22887 var TEMPLATES = {}; 22888 22889 function setTemplates(templates) { 22890 TEMPLATES = templates; 22891 } 22892 22893 function getTemplates() { 22894 return TEMPLATES; 22895 } 22896 22897 function get(name) { 22898 if (TEMPLATES.hasOwnProperty(name)) { 22899 return TEMPLATES[name]; 22900 } 22901 } 22902 22903 function has(name) { 22904 return TEMPLATES.hasOwnProperty(name); 22905 } 22906 22907 function set(name, template) { 22908 return TEMPLATES[name] = template; 22909 } 22910}); 22911enifed("ember-htmlbars/templates/component", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 22912 "use strict"; 22913 22914 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 22915 return { 22916 meta: {}, 22917 isEmpty: false, 22918 arity: 0, 22919 cachedFragment: null, 22920 hasRendered: false, 22921 buildFragment: function buildFragment(dom) { 22922 var el0 = dom.createDocumentFragment(); 22923 var el1 = dom.createComment(""); 22924 dom.appendChild(el0, el1); 22925 return el0; 22926 }, 22927 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 22928 var morphs = new Array(1); 22929 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 22930 dom.insertBoundary(fragment, 0); 22931 dom.insertBoundary(fragment, null); 22932 return morphs; 22933 }, 22934 statements: [["content", "yield", ["loc", [null, [1, 0], [1, 9]]]]], 22935 locals: [], 22936 templates: [] 22937 }; 22938 })()); 22939}); 22940enifed("ember-htmlbars/templates/container-view", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 22941 "use strict"; 22942 22943 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 22944 var child0 = (function () { 22945 return { 22946 meta: {}, 22947 isEmpty: false, 22948 arity: 1, 22949 cachedFragment: null, 22950 hasRendered: false, 22951 buildFragment: function buildFragment(dom) { 22952 var el0 = dom.createDocumentFragment(); 22953 var el1 = dom.createComment(""); 22954 dom.appendChild(el0, el1); 22955 return el0; 22956 }, 22957 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 22958 var morphs = new Array(1); 22959 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 22960 dom.insertBoundary(fragment, 0); 22961 dom.insertBoundary(fragment, null); 22962 return morphs; 22963 }, 22964 statements: [["inline", "view", [["get", "childView", ["loc", [null, [1, 63], [1, 72]]]]], [], ["loc", [null, [1, 56], [1, 74]]]]], 22965 locals: ["childView"], 22966 templates: [] 22967 }; 22968 })(); 22969 var child1 = (function () { 22970 var child0 = (function () { 22971 return { 22972 meta: {}, 22973 isEmpty: false, 22974 arity: 0, 22975 cachedFragment: null, 22976 hasRendered: false, 22977 buildFragment: function buildFragment(dom) { 22978 var el0 = dom.createDocumentFragment(); 22979 var el1 = dom.createComment(""); 22980 dom.appendChild(el0, el1); 22981 return el0; 22982 }, 22983 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 22984 var morphs = new Array(1); 22985 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 22986 dom.insertBoundary(fragment, 0); 22987 dom.insertBoundary(fragment, null); 22988 return morphs; 22989 }, 22990 statements: [["inline", "view", [["get", "view._emptyView", ["loc", [null, [1, 108], [1, 123]]]]], ["_defaultTagName", ["get", "view._emptyViewTagName", ["loc", [null, [1, 140], [1, 162]]]]], ["loc", [null, [1, 101], [1, 164]]]]], 22991 locals: [], 22992 templates: [] 22993 }; 22994 })(); 22995 return { 22996 meta: {}, 22997 isEmpty: false, 22998 arity: 0, 22999 cachedFragment: null, 23000 hasRendered: false, 23001 buildFragment: function buildFragment(dom) { 23002 var el0 = dom.createDocumentFragment(); 23003 var el1 = dom.createComment(""); 23004 dom.appendChild(el0, el1); 23005 return el0; 23006 }, 23007 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23008 var morphs = new Array(1); 23009 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23010 dom.insertBoundary(fragment, 0); 23011 dom.insertBoundary(fragment, null); 23012 return morphs; 23013 }, 23014 statements: [["block", "if", [["get", "view._emptyView", ["loc", [null, [1, 84], [1, 99]]]]], [], 0, null, ["loc", [null, [1, 74], [1, 164]]]]], 23015 locals: [], 23016 templates: [child0] 23017 }; 23018 })(); 23019 return { 23020 meta: {}, 23021 isEmpty: false, 23022 arity: 0, 23023 cachedFragment: null, 23024 hasRendered: false, 23025 buildFragment: function buildFragment(dom) { 23026 var el0 = dom.createDocumentFragment(); 23027 var el1 = dom.createComment(""); 23028 dom.appendChild(el0, el1); 23029 return el0; 23030 }, 23031 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23032 var morphs = new Array(1); 23033 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23034 dom.insertBoundary(fragment, 0); 23035 dom.insertBoundary(fragment, null); 23036 return morphs; 23037 }, 23038 statements: [["block", "each", [["get", "view.childViews", ["loc", [null, [1, 8], [1, 23]]]]], ["key", "elementId"], 0, 1, ["loc", [null, [1, 0], [1, 173]]]]], 23039 locals: [], 23040 templates: [child0, child1] 23041 }; 23042 })()); 23043}); 23044enifed("ember-htmlbars/templates/empty", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 23045 "use strict"; 23046 23047 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 23048 return { 23049 meta: {}, 23050 isEmpty: true, 23051 arity: 0, 23052 cachedFragment: null, 23053 hasRendered: false, 23054 buildFragment: function buildFragment(dom) { 23055 var el0 = dom.createDocumentFragment(); 23056 return el0; 23057 }, 23058 buildRenderNodes: function buildRenderNodes() { 23059 return []; 23060 }, 23061 statements: [], 23062 locals: [], 23063 templates: [] 23064 }; 23065 })()); 23066}); 23067enifed("ember-htmlbars/templates/legacy-each", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 23068 "use strict"; 23069 23070 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 23071 var child0 = (function () { 23072 var child0 = (function () { 23073 var child0 = (function () { 23074 var child0 = (function () { 23075 return { 23076 meta: {}, 23077 isEmpty: false, 23078 arity: 0, 23079 cachedFragment: null, 23080 hasRendered: false, 23081 buildFragment: function buildFragment(dom) { 23082 var el0 = dom.createDocumentFragment(); 23083 var el1 = dom.createComment(""); 23084 dom.appendChild(el0, el1); 23085 return el0; 23086 }, 23087 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23088 var morphs = new Array(1); 23089 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23090 dom.insertBoundary(fragment, 0); 23091 dom.insertBoundary(fragment, null); 23092 return morphs; 23093 }, 23094 statements: [["inline", "legacy-yield", [["get", "item", ["loc", [null, [5, 24], [5, 28]]]]], [], ["loc", [null, [5, 8], [5, 31]]]]], 23095 locals: [], 23096 templates: [] 23097 }; 23098 })(); 23099 return { 23100 meta: {}, 23101 isEmpty: false, 23102 arity: 0, 23103 cachedFragment: null, 23104 hasRendered: false, 23105 buildFragment: function buildFragment(dom) { 23106 var el0 = dom.createDocumentFragment(); 23107 var el1 = dom.createComment(""); 23108 dom.appendChild(el0, el1); 23109 return el0; 23110 }, 23111 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23112 var morphs = new Array(1); 23113 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23114 dom.insertBoundary(fragment, 0); 23115 dom.insertBoundary(fragment, null); 23116 return morphs; 23117 }, 23118 statements: [["block", "view", [["get", "attrs.itemViewClass", ["loc", [null, [4, 15], [4, 34]]]]], ["_defaultTagName", ["get", "view._itemTagName", ["loc", [null, [4, 51], [4, 68]]]]], 0, null, ["loc", [null, [4, 6], [6, 17]]]]], 23119 locals: [], 23120 templates: [child0] 23121 }; 23122 })(); 23123 var child1 = (function () { 23124 return { 23125 meta: {}, 23126 isEmpty: false, 23127 arity: 0, 23128 cachedFragment: null, 23129 hasRendered: false, 23130 buildFragment: function buildFragment(dom) { 23131 var el0 = dom.createDocumentFragment(); 23132 var el1 = dom.createComment(""); 23133 dom.appendChild(el0, el1); 23134 return el0; 23135 }, 23136 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23137 var morphs = new Array(1); 23138 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23139 dom.insertBoundary(fragment, 0); 23140 dom.insertBoundary(fragment, null); 23141 return morphs; 23142 }, 23143 statements: [["inline", "legacy-yield", [["get", "item", ["loc", [null, [8, 22], [8, 26]]]]], [], ["loc", [null, [8, 6], [8, 29]]]]], 23144 locals: [], 23145 templates: [] 23146 }; 23147 })(); 23148 return { 23149 meta: {}, 23150 isEmpty: false, 23151 arity: 0, 23152 cachedFragment: null, 23153 hasRendered: false, 23154 buildFragment: function buildFragment(dom) { 23155 var el0 = dom.createDocumentFragment(); 23156 var el1 = dom.createComment(""); 23157 dom.appendChild(el0, el1); 23158 return el0; 23159 }, 23160 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23161 var morphs = new Array(1); 23162 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23163 dom.insertBoundary(fragment, 0); 23164 dom.insertBoundary(fragment, null); 23165 return morphs; 23166 }, 23167 statements: [["block", "if", [["get", "attrs.itemViewClass", ["loc", [null, [3, 11], [3, 30]]]]], [], 0, 1, ["loc", [null, [3, 4], [9, 13]]]]], 23168 locals: [], 23169 templates: [child0, child1] 23170 }; 23171 })(); 23172 var child1 = (function () { 23173 var child0 = (function () { 23174 var child0 = (function () { 23175 return { 23176 meta: {}, 23177 isEmpty: false, 23178 arity: 0, 23179 cachedFragment: null, 23180 hasRendered: false, 23181 buildFragment: function buildFragment(dom) { 23182 var el0 = dom.createDocumentFragment(); 23183 var el1 = dom.createComment(""); 23184 dom.appendChild(el0, el1); 23185 return el0; 23186 }, 23187 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23188 var morphs = new Array(1); 23189 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23190 dom.insertBoundary(fragment, 0); 23191 dom.insertBoundary(fragment, null); 23192 return morphs; 23193 }, 23194 statements: [["inline", "legacy-yield", [["get", "item", ["loc", [null, [13, 24], [13, 28]
23194]]]], [], ["loc", [null, [13, 8], [13, 31]]]]], 23195 locals: [], 23196 templates: [] 23197 }; 23198 })(); 23199 return { 23200 meta: {}, 23201 isEmpty: false, 23202 arity: 0, 23203 cachedFragment: null, 23204 hasRendered: false, 23205 buildFragment: function buildFragment(dom) { 23206 var el0 = dom.createDocumentFragment(); 23207 var el1 = dom.createComment(""); 23208 dom.appendChild(el0, el1); 23209 return el0; 23210 }, 23211 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23212 var morphs = new Array(1); 23213 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23214 dom.insertBoundary(fragment, 0); 23215 dom.insertBoundary(fragment, null); 23216 return morphs; 23217 }, 23218 statements: [["block", "view", [["get", "attrs.itemViewClass", ["loc", [null, [12, 15], [12, 34]]]]], ["controller", ["get", "item", ["loc", [null, [12, 46], [12, 50]]]], "_defaultTagName", ["get", "view._itemTagName", ["loc", [null, [12, 67], [12, 84]]]]], 0, null, ["loc", [null, [12, 6], [14, 17]]]]], 23219 locals: [], 23220 templates: [child0] 23221 }; 23222 })(); 23223 var child1 = (function () { 23224 return { 23225 meta: {}, 23226 isEmpty: false, 23227 arity: 0, 23228 cachedFragment: null, 23229 hasRendered: false, 23230 buildFragment: function buildFragment(dom) { 23231 var el0 = dom.createDocumentFragment(); 23232 var el1 = dom.createComment(""); 23233 dom.appendChild(el0, el1); 23234 return el0; 23235 }, 23236 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23237 var morphs = new Array(1); 23238 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23239 dom.insertBoundary(fragment, 0); 23240 dom.insertBoundary(fragment, null); 23241 return morphs; 23242 }, 23243 statements: [["inline", "legacy-yield", [["get", "item", ["loc", [null, [16, 22], [16, 26]]]]], ["controller", ["get", "item", ["loc", [null, [16, 38], [16, 42]]]]], ["loc", [null, [16, 6], [16, 45]]]]], 23244 locals: [], 23245 templates: [] 23246 }; 23247 })(); 23248 return { 23249 meta: {}, 23250 isEmpty: false, 23251 arity: 0, 23252 cachedFragment: null, 23253 hasRendered: false, 23254 buildFragment: function buildFragment(dom) { 23255 var el0 = dom.createDocumentFragment(); 23256 var el1 = dom.createComment(""); 23257 dom.appendChild(el0, el1); 23258 return el0; 23259 }, 23260 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23261 var morphs = new Array(1); 23262 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23263 dom.insertBoundary(fragment, 0); 23264 dom.insertBoundary(fragment, null); 23265 return morphs; 23266 }, 23267 statements: [["block", "if", [["get", "attrs.itemViewClass", ["loc", [null, [11, 11], [11, 30]]]]], [], 0, 1, ["loc", [null, [11, 4], [17, 13]]]]], 23268 locals: [], 23269 templates: [child0, child1] 23270 }; 23271 })(); 23272 return { 23273 meta: {}, 23274 isEmpty: false, 23275 arity: 1, 23276 cachedFragment: null, 23277 hasRendered: false, 23278 buildFragment: function buildFragment(dom) { 23279 var el0 = dom.createDocumentFragment(); 23280 var el1 = dom.createComment(""); 23281 dom.appendChild(el0, el1); 23282 return el0; 23283 }, 23284 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23285 var morphs = new Array(1); 23286 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23287 dom.insertBoundary(fragment, 0); 23288 dom.insertBoundary(fragment, null); 23289 return morphs; 23290 }, 23291 statements: [["block", "if", [["get", "view.keyword", ["loc", [null, [2, 9], [2, 21]]]]], [], 0, 1, ["loc", [null, [2, 2], [18, 11]]]]], 23292 locals: ["item"], 23293 templates: [child0, child1] 23294 }; 23295 })(); 23296 var child1 = (function () { 23297 var child0 = (function () { 23298 return { 23299 meta: {}, 23300 isEmpty: false, 23301 arity: 0, 23302 cachedFragment: null, 23303 hasRendered: false, 23304 buildFragment: function buildFragment(dom) { 23305 var el0 = dom.createDocumentFragment(); 23306 var el1 = dom.createComment(""); 23307 dom.appendChild(el0, el1); 23308 return el0; 23309 }, 23310 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23311 var morphs = new Array(1); 23312 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23313 dom.insertBoundary(fragment, 0); 23314 dom.insertBoundary(fragment, null); 23315 return morphs; 23316 }, 23317 statements: [["inline", "view", [["get", "view._emptyView", ["loc", [null, [20, 10], [20, 25]]]]], ["_defaultTagName", ["get", "view._itemTagName", ["loc", [null, [20, 42], [20, 59]]]]], ["loc", [null, [20, 2], [20, 62]]]]], 23318 locals: [], 23319 templates: [] 23320 }; 23321 })(); 23322 return { 23323 meta: {}, 23324 isEmpty: false, 23325 arity: 0, 23326 cachedFragment: null, 23327 hasRendered: false, 23328 buildFragment: function buildFragment(dom) { 23329 var el0 = dom.createDocumentFragment(); 23330 var el1 = dom.createComment(""); 23331 dom.appendChild(el0, el1); 23332 return el0; 23333 }, 23334 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23335 var morphs = new Array(1); 23336 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23337 dom.insertBoundary(fragment, 0); 23338 dom.insertBoundary(fragment, null); 23339 return morphs; 23340 }, 23341 statements: [["block", "if", [["get", "view._emptyView", ["loc", [null, [19, 11], [19, 26]]]]], [], 0, null, ["loc", [null, [19, 0], [21, 0]]]]], 23342 locals: [], 23343 templates: [child0] 23344 }; 23345 })(); 23346 return { 23347 meta: {}, 23348 isEmpty: false, 23349 arity: 0, 23350 cachedFragment: null, 23351 hasRendered: false, 23352 buildFragment: function buildFragment(dom) { 23353 var el0 = dom.createDocumentFragment(); 23354 var el1 = dom.createComment(""); 23355 dom.appendChild(el0, el1); 23356 return el0; 23357 }, 23358 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23359 var morphs = new Array(1); 23360 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23361 dom.insertBoundary(fragment, 0); 23362 dom.insertBoundary(fragment, null); 23363 return morphs; 23364 }, 23365 statements: [["block", "each", [["get", "view._arrangedContent", ["loc", [null, [1, 9], [1, 30]]]]], ["-legacy-keyword", ["get", "view.keyword", ["loc", [null, [1, 47], [1, 59]]]]], 0, 1, ["loc", [null, [1, 0], [21, 11]]]]], 23366 locals: [], 23367 templates: [child0, child1] 23368 }; 23369 })()); 23370}); 23371enifed("ember-htmlbars/templates/link-to", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 23372 "use strict"; 23373 23374 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 23375 var child0 = (function () { 23376 return { 23377 meta: {}, 23378 isEmpty: false, 23379 arity: 0, 23380 cachedFragment: null, 23381 hasRendered: false, 23382 buildFragment: function buildFragment(dom) { 23383 var el0 = dom.createDocumentFragment(); 23384 var el1 = dom.createComment(""); 23385 dom.appendChild(el0, el1); 23386 return el0; 23387 }, 23388 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23389 var morphs = new Array(1); 23390 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23391 dom.insertBoundary(fragment, 0); 23392 dom.insertBoundary(fragment, null); 23393 return morphs; 23394 }, 23395 statements: [["content", "linkTitle", ["loc", [null, [1, 17], [1, 30]]]]], 23396 locals: [], 23397 templates: [] 23398 }; 23399 })(); 23400 var child1 = (function () { 23401 return { 23402 meta: {}, 23403 isEmpty: false, 23404 arity: 0, 23405 cachedFragment: null, 23406 hasRendered: false, 23407 buildFragment: function buildFragment(dom) { 23408 var el0 = dom.createDocumentFragment(); 23409 var el1 = dom.createComment(""); 23410 dom.appendChild(el0, el1); 23411 return el0; 23412 }, 23413 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23414 var morphs = new Array(1); 23415 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23416 dom.insertBoundary(fragment, 0); 23417 dom.insertBoundary(fragment, null); 23418 return morphs; 23419 }, 23420 statements: [["content", "yield", ["loc", [null, [1, 38], [1, 47]]]]], 23421 locals: [], 23422 templates: [] 23423 }; 23424 })(); 23425 return { 23426 meta: {}, 23427 isEmpty: false, 23428 arity: 0, 23429 cachedFragment: null, 23430 hasRendered: false, 23431 buildFragment: function buildFragment(dom) { 23432 var el0 = dom.createDocumentFragment(); 23433 var el1 = dom.createComment(""); 23434 dom.appendChild(el0, el1); 23435 return el0; 23436 }, 23437 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23438 var morphs = new Array(1); 23439 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23440 dom.insertBoundary(fragment, 0); 23441 dom.insertBoundary(fragment, null); 23442 return morphs; 23443 }, 23444 statements: [["block", "if", [["get", "linkTitle", ["loc", [null, [1, 6], [1, 15]]]]], [], 0, 1, ["loc", [null, [1, 0], [1, 54]]]]], 23445 locals: [], 23446 templates: [child0, child1] 23447 }; 23448 })()); 23449}); 23450enifed("ember-htmlbars/templates/select-optgroup", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 23451 "use strict"; 23452 23453 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 23454 var child0 = (function () { 23455 return { 23456 meta: {}, 23457 isEmpty: false, 23458 arity: 1, 23459 cachedFragment: null, 23460 hasRendered: false, 23461 buildFragment: function buildFragment(dom) { 23462 var el0 = dom.createDocumentFragment(); 23463 var el1 = dom.createComment(""); 23464 dom.appendChild(el0, el1); 23465 return el0; 23466 }, 23467 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23468 var morphs = new Array(1); 23469 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23470 dom.insertBoundary(fragment, 0); 23471 dom.insertBoundary(fragment, null); 23472 return morphs; 23473 }, 23474 statements: [["inline", "view", [["get", "attrs.optionView", ["loc", [null, [1, 40], [1, 56]]]]], ["content", ["get", "item", ["loc", [null, [1, 65], [1, 69]]]], "selection", ["get", "attrs.selection", ["loc", [null, [1, 80], [1, 95]]]], "parentValue", ["get", "attrs.value", ["loc", [null, [1, 108], [1, 119]]]], "multiple", ["get", "attrs.multiple", ["loc", [null, [1, 129], [1, 143]]]], "optionLabelPath", ["get", "attrs.optionLabelPath", ["loc", [null, [1, 160], [1, 181]]]], "optionValuePath", ["get", "attrs.optionValuePath", ["loc", [null, [1, 198], [1, 219]]]]], ["loc", [null, [1, 33], [1, 221]]]]], 23475 locals: ["item"], 23476 templates: [] 23477 }; 23478 })(); 23479 return { 23480 meta: {}, 23481 isEmpty: false, 23482 arity: 0, 23483 cachedFragment: null, 23484 hasRendered: false, 23485 buildFragment: function buildFragment(dom) { 23486 var el0 = dom.createDocumentFragment(); 23487 var el1 = dom.createComment(""); 23488 dom.appendChild(el0, el1); 23489 return el0; 23490 }, 23491 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23492 var morphs = new Array(1); 23493 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23494 dom.insertBoundary(fragment, 0); 23495 dom.insertBoundary(fragment, null); 23496 return morphs; 23497 }, 23498 statements: [["block", "each", [["get", "attrs.content", ["loc", [null, [1, 8], [1, 21]]]]], [], 0, null, ["loc", [null, [1, 0], [1, 230]]]]], 23499 locals: [], 23500 templates: [child0] 23501 }; 23502 })()); 23503}); 23504enifed("ember-htmlbars/templates/select-option", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 23505 "use strict"; 23506 23507 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 23508 return { 23509 meta: {}, 23510 isEmpty: false, 23511 arity: 0, 23512 cachedFragment: null, 23513 hasRendered: false, 23514 buildFragment: function buildFragment(dom) { 23515 var el0 = dom.createDocumentFragment(); 23516 var el1 = dom.createComment(""); 23517 dom.appendChild(el0, el1); 23518 return el0; 23519 }, 23520 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23521 var morphs = new Array(1); 23522 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23523 dom.insertBoundary(fragment, 0); 23524 dom.insertBoundary(fragment, null); 23525 return morphs; 23526 }, 23527 statements: [["content", "view.label", ["loc", [null, [1, 0], [1, 16]]]]], 23528 locals: [], 23529 templates: [] 23530 }; 23531 })()); 23532}); 23533enifed("ember-htmlbars/templates/select", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 23534 "use strict"; 23535 23536 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 23537 var child0 = (function () { 23538 return { 23539 meta: {}, 23540 isEmpty: false, 23541 arity: 0, 23542 cachedFragment: null, 23543 hasRendered: false, 23544 buildFragment: function buildFragment(dom) { 23545 var el0 = dom.createDocumentFragment(); 23546 var el1 = dom.createElement("option"); 23547 dom.setAttribute(el1, "value", ""); 23548 var el2 = dom.createComment(""); 23549 dom.appendChild(el1, el2); 23550 dom.appendChild(el0, el1); 23551 return el0; 23552 }, 23553 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23554 var morphs = new Array(1); 23555 morphs[0] = dom.createMorphAt(dom.childAt(fragment, [0]), 0, 0); 23556 return morphs; 23557 }, 23558 statements: [["content", "view.prompt", ["loc", [null, [1, 36], [1, 51]]]]], 23559 locals: [], 23560 templates: [] 23561 }; 23562 })(); 23563 var child1 = (function () { 23564 var child0 = (function () { 23565 return { 23566 meta: {}, 23567 isEmpty: false, 23568 arity: 1, 23569 cachedFragment: null, 23570 hasRendered: false, 23571 buildFragment: function buildFragment(dom) { 23572 var el0 = dom.createDocumentFragment(); 23573 var el1 = dom.createComment(""); 23574 dom.appendChild(el0, el1); 23575 return el0; 23576 }, 23577 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23578 var morphs = new Array(1); 23579 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23580 dom.insertBoundary(fragment, 0); 23581 dom.insertBoundary(fragment, null); 23582 return morphs; 23583 }, 23584 statements: [["inline", "view", [["get", "view.groupView", ["loc", [null, [1, 142], [1, 156]]]]], ["content", ["get", "group.content", ["loc", [null, [1, 165], [1, 178]]]], "label", ["get", "group.label", ["loc", [null, [1, 185], [1, 196]]]], "selection", ["get", "view.selection", ["loc", [null, [1, 207], [1, 221]]]], "value", ["get", "view.value", ["loc", [null, [1, 228], [1, 238]]]], "multiple", ["get", "view.multiple", ["loc", [null, [1, 248], [1, 261]]]], "optionLabelPath", ["get", "view.optionLabelPath", ["loc", [null, [1, 278], [1, 298]]]], "optionValuePath", ["get", "view.optionValuePath", ["loc", [null, [1, 315], [1, 335]]]], "optionView", ["get", "view.optionView", ["loc", [null, [1, 347], [1, 362]]]]], ["loc", [null, [1, 135], [1, 364]]]]], 23585 locals: ["group"], 23586 templates: [] 23587 }; 23588 })(); 23589 return { 23590 meta: {}, 23591 isEmpty: false, 23592 arity: 0, 23593 cachedFragment: null, 23594 hasRendered: fal
23594se, 23595 buildFragment: function buildFragment(dom) { 23596 var el0 = dom.createDocumentFragment(); 23597 var el1 = dom.createComment(""); 23598 dom.appendChild(el0, el1); 23599 return el0; 23600 }, 23601 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23602 var morphs = new Array(1); 23603 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23604 dom.insertBoundary(fragment, 0); 23605 dom.insertBoundary(fragment, null); 23606 return morphs; 23607 }, 23608 statements: [["block", "each", [["get", "view.groupedContent", ["loc", [null, [1, 103], [1, 122]]]]], [], 0, null, ["loc", [null, [1, 95], [1, 373]]]]], 23609 locals: [], 23610 templates: [child0] 23611 }; 23612 })(); 23613 var child2 = (function () { 23614 var child0 = (function () { 23615 return { 23616 meta: {}, 23617 isEmpty: false, 23618 arity: 1, 23619 cachedFragment: null, 23620 hasRendered: false, 23621 buildFragment: function buildFragment(dom) { 23622 var el0 = dom.createDocumentFragment(); 23623 var el1 = dom.createComment(""); 23624 dom.appendChild(el0, el1); 23625 return el0; 23626 }, 23627 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23628 var morphs = new Array(1); 23629 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23630 dom.insertBoundary(fragment, 0); 23631 dom.insertBoundary(fragment, null); 23632 return morphs; 23633 }, 23634 statements: [["inline", "view", [["get", "view.optionView", ["loc", [null, [1, 420], [1, 435]]]]], ["content", ["get", "item", ["loc", [null, [1, 444], [1, 448]]]], "selection", ["get", "view.selection", ["loc", [null, [1, 459], [1, 473]]]], "parentValue", ["get", "view.value", ["loc", [null, [1, 486], [1, 496]]]], "multiple", ["get", "view.multiple", ["loc", [null, [1, 506], [1, 519]]]], "optionLabelPath", ["get", "view.optionLabelPath", ["loc", [null, [1, 536], [1, 556]]]], "optionValuePath", ["get", "view.optionValuePath", ["loc", [null, [1, 573], [1, 593]]]]], ["loc", [null, [1, 413], [1, 595]]]]], 23635 locals: ["item"], 23636 templates: [] 23637 }; 23638 })(); 23639 return { 23640 meta: {}, 23641 isEmpty: false, 23642 arity: 0, 23643 cachedFragment: null, 23644 hasRendered: false, 23645 buildFragment: function buildFragment(dom) { 23646 var el0 = dom.createDocumentFragment(); 23647 var el1 = dom.createComment(""); 23648 dom.appendChild(el0, el1); 23649 return el0; 23650 }, 23651 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23652 var morphs = new Array(1); 23653 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23654 dom.insertBoundary(fragment, 0); 23655 dom.insertBoundary(fragment, null); 23656 return morphs; 23657 }, 23658 statements: [["block", "each", [["get", "view.content", ["loc", [null, [1, 389], [1, 401]]]]], [], 0, null, ["loc", [null, [1, 381], [1, 604]]]]], 23659 locals: [], 23660 templates: [child0] 23661 }; 23662 })(); 23663 return { 23664 meta: {}, 23665 isEmpty: false, 23666 arity: 0, 23667 cachedFragment: null, 23668 hasRendered: false, 23669 buildFragment: function buildFragment(dom) { 23670 var el0 = dom.createDocumentFragment(); 23671 var el1 = dom.createComment(""); 23672 dom.appendChild(el0, el1); 23673 var el1 = dom.createComment(""); 23674 dom.appendChild(el0, el1); 23675 var el1 = dom.createTextNode("\n"); 23676 dom.appendChild(el0, el1); 23677 return el0; 23678 }, 23679 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23680 var morphs = new Array(2); 23681 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23682 morphs[1] = dom.createMorphAt(fragment, 1, 1, contextualElement); 23683 dom.insertBoundary(fragment, 0); 23684 return morphs; 23685 }, 23686 statements: [["block", "if", [["get", "view.prompt", ["loc", [null, [1, 6], [1, 17]]]]], [], 0, null, ["loc", [null, [1, 0], [1, 67]]]], ["block", "if", [["get", "view.optionGroupPath", ["loc", [null, [1, 73], [1, 93]]]]], [], 1, 2, ["loc", [null, [1, 67], [1, 611]]]]], 23687 locals: [], 23688 templates: [child0, child1, child2] 23689 }; 23690 })()); 23691}); 23692enifed("ember-htmlbars/templates/top-level-view", ["exports", "ember-template-compiler/system/template"], function (exports, _emberTemplateCompilerSystemTemplate) { 23693 "use strict"; 23694 23695 exports.default = _emberTemplateCompilerSystemTemplate.default((function () { 23696 return { 23697 meta: {}, 23698 isEmpty: false, 23699 arity: 0, 23700 cachedFragment: null, 23701 hasRendered: false, 23702 buildFragment: function buildFragment(dom) { 23703 var el0 = dom.createDocumentFragment(); 23704 var el1 = dom.createComment(""); 23705 dom.appendChild(el0, el1); 23706 return el0; 23707 }, 23708 buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 23709 var morphs = new Array(1); 23710 morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 23711 dom.insertBoundary(fragment, 0); 23712 dom.insertBoundary(fragment, null); 23713 return morphs; 23714 }, 23715 statements: [["content", "outlet", ["loc", [null, [1, 0], [1, 10]]]]], 23716 locals: [], 23717 templates: [] 23718 }; 23719 })()); 23720}); 23721enifed('ember-htmlbars/utils/decode-each-key', ['exports', 'ember-metal/property_get', 'ember-metal/utils'], function (exports, _emberMetalProperty_get, _emberMetalUtils) { 23722 'use strict'; 23723 23724 exports.default = decodeEachKey; 23725 23726 function identity(item) { 23727 var key = undefined; 23728 var type = typeof item; 23729 23730 if (type === 'string' || type === 'number') { 23731 key = item; 23732 } else { 23733 key = _emberMetalUtils.guidFor(item); 23734 } 23735 23736 return key; 23737 } 23738 23739 function decodeEachKey(item, keyPath, index) { 23740 var key; 23741 23742 switch (keyPath) { 23743 case '@index': 23744 key = index; 23745 break; 23746 case '@identity': 23747 key = identity(item); 23748 break; 23749 default: 23750 if (keyPath) { 23751 key = _emberMetalProperty_get.get(item, keyPath); 23752 } else { 23753 key = identity(item); 23754 } 23755 } 23756 23757 if (typeof key === 'number') { 23758 key = String(key); 23759 } 23760 23761 return key; 23762 } 23763}); 23764enifed('ember-htmlbars/utils/extract-positional-params', ['exports', 'ember-metal/debug', 'ember-metal/stream
23764s/stream', 'ember-metal/streams/utils'], function (exports, _emberMetalDebug, _emberMetalStreamsStream, _emberMetalStreamsUtils) { 23765 'use strict'; 23766 23767 exports.default = extractPositionalParams; 23768 exports.processPositionalParams = processPositionalParams; 23769 23770 function extractPositionalParams(renderNode, component, params, attrs) { 23771 var positionalParams = component.positionalParams; 23772 23773 if (positionalParams) { 23774 processPositionalParams(renderNode, positionalParams, params, attrs); 23775 } 23776 } 23777 23778 function processPositionalParams(renderNode, positionalParams, params, attrs) { 23779 var isRest = typeof positionalParams === 'string'; 23780 23781 if (isRest) { 23782 processRestPositionalParameters(renderNode, positionalParams, params, attrs); 23783 } else { 23784 processNamedPositionalParameters(renderNode, positionalParams, params, attrs); 23785 } 23786 } 23787 23788 function processNamedPositionalParameters(renderNode, positionalParams, params, attrs) { 23789 var limit = Math.min(params.length, positionalParams.length); 23790 23791 for (var i = 0; i < limit; i++) { 23792 var param = params[i]; 23793 23794 _emberMetalDebug.assert('You cannot specify both a positional param (at position ' + i + ') and the hash argument `' + positionalParams[i] + '`.', !(positionalParams[i] in attrs)); 23795 23796 attrs[positionalParams[i]] = param; 23797 } 23798 } 23799 23800 function processRestPositionalParameters(renderNode, positionalParamsName, params, attrs) { 23801 var nameInAttrs = (positionalParamsName in attrs); 23802 23803 // when no params are used, do not override the specified `attrs.stringParamName` value 23804 if (params.length === 0 && nameInAttrs) { 23805 return; 23806 } 23807 23808 // If there is already an attribute for that variable, do nothing 23809 _emberMetalDebug.assert('You cannot specify positional parameters and the hash argument `' + positionalParamsName + '`.', !nameInAttrs); 23810 23811 var paramsStream = new _emberMetalStreamsStream.Stream(function () { 23812 return _emberMetalStreamsUtils.readArray(params.slice(0)); 23813 }, 'params'); 23814 23815 attrs[positionalParamsName] = paramsStream; 23816 23817 for (var i = 0; i < params.length; i++) { 23818 var param = params[i]; 23819 paramsStream.addDependency(param); 23820 } 23821 } 23822}); 23823enifed('ember-htmlbars/utils/is-component', ['exports', 'ember-metal/features', 'ember-htmlbars/system/lookup-helper', 'ember-htmlbars/keywords/closure-component', 'ember-metal/streams/utils'], function (exports, _emberMetalFeatures, _emberHtmlbarsSystemLookupHelper, _emberHtmlbarsKeywordsClosureComponent, _emberMetalStreamsUtils) { 23824 /** 23825 @module ember 23826 @submodule ember-htmlbars 23827 */ 23828 23829 'use strict'; 23830 23831 exports.default = isComponent; 23832 23833 function hasComponentOrTemplate(owner, path, options) { 23834 return owner.hasRegistration('component:' + path, options) || owner.hasRegistration('template:components/' + path, options); 23835 } 23836 23837 /* 23838 Given a path name, returns whether or not a component with that 23839 name was found in the container. 23840 */ 23841 23842 function isComponent(env, scope, path) { 23843 var owner = env.owner; 23844 if (!owner) { 23845 return false; 23846 } 23847 if (typeof path === 'string') { 23848 if (_emberHtmlbarsSystemLookupHelper.CONTAINS_DOT_CACHE.get(path)) { 23849 var stream = env.hooks.get(env, scope, path); 23850 if (_emberMetalStreamsUtils.isStream(stream)) { 23851 var cell = stream.value(); 23852 if (_emberHtmlbarsKeywordsClosureComponent.isComponentCell(cell)) { 23853 return true; 23854 } 23855 } 23856 } 23857 if (!_emberHtmlbarsSystemLookupHelper.CONTAINS_DASH_CACHE.get(path)) { 23858 return false; 23859 } 23860 23861 if (hasComponentOrTemplate(owner, path)) { 23862 return true; // global component found 23863 } else { 23864 var moduleName = env.meta && env.meta.moduleName; 23865 23866 if (!moduleName) {
23867 // Without a source moduleName, we can not perform local lookups. 23868 return false; 23869 } 23870 23871 var options = { source: 'template:' + moduleName }; 23872 23873 return hasComponentOrTemplate(owner, path, options); 23874 } 23875 } 23876 } 23877}); 23878enifed('ember-htmlbars/utils/lookup-component', ['exports', 'ember-metal/features'], function (exports, _emberMetalFeatures) { 23879 'use strict'; 23880 23881 exports.default = lookupComponent; 23882 23883 function lookupComponentPair(componentLookup, owner, name, options) { 23884 return { 23885 component: componentLookup.componentFor(name, owner, options), 23886 layout: componentLookup.layoutFor(name, owner, options) 23887 }; 23888 } 23889 23890 function lookupComponent(owner, name, options) { 23891 var componentLookup = owner.lookup('component-lookup:main'); 23892 23893 var source = options && options.source; 23894 23895 if (source) { 23896 var localResult = lookupComponentPair(componentLookup, owner, name, options); 23897 23898 if (localResult.component || localResult.layout) { 23899 return localResult; 23900 } 23901 } 23902 23903 return lookupComponentPair(componentLookup, owner, name); 23904 } 23905}); 23906enifed('ember-htmlbars/utils/new-stream', ['exports', 'ember-metal/streams/proxy-stream', 'ember-htmlbars/utils/subscribe'], function (exports, _emberMetalStreamsProxyStream, _emberHtmlbarsUtilsSubscribe) { 23907 'use strict'; 23908 23909 exports.default = newStream; 23910 23911 function newStream(scope, key, newValue, renderNode, isSelf) { 23912 var stream = new _emberMetalStreamsProxyStream.default(newValue, isSelf ? '' : key); 23913 if (renderNode) { 23914 _emberHtmlbarsUtilsSubscribe.default(renderNode, scope, stream); 23915 } 23916 scope[key] = stream; 23917 } 23918}); 23919enifed("ember-htmlbars/utils/normalize-self", ["exports"], function (exports) { 23920 "use strict"; 23921 23922 exports.default = normalizeSelf; 23923 23924 function normalizeSelf(self) { 23925 if (self === undefined) { 23926 return null; 23927 } else { 23928 return self; 23929 } 23930 } 23931}); 23932enifed('ember-htmlbars/utils/string', ['exports', 'ember-metal/core', 'ember-runtime/system/string', 'htmlbars-util'], function (exports, _emberMetalCore, _emberRuntimeSystemString, _htmlbarsUtil) { 23933 /** 23934 @module ember 23935 @submodule ember-htmlbars 23936 */ 23937 23938 'use strict'; 23939 23940 /** 23941 Mark a string as safe for unescaped output with Ember templates. If you 23942 return HTML from a helper, use this function to 23943 ensure Ember's rendering layer does not escape the HTML. 23944 23945 ```javascript 23946 Ember.String.htmlSafe('<div>someString</div>') 23947 ``` 23948 23949 @method htmlSafe 23950 @for Ember.String 23951 @static 23952 @return {Handlebars.SafeString} A string that will not be HTML escaped by Handlebars. 23953 @public 23954 */ 23955 function htmlSafe(str) { 23956 if (str === null || str === undefined) { 23957 str = ''; 23958 } else if (typeof str !== 'string') { 23959 str = '' + str; 23960 } 23961 return new _htmlbarsUtil.SafeString(str); 23962 } 23963 23964 _emberRuntimeSystemString.default.htmlSafe = htmlSafe; 23965 if (_emberMetalCore.default.EXTEND_PROTOTYPES === true || _emberMetalCore.default.EXTEND_PROTOTYPES.String) { 23966 String.prototype.htmlSafe = function () { 23967 return htmlSafe(this); 23968 }; 23969 } 23970 23971 exports.SafeString = _htmlbarsUtil.SafeString; 23972 exports.htmlSafe = htmlSafe; 23973 exports.escapeExpression = _htmlbarsUtil.escapeExpression; 23974}); 23975enifed('ember-htmlbars/utils/subscribe', ['exports', 'ember-metal/streams/utils'], function (exports, _emberMetalStreamsUtils) { 23976 'use strict'; 23977 23978 exports.default = subscribe; 23979 23980 function subscribe(node, env, scope, stream) { 23981 if (!_emberMetalStreamsUtils.isStream(stream)) { 23982 return; 23983 } 23984 var component = scope.getComponent(); 23985 var unsubscribers = node.streamUnsubscribers = node.streamUnsubscribers || []; 23986 23987 unsubscribers.push(stream.subscribe(function () { 23988 node.isDirty = true; 23989 23990 // Whenever a render node directly inside a component becomes 23991 // dirty, we want to invoke the willRenderElement and 23992 // didRenderElement lifecycle hooks. From the perspective of the 23993 // programming model, whenever anything in the DOM changes, a 23994 // "re-render" has occured. 23995 if (component && component._renderNode) { 23996 component._renderNode.isDirty = true; 23997 } 23998 23999 if (node.getState().manager) { 24000 node.shouldReceiveAttrs = true; 24001 } 24002 24003 node.ownerNode.emberView.scheduleRevalidate(node, _emberMetalStreamsUtils.labelFor(stream)); 24004 })); 24005 } 24006}); 24007enifed('ember-htmlbars/utils/update-scope', ['exports', 'ember-metal/stream
24007s/proxy-stream', 'ember-htmlbars/utils/subscribe'], function (exports, _emberMetalStreamsProxyStream, _emberHtmlbarsUtilsSubscribe) { 24008 'use strict'; 24009 24010 exports.default = updateScope; 24011 24012 function updateScope(scope, key, newValue, renderNode, isSelf) { 24013 var existing = scope[key]; 24014 24015 if (existing) { 24016 existing.setSource(newValue); 24017 } else { 24018 var stream = new _emberMetalStreamsProxyStream.default(newValue, isSelf ? null : key); 24019 if (renderNode) { 24020 _emberHtmlbarsUtilsSubscribe.default(renderNode, scope, stream); 24021 } 24022 scope[key] = stream; 24023 } 24024 } 24025}); 24026enifed('ember-metal/alias', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/error', 'ember-metal/properties', 'ember-metal/computed', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/dependent_keys'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalError, _emberMetalProperties, _emberMetalComputed, _emberMetalUtils, _emberMetalMeta, _emberMetalDependent_keys) { 24027 'use strict'; 24028 24029 exports.default = alias; 24030 exports.AliasedProperty = AliasedProperty; 24031 24032 function alias(altKey) { 24033 return new AliasedProperty(altKey); 24034 } 24035 24036 function AliasedProperty(altKey) { 24037 this.isDescriptor = true; 24038 this.altKey = altKey; 24039 this._dependentKeys = [altKey]; 24040 } 24041 24042 AliasedProperty.prototype = Object.create(_emberMetalProperties.Descriptor.prototype); 24043 24044 AliasedProperty.prototype.get = function AliasedProperty_get(obj, keyName) { 24045 return _emberMetalProperty_get.get(obj, this.altKey); 24046 }; 24047 24048 AliasedProperty.prototype.set = function AliasedProperty_set(obj, keyName, value) { 24049 return _emberMetalProperty_set.set(obj, this.altKey, value); 24050 }; 24051 24052 AliasedProperty.prototype.willWatch = function (obj, keyName) { 24053 _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, _emberMetalMeta.meta(obj)); 24054 }; 24055 24056 AliasedProperty.prototype.didUnwatch = function (obj, keyName) { 24057 _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, _emberMetalMeta.meta(obj)); 24058 }; 24059 24060 AliasedProperty.prototype.setup = function (obj, keyName) { 24061 _emberMetalDebug.assert('Setting alias \'' + keyName + '\' on self', this.altKey !== keyName); 24062 var m = _emberMetalMeta.meta(obj); 24063 if (m.peekWatching(keyName)) { 24064 _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, m); 24065 } 24066 }; 24067 24068 AliasedProperty.prototype.teardown = function (obj, keyName) { 24069 var m = _emberMetalMeta.meta(obj); 24070 if (m.peekWatching(keyName)) { 24071 _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, m); 24072 } 24073 }; 24074 24075 AliasedProperty.prototype.readOnly = function () { 24076 this.set = AliasedProperty_readOnlySet; 24077 return this; 24078 }; 24079 24080 function AliasedProperty_readOnlySet(obj, keyName, value) { 24081 throw new _emberMetalError.default('Cannot set read-only property \'' + keyName + '\' on object: ' + _emberMetalUtils.inspect(obj)); 24082 } 24083 24084 AliasedProperty.prototype.oneWay = function () { 24085 this.set = AliasedProperty_oneWaySet; 24086 return this; 24087 }; 24088 24089 function AliasedProperty_oneWaySet(obj, keyName, value) { 24090 _emberMetalProperties.defineProperty(obj, keyName, null); 24091 return _emberMetalProperty_set.set(obj, keyName, value); 24092 } 24093 24094 // Backwards compatibility with Ember Data. 24095 AliasedProperty.prototype._meta = undefined; 24096 AliasedProperty.prototype.meta = _emberMetalComputed.ComputedProperty.prototype.meta; 24097}); 24098enifed("ember-metal/assign", ["exports"], function (exports) { 24099 /** 24100 Copy properties from a source object to a target object. 24101 24102 ```javascript 24103 var a = {first: 'Yehuda'}; 24104 var b = {last: 'Katz'}; 24105 var c = {company: 'Tilde Inc.'}; 24106 Ember.assign(a, b, c); // a === {first: 'Yehuda', last: 'Katz', company: 'Tilde Inc.'}, b === {last: 'Katz'}, c === {company: 'Tilde Inc.'} 24107 ``` 24108 24109 @method assign 24110 @for Ember 24111 @param {Object} original The object to assign into 24112 @param {Object} ...args The objects to copy properties from 24113 @return {Object} 24114 @public 24115 */ 24116 "use strict"; 24117 24118 exports.default = assign; 24119 24120 function assign(original) { 24121 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 24122 args[_key - 1] = arguments[_key]; 24123 } 24124 24125 for (var i = 0, l = args.length; i < l; i++) { 24126 var arg = args[i]; 24127 if (!arg) { 24128 continue; 24129 } 24130 24131 var updates = Object.keys(arg); 24132 24133 for (var _i = 0, _l = updates.length; _i < _l; _i++) { 24134 var prop = updates[_i]; 24135 original[prop] = arg[prop]; 24136 } 24137 } 24138 24139 return original; 24140 } 24141}); 24142enifed('ember-metal/binding', ['exports', 'ember-metal/core', 'ember-metal/logger', 'ember-metal/run_loop', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/utils', 'ember-metal/events', 'ember-metal/observer', 'ember-metal/path_cache'], function (exports, _emberMetalCore, _emberMetalLogger, _emberMetalRun_loop, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalUtils, _emberMetalEvents, _emberMetalObserver, _emberMetalPath_cache) { 24143 'use strict'; 24144 24145 exports.bind = bind; 24146 24147 // ES6TODO: where is Ember.lookup defined? 24148 /** 24149 @module ember 24150 @submodule ember-metal 24151 */ 24152 24153 // .......................................................... 24154 // CONSTANTS 24155 // 24156 24157 /** 24158 Debug parameter you can turn on. This will log all bindings that fire to 24159 the console. This should be disabled in production code. Note that you 24160 can also enable this from the console or temporarily. 24161 24162 @property LOG_BINDINGS 24163 @for Ember 24164 @type Boolean 24165 @default false 24166 @public 24167 */ 24168 _emberMetalCore.default.LOG_BINDINGS = false || !!_emberMetalCore.default.ENV.LOG_BINDINGS; 24169 24170 // .......................................................... 24171 // BINDING 24172 // 24173 24174 function Binding(toPath, fromPath) { 24175 // Configuration 24176 this._from = fromPath; 24177 this._to = toPath; 24178 this._oneWay = undefined; 24179 24180 // State 24181 this._direction = undefined; 24182 this._readyToSync = undefined; 24183 this._fromObj = undefined; 24184 this._fromPath = undefined; 24185 this._toObj = undefined; 24186 } 24187 24188 /** 24189 @class Binding 24190 @namespace Ember 24191 @public 24192 */ 24193 24194 Binding.prototype = { 24195 /** 24196 This copies the Binding so it can be connected to another object. 24197 @method copy 24198 @return {Ember.Binding} `this` 24199 @public 24200 */ 24201 copy: function () { 24202 var copy = new Binding(this._to, this._from); 24203 if (this._oneWay) { 24204 copy._oneWay = true; 24205 } 24206 return copy; 24207 }, 24208 24209 // .......................................................... 24210 // CONFIG 24211 // 24212 24213 /** 24214 This will set `from` property path to the specified value. It will not 24215 attempt to resolve this property path to an actual object until you 24216 connect the binding. 24217 The binding will search for the property path starting at the root object 24218 you pass when you `connect()` the binding. It follows the same rules as 24219 `get()` - see that method for more information. 24220 @method from 24221 @param {String} path The property path to connect to. 24222 @return {Ember.Binding} `this` 24223 @public 24224 */ 24225 from: function (path) { 24226 this._from = path; 24227 return this; 24228 }, 24229 24230 /** 24231 This will set the `to` property path to the specified value. It will not 24232 attempt to resolve this property path to an actual object until you 24233 connect the binding. 24234 The binding will search for the property path starting at the root object 24235 you pass when you `connect()` the binding. It follows the same rules as 24236 `get()` - see that method for more information. 24237 @method to 24238 @param {String|Tuple} path A property path or tuple. 24239 @return {Ember.Binding} `this` 24240 @public 24241 */ 24242 to: function (path) { 24243 this._to = path; 24244 return this; 24245 }, 24246 24247 /** 24248 Configures the binding as one way. A one-way binding will relay changes 24249 on the `from` side to the `to` side, but not the other way around. This 24250 means that if you change the `to` side directly, the `from` side may have 24251 a different value. 24252 @method oneWay 24253 @return {Ember.Binding} `this` 24254 @public 24255 */ 24256 oneWay: function () { 24257 this._oneWay = true; 24258 return this; 24259 }, 24260 24261 /** 24262 @method toString 24263 @return {String} string representation of binding 24264 @public 24265 */ 24266 toString: function () { 24267 var oneWay = this._oneWay ? '[oneWay]' : ''; 24268 return 'Ember.Binding<' + _emberMetalUtils.guidFor(this) + '>(' + this._from + ' -> ' + this._to + ')' + oneWay; 24269 }, 24270 24271 // .......................................................... 24272 // CONNECT AND SYNC 24273 // 24274 24275 /** 24276 Attempts to connect this binding instance so that it can receive and relay 24277 changes. This method will raise an exception if you have not set the 24278 from/to properties yet. 24279 @method connect 24280 @param {Object} obj The root object for this binding. 24281 @return {Ember.Binding} `this` 24282 @public 24283 */ 24284 connect: function (obj) { 24285 _emberMetalDebug.assert('Must pass a valid object to Ember.Binding.connect()', !!obj); 24286 24287 var fromObj = undefined, 24288 fromPath = undefined; 24289 24290 // If the binding's "from" path could be interpreted as a global, verify 24291 // whether the path refers to a global or not by consulting `Ember.lookup`. 24292 if (_emberMetalPath_cache.isGlobalPath(this._from)) { 24293 var _name = _emberMetalPath_cache.getFirstKey(this._from); 24294 var possibleGlobal = _emberMetalCore.default.lookup[_name]; 24295 24296 if (possibleGlobal) { 24297 fromObj = possibleGlobal; 24298 fromPath = _emberMetalPath_cache.getTailPath(this._from); 24299 } 24300 } 24301 24302 if (fromObj === undefined) { 24303 fromObj = obj; 24304 fromPath = this._from; 24305 } 24306 24307 _emberMetalProperty_set.trySet(obj, this._to, _emberMetalProperty_get.get(fromObj, fromPath)); 24308 24309 // Add an observer on the object to be notified when the binding should be updated. 24310 _emberMetalObserver.addObserver(fromObj, fromPath, this, 'fromDidChange'); 24311 24312 // If the binding is a two-way binding, also set up an observer on the target. 24313 if (!this._oneWay) { 24314 _emberMetalObserver.addObserver(obj, this._to, this, 'toDidChange'); 24315 } 24316 24317 _emberMetalEvents.addListener(obj, 'willDestroy', this, 'disconnect'); 24318 24319 this._readyToSync = true; 24320 this._fromObj = fromObj; 24321 this._fromPath = fromPath; 24322 this._toObj = obj; 24323 24324 return this; 24325 }, 24326 24327 /** 24328 Disconnects the binding instance. Changes will no longer be relayed. You 24329 will not usually need to call this method. 24330 @method disconnect 24331 @return {Ember.Binding} `this` 24332 @public 24333 */ 24334 disconnect: function () { 24335 _emberMetalDebug.assert('Must pass a valid object to Ember.Binding.disconnect()', !!this._toObj); 24336 24337 // Remove an observer on the object so we're no longer notified of 24338 // changes that should update bindings. 24339 _emberMetalObserver.removeObserver(this._fromObj, this._fromPath, this, 'fromDidChange'); 24340 24341 // If the binding is two-way, remove the observer from the target as well. 24342 if (!this._oneWay) { 24343 _emberMetalObserver.removeObserver(this._toObj, this._to, this, 'toDidChange'); 24344 } 24345 24346 this._readyToSync = false; // Disable scheduled syncs... 24347 return this; 24348 }, 24349 24350 // .......................................................... 24351 // PRIVATE 24352 // 24353 24354 /* Called when the from side changes. */ 24355 fromDidChange: function (target) { 24356 this._scheduleSync('fwd'); 24357 }, 24358 24359 /* Called when the to side changes. */ 24360 toDidChange: function (target) { 24361 this._scheduleSync('back'); 24362 }, 24363 24364 _scheduleSync: function (dir) { 24365 var existingDir = this._direction; 24366 24367 // If we haven't scheduled the binding yet, schedule it. 24368 if (existingDir === undefined) { 24369 _emberMetalRun_loop.default.schedule('sync', this, '_sync'); 24370 this._direction = dir; 24371 } 24372
24373 // If both a 'back' and 'fwd' sync have been scheduled on the same object, 24374 // default to a 'fwd' sync so that it remains deterministic. 24375 if (existingDir === 'back' && dir === 'fwd') { 24376 this._direction = 'fwd'; 24377 } 24378 }, 24379 24380 _sync: function () { 24381 var log = _emberMetalCore.default.LOG_BINDINGS; 24382 24383 var toObj = this._toObj; 24384 24385 // Don't synchronize destroyed objects or disconnected bindings. 24386 if (toObj.isDestroyed || !this._readyToSync) { 24387 return; 24388 } 24389 24390 // Get the direction of the binding for the object we are 24391 // synchronizing from. 24392 var direction = this._direction; 24393 24394 var fromObj = this._fromObj; 24395 var fromPath = this._fromPath; 24396 24397 this._direction = undefined; 24398 24399 // If we're synchronizing from the remote object... 24400 if (direction === 'fwd') { 24401 var fromValue = _emberMetalProperty_get.get(fromObj, fromPath); 24402 if (log) { 24403 _emberMetalLogger.default.log(' ', this.toString(), '->', fromValue, fromObj); 24404 } 24405 if (this._oneWay) { 24406 _emberMetalProperty_set.trySet(toObj, this._to, fromValue); 24407 } else { 24408 _emberMetalObserver._suspendObserver(toObj, this._to, this, 'toDidChange', function () { 24409 _emberMetalProperty_set.trySet(toObj, this._to, fromValue); 24410 }); 24411 } 24412 // If we're synchronizing *to* the remote object. 24413 } else if (direction === 'back') { 24414 var toValue = _emberMetalProperty_get.get(toObj, this._to); 24415 if (log) { 24416 _emberMetalLogger.default.log(' ', this.toString(), '<-', toValue, toObj); 24417 } 24418 _emberMetalObserver._suspendObserver(fromObj, fromPath, this, 'fromDidChange', function () { 24419 _emberMetalProperty_set.trySet(fromObj, fromPath, toValue); 24420 }); 24421 } 24422 } 24423 24424 }; 24425 24426 function mixinProperties(to, from) { 24427 for (var key in from) { 24428 if (from.hasOwnProperty(key)) { 24429 to[key] = from[key]; 24430 } 24431 } 24432 } 24433 24434 mixinProperties(Binding, { 24435 24436 /* 24437 See `Ember.Binding.from`. 24438 @method from 24439 @static 24440 */ 24441 from: function (from) { 24442 var C = this; 24443 return new C(undefined, from); 24444 }, 24445 24446 /* 24447 See `Ember.Binding.to`. 24448 @method to 24449 @static 24450 */ 24451 to: function (to) { 24452 var C = this; 24453 return new C(to, undefined); 24454 } 24455 }); 24456 /** 24457 An `Ember.Binding` connects the properties of two objects so that whenever 24458 the value of one property changes, the other property will be changed also. 24459 24460 ## Automatic Creation of Bindings with `/^*Binding/`-named Properties. 24461 24462 You do not usually create Binding objects directly but instead describe 24463 bindings in your class or object definition using automatic binding 24464 detection. 24465 24466 Properties ending in a `Binding` suffix will be converted to `Ember.Binding` 24467 instances. The value of this property should be a string representing a path 24468 to another object or a custom binding instance created using Binding helpers 24469 (see "One Way Bindings"): 24470 24471 ``` 24472 valueBinding: "MyApp.someController.title" 24473 ``` 24474 24475 This will create a binding from `MyApp.someController.title` to the `value` 24476 property of your object instance automatically. Now the two values will be 24477 kept in sync. 24478 24479 ## One Way Bindings 24480 24481 One especially useful binding customization you can use is the `oneWay()` 24482 helper. This helper tells Ember that you are only interested in 24483 receiving changes on the object you are binding from. For example, if you 24484 are binding to a preference and you want to be notified if the preference 24485 has changed, but your object will not be changing the preference itself, you 24486 could do: 24487 24488 ``` 24489 bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles") 24490 ``` 24491 24492 This way if the value of `MyApp.preferencesController.bigTitles` changes the 24493 `bigTitles` property of your object will change also. However, if you 24494 change the value of your `bigTitles` property, it will not update the 24495 `preferencesController`. 24496
24497 One way bindings are almost twice as fast to setup and twice as fast to 24498 execute because the binding only has to worry about changes to one side. 24499 24500 You should consider using one way bindings anytime you have an object that 24501 may be created frequently and you do not intend to change a property; only 24502 to monitor it for changes (such as in the example above). 24503 24504 ## Adding Bindings Manually 24505 24506 All of the examples above show you how to configure a custom binding, but the 24507 result of these customizations will be a binding template, not a fully active 24508 Binding instance. The binding will actually become active only when you 24509 instantiate the object the binding belongs to. It is useful, however, to 24510 understand what actually happens when the binding is activated. 24511 24512 For a binding to function it must have at least a `from` property and a `to` 24513 property. The `from` property path points to the object/key that you want to 24514 bind from while the `to` path points to the object/key you want to bind to. 24515 24516 When you define a custom binding, you are usually describing the property 24517 you want to bind from (such as `MyApp.someController.value` in the examples 24518 above). When your object is created, it will automatically assign the value 24519 you want to bind `to` based on the name of your binding key. In the 24520 examples above, during init, Ember objects will effectively call 24521 something like this on your binding: 24522 24523 ```javascript 24524 binding = Ember.Binding.from("valueBinding").to("value"); 24525 ``` 24526 24527 This creates a new binding instance based on the template you provide, and 24528 sets the to path to the `value` property of the new object. Now that the 24529 binding is fully configured with a `from` and a `to`, it simply needs to be 24530 connected to become active. This is done through the `connect()` method: 24531 24532 ```javascript 24533 binding.connect(this); 24534 ``` 24535 24536 Note that when you connect a binding you pass the object you want it to be 24537 connected to. This object will be used as the root for both the from and 24538 to side of the binding when inspecting relative paths. This allows the 24539 binding to be automatically inherited by subclassed objects as well. 24540 24541 This also allows you to bind between objects using the paths you declare in 24542 `from` and `to`: 24543 24544 ```javascript 24545 // Example 1 24546 binding = Ember.Binding.from("App.someObject.value").to("value"); 24547 binding.connect(this); 24548 24549 // Example 2 24550 binding = Ember.Binding.from("parentView.value").to("App.someObject.value"); 24551 binding.connect(this); 24552 ``` 24553 24554 Now that the binding is connected, it will observe both the from and to side 24555 and relay changes. 24556 24557 If you ever needed to do so (you almost never will, but it is useful to 24558 understand this anyway), you could manually create an active binding by 24559 using the `Ember.bind()` helper method. (This is the same method used by 24560 to setup your bindings on objects): 24561 24562 ```javascript 24563 Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value"); 24564 ``` 24565 24566 Both of these code fragments have the same effect as doing the most friendly 24567 form of binding creation like so: 24568 24569 ```javascript 24570 MyApp.anotherObject = Ember.Object.create({ 24571 valueBinding: "MyApp.someController.value", 24572 24573 // OTHER CODE FOR THIS OBJECT... 24574 }); 24575 ``` 24576 24577 Ember's built in binding creation method makes it easy to automatically 24578 create bindings for you. You should always use the highest-level APIs 24579 available, even if you understand how it works underneath. 24580 24581 @class Binding 24582 @namespace Ember 24583 @since Ember 0.9 24584 @public 24585 */ 24586 // Ember.Binding = Binding; ES6TODO: where to put this? 24587 24588 /** 24589 Global helper method to create a new binding. Just pass the root object 24590 along with a `to` and `from` path to create and connect the binding. 24591 24592 @method bind 24593 @for Ember 24594 @param {Object} obj The root object of the transform. 24595 @param {String} to The path to the 'to' side of the binding. 24596 Must be relative to obj. 24597 @param {String} from The path to the 'from' side of the binding. 24598 Must be relative to obj or a global path.
24599 @return {Ember.Binding} binding instance 24600 @public 24601 */ 24602 24603 function bind(obj, to, from) { 24604 return new Binding(to, from).connect(obj); 24605 } 24606 24607 exports.Binding = Binding; 24608}); 24609// Ember.LOG_BINDINGS 24610enifed('ember-metal/cache', ['exports', 'ember-metal/empty_object'], function (exports, _emberMetalEmpty_object) { 24611 'use strict'; 24612 24613 exports.default = Cache; 24614 24615 function Cache(limit, func) { 24616 this.store = new _emberMetalEmpty_object.default(); 24617 this.size = 0; 24618 this.misses = 0; 24619 this.hits = 0; 24620 this.limit = limit; 24621 this.func = func; 24622 } 24623 24624 var UNDEFINED = function () {}; 24625 24626 Cache.prototype = { 24627 set: function (key, value) { 24628 if (this.limit > this.size) { 24629 this.size++; 24630 if (value === undefined) { 24631 this.store[key] = UNDEFINED; 24632 } else { 24633 this.store[key] = value; 24634 } 24635 } 24636 24637 return value; 24638 }, 24639 24640 get: function (key) { 24641 var value = this.store[key]; 24642 24643 if (value === undefined) { 24644 this.misses++; 24645 value = this.set(key, this.func(key)); 24646 } else if (value === UNDEFINED) { 24647 this.hits++; 24648 value = undefined; 24649 } else { 24650 this.hits++; 24651 // nothing to translate 24652 } 24653 24654 return value; 24655 }, 24656 24657 purge: function () { 24658 this.store = new _emberMetalEmpty_object.default(); 24659 this.size = 0; 24660 this.hits = 0; 24661 this.misses = 0; 24662 } 24663 }; 24664}); 24665enifed('ember-metal/chains', ['exports', 'ember-metal/property_get', 'ember-metal/meta', 'ember-metal/watch_key', 'ember-metal/empty_object'], function (exports, _emberMetalProperty_get, _emberMetalMeta, _emberMetalWatch_key, _emberMetalEmpty_object) { 24666 'use strict'; 24667 24668 exports.finishChains = finishChains; 24669 24670 var FIRST_KEY = /^([^\.]+)/; 24671 24672 function firstKey(path) { 24673 return path.match(FIRST_KEY)[0]; 24674 } 24675 24676 function isObject(obj) { 24677 return obj && typeof obj === 'object'; 24678 } 24679 24680 function isVolatile(obj) { 24681 return !(isObject(obj) && obj.isDescriptor && obj._volatile === false); 24682 } 24683 24684 function ChainWatchers() { 24685 // chain nodes that reference a key in this obj by key 24686 // we only create ChainWatchers when we are going to add them 24687 // so create this upfront 24688 this.chains = new _emberMetalEmpty_object.default(); 24689 } 24690 24691 ChainWatchers.prototype = { 24692 add: function (key, node) { 24693 var nodes = this.chains[key]; 24694 if (nodes === undefined) { 24695 this.chains[key] = [node]; 24696 } else { 24697 nodes.push(node); 24698 } 24699 }, 24700 24701 remove: function (key, node) { 24702 var nodes = this.chains[key]; 24703 if (nodes) { 24704 for (var i = 0, l = nodes.length; i < l; i++) { 24705 if (nodes[i] === node) { 24706 nodes.splice(i, 1); 24707 break; 24708 } 24709 } 24710 } 24711 }, 24712 24713 has: function (key, node) { 24714 var nodes = this.chains[key]; 24715 if (nodes) { 24716 for (var i = 0, l = nodes.length; i < l; i++) { 24717 if (nodes[i] === node) { 24718 return true; 24719 } 24720 } 24721 } 24722 return false; 24723 }, 24724 24725 revalidateAll: function () { 24726 for (var key in this.chains) { 24727 this.notify(key, true, undefined); 24728 } 24729 }, 24730 24731 revalidate: function (key) { 24732 this.notify(key, true, undefined); 24733 }, 24734 24735 // key: the string key that is part of a path changed 24736 // revalidate: boolean; the chains that are watching this value should revalidate 24737 // callback: function that will be called with the object and path that 24738 // will be/are invalidated by this key change, depending on 24739 // whether the revalidate flag is passed 24740 notify: function (key, revalidate, callback) { 24741 var nodes = this.chains[key]; 24742 if (nodes === undefined || nodes.length === 0) { 24743 return; 24744 } 24745 24746 var affected = undefined; 24747 24748 if (callback) { 24749 affected = []; 24750 } 24751 24752 for (var i = 0, l = nodes.length; i < l; i++) { 24753 nodes[i].notify(revalidate, affected); 24754 } 24755 24756 if (callback === undefined) { 24757 return; 24758 } 24759 24760 // we gather callbacks so we don't notify them during revalidation 24761 for (var i = 0, l = affected.length; i < l; i += 2) { 24762 var obj = affected[i]; 24763 var path = affected[i + 1]; 24764 callback(obj, path); 24765 } 24766 } 24767 }; 24768 24769 function makeChainWatcher() { 24770 return new ChainWatchers(); 24771 } 24772 24773 function addChainWatcher(obj, keyName, node) { 24774 if (!isObject(obj)) { 24775 return; 24776 } 24777 24778 var m = _emberMetalMeta.meta(obj); 24779 m.writableChainWatchers(makeChainWatcher).add(keyName, node); 24780 _emberMetalWatch_key.watchKey(obj, keyName, m); 24781 } 24782 24783 function removeChainWatcher(obj, keyName, node) { 24784 if (!isObject(obj)) { 24785 return; 24786 } 24787 24788 var m = _emberMetalMeta.peekMeta(obj); 24789 24790 if (!m || !m.readableChainWatchers()) { 24791 return; 24792 } 24793 24794 // make meta writable 24795 m = _emberMetalMeta.meta(obj); 24796 24797 m.readableChainWatchers().remove(keyName, node); 24798 24799 _emberMetalWatch_key.unwatchKey(obj, keyName, m); 24800 } 24801 24802 // A ChainNode watches a single key on an object. If you provide a starting 24803 // value for the key then the node won't actually watch it. For a root node 24804 // pass null for parent and key and object for value. 24805 function ChainNode(parent, key, value) { 24806 this._parent = parent; 24807 this._key = key; 24808 24809 // _watching is true when calling get(this._parent, this._key) will 24810 // return the value of this node. 24811 // 24812 // It is false for the root of a chain (because we have no parent) 24813 // and for global paths (because the parent node is the object with 24814 // the observer on it) 24815 this._watching = value === undefined; 24816 24817 this._chains = undefined; 24818 this._object = undefined; 24819 this.count = 0; 24820 24821 this._value = value; 24822 this._paths = {}; 24823 if (this._watching) { 24824 this._object = parent.value(); 24825 if (this._object) { 24826 addChainWatcher(this._object, this._key, this); 24827 } 24828 } 24829 } 24830 24831 function lazyGet(obj, key) { 24832 if (!obj) { 24833 return; 24834 } 24835 24836 var meta = _emberMetalMeta.peekMeta(obj); 24837 24838 // check if object meant only to be a prototype 24839 if (meta && meta.proto === obj) { 24840 return; 24841 } 24842 24843 // Use `get` if the return value is an EachProxy or an uncacheable value. 24844 if (isVolatile(obj[key])) { 24845 return _emberMetalProperty_get.get(obj, key); 24846 // Otherwise attempt to get the cached value of the computed property 24847 } else { 24848 var cache = meta.readableCache(); 24849 if (cache && key in cache) { 24850 return cache[key]; 24851 } 24852 } 24853 } 24854 24855 ChainNode.prototype = { 24856 value: function () { 24857 if (this._value === undefined && this._watching) { 24858 var obj = this._parent.value(); 24859 this._value = lazyGet(obj, this._key); 24860 } 24861 return this._value; 24862 }, 24863 24864 destroy: function () { 24865 if (this._watching) { 24866 var obj = this._object; 24867 if (obj) { 24868 removeChainWatcher(obj, this._key, this); 24869 } 24870 this._watching = false; // so future calls do nothing 24871 } 24872 }, 24873 24874 // copies a top level object only 24875 copy: function (obj) { 24876 var ret = new ChainNode(null, null, obj); 24877 var paths = this._paths; 24878 var path; 24879 24880 for (path in paths) { 24881 // this check will also catch non-number vals. 24882 if (paths[path] <= 0) { 24883 continue; 24884 } 24885 ret.add(path); 24886 } 24887 return ret; 24888 }, 24889 24890 // called on the root node of a chain to setup watchers on the specified 24891 // path. 24892 add: function (path) { 24893 var paths = this._paths; 24894 paths[path] = (paths[path] || 0) + 1; 24895 24896 var key = firstKey(path); 24897 var tail = path.slice(key.length + 1); 24898 24899 this.chain(key, tail); 24900 }, 24901 24902 // called on the root node of a chain to teardown watcher on the specified 24903 // path 24904 remove: function (path) { 24905 var paths = this._paths; 24906 if (paths[path] > 0) { 24907 paths[path]--; 24908 } 24909 24910 var key = firstKey(path); 24911 var tail = path.slice(key.length + 1); 24912 24913 this.unchain(key, tail); 24914 }, 24915 24916 chain: function (key, path) { 24917 var chains = this._chains; 24918 var node; 24919 if (chains === undefined) { 24920 chains = this._chains = new _emberMetalEmpty_object.default(); 24921 } else { 24922 node = chains[key]; 24923 } 24924 24925 if (node === undefined) { 24926 node = chains[key] = new ChainNode(this, key, undefined); 24927 } 24928 24929 node.count++; // count chains... 24930 24931 // chain rest of path if there is one 24932 if (path) { 24933 key = firstKey(path); 24934 path = path.slice(key.length + 1); 24935 node.chain(key, path); 24936 } 24937 }, 24938 24939 unchain: function (key, path) { 24940 var chains = this._chains; 24941 var node = chains[key]; 24942 24943 // unchain rest of path first... 24944 if (path && path.length > 1) { 24945 var nextKey = firstKey(path);
24946 var nextPath = path.slice(nextKey.length + 1); 24947 node.unchain(nextKey, nextPath); 24948 } 24949 24950 // delete node if needed. 24951 node.count--; 24952 if (node.count <= 0) { 24953 chains[node._key] = undefined; 24954 node.destroy(); 24955 } 24956 }, 24957 24958 notify: function (revalidate, affected) { 24959 if (revalidate && this._watching) { 24960 var obj = this._parent.value(); 24961 if (obj !== this._object) { 24962 removeChainWatcher(this._object, this._key, this); 24963 this._object = obj; 24964 addChainWatcher(obj, this._key, this); 24965 } 24966 this._value = undefined; 24967 } 24968 24969 // then notify chains... 24970 var chains = this._chains; 24971 var node; 24972 if (chains) { 24973 for (var key in chains) { 24974 node = chains[key]; 24975 if (node !== undefined) { 24976 node.notify(revalidate, affected); 24977 } 24978 } 24979 } 24980 24981 if (affected && this._parent) { 24982 this._parent.populateAffected(this._key, 1, affected); 24983 } 24984 }, 24985 24986 populateAffected: function (path, depth, affected) { 24987 if (this._key) { 24988 path = this._key + '.' + path; 24989 } 24990 24991 if (this._parent) { 24992 this._parent.populateAffected(path, depth + 1, affected); 24993 } else { 24994 if (depth > 1) { 24995 affected.push(this.value(), path); 24996 } 24997 } 24998 } 24999 }; 25000 25001 function finishChains(obj) { 25002 // We only create meta if we really have to 25003 var m = _emberMetalMeta.peekMeta(obj); 25004 if (m) { 25005 m = _emberMetalMeta.meta(obj); 25006 25007 // finish any current chains node watchers that reference obj 25008 var chainWatchers = m.readableChainWatchers(); 25009 if (chainWatchers) { 25010 chainWatchers.revalidateAll(); 25011 } 25012 // ensure that if we have inherited any chains they have been 25013 // copied onto our own meta. 25014 if (m.readableChains()) { 25015 m.writableChains(); 25016 } 25017 } 25018 } 25019 25020 exports.removeChainWatcher = removeChainWatcher; 25021 exports.ChainNode = ChainNode; 25022}); 25023enifed('ember-metal/computed', ['exports', 'ember-metal/debug', 'ember-metal/property_set', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/expand_properties', 'ember-metal/error', 'ember-metal/properties', 'ember-metal/property_events', 'ember-metal/dependent_keys'], function (exports, _emberMetalDebug, _emberMetalProperty_set, _emberMetalUtils, _emberMetalMeta, _emberMetalExpand_properties, _emberMetalError, _emberMetalProperties, _emberMetalProperty_events, _emberMetalDependent_keys) { 25024 'use strict'; 25025 25026 exports.default = computed; 25027 25028 /** 25029 @module ember 25030 @submodule ember-metal 25031 */ 25032 25033 function UNDEFINED() {} 25034 25035 var DEEP_EACH_REGEX = /\.@each\.[^.]+\./; 25036 25037 /** 25038 A computed property transforms an object literal with object's accessor function(s) into a property. 25039 25040 By default the function backing the computed property will only be called 25041 once and the result will be cached. You can specify various properties 25042 that your computed property depends on. This will force the cached 25043 result to be recomputed if the dependencies are modified. 25044 25045 In the following example we declare a computed property - `fullName` - by calling 25046 `.Ember.computed()` with property dependencies (`firstName` and `lastName`) as leading arguments and getter accessor function. The `fullName` getter function 25047 will be called once (regardless of how many times it is accessed) as long 25048 as its dependencies have not changed. Once `firstName` or `lastName` are updated 25049 any future calls (or anything bound) to `fullName` will incorporate the new 25050 values. 25051 25052 ```javascript 25053 let Person = Ember.Object.extend({ 25054 // these will be supplied by `create` 25055 firstName: null, 25056 lastName: null, 25057 25058 fullName: Ember.computed('firstName', 'lastName', function() { 25059 let firstName = this.get('firstName'), 25060 lastName = this.get('lastName'); 25061 25062 return firstName + ' ' + lastName; 25063 }) 25064 }); 25065 25066 let tom = Person.create({ 25067 firstName: 'Tom', 25068 lastName: 'Dale' 25069 }); 25070 25071 tom.get('fullName') // 'Tom Dale' 25072 ``` 25073 25074 You can also define what Ember should do when setting a computed property by providing additional function (`set`) in hash argument. 25075 If you try to set a computed property, it will try to invoke setter accessor function with the key and 25076 value you want to set it to as arguments. 25077 25078 ```javascript 25079 let Person = Ember.Object.extend({ 25080 // these will be supplied by `create` 25081 firstName: null, 25082 lastName: null, 25083 25084 fullName: Ember.computed('firstName', 'lastName', { 25085 get(key) { 25086 let firstName = this.get('firstName'), 25087 lastName = this.get('lastName'); 25088 25089 return firstName + ' ' + lastName; 25090 }, 25091 set(key, value) { 25092 let [firstName, lastName] = value.split(' '); 25093 25094 this.set('firstName', firstName); 25095 this.set('lastName', lastName); 25096 25097 return value; 25098 } 25099 }) 25100 }); 25101 25102 let person = Person.create(); 25103 25104 person.set('fullName', 'Peter Wagenet'); 25105 person.get('firstName'); // 'Peter' 25106 person.get('lastName'); // 'Wagenet' 25107 ``` 25108 25109 You can overwrite computed property with normal property (no longer computed), that won't
25109change if dependencies change, if you set computed property and it won't have setter accessor function defined. 25110 25111 You can also mark computed property as `.readOnly()` and block all attempts to set it. 25112 25113 ```javascript 25114 let Person = Ember.Object.extend({ 25115 // these will be supplied by `create` 25116 firstName: null, 25117 lastName: null, 25118 25119 fullName: Ember.computed('firstName', 'lastName', { 25120 get(key) { 25121 let firstName = this.get('firstName'); 25122 let lastName = this.get('lastName'); 25123 25124 return firstName + ' ' + lastName; 25125 } 25126 }).readOnly() 25127 }); 25128 25129 let person = Person.create(); 25130 person.set('fullName', 'Peter Wagenet'); // Uncaught Error: Cannot set read-only property "fullName" on object: <(...):emberXXX> 25131 ``` 25132 25133 Additional resources: 25134 - [New CP syntax RFC](https://github.com/emberjs/rfcs/blob/master/text/0011-improved-cp-syntax.md) 25135 - [New computed syntax explained in "Ember 1.12 released" ](http://emberjs.com/blog/2015/05/13/ember-1-12-released.html#toc_new-computed-syntax) 25136 25137 @class ComputedProperty 25138 @namespace Ember 25139 @public 25140 */ 25141 function ComputedProperty(config, opts) { 25142 this.isDescriptor = true; 25143 if (typeof config === 'function') { 25144 this._getter = config; 25145 } else { 25146 _emberMetalDebug.assert('Ember.computed expects a function or an object as last argument.', typeof config === 'object' && !Array.isArray(config)); 25147 _emberMetalDebug.assert('Config object pased to a Ember.computed can only contain `get` or `set` keys.', (function () { 25148 var keys = Object.keys(config); 25149 for (var i = 0; i < keys.length; i++) { 25150 if (keys[i] !== 'get' && keys[i] !== 'set') { 25151 return false; 25152 } 25153 } 25154 return true; 25155 })()); 25156 this._getter = config.get; 25157 this._setter = config.set; 25158 } 25159 _emberMetalDebug.assert('Computed properties must receive a getter or a setter, you passed none.', !!this._getter || !!this._setter); 25160 this._dependentKeys = undefined; 25161 this._suspended = undefined; 25162 this._meta = undefined; 25163 this._volatile = false; 25164 this._dependentKeys = opts && opts.dependentKeys; 25165 this._readOnly = false; 25166 } 25167 25168 ComputedProperty.prototype = new _emberMetalProperties.Descriptor(); 25169 25170 var ComputedPropertyPrototype = ComputedProperty.prototype; 25171 25172 /** 25173 Call on a computed property to set it into non-cached mode. When in this 25174 mode the computed property will not automatically cache the return value. 25175 25176 It also does not automatically fire any change events. You must manually notify 25177 any changes if you want to observe this property. 25178 25179 Dependency keys have no effect on volatile properties as they are for cache 25180 invalidation and notification when cached value is invalidated. 25181 25182 ```javascript 25183 let outsideService = Ember.Object.extend({ 25184 value: Ember.computed(function() { 25185 return OutsideService.getValue(); 25186 }).volatile() 25187 }).create(); 25188 ``` 25189 25190 @method volatile 25191 @return {Ember.ComputedProperty} this 25192 @chainable 25193 @public 25194 */ 25195 ComputedPropertyPrototype.volatile = function () { 25196 this._volatile = true; 25197 return this; 25198 }; 25199 25200 /** 25201 Call on a computed property to set it into read-only mode. When in this 25202 mode the computed property will throw an error when set. 25203 25204 ```javascript 25205 let Person = Ember.Object.extend({ 25206 guid: Ember.computed(function() { 25207 return 'guid-guid-guid'; 25208 }).readOnly() 25209 }); 25210 25211 let person = Person.create(); 25212 25213 person.set('guid', 'new-guid'); // will throw an exception 25214 ``` 25215 25216 @method readOnly 25217 @return {Ember.ComputedProperty} this 25218 @chainable 25219 @public 25220 */ 25221 ComputedPropertyPrototype.readOnly = function () { 25222 this._readOnly = true; 25223 _emberMetalDebug.assert('Computed properties that define a setter using the new syntax cannot be read-only', !(this._readOnly && this._setter && this._setter !== this._getter)); 25224 return this; 25225 }; 25226 25227 /** 25228 Sets the dependent keys on this computed property. Pass any number of 25229 arguments containing key paths that this computed property depen
25229ds on. 25230 25231 ```javascript 25232 let President = Ember.Object.extend({ 25233 fullName: Ember.computed(function() { 25234 return this.get('firstName') + ' ' + this.get('lastName'); 25235 25236 // Tell Ember that this computed property depends on firstName 25237 // and lastName 25238 }).property('firstName', 'lastName') 25239 }); 25240 25241 let president = President.create({ 25242 firstName: 'Barack', 25243 lastName: 'Obama' 25244 }); 25245 25246 president.get('fullName'); // 'Barack Obama' 25247 ``` 25248 25249 @method property 25250 @param {String} path* zero or more property paths 25251 @return {Ember.ComputedProperty} this 25252 @chainable 25253 @public 25254 */ 25255 ComputedPropertyPrototype.property = function () { 25256 var args; 25257 25258 var addArg = function (property) { 25259 _emberMetalDebug.warn('Dependent keys containing @each only work one level deep. ' + 'You cannot use nested forms like [email protected] or [email protected][email protected]. ' + 'Please create an intermediary computed property.', DEEP_EACH_REGEX.test(property) === false, { id: 'ember-metal.computed-deep-each' }); 25260 args.push(property); 25261 }; 25262 25263 args = []; 25264 for (var i = 0, l = arguments.length; i < l; i++) { 25265 _emberMetalExpand_properties.default(arguments[i], addArg); 25266 } 25267 25268 this._dependentKeys = args; 25269 return this; 25270 }; 25271 25272 /** 25273 In some cases, you may want to annotate computed properties with additional 25274 metadata about how they function or what values they operate on. For example, 25275 computed property functions may close over variables that are then no longer 25276 available for introspection. 25277 25278 You can pass a hash of these values to a computed property like this: 25279 25280 ``` 25281 person: Ember.computed(function() { 25282 let personId = this.get('personId'); 25283 return App.Person.create({ id: personId }); 25284 }).meta({ type: App.Person }) 25285 ``` 25286 25287 The hash that you pass to the `meta()` function will be saved on the 25288 computed property descriptor under the `_meta` key. Ember runtime 25289 exposes a public API for retrieving these values from classes, 25290 via the `metaForProperty()` function. 25291 25292 @method meta 25293 @param {Object} meta 25294 @chainable 25295 @public 25296 */ 25297 ComputedPropertyPrototype.meta = function (meta) { 25298 if (arguments.length === 0) { 25299 return this._meta || {}; 25300 } else { 25301 this._meta = meta; 25302 return this; 25303 } 25304 }; 25305 25306 // invalidate cache when CP key changes 25307 ComputedPropertyPrototype.didChange = function (obj, keyName) { 25308 // _suspended is set via a CP.set to ensure we don't clear 25309 // the cached value set by the setter 25310 if (this._volatile || this._suspended === obj) { 25311 return; 25312 } 25313 25314 // don't create objects just to invalidate 25315 var meta = _emberMetalMeta.peekMeta(obj); 25316 if (!meta || meta.source !== obj) { 25317 return; 25318 } 25319 25320 var cache = meta.readableCache(); 25321 if (cache && cache[keyName] !== undefined) { 25322 cache[keyName] = undefined; 25323 _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, meta); 25324 } 25325 }; 25326 25327 ComputedPropertyPrototype.get = function (obj, keyName) { 25328 if (this._volatile) { 25329 return this._getter.call(obj, keyName); 25330 } 25331 25332 var meta = _emberMetalMeta.meta(obj); 25333 var cache = meta.writableCache(); 25334 25335 var result = cache[keyName]; 25336 if (result === UNDEFINED) { 25337 return undefined; 25338 } else if (result !== undefined) { 25339 return result; 25340 } 25341 25342 var ret = this._getter.call(obj, keyName); 25343 if (ret === undefined) { 25344 cache[keyName] = UNDEFINED; 25345 } else { 25346 cache[keyName] = ret; 25347 } 25348 25349 var chainWatchers = meta.readableChainWatchers(); 25350 if (chainWatchers) { 25351 chainWatchers.revalidate(keyName); 25352 } 25353 _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, meta); 25354 25355 return ret; 25356 }; 25357 25358 ComputedPropertyPrototype.set = function computedPropertySetEntry(obj, keyName, value) { 25359 if (this._readOnly) { 25360 this._throwReadOnlyError(obj, keyName); 25361 } 25362 25363 if (!this._setter) { 25364 return this.clobberSet(obj, keyName, value); 25365 } 25366 25367 if (this._volatile) { 25368 return this.volatileSet(obj, keyName, value); 25369 } 25370 25371 return this.setWithSuspend(obj, keyName, value); 25372 }; 25373 25374 ComputedPropertyPrototype._throwReadOnlyError = function computedPropertyThrowReadOnlyError(obj, keyName) { 25375 throw new _emberMetalError.default('Cannot set read-only property "' + keyName + '" on object: ' + _emberMetalUtils.inspect(obj)); 25376 }; 25377 25378 ComputedPropertyPrototype.clobberSet = function computedPropertyClobberSet(obj, keyName, value) {
25379 var cachedValue = cacheFor(obj, keyName); 25380 _emberMetalProperties.defineProperty(obj, keyName, null, cachedValue); 25381 _emberMetalProperty_set.set(obj, keyName, value); 25382 return value; 25383 }; 25384 25385 ComputedPropertyPrototype.volatileSet = function computedPropertyVolatileSet(obj, keyName, value) { 25386 return this._setter.call(obj, keyName, value); 25387 }; 25388 25389 ComputedPropertyPrototype.setWithSuspend = function computedPropertySetWithSuspend(obj, keyName, value) { 25390 var oldSuspended = this._suspended; 25391 this._suspended = obj; 25392 try { 25393 return this._set(obj, keyName, value); 25394 } finally { 25395 this._suspended = oldSuspended; 25396 } 25397 }; 25398 25399 ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, value) { 25400 // cache requires own meta 25401 var meta = _emberMetalMeta.meta(obj); 25402 // either there is a writable cache or we need one to update 25403 var cache = meta.writableCache(); 25404 var hadCachedValue = false; 25405 var cachedValue = undefined; 25406 if (cache[keyName] !== undefined) { 25407 if (cache[keyName] !== UNDEFINED) { 25408 cachedValue = cache[keyName]; 25409 } 25410 hadCachedValue = true; 25411 } 25412 25413 var ret = this._setter.call(obj, keyName, value, cachedValue); 25414 25415 // allows setter to return the same value that is cached already 25416 if (hadCachedValue && cachedValue === ret) { 25417 return ret; 25418 } 25419 25420 var watched = meta.peekWatching(keyName); 25421 if (watched) { 25422 _emberMetalProperty_events.propertyWillChange(obj, keyName); 25423 } 25424 25425 if (hadCachedValue) { 25426 cache[keyName] = undefined; 25427 } 25428 25429 if (!hadCachedValue) { 25430 _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, meta); 25431 } 25432 25433 if (ret === undefined) { 25434 cache[keyName] = UNDEFINED; 25435 } else { 25436 cache[keyName] = ret; 25437 } 25438 25439 if (watched) { 25440 _emberMetalProperty_events.propertyDidChange(obj, keyName); 25441 } 25442 25443 return ret; 25444 }; 25445 25446 /* called before property is overridden */ 25447 ComputedPropertyPrototype.teardown = function (obj, keyName) { 25448 if (this._volatile) { 25449 return; 25450 } 25451 var meta = _emberMetalMeta.meta(obj); 25452 var cache = meta.readableCache(); 25453 if (cache && cache[keyName] !== undefined) { 25454 _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, meta); 25455 cache[keyName] = undefined; 25456 } 25457 }; 25458 25459 /** 25460 This helper returns a new property descriptor that wraps the passed 25461 computed property function. You can use this helper to define properties 25462 with mixins or via `Ember.defineProperty()`. 25463 25464 If you pass a function as an argument, it will be used as a getter. A computed 25465 property defined in this way might look like this: 25466 25467 ```js 25468 let Person = Ember.Object.extend({ 25469 init() { 25470 this._super(...arguments); 25471 25472 this.firstName = 'Betty'; 25473 this.lastName = 'Jones'; 25474 }, 25475 25476 fullName: Ember.computed('firstName', 'lastName', function() { 25477 return `${this.get('firstName')} ${this.get('lastName')}`; 25478 }) 25479 }); 25480 25481 let client = Person.create(); 25482 25483 client.get('fullName'); // 'Betty Jones' 25484 25485 client.set('lastName', 'Fuller'); 25486 client.get('fullName'); // 'Betty Fuller' 25487 ``` 25488 25489 You can pass a hash with two functions, `get` and `set`, as an 25490 argument to provide both a getter and setter: 25491 25492 ```js 25493 let Person = Ember.Object.extend({ 25494 init() { 25495 this._super(...arguments); 25496 25497 this.firstName = 'Betty'; 25498 this.lastName = 'Jones'; 25499 }, 25500 25501 fullName: Ember.computed('firstName', 'lastName', { 25502 get(key) { 25503 return `${this.get('firstName')} ${this.get('lastName')}`; 25504 }, 25505 set(key, value) { 25506 let [firstName, lastName] = value.split(/\s+/); 25507 this.setProperties({ firstName, lastName }); 25508 return value; 25509 } 25510 }); 25511 }) 25512 25513 let client = Person.create(); 25514 client.get('firstName'); // 'Betty' 25515 25516 client.set('fullName', 'Carroll Fuller'); 25517 client.get('firstName'); // 'Carroll' 25518 ``` 25519 25520 The `set` function should accept two parameters, `key` and `value`. The value 25521 returned from `set` will be the new value of the property. 25522 25523 _Note: This is the preferred way to define computed properties when writing third-party 25524 libraries that depend on or use Ember, since there is no guarantee that the user 25525 will have [prototype Extensions](http://emberjs.com/guides/configuring-ember/disabling-prototype-extensions/) enabled._ 25526 25527 The alternative syntax, with prototype extensions, might look like: 25528 25529 ```js 25530 fullName() { 25531 return this.get('firstName') + ' ' + this.get('lastName'); 25532 }.property('firstName', 'lastName') 25533 ``` 25534 25535 @class computed 25536 @namespace Ember 25537 @constructor 25538 @static 25539 @param {String} [dependentKeys*] Optional dependent keys that trigger this computed property. 25540 @param {Function} func The computed property function. 25541 @return {Ember.ComputedProperty} property descriptor instance 25542 @public 25543 */ 25544 25545 function computed(func) { 25546 var args; 25547 25548 if (arguments.length > 1) { 25549 args = [].slice.call(arguments); 25550 func = args.pop(); 25551 } 25552 25553 var cp = new ComputedProperty(func); 25554 25555 if (args) { 25556 cp.property.apply(cp, args); 25557 } 25558 25559 return cp; 25560 } 25561 25562 /** 25563 Returns the cached value for a property, if one exists. 25564 This can be useful for peeking at the value of a computed 25565 property that is generated lazily, without accidentally causing 25566 it to be created. 25567
25568 @method cacheFor 25569 @for Ember 25570 @param {Object} obj the object whose property you want to check 25571 @param {String} key the name of the property whose cached value you want 25572 to return 25573 @return {Object} the cached value 25574 @public 25575 */ 25576 function cacheFor(obj, key) { 25577 var meta = _emberMetalMeta.peekMeta(obj); 25578 var cache = meta && meta.source === obj && meta.readableCache(); 25579 var ret = cache && cache[key]; 25580 25581 if (ret === UNDEFINED) { 25582 return undefined; 25583 } 25584 return ret; 25585 } 25586 25587 cacheFor.set = function (cache, key, value) { 25588 if (value === undefined) { 25589 cache[key] = UNDEFINED; 25590 } else { 25591 cache[key] = value; 25592 } 25593 }; 25594 25595 cacheFor.get = function (cache, key) { 25596 var ret = cache[key]; 25597 if (ret === UNDEFINED) { 25598 return undefined; 25599 } 25600 return ret; 25601 }; 25602 25603 cacheFor.remove = function (cache, key) { 25604 cache[key] = undefined; 25605 }; 25606 25607 exports.ComputedProperty = ComputedProperty; 25608 exports.computed = computed; 25609 exports.cacheFor = cacheFor; 25610}); 25611enifed('ember-metal/computed_macros', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/computed', 'ember-metal/is_empty', 'ember-metal/is_none', 'ember-metal/alias'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalComputed, _emberMetalIs_empty, _emberMetalIs_none, _emberMetalAlias) { 25612 'use strict'; 25613 25614 exports.empty = empty; 25615 exports.notEmpty = notEmpty; 25616 exports.none = none; 25617 exports.not = not; 25618 exports.bool = bool; 25619 exports.match = match; 25620 exports.equal = equal; 25621 exports.gt = gt; 25622 exports.gte = gte; 25623 exports.lt = lt; 25624 exports.lte = lte; 25625 exports.oneWay = oneWay; 25626 exports.readOnly = readOnly; 25627 exports.deprecatingAlias = deprecatingAlias; 25628 25629 /** 25630 @module ember 25631 @submodule ember-metal 25632 */ 25633 25634 function getProperties(self, propertyNames) { 25635 var ret = {}; 25636 for (var i = 0; i < propertyNames.length; i++) { 25637 ret[propertyNames[i]] = _emberMetalProperty_get.get(self, propertyNames[i]); 25638 } 25639 return ret; 25640 } 25641 25642 function generateComputedWithProperties(macro) { 25643 return function () { 25644 for (var _len = arguments.length, properties = Array(_len), _key = 0; _key < _len; _key++) { 25645 properties[_key] = arguments[_key]; 25646 } 25647 25648 var computedFunc = _emberMetalComputed.computed(function () { 25649 return macro.apply(this, [getProperties(this, properties)]); 25650 }); 25651 25652 return computedFunc.property.apply(computedFunc, properties); 25653 }; 25654 } 25655 25656 /** 25657 A computed property that returns true if the value of the dependent 25658 property is null, an empty string, empty array, or empty function. 25659 25660 Example 25661 25662 ```javascript 25663 var ToDoList = Ember.Object.extend({ 25664 isDone: Ember.computed.empty('todos') 25665 }); 25666 25667 var todoList = ToDoList.create({ 25668 todos: ['Unit Test', 'Documentation', 'Release'] 25669 }); 25670 25671 todoList.get('isDone'); // false 25672 todoList.get('todos').clear(); 25673 todoList.get('isDone'); // true 25674 ``` 25675 25676 @since 1.6.0 25677 @method empty 25678 @for Ember.computed 25679 @param {String} dependentKey 25680 @return {Ember.ComputedProperty} computed property which negate 25681 the original value for property 25682 @public 25683 */ 25684 25685 function empty(dependentKey) { 25686 return _emberMetalComputed.computed(dependentKey + '.length', function () { 25687 return _emberMetalIs_empty.default(_emberMetalProperty_get.get(this, dependentKey)); 25688 }); 25689 } 25690 25691 /** 25692 A computed property that returns true if the value of the dependent 25693 property is NOT null, an empty string, empty array, or empty function. 25694 25695 Example 25696 25697 ```javascript 25698 var Hamster = Ember.Object.extend({ 25699 hasStuff: Ember.computed.notEmpty('backpack') 25700 }); 25701 25702 var hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); 25703 25704 hamster.get('hasStuff'); // true 25705 hamster.get('backpack').clear(); // [] 25706 hamster.get('hasStuff'); // false 25707 ``` 25708 25709 @method notEmpty 25710 @for Ember.computed 25711 @param {String} dependentKey 25712 @return {Ember.ComputedProperty} computed property which returns true if 25713 original value for property is not empty. 25714 @public 25715 */ 25716 25717 function notEmpty(dependentKey) { 25718 return _emberMetalComputed.computed(dependentKey + '.length', function () { 25719 return !_emberMetalIs_empty.default(_emberMetalProperty_get.get(this, dependentKey)); 25720 }); 25721 } 25722 25723 /** 25724 A computed property that returns true if the value of the dependent 25725 property is null or undefined. This avoids errors from JSLint complaining 25726 about use of ==, which can be technically confusing. 25727 25728 Example 25729 25730 ```javascript 25731 var Hamster = Ember.Object.extend({ 25732 isHungry: Ember.computed.none('food') 25733 }); 25734 25735 var hamster = Hamster.create(); 25736 25737 hamster.get('isHungry'); // true 25738 hamster.set('food', 'Banana'); 25739 hamster.get('isHungry'); // false 25740 hamster.set('food', null); 25741 hamster.get('isHungry'); // true 25742 ``` 25743 25744 @method none 25745 @for Ember.computed 25746 @param {String} dependentKey 25747 @return {Ember.ComputedProperty} computed property which 25748 returns true if original value for property is null or undefined. 25749 @public 25750 */ 25751 25752 function none(dependentKey) { 25753 return _emberMetalComputed.computed(dependentKey, function () { 25754 return _emberMetalIs_none.default(_emberMetalProperty_get.get(this, dependentKey)); 25755 }); 25756 } 25757 25758 /** 25759 A computed property that returns the inverse boolean value 25760 of the original value for the dependent property. 25761 25762 Example 25763 25764 ```javascript 25765 var User = Ember.Object.extend({ 25766 isAnonymous: Ember.computed.not('loggedIn') 25767 }); 25768 25769 var user = User.create({loggedIn: false}); 25770 25771 user.get('isAnonymous'); // true 25772 user.set('loggedIn', true); 25773 user.get('isAnonymous'); // false 25774 ``` 25775 25776 @method not 25777 @for Ember.computed 25778 @param {String} dependentKey 25779 @return {Ember.ComputedProperty} computed property which returns 25780 inverse of the original value for property 25781 @public 25782 */ 25783 25784 function not(dependentKey) { 25785 return _emberMetalComputed.computed(dependentKey, function () { 25786 return !_emberMetalProperty_get.get(this, dependentKey); 25787 }); 25788 } 25789 25790 /** 25791 A computed property that converts the provided dependent property 25792 into a boolean value. 25793 25794 ```javascript 25795 var Hamster = Ember.Object.extend({ 25796 hasBananas: Ember.computed.bool('numBananas') 25797 }); 25798 25799 var hamster = Hamster.create(); 25800 25801 hamster.get('hasBananas'); // false 25802 hamster.set('numBananas', 0); 25803 hamster.get('hasBananas'); // false 25804 hamster.set('numBananas', 1); 25805 hamster.get('hasBananas'); // true 25806 hamster.set('numBananas', null); 25807 hamster.get('hasBananas'); // false 25808 ``` 25809 25810 @method bool 25811 @for Ember.computed 25812 @param {String} dependentKey 25813 @return {Ember.ComputedProperty} computed property which converts 25814 to boolean the original value for property 25815 @public 25816 */ 25817 25818 function bool(dependentKey) { 25819 return _emberMetalComputed.computed(dependentKey, function () { 25820 return !!_emberMetalProperty_get.get(this, dependentKey); 25821 }); 25822 } 25823 25824 /** 25825 A computed property which matches the original value for the 25826 dependent property against a given RegExp, returning `true` 25827 if the value matches the RegExp and `false` if it does not. 25828 25829 Example 25830 25831 ```javascript 25832 var User = Ember.Object.extend({ 25833 hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/) 25834 }); 25835 25836 var user = User.create({loggedIn: false}); 25837 25838 user.get('hasValidEmail'); // false 25839 user.set('email', ''); 25840 user.get('hasValidEmail'); // false 25841 user.set('email', '[email protected]'); 25842 user.get('hasValidEmail'); // true 25843 ``` 25844 25845 @method match 25846 @for Ember.computed 25847 @param {String} dependentKey 25848 @param {RegExp} regexp 25849 @return {Ember.ComputedProperty} computed property which match 25850 the original value for property against a given RegExp 25851 @public 25852 */ 25853 25854 function match(dependentKey, regexp) { 25855 return _emberMetalComputed.computed(dependentKey, function () { 25856 var value = _emberMetalProperty_get.get(this, dependentKey); 25857 25858 return typeof value === 'string' ? regexp.test(value) : false;
25859 }); 25860 } 25861 25862 /** 25863 A computed property that returns true if the provided dependent property 25864 is equal to the given value. 25865 25866 Example 25867 25868 ```javascript 25869 var Hamster = Ember.Object.extend({ 25870 napTime: Ember.computed.equal('state', 'sleepy') 25871 }); 25872 25873 var hamster = Hamster.create(); 25874 25875 hamster.get('napTime'); // false 25876 hamster.set('state', 'sleepy'); 25877 hamster.get('napTime'); // true 25878 hamster.set('state', 'hungry'); 25879 hamster.get('napTime'); // false 25880 ``` 25881 25882 @method equal 25883 @for Ember.computed 25884 @param {String} dependentKey 25885 @param {String|Number|Object} value 25886 @return {Ember.ComputedProperty} computed property which returns true if 25887 the original value for property is equal to the given value. 25888 @public 25889 */ 25890 25891 function equal(dependentKey, value) { 25892 return _emberMetalComputed.computed(dependentKey, function () { 25893 return _emberMetalProperty_get.get(this, dependentKey) === value; 25894 }); 25895 } 25896 25897 /** 25898 A computed property that returns true if the provided dependent property 25899 is greater than the provided value. 25900 25901 Example 25902 25903 ```javascript 25904 var Hamster = Ember.Object.extend({ 25905 hasTooManyBananas: Ember.computed.gt('numBananas', 10) 25906 }); 25907 25908 var hamster = Hamster.create(); 25909 25910 hamster.get('hasTooManyBananas'); // false 25911 hamster.set('numBananas', 3); 25912 hamster.get('hasTooManyBananas'); // false 25913 hamster.set('numBananas', 11); 25914 hamster.get('hasTooManyBananas'); // true 25915 ``` 25916 25917 @method gt 25918 @for Ember.computed 25919 @param {String} dependentKey 25920 @param {Number} value 25921 @return {Ember.ComputedProperty} computed property which returns true if 25922 the original value for property is greater than given value. 25923 @public 25924 */ 25925 25926 function gt(dependentKey, value) { 25927 return _emberMetalComputed.computed(dependentKey, function () { 25928 return _emberMetalProperty_get.get(this, dependentKey) > value; 25929 }); 25930 } 25931 25932 /** 25933 A computed property that returns true if the provided dependent property 25934 is greater than or equal to the provided value. 25935 25936 Example 25937 25938 ```javascript 25939 var Hamster = Ember.Object.extend({ 25940 hasTooManyBananas: Ember.computed.gte('numBananas', 10) 25941 }); 25942 25943 var hamster = Hamster.create(); 25944 25945 hamster.get('hasTooManyBananas'); // false 25946 hamster.set('numBananas', 3); 25947 hamster.get('hasTooManyBananas'); // false 25948 hamster.set('numBananas', 10); 25949 hamster.get('hasTooManyBananas'); // true 25950 ``` 25951 25952 @method gte 25953 @for Ember.computed 25954 @param {String} dependentKey 25955 @param {Number} value 25956 @return {Ember.ComputedProperty} computed property which returns true if 25957 the original value for property is greater or equal then given value. 25958 @public 25959 */ 25960 25961 function gte(dependentKey, value) { 25962 return _emberMetalComputed.computed(dependentKey, function () { 25963 return _emberMetalProperty_get.get(this, dependentKey) >= value; 25964 }); 25965 } 25966 25967 /** 25968 A computed property that returns true if the provided dependent property 25969 is less than the provided value. 25970 25971 Example 25972 25973 ```javascript 25974 var Hamster = Ember.Object.extend({ 25975 needsMoreBananas: Ember.computed.lt('numBananas', 3) 25976 }); 25977 25978 var hamster = Hamster.create(); 25979 25980 hamster.get('needsMoreBananas'); // true 25981 hamster.set('numBananas', 3); 25982 hamster.get('needsMoreBananas'); // false 25983 hamster.set('numBananas', 2); 25984 hamster.get('needsMoreBananas'); // true 25985 ``` 25986 25987 @method lt 25988 @for Ember.computed 25989 @param {String} dependentKey 25990 @param {Number} value 25991 @return {Ember.ComputedProperty} computed property which returns true if 25992 the original value for property is less then given value. 25993 @public 25994 */ 25995 25996 function lt(dependentKey, value) { 25997 return _emberMetalComputed.computed(dependentKey, function () { 25998 return _emberMetalProperty_get.get(this, dependentKey) < value; 25999 }); 26000 } 26001 26002 /** 26003 A computed property that returns true if the provided dependent property 26004 is less than or equal to the provided value. 26005 26006 Example 26007 26008 ```javascript 26009 var Hamster = Ember.Object.extend({ 26010 needsMoreBananas: Ember.computed.lte('numBananas', 3) 26011 }); 26012 26013 var hamster = Hamster.create(); 26014 26015 hamster.get('needsMoreBananas'); // true 26016 hamster.set('numBananas', 5); 26017 hamster.get('needsMoreBananas'); // false 26018 hamster.set('numBananas', 3); 26019 hamster.get('needsMoreBananas'); // true 26020 ``` 26021 26022 @method lte 26023 @for Ember.computed 26024 @param {String} dependentKey 26025 @param {Number} value 26026 @return {Ember.ComputedProperty} computed property which returns true if 26027 the original value for property is less or equal than given value. 26028 @public 26029 */ 26030 26031 function lte(dependentKey, value) { 26032 return _emberMetalComputed.computed(dependentKey, function () { 26033 return _emberMetalProperty_get.get(this, dependentKey) <= value; 26034 }); 26035 } 26036 26037 /** 26038 A computed property that performs a logical `and` on the 26039 original values for the provided dependent properties. 26040 26041 Example 26042 26043 ```javascript 26044 var Hamster = Ember.Object.extend({ 26045 readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') 26046 }); 26047 26048 var hamster = Hamster.create(); 26049 26050 hamster.get('readyForCamp'); // false 26051 hamster.set('hasTent', true); 26052 hamster.get('readyForCamp'); // false 26053 hamster.set('hasBackpack', true); 26054 hamster.get('readyForCamp'); // true 26055 hamster.set('hasBackpack', 'Yes'); 26056 hamster.get('readyForCamp'); // 'Yes' 26057 ``` 26058 26059 @method and 26060 @for Ember.computed 26061 @param {String} dependentKey* 26062 @return {Ember.ComputedProperty} computed property which performs 26063 a logical `and` on the values of all the original values for properties. 26064 @public 26065 */ 26066 var and = generateComputedWithProperties(function (properties) { 26067 var value; 26068 for (var key in properties) { 26069 value = properties[key]; 26070 if (properties.hasOwnProperty(key) && !value) { 26071 return false;
26072 } 26073 } 26074 return value; 26075 }); 26076 26077 exports.and = and; 26078 /** 26079 A computed property which performs a logical `or` on the 26080 original values for the provided dependent properties. 26081 26082 Example 26083 26084 ```javascript 26085 var Hamster = Ember.Object.extend({ 26086 readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') 26087 }); 26088 26089 var hamster = Hamster.create(); 26090 26091 hamster.get('readyForRain'); // false 26092 hamster.set('hasUmbrella', true); 26093 hamster.get('readyForRain'); // true 26094 hamster.set('hasJacket', 'Yes'); 26095 hamster.get('readyForRain'); // 'Yes' 26096 ``` 26097 26098 @method or 26099 @for Ember.computed 26100 @param {String} dependentKey* 26101 @return {Ember.ComputedProperty} computed property which performs 26102 a logical `or` on the values of all the original values for properties. 26103 @public 26104 */ 26105 var or = generateComputedWithProperties(function (properties) { 26106 var value; 26107 for (var key in properties) { 26108 value = properties[key]; 26109 if (properties.hasOwnProperty(key) && value) { 26110 return value; 26111 } 26112 } 26113 return value; 26114 }); 26115 26116 exports.or = or; 26117 /** 26118 Creates a new property that is an alias for another property 26119 on an object. Calls to `get` or `set` this property behave as 26120 though they were called on the original property. 26121 26122 ```javascript 26123 var Person = Ember.Object.extend({ 26124 name: 'Alex Matchneer', 26125 nomen: Ember.computed.alias('name') 26126 }); 26127 26128 var alex = Person.create(); 26129 26130 alex.get('nomen'); // 'Alex Matchneer' 26131 alex.get('name'); // 'Alex Matchneer' 26132 26133 alex.set('nomen', '@machty'); 26134 alex.get('name'); // '@machty' 26135 ``` 26136 26137 @method alias 26138 @for Ember.computed 26139 @param {String} dependentKey 26140 @return {Ember.ComputedProperty} computed property which creates an 26141 alias to the original value for property. 26142 @public 26143 */ 26144 26145 /** 26146 Where `computed.alias` aliases `get` and `set`, and allows for bidirectional 26147 data flow, `computed.oneWay` only provides an aliased `get`. The `set` will 26148 not mutate the upstream property, rather causes the current property to 26149 become the value set. This causes the downstream property to permanently 26150 diverge from the upstream property. 26151 26152 Example 26153 26154 ```javascript 26155 var User = Ember.Object.extend({ 26156 firstName: null, 26157 lastName: null, 26158 nickName: Ember.computed.oneWay('firstName') 26159 }); 26160 26161 var teddy = User.create({ 26162 firstName: 'Teddy', 26163 lastName: 'Zeenny' 26164 }); 26165 26166 teddy.get('nickName'); // 'Teddy' 26167 teddy.set('nickName', 'TeddyBear'); // 'TeddyBear' 26168 teddy.get('firstName'); // 'Teddy' 26169 ``` 26170 26171 @method oneWay 26172 @for Ember.computed 26173 @param {String} dependentKey 26174 @return {Ember.ComputedProperty} computed property which creates a 26175 one way computed property to the original value for property. 26176 @public 26177 */ 26178 26179 function oneWay(dependentKey) { 26180 return _emberMetalAlias.default(dependentKey).oneWay(); 26181 } 26182 26183 /** 26184 This is a more semantically meaningful alias of `computed.oneWay`, 26185 whose name is somewhat ambiguous as to which direction the data flows. 26186 26187 @method reads 26188 @for Ember.computed 26189 @param {String} dependentKey 26190 @return {Ember.ComputedProperty} computed property which creates a 26191 one way computed property to the original value for property. 26192 @public 26193 */ 26194 26195 /** 26196 Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides 26197 a readOnly one way binding. Very often when using `computed.oneWay` one does 26198 not also want changes to propagate back up, as they will replace the value. 26199 26200 This prevents the reverse flow, and also throws an exception when it occurs. 26201 26202 Example 26203 26204 ```javascript 26205 var User = Ember.Object.extend({ 26206 firstName: null, 26207 lastName: null, 26208 nickName: Ember.computed.readOnly('firstName') 26209 }); 26210 26211 var teddy = User.create({ 26212 firstName: 'Teddy', 26213 lastName: 'Zeenny' 26214 }); 26215 26216 teddy.get('nickName'); // 'Teddy' 26217 teddy.set('nickName', 'TeddyBear'); // throws Exception 26218 // throw new Ember.Error('Cannot Set: nickName on: <User:ember27288>' );` 26219 teddy.get('firstName'); // 'Teddy' 26220 ``` 26221 26222 @method readOnly 26223 @for Ember.computed 26224 @param {String} dependentKey 26225 @return {Ember.ComputedProperty} computed property which creates a 26226 one way computed property to the original value for property. 26227 @since 1.5.0 26228 @public 26229 */ 26230 26231 function readOnly(dependentKey) { 26232 return _emberMetalAlias.default(dependentKey).readOnly(); 26233 } 26234 26235 /** 26236 Creates a new property that is an alias for another property 26237 on an object. Calls to `get` or `set` this property behave as 26238 though they were called on the original property, but also 26239 print a deprecation warning. 26240 26241 @method deprecatingAlias 26242 @for Ember.computed 26243 @param {String} dependentKey 26244 @return {Ember.ComputedProperty} computed property which creates an 26245 alias with a deprecation to the original value for property. 26246 @since 1.7.0 26247 @public 26248 */ 26249 26250 function deprecatingAlias(dependentKey, options) { 26251 return _emberMetalComputed.computed(dependentKey, { 26252 get: function (key) { 26253 _emberMetalDebug.deprecate('Usage of `' + key + '` is deprecated, use `' + depen
26253dentKey + '` instead.', false, options); 26254 return _emberMetalProperty_get.get(this, dependentKey); 26255 }, 26256 set: function (key, value) { 26257 _emberMetalDebug.deprecate('Usage of `' + key + '` is deprecated, use `' + dependentKey + '` instead.', false, options); 26258 _emberMetalProperty_set.set(this, dependentKey, value); 26259 return value; 26260 } 26261 }); 26262 } 26263}); 26264enifed('ember-metal/core', ['exports', 'require'], function (exports, _require) { 26265 /*globals Ember:true,ENV,EmberENV */ 26266 26267 'use strict'; 26268 26269 /** 26270 @module ember 26271 @submodule ember-metal 26272 */ 26273 26274 /** 26275 This namespace contains all Ember methods and functions. Future versions of 26276 Ember may overwrite this namespace and therefore, you should avoid adding any 26277 new properties. 26278 26279 At the heart of Ember is Ember-Runtime, a set of core functions that provide 26280 cross-platform compatibility and object property observing. Ember-Runtime is 26281 small and performance-focused so you can use it alongside other 26282 cross-platform libraries such as jQuery. For more details, see 26283 [Ember-Runtime](http://emberjs.com/api/modules/ember-runtime.html). 26284 26285 @class Ember 26286 @static 26287 @version 2.5.1 26288 @public 26289 */ 26290 26291 if ('undefined' === typeof Ember) { 26292 // Create core object. Make it act like an instance of Ember.Namespace so that 26293 // objects assigned to it are given a sane string representation. 26294 Ember = {}; 26295 } 26296 26297 // Default imports, exports and lookup to the global object; 26298 var global = mainContext || {}; // jshint ignore:line 26299 Ember.imports = Ember.imports || global; 26300 Ember.lookup = Ember.lookup || global; 26301 var emExports = Ember.exports = Ember.exports || global; 26302 26303 // aliases needed to keep minifiers from removing the global context 26304 emExports.Em = emExports.Ember = Ember; 26305 26306 // Make sure these are set whether Ember was already defined or not 26307 26308 Ember.isNamespace = true; 26309 26310 Ember.toString = function () { 26311 return 'Ember'; 26312 }; 26313 26314 // The debug functions are exported to globals with `require` to 26315 // prevent babel-plugin-filter-imports from removing them. 26316 var debugModule = _require.default('ember-metal/debug'); 26317 Ember.assert = debugModule.assert; 26318 Ember.warn = debugModule.warn; 26319 Ember.debug = debugModule.debug; 26320 Ember.deprecate = debugModule.deprecate; 26321 Ember.deprecateFunc = debugModule.deprecateFunc; 26322 Ember.runInDebug = debugModule.runInDebug; 26323 26324 /** 26325 The semantic version. 26326 26327 @property VERSION 26328 @type String 26329 @default '2.5.1' 26330 @static 26331 @public 26332 */ 26333 Ember.VERSION = '2.5.1'; 26334 26335 /** 26336 The hash of environment variables used to control various configuration 26337 settings. To specify your own or override default settings, add the 26338 desired properties to a global hash named `EmberENV` (or `ENV` for 26339 backwards compatibility with earlier versions of Ember). The `EmberENV` 26340 hash must be created before loading Ember. 26341 26342 @property ENV 26343 @type Object 26344 @public 26345 */ 26346 26347 if (Ember.ENV) { 26348 // do nothing if Ember.ENV is already setup 26349 Ember.assert('Ember.ENV should be an object.', 'object' !== typeof Ember.ENV); 26350 } else if ('undefined' !== typeof EmberENV) { 26351 Ember.ENV = EmberENV; 26352 } else if ('undefined' !== typeof ENV) { 26353 Ember.ENV = ENV; 26354 } else { 26355 Ember.ENV = {}; 26356 } 26357 26358 // ENABLE_ALL_FEATURES was documented, but you can't actually enable non optional features. 26359 if (Ember.ENV.ENABLE_ALL_FEATURES) { 26360 Ember.ENV.ENABLE_OPTIONAL_FEATURES = Ember.ENV.ENABLE_ALL_FEATURES; 26361 } 26362 26363 Ember.config = Ember.config || {}; 26364 26365 // .......................................................... 26366 // BOOTSTRAP 26367 // 26368 26369 /** 26370 Determines whether Ember should add to `Array`, `Function`, and `String` 26371 native object prototypes, a few extra methods in order to provide a more 26372 friendly API. 26373 26374 We generally recommend leaving this option set to true however, if you need 26375 to turn it off, you can add the configuration property 26376 `EXTEND_PROTOTYPES` to `EmberENV` and set it to `false`. 26377 26378 Note, when disabled (the default configuration for Ember Addons), you will 26379 instead have to access all methods and functions from the Ember 26380 namespace. 26381 26382 @property EXTEND_PROTOTYPES 26383 @type Boolean 26384 @default true 26385 @for Ember 26386 @public 26387 */ 26388 Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES; 26389 26390 if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') { 26391 Ember.EXTEND_PROTOTYPES = true; 26392 } 26393 26394 /** 26395 The `LOG_STACKTRACE_ON_DEPRECATION` property, when true, tells Ember to log 26396 a full stack trace during deprecation warnings. 26397 26398 @property LOG_STACKTRACE_ON_DEPRECATION 26399 @type Boolean 26400 @default true 26401 @public 26402 */ 26403 Ember.LOG_STACKTRACE_ON_DEPRECATION = Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false; 26404 26405 /** 26406 The `LOG_VERSION` property, when true, tells Ember to log versions of all 26407 dependent libraries in use. 26408 26409 @property LOG_VERSION 26410 @type Boolean 26411 @default true 26412 @public 26413 */ 26414 Ember.LOG_VERSION = Ember.ENV.LOG_VERSION === false ? false : true; 26415 26416 /** 26417 An empty function useful for some operations. Always returns `this`. 26418 26419 @method K 26420 @return {Object} 26421 @public 26422 */ 26423 function K() { 26424 return this; 26425 } 26426 exports.K = K; 26427 26428 Ember.K = K; 26429 //TODO: ES6 GLOBAL TODO 26430 26431 exports.default = Ember; 26432}); 26433enifed("ember-metal/debug", ["exports"], function (exports) { 26434 "use strict"; 26435 26436 exports.getDebugFunction = getDebugFunction; 26437 exports.setDebugFunction = setDebugFunction; 26438 exports.assert = assert; 26439 exports.info = info; 26440 exports.warn = warn; 26441 exports.debug = debug; 26442 exports.deprecate = deprecate; 26443 exports.deprecateFunc = deprecateFunc; 26444 exports.runInDebug = runInDebug; 26445 exports.debugSeal = debugSeal; 26446 var debugFunctions = { 26447 assert: function () {}, 26448 info: function () {}, 26449 warn: function () {}, 26450 debug: function () {}, 26451 deprecate: function () {}, 26452 deprecateFunc: function () { 26453 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 26454 args[_key] = arguments[_key]; 26455 } 26456 26457 return args[args.length - 1]; 26458 }, 26459 runInDebug: function () {}, 26460 debugSeal: function () {} 26461 }; 26462 26463 exports.debugFunctions = debugFunctions; 26464 26465 function getDebugFunction(name) { 26466 return debugFunctions[name]; 26467 } 26468 26469 function setDebugFunction(name, fn) { 26470 debugFunctions[name] = fn; 26471 } 26472 26473 function assert() { 26474 return debugFunctions.assert.apply(undefined, arguments); 26475 } 26476 26477 function info() { 26478 return debugFunctions.info.apply(undefined, arguments); 26479 } 26480 26481 function warn() { 26482 return debugFunctions.warn.apply(undefined, arguments); 26483 } 26484 26485 function debug() { 26486 return debugFunctions.debug.apply(undefined, arguments); 26487 } 26488 26489 function deprecate() { 26490 return debugFunctions.deprecate.apply(undefined, arguments); 26491 } 26492 26493 function deprecateFunc() { 26494 return debugFunctions.deprecateFunc.apply(undefined, arguments); 26495 } 26496 26497 function runInDebug() { 26498 return debugFunctions.runInDebug.apply(undefined, arguments); 26499 } 26500 26501 function debugSeal() { 26502 return debugFunctions.debugSeal.apply(undefined, arguments); 26503 } 26504}); 26505enifed('ember-metal/dependent_keys', ['exports', 'ember-metal/watching'], function (exports, _emberMetalWatching) { 26506 'no use strict'; 26507 // Remove "use strict"; from transpiled module until 26508 // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed 26509 26510 exports.addDependentKeys = addDependentKeys; 26511 exports.removeDependentKeys = removeDependentKeys; 26512 26513 /** 26514 @module ember 26515 @submodule ember-metal 26516 */ 26517 26518 // .......................................................... 26519 // DEPENDENT KEYS 26520 // 26521 26522 function addDependentKeys(desc, obj, keyName, meta) { 26523 // the descriptor has a list of dependent keys, so 26524 // add all of its dependent keys. 26525 var idx, len, depKey; 26526 var depKeys = desc._dependentKeys; 26527 if (!depKeys) { 26528 return; 26529 } 26530 26531 for (idx = 0, len = depKeys.length; idx < len; idx++) { 26532 depKey = depKeys[idx];
26533 // Increment the number of times depKey depends on keyName. 26534 meta.writeDeps(depKey, keyName, (meta.peekDeps(depKey, keyName) || 0) + 1); 26535 // Watch the depKey 26536 _emberMetalWatching.watch(obj, depKey, meta); 26537 } 26538 } 26539 26540 function removeDependentKeys(desc, obj, keyName, meta) { 26541 // the descriptor has a list of dependent keys, so 26542 // remove all of its dependent keys. 26543 var depKeys = desc._dependentKeys; 26544 var idx, len, depKey; 26545 if (!depKeys) { 26546 return; 26547 } 26548 26549 for (idx = 0, len = depKeys.length; idx < len; idx++) { 26550 depKey = depKeys[idx]; 26551 // Decrement the number of times depKey depends on keyName. 26552 meta.writeDeps(depKey, keyName, (meta.peekDeps(depKey, keyName) || 0) - 1); 26553 // Unwatch the depKey 26554 _emberMetalWatching.unwatch(obj, depKey, meta); 26555 } 26556 } 26557}); 26558enifed('ember-metal/deprecate_property', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set) { 26559 /** 26560 @module ember 26561 @submodule ember-metal 26562 */ 26563 26564 'use strict'; 26565 26566 exports.deprecateProperty = deprecateProperty; 26567 26568 /** 26569 Used internally to allow changing properties in a backwards compatible way, and print a helpful 26570 deprecation warning. 26571 26572 @method deprecateProperty 26573 @param {Object} object The object to add the deprecated property to. 26574 @param {String} deprecatedKey The property to add (and print deprecation warnings upon accessing). 26575 @param {String} newKey The property that will be aliased. 26576 @private 26577 @since 1.7.0 26578 */ 26579 26580 function deprecateProperty(object, deprecatedKey, newKey, options) { 26581 function _deprecate() { 26582 _emberMetalDebug.deprecate('Usage of `' + deprecatedKey + '` is deprecated, use `' + newKey + '` instead.', false, options); 26583 } 26584 26585 Object.defineProperty(object, deprecatedKey, { 26586 configurable: true, 26587 enumerable: false, 26588 set: function (value) { 26589 _deprecate(); 26590 _emberMetalProperty_set.set(this, newKey, value); 26591 }, 26592 get: function () { 26593 _deprecate(); 26594 return _emberMetalProperty_get.get(this, newKey); 26595 } 26596 }); 26597 } 26598}); 26599enifed('ember-metal/dictionary', ['exports', 'ember-metal/empty_object'], function (exports, _emberMetalEmpty_object) { 26600 'use strict'; 26601 26602 exports.default = makeDictionary; 26603 26604 // the delete is meant to hint at runtimes that this object should remain in 26605 // dictionary mode. This is clearly a runtime specific hack, but currently it 26606 // appears worthwhile in some usecases. Please note, these deletes do increase 26607 // the cost of creation dramatically over a plain Object.create. And as this 26608 // only makes sense for long-lived dictionaries that aren't instantiated often. 26609 26610 function makeDictionary(parent) { 26611 var dict; 26612 if (parent === null) { 26613 dict = new _emberMetalEmpty_object.default(); 26614 } else { 26615 dict = Object.create(parent); 26616 } 26617 dict['_dict'] = null; 26618 delete dict['_dict']; 26619 return dict; 26620 } 26621}); 26622enifed("ember-metal/empty_object", ["exports"], function (exports) { 26623 // This exists because `Object.create(null)` is absurdly slow compared 26624 // to `new EmptyObject()`. In either case, you want a null prototype 26625 // when you're treating the object instances as arbitrary dictionaries 26626 // and don't want your keys colliding with build-in methods on the 26627 // default object prototype. 26628 26629 "use strict"; 26630 26631 var proto = Object.create(null, { 26632 // without this, we will always still end up with (new 26633 // EmptyObject()).constructor === Object 26634 constructor: { 26635 value: undefined, 26636 enumerable: false, 26637 writable: true 26638 } 26639 }); 26640 26641 function EmptyObject() {} 26642 EmptyObject.prototype = proto; 26643 exports.default = EmptyObject; 26644}); 26645enifed('ember-metal/environment', ['exports', 'ember-metal/core'], function (exports, _emberMetalCore) { 26646 'use strict'; 26647 26648 /* 26649 Ember can run in many different environments, including environments like 26650 Node.js where the DOM is unavailable. This object serves as an abstraction 26651 over the browser features that Ember relies on, so that code does not 26652 explode when trying to boot in an environment that doesn't have them. 26653 26654 This is a private abstraction. In the future, we hope that other 26655 abstractions (like `Location`, `Renderer`, `dom-helper`) can fully abstract 26656 over the differences in environment. 26657 */ 26658 var environment; 26659 26660 // This code attempts to automatically detect an environment with DOM 26661 // by searching for window and document.createElement. An environment 26662 // with DOM may disable the DOM functionality of Ember explicitly by 26663 // defining a `disableBrowserEnvironment` ENV. 26664 var hasDOM = typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.createElement !== 'undefined' && !_emberMetalCore.default.ENV.disableBrowserEnvironment; 26665 26666 if (hasDOM) { 26667 environment = { 26668 hasDOM: true, 26669 isChrome: !!window.chrome && !window.opera, 26670 isFirefox: typeof InstallTrigger !== 'undefined', 26671 isPhantom: !!window.callPhantom, 26672 location: window.location, 26673 history: window.history, 26674 userAgent: window.navigator.userAgent, 26675 global: window 26676 }; 26677 } else { 26678 environment = { 26679 hasDOM: false, 26680 isChrome: false, 26681 isFirefox: false, 26682 isPhantom: false, 26683 location: null, 26684 history: null, 26685 userAgent: 'Lynx (textmode)', 26686 global: null 26687 }; 26688 } 26689 26690 exports.default = environment; 26691}); 26692enifed('ember-metal/error', ['exports', 'ember-metal/core'], function (exports, _emberMetalCore) { 26693 'use strict'; 26694 26695 exports.default = EmberError; 26696 26697 var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; 26698 26699 /** 26700 A subclass of the JavaScript Error object for use in Ember. 26701 26702 @class Error 26703 @namespace Ember
26704 @extends Error 26705 @constructor 26706 @public 26707 */ 26708 26709 function EmberError() { 26710 var tmp = Error.apply(this, arguments); 26711 26712 // Adds a `stack` property to the given error object that will yield the 26713 // stack trace at the time captureStackTrace was called. 26714 // When collecting the stack trace all frames above the topmost call 26715 // to this function, including that call, will be left out of the 26716 // stack trace. 26717 // This is useful because we can hide Ember implementation details 26718 // that are not very helpful for the user. 26719 if (Error.captureStackTrace) { 26720 Error.captureStackTrace(this, _emberMetalCore.default.Error); 26721 } 26722 // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. 26723 for (var idx = 0; idx < errorProps.length; idx++) { 26724 this[errorProps[idx]] = tmp[errorProps[idx]]; 26725 } 26726 } 26727 26728 EmberError.prototype = Object.create(Error.prototype); 26729}); 26730enifed('ember-metal/events', ['exports', 'ember-metal/debug', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/meta_listeners'], function (exports, _emberMetalDebug, _emberMetalUtils, _emberMetalMeta, _emberMetalMeta_listeners) { 26731 'no use strict'; 26732 // Remove "use strict"; from transpiled module until 26733 // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed 26734 26735 /** 26736 @module ember 26737 @submodule ember-metal 26738 */ 26739 exports.accumulateListeners = accumulateListeners; 26740 exports.addListener = addListener; 26741 exports.removeListener = removeListener; 26742 exports.suspendListener = suspendListener; 26743 exports.suspendListeners = suspendListeners; 26744 exports.watchedEvents = watchedEvents; 26745 exports.sendEvent = sendEvent; 26746 exports.hasListeners = hasListeners; 26747 exports.listenersFor = listenersFor; 26748 exports.on = on; 26749 26750 /* 26751 The event system uses a series of nested hashes to store listeners on an 26752 object. When a listener is registered, or when an event arrives, these 26753 hashes are consulted to determine which target and action pair to invoke. 26754 26755 The hashes are stored in the object's meta hash, and look like this: 26756 26757 // Object's meta hash 26758 { 26759 listeners: { // variable name: `listenerSet` 26760 "foo:changed": [ // variable name: `actions` 26761 target, method, flags 26762 ] 26763 } 26764 } 26765 26766 */ 26767 26768 function indexOf(array, target, method) { 26769 var index = -1; 26770 // hashes are added to the end of the event array 26771 // so it makes sense to start searching at the end 26772 // of the array and search in reverse 26773 for (var i = array.length - 3; i >= 0; i -= 3) { 26774 if (target === array[i] && method === array[i + 1]) { 26775 index = i; 26776 break; 26777 } 26778 } 26779 return index; 26780 } 26781 26782 function accumulateListeners(obj, eventName, otherActions) { 26783 var meta = _emberMetalMeta.peekMeta(obj); 26784 if (!meta) { 26785 return; 26786 } 26787 var actions = meta.matchingListeners(eventName); 26788 var newActions = []; 26789 26790 for (var i = actions.length - 3; i >= 0; i -= 3) { 26791 var target = actions[i]; 26792 var method = actions[i + 1]; 26793 var flags = actions[i + 2]; 26794 var actionIndex = indexOf(otherActions, target, method); 26795 26796 if (actionIndex === -1) { 26797 otherActions.push(target, method, flags); 26798 newActions.push(target, method, flags); 26799 } 26800 } 26801 26802 return newActions; 26803 } 26804 26805 /** 26806 Add an event listener 26807 26808 @method addListener 26809 @for Ember 26810 @param obj 26811 @param {String} eventName 26812 @param {Object|Function} target A target object or a function 26813 @param {Function|String} method A function or the name of a function to be called on `target` 26814 @param {Boolean} once A flag whether a function should only be called once 26815 @public 26816 */ 26817 26818 function addListener(obj, eventName, target, method, once) { 26819 _emberMetalDebug.assert('You must pass at least an object and event name to Ember.addListener', !!obj && !!eventName); 26820 26821 if (!method && 'function' === typeof target) { 26822 method = target; 26823 target = null; 26824 } 26825 26826 var flags = 0; 26827 if (once) { 26828 flags |= _emberMetalMeta_listeners.ONCE; 26829 } 26830 26831 _emberMetalMeta.meta(obj).addToListeners(eventName, target, method, flags); 26832 26833 if ('function' === typeof obj.didAddListener) { 26834 obj.didAddListener(eventName, target, method); 26835 } 26836 } 26837 26838 /** 26839 Remove an event listener 26840 26841 Arguments should match those passed to `Ember.addListener`. 26842 26843 @method removeListener 26844 @for Ember 26845 @param obj 26846 @param {String} eventName 26847 @param {Object|Function} target A target object or a function 26848 @param {Function|String} method A function or the name of a function to be called on `target`
26849 @public 26850 */ 26851 26852 function removeListener(obj, eventName, target, method) { 26853 _emberMetalDebug.assert('You must pass at least an object and event name to Ember.removeListener', !!obj && !!eventName); 26854 26855 if (!method && 'function' === typeof target) { 26856 method = target; 26857 target = null; 26858 } 26859 26860 _emberMetalMeta.meta(obj).removeFromListeners(eventName, target, method, function () { 26861 if ('function' === typeof obj.didRemoveListener) { 26862 obj.didRemoveListener.apply(obj, arguments); 26863 } 26864 }); 26865 } 26866 26867 /** 26868 Suspend listener during callback. 26869 26870 This should only be used by the target of the event listener 26871 when it is taking an action that would cause the event, e.g. 26872 an object might suspend its property change listener while it is 26873 setting that property. 26874 26875 @method suspendListener 26876 @for Ember 26877 26878 @private 26879 @param obj 26880 @param {String} eventName 26881 @param {Object|Function} target A target object or a function 26882 @param {Function|String} method A function or the name of a function to be called on `target` 26883 @param {Function} callback 26884 */ 26885 26886 function suspendListener(obj, eventName, target, method, callback) { 26887 return suspendListeners(obj, [eventName], target, method, callback); 26888 } 26889 26890 /** 26891 Suspends multiple listeners during a callback. 26892 26893 @method suspendListeners 26894 @for Ember 26895 26896 @private 26897 @param obj 26898 @param {Array} eventNames Array of event names 26899 @param {Object|Function} target A target object or a function 26900 @param {Function|String} method A function or the name of a function to be called on `target` 26901 @param {Function} callback 26902 */ 26903 26904 function suspendListeners(obj, eventNames, target, method, callback) { 26905 if (!method && 'function' === typeof target) { 26906 method = target; 26907 target = null; 26908 } 26909 return _emberMetalMeta.meta(obj).suspendListeners(eventNames, target, method, callback); 26910 } 26911 26912 /** 26913 Return a list of currently watched events 26914 26915 @private 26916 @method watchedEvents 26917 @for Ember 26918 @param obj 26919 */ 26920 26921 function watchedEvents(obj) { 26922 return _emberMetalMeta.meta(obj).watchedEvents(); 26923 } 26924 26925 /** 26926 Send an event. The execution of suspended listeners 26927 is skipped, and once listeners are removed. A listener without 26928 a target is executed on the passed object. If an array of actions 26929 is not passed, the actions stored on the passed object are invoked. 26930 26931 @method sendEvent 26932 @for Ember 26933 @param obj 26934 @param {String} eventName 26935 @param {Array} params Optional parameters for each listener. 26936 @param {Array} actions Optional array of actions (listeners). 26937 @return true 26938 @public 26939 */ 26940 26941 function sendEvent(obj, eventName, params, actions) { 26942 if (!actions) { 26943 var meta = _emberMetalMeta.peekMeta(obj); 26944 actions = meta && meta.matchingListeners(eventName); 26945 } 26946 26947 if (!actions || actions.length === 0) { 26948 return; 26949 } 26950 26951 for (var i = actions.length - 3; i >= 0; i -= 3) { 26952 // looping in reverse for once listeners 26953 var target = actions[i]; 26954 var method = actions[i + 1]; 26955 var flags = actions[i + 2]; 26956 26957 if (!method) { 26958 continue; 26959 } 26960 if (flags & _emberMetalMeta_listeners.SUSPENDED) { 26961 continue; 26962 } 26963 if (flags & _emberMetalMeta_listeners.ONCE) { 26964 removeListener(obj, eventName, target, method); 26965 } 26966 if (!target) { 26967 target = obj; 26968 } 26969 if ('string' === typeof method) { 26970 if (params) { 26971 _emberMetalUtils.applyStr(target, method, params); 26972 } else { 26973 target[method](); 26974 } 26975 } else { 26976 if (params) { 26977 _emberMetalUtils.apply(target, method, params); 26978 } else { 26979 method.call(target); 26980 } 26981 } 26982 } 26983 return true; 26984 } 26985 26986 /** 26987 @private 26988 @method hasListeners 26989 @for Ember 26990 @param obj 26991 @param {String} eventName 26992 */ 26993 26994 function hasListeners(obj, eventName) { 26995 var meta = _emberMetalMeta.peekMeta(obj); 26996 if (!meta) { 26997 return false; 26998 } 26999 return meta.matchingListeners(eventName).length > 0; 27000 } 27001 27002 /** 27003 @private 27004 @method listenersFor 27005 @for Ember 27006 @param obj 27007 @param {String} eventName 27008 */ 27009 27010 function listenersFor(obj, eventName) { 27011 var ret = []; 27012 var meta = _emberMetalMeta.peekMeta(obj); 27013 var actions = meta && meta.matchingListeners(eventName); 27014 27015 if (!actions) { 27016 return ret; 27017 } 27018 27019 for (var i = 0, l = actions.length; i < l; i += 3) { 27020 var target = actions[i]; 27021 var method = actions[i + 1];
27022 ret.push([target, method]); 27023 } 27024 27025 return ret; 27026 } 27027 27028 /** 27029 Define a property as a function that should be executed when 27030 a specified event or events are triggered. 27031 27032 27033 ``` javascript 27034 var Job = Ember.Object.extend({ 27035 logCompleted: Ember.on('completed', function() { 27036 console.log('Job completed!'); 27037 }) 27038 }); 27039 27040 var job = Job.create(); 27041 27042 Ember.sendEvent(job, 'completed'); // Logs 'Job completed!' 27043 ``` 27044 27045 @method on 27046 @for Ember 27047 @param {String} eventNames* 27048 @param {Function} func 27049 @return func 27050 @public 27051 */ 27052 27053 function on() { 27054 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 27055 args[_key] = arguments[_key]; 27056 } 27057 27058 var func = args.pop(); 27059 var events = args; 27060 func.__ember_listens__ = events; 27061 return func; 27062 } 27063}); 27064enifed('ember-metal/expand_properties', ['exports', 'ember-metal/debug'], function (exports, _emberMetalDebug) { 27065 'use strict'; 27066 27067 exports.default = expandProperties; 27068 27069 /** 27070 @module ember 27071 @submodule ember-metal 27072 */ 27073 27074 var SPLIT_REGEX = /\{|\}/; 27075 var END_WITH_EACH_REGEX = /\.@each$/; 27076 27077 /** 27078 Expands `pattern`, invoking `callback` for each expansion. 27079 27080 The only pattern supported is brace-expansion, anything else will be passed 27081 once to `callback` directly. 27082 27083 Example 27084 27085 ```js 27086 function echo(arg){ console.log(arg); } 27087 27088 Ember.expandProperties('foo.bar', echo); //=> 'foo.bar' 27089 Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' 27090 Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' 27091 Ember.expandProperties('{foo,bar}.baz', echo); //=> 'foo.baz', 'bar.baz' 27092 Ember.expandProperties('foo.{bar,baz}.[]', echo) //=> 'foo.bar.[]', 'foo.baz.[]' 27093 Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' 27094 Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' 27095 ``` 27096 27097 @method expandProperties 27098 @for Ember 27099 @private 27100 @param {String} pattern The property pattern to expand. 27101 @param {Function} callback The callback to invoke. It is invoked once per 27102 expansion, and is passed the expansion. 27103 */ 27104 27105 function expandProperties(pattern, callback) { 27106 _emberMetalDebug.assert('A computed property key must be a string', typeof pattern === 'string'); 27107 _emberMetalDebug.assert('Brace expanded properties cannot contain spaces, e.g. "user.{firstName, lastName}" should be "user.{firstName,lastName}"', pattern.indexOf(' ') === -1); 27108 27109 var parts = pattern.split(SPLIT_REGEX); 27110 var properties = [parts]; 27111 27112 for (var i = 0; i < parts.length; i++) { 27113 var part = parts[i]; 27114 if (part.indexOf(',') >= 0) { 27115 properties = duplicateAndReplace(properties, part.split(','), i); 27116 } 27117 } 27118 27119 for (var i = 0; i < properties.length; i++) { 27120 callback(properties[i].join('').replace(END_WITH_EACH_REGEX, '.[]')); 27121 } 27122 } 27123 27124 function duplicateAndReplace(properties, currentParts, index) { 27125 var all = []; 27126 27127 properties.forEach(function (property) { 27128 currentParts.forEach(function (part) { 27129 var current = property.slice(0); 27130 current[index] = part; 27131 all.push(current); 27132 }); 27133 }); 27134 27135 return all; 27136 } 27137}); 27138enifed('ember-metal/features', ['exports', 'ember-metal/core', 'ember-metal/assign'], function (exports, _emberMetalCore, _emberMetalAssign) { 27139 'use strict'; 27140 27141 exports.default = isEnabled; 27142 27143 /** 27144 The hash of enabled Canary features. Add to this, any canary features 27145 before creating your application. 27146 27147 Alternatively (and recommended), you can also define `EmberENV.FEATURES` 27148 if you need to enable features flagged at runtime. 27149 27150 @class FEATURES 27151 @namespace Ember 27152 @static 27153 @since 1.1.0 27154 @public 27155 */ 27156 var KNOWN_FEATURES = {};exports.KNOWN_FEATURES = KNOWN_FEATURES; 27157 // jshint ignore:line 27158 var FEATURES = _emberMetalAssign.default(KNOWN_FEATURES, _emberMetalCore.default.ENV.FEATURES); 27159 27160 exports.FEATURES = FEATURES; 27161 /** 27162 Determine whether the specified `feature` is enabled. Used by Ember's 27163 build tools to exclude experimental features from beta/stable builds. 27164 27165 You can define the following configuration options: 27166 27167 * `EmberENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly 27168 enabled/disabled. 27169
27170 @method isEnabled 27171 @param {String} feature The feature to check 27172 @return {Boolean} 27173 @for Ember.FEATURES 27174 @since 1.1.0 27175 @public 27176 */ 27177 27178 function isEnabled(feature) { 27179 var featureValue = FEATURES[feature]; 27180 27181 if (featureValue === true || featureValue === false || featureValue === undefined) { 27182 return featureValue; 27183 } else if (_emberMetalCore.default.ENV.ENABLE_OPTIONAL_FEATURES) { 27184 return true; 27185 } else { 27186 return false; 27187 } 27188 } 27189}); 27190enifed('ember-metal/get_properties', ['exports', 'ember-metal/property_get'], function (exports, _emberMetalProperty_get) { 27191 'use strict'; 27192 27193 exports.default = getProperties; 27194 27195 /** 27196 To get multiple properties at once, call `Ember.getProperties` 27197 with an object followed by a list of strings or an array: 27198 27199 ```javascript 27200 Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); 27201 // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } 27202 ``` 27203 27204 is equivalent to: 27205 27206 ```javascript 27207 Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); 27208 // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } 27209 ``` 27210 27211 @method getProperties 27212 @for Ember 27213 @param {Object} obj 27214 @param {String...|Array} list of keys to get 27215 @return {Object} 27216 @public 27217 */ 27218 27219 function getProperties(obj) { 27220 var ret = {}; 27221 var propertyNames = arguments; 27222 var i = 1; 27223 27224 if (arguments.length === 2 && Array.isArray(arguments[1])) { 27225 i = 0; 27226 propertyNames = arguments[1]; 27227 } 27228 for (var len = propertyNames.length; i < len; i++) { 27229 ret[propertyNames[i]] = _emberMetalProperty_get.get(obj, propertyNames[i]); 27230 } 27231 return ret; 27232 } 27233}); 27234enifed('ember-metal/index', ['exports', 'require', 'ember-metal/core', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/assign', 'ember-metal/merge', 'ember-metal/instrumentation', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/error', 'ember-metal/cache', 'ember-metal/logger', 'ember-metal/property_get', 'ember-metal/events', 'ember-metal/observer_set', 'ember-metal/property_events', 'ember-metal/properties', 'ember-metal/property_set', 'ember-metal/map', 'ember-metal/get_properties', 'ember-metal/set_properties', 'ember-metal/watch_key', 'ember-metal/chains', 'ember-metal/watch_path', 'ember-metal/watching', 'ember-metal/expand_properties', 'ember-metal/computed', 'ember-metal/alias', 'ember-metal/computed_macros', 'ember-metal/observer', 'ember-metal/mixin', 'ember-metal/binding', 'ember-metal/path_cache', 'ember-metal/run_loop', 'ember-metal/libraries', 'ember-metal/is_none', 'ember-metal/is_empty', 'ember-metal/is_blank', 'ember-metal/is_present', 'backburner'], function (exports, _require, _emberMetalCore, _emberMetalDebug, _emberMetalFeatures, _emberMetalAssign, _emberMetalMerge, _emberMetalInstrumentation, _emberMetalUtils, _emberMetalMeta, _emberMetalError, _emberMetalCache, _emberMetalLogger, _emberMetalProperty_get, _emberMetalEvents, _emberMetalObserver_set, _emberMetalProperty_events, _emberMetalProperties, _emberMetalProperty_set, _emberMetalMap, _emberMetalGet_properties, _emberMetalSet_properties, _emberMetalWatch_key, _emberMetalChains, _emberMetalWatch_path, _emberMetalWatching, _emberMetalExpand_properties, _emberMetalComputed, _emberMetalAlias, _emberMetalComputed_macros, _emberMetalObserver, _emberMetalMixin, _emberMetalBinding, _emberMetalPath_cache, _emberMetalRun_loop, _emberMetalLibraries, _emberMetalIs_none, _emberMetalIs_empty, _emberMetalIs_blank, _emberMetalIs_present, _backburner) { 27235 /** 27236 @module ember 27237 @submodule ember-metal 27238 */ 27239 27240 // BEGIN IMPORTS 27241 'use strict'; 27242 27243 _emberMetalComputed.computed.empty = _emberMetalComputed_macros.empty; 27244 _emberMetalComputed.computed.notEmpty = _emberMetalComputed_macros.notEmpty; 27245 _emberMetalComputed.computed.none = _emberMetalComputed_macros.none; 27246 _emberMetalComputed.computed.not = _emberMetalComputed_macros.not; 27247 _emberMetalComputed.computed.bool = _emberMetalComputed_macros.bool; 27248 _emberMetalComputed.computed.match = _emberMetalComputed_macros.match; 27249 _emberMetalComputed.computed.equal = _emberMetalComputed_macros.equal; 27250 _emberMetalComputed.computed.gt = _emberMetalComputed_macros.gt; 27251 _emberMetalComputed.computed.gte = _emberMetalComputed_macros.gte; 27252 _emberMetalComputed.computed.lt = _emberMetalComputed_macros.lt; 27253 _emberMetalComputed.computed.lte = _emberMetalComputed_macros.lte; 27254 _emberMetalComputed.computed.alias = _emberMetalAlias.default; 27255 _emberMetalComputed.computed.oneWay = _emberMetalComputed_macros.oneWay; 27256 _emberMetalComputed.computed.reads = _emberMetalComputed_macros.oneWay; 27257 _emberMetalComputed.computed.readOnly = _emberMetalComputed_macros.readOnly; 27258 _emberMetalComputed.computed.defaultTo = _emberMetalComputed_macros.defaultTo; 27259 _emberMetalComputed.computed.deprecatingAlias = _emberMetalComputed_macros.deprecatingAlias; 27260 _emberMetalComputed.computed.and = _emberMetalComputed_macros.and; 27261 _emberMetalComputed.computed.or = _emberMetalComputed_macros.or; 27262 _emberMetalComputed.computed.any = _emberMetalComputed_macros.any; 27263 27264 // END IMPORTS 27265 27266 // BEGIN EXPORTS 27267 var EmberInstrumentation = _emberMetalCore.default.Instrumentation = {}; 27268 EmberInstrumentation.instrument = _emberMetalInstrumentation.instrument; 27269 EmberInstrumentation.subscribe = _emberMetalInstrumentation.subscribe; 27270 EmberInstrumentation.unsubscribe = _emberMetalInstrumentation.unsubscribe; 27271 EmberInstrumentation.reset = _emberMetalInstrumentation.reset; 27272 27273 _emberMetalCore.default.instrument = _emberMetalInstrumentation.instrument; 27274 _emberMetalCore.default.subscribe = _emberMetalInstrumentation.subscribe; 27275
27276 _emberMetalCore.default._Cache = _emberMetalCache.default; 27277 27278 _emberMetalCore.default.generateGuid = _emberMetalUtils.generateGuid; 27279 _emberMetalCore.default.GUID_KEY = _emberMetalUtils.GUID_KEY; 27280 _emberMetalCore.default.platform = { 27281 defineProperty: true, 27282 hasPropertyAccessors: true 27283 }; 27284 27285 _emberMetalCore.default.Error = _emberMetalError.default; 27286 _emberMetalCore.default.guidFor = _emberMetalUtils.guidFor; 27287 _emberMetalCore.default.META_DESC = _emberMetalMeta.META_DESC; 27288 _emberMetalCore.default.meta = _emberMetalMeta.meta; 27289 _emberMetalCore.default.inspect = _emberMetalUtils.inspect; 27290 27291 _emberMetalCore.default.tryCatchFinally = _emberMetalUtils.deprecatedTryCatchFinally; 27292 _emberMetalCore.default.makeArray = _emberMetalUtils.makeArray; 27293 _emberMetalCore.default.canInvoke = _emberMetalUtils.canInvoke; 27294 _emberMetalCore.default.tryInvoke = _emberMetalUtils.tryInvoke; 27295 _emberMetalCore.default.wrap = _emberMetalUtils.wrap; 27296 _emberMetalCore.default.apply = _emberMetalUtils.apply; 27297 _emberMetalCore.default.applyStr = _emberMetalUtils.applyStr; 27298 _emberMetalCore.default.uuid = _emberMetalUtils.uuid; 27299 27300 _emberMetalCore.default.Logger = _emberMetalLogger.default; 27301 27302 _emberMetalCore.default.get = _emberMetalProperty_get.get; 27303 _emberMetalCore.default.getWithDefault = _emberMetalProperty_get.getWithDefault; 27304 _emberMetalCore.default._getPath = _emberMetalProperty_get._getPath; 27305 27306 _emberMetalCore.default.on = _emberMetalEvents.on; 27307 _emberMetalCore.default.addListener = _emberMetalEvents.addListener; 27308 _emberMetalCore.default.removeListener = _emberMetalEvents.removeListener; 27309 _emberMetalCore.default._suspendListener = _emberMetalEvents.suspendListener; 27310 _emberMetalCore.default._suspendListeners = _emberMetalEvents.suspendListeners; 27311 _emberMetalCore.default.sendEvent = _emberMetalEvents.sendEvent; 27312 _emberMetalCore.default.hasListeners = _emberMetalEvents.hasListeners; 27313 _emberMetalCore.default.watchedEvents = _emberMetalEvents.watchedEvents; 27314 _emberMetalCore.default.listenersFor = _emberMetalEvents.listenersFor; 27315 _emberMetalCore.default.accumulateListeners = _emberMetalEvents.accumulateListeners; 27316 27317 _emberMetalCore.default._ObserverSet = _emberMetalObserver_set.default; 27318 27319 _emberMetalCore.default.propertyWillChange = _emberMetalProperty_events.propertyWillChange; 27320 _emberMetalCore.default.propertyDidChange = _emberMetalProperty_events.propertyDidChange; 27321 _emberMetalCore.default.overrideChains = _emberMetalProperty_events.overrideChains; 27322 _emberMetalCore.default.beginPropertyChanges = _emberMetalProperty_events.beginPropertyChanges; 27323 _emberMetalCore.default.endPropertyChanges = _emberMetalProperty_events.endPropertyChanges; 27324 _emberMetalCore.default.changeProperties = _emberMetalProperty_events.changeProperties; 27325 27326 _emberMetalCore.default.defineProperty = _emberMetalProperties.defineProperty; 27327 27328 _emberMetalCore.default.set = _emberMetalProperty_set.set; 27329 _emberMetalCore.default.trySet = _emberMetalProperty_set.trySet; 27330 27331 _emberMetalCore.default.OrderedSet = _emberMetalMap.OrderedSet; 27332 _emberMetalCore.default.Map = _emberMetalMap.Map; 27333 _emberMetalCore.default.MapWithDefault = _emberMetalMap.MapWithDefault; 27334 27335 _emberMetalCore.default.getProperties = _emberMetalGet_properties.default; 27336 _emberMetalCore.default.setProperties = _emberMetalSet_properties.default; 27337 27338 _emberMetalCore.default.watchKey = _emberMetalWatch_key.watchKey; 27339 _emberMetalCore.default.unwatchKey = _emberMetalWatch_key.unwatchKey; 27340 27341 _emberMetalCore.default.removeChainWatcher = _emberMetalChains.removeChainWatcher; 27342 _emberMetalCore.default._ChainNode = _emberMetalChains.ChainNode; 27343 _emberMetalCore.default.finishChains = _emberMetalChains.finishChains; 27344 27345 _emberMetalCore.default.watchPath = _emberMetalWatch_path.watchPath; 27346 _emberMetalCore.default.unwatchPath = _emberMetalWatch_path.unwatchPath; 27347 27348 _emberMetalCore.default.watch = _emberMetalWatching.watch; 27349 _emberMetalCore.default.isWatching = _emberMetalWatching.isWatching; 27350 _emberMetalCore.default.unwatch = _emberMetalWatching.unwatch; 27351 _emberMetalCore.default.rewatch = _emberMetalWatching.rewatch; 27352 _emberMetalCore.default.destroy = _emberMetalWatching.destroy; 27353 27354 _emberMetalCore.default.expandProperties = _emberMetalExpand_properties.default; 27355 27356 _emberMetalCore.default.ComputedProperty = _emberMetalComputed.ComputedProperty; 27357 _emberMetalCore.default.computed = _emberMetalComputed.computed; 27358 _emberMetalCore.default.cacheFor = _emberMetalComputed.cacheFor; 27359 27360 _emberMetalCore.default.addObserver = _emberMetalObserver.addObserver; 27361 _emberMetalCore.default.observersFor = _emberMetalObserver.observersFor; 27362 _emberMetalCore.default.removeObserver = _emberMetalObserver.removeObserver; 27363 _emberMetalCore.default._suspendObserver = _emberMetalObserver._suspendObserver; 27364 _emberMetalCore.default._suspendObservers = _emberMetalObserver._suspendObservers; 27365 27366 _emberMetalCore.default.IS_BINDING = _emberMetalMixin.IS_BINDING; 27367 _emberMetalCore.default.required = _emberMetalMixin.required; 27368 _emberMetalCore.default.aliasMethod = _emberMetalMixin.aliasMethod; 27369 _emberMetalCore.default.observer = _emberMetalMixin.observer; 27370 _emberMetalCore.default.immediateObserver = _emberMetalMixin._immediateObserver; 27371 _emberMetalCore.default.mixin = _emberMetalMixin.mixin; 27372 _emberMetalCore.default.Mixin = _emberMetalMixin.Mixin; 27373 27374 _emberMetalCore.default.bind = _emberMetalBinding.bind; 27375 _emberMetalCore.default.Binding = _emberMetalBinding.Binding; 27376 _emberMetalCore.default.isGlobalPath = _emberMetalPath_cache.isGlobalPath; 27377 27378 _emberMetalCore.default.run = _emberMetalRun_loop.default; 27379 27380 /** 27381 @class Backburner 27382 @for Ember 27383 @private 27384 */ 27385 _emberMetalCore.default.Backburner = _backburner.default; 27386 // this is the new go forward, once Ember Data updates to using `_Backburner` we
27387 // can remove the non-underscored version. 27388 _emberMetalCore.default._Backburner = _backburner.default; 27389 27390 _emberMetalCore.default.libraries = new _emberMetalLibraries.default(); 27391 _emberMetalCore.default.libraries.registerCoreLibrary('Ember', _emberMetalCore.default.VERSION); 27392 27393 _emberMetalCore.default.isNone = _emberMetalIs_none.default; 27394 _emberMetalCore.default.isEmpty = _emberMetalIs_empty.default; 27395 _emberMetalCore.default.isBlank = _emberMetalIs_blank.default; 27396 _emberMetalCore.default.isPresent = _emberMetalIs_present.default; 27397 27398 _emberMetalCore.default.assign = Object.assign || _emberMetalAssign.default; 27399 _emberMetalCore.default.merge = _emberMetalMerge.default; 27400 27401 _emberMetalCore.default.FEATURES = _emberMetalFeatures.FEATURES; 27402 _emberMetalCore.default.FEATURES.isEnabled = _emberMetalFeatures.default; 27403 27404 /** 27405 A function may be assigned to `Ember.onerror` to be called when Ember 27406 internals encounter an error. This is useful for specialized error handling 27407 and reporting code. 27408 27409 ```javascript 27410 Ember.onerror = function(error) { 27411 Em.$.ajax('/report-error', 'POST', { 27412 stack: error.stack, 27413 otherInformation: 'whatever app state you want to provide' 27414 }); 27415 }; 27416 ``` 27417 27418 Internally, `Ember.onerror` is used as Backburner's error handler. 27419 27420 @event onerror 27421 @for Ember 27422 @param {Exception} error the error object 27423 @public 27424 */ 27425 _emberMetalCore.default.onerror = null; 27426 // END EXPORTS 27427 27428 // do this for side-effects of updating Ember.assert, warn, etc when 27429 // ember-debug is present 27430 // This needs to be called before any deprecateFunc 27431 if (_require.has('ember-debug')) { 27432 _require.default('ember-debug'); 27433 } else { 27434 _emberMetalCore.default.Debug = {}; 27435 27436 _emberMetalCore.default.Debug.registerDeprecationHandler = function () {}; 27437 _emberMetalCore.default.Debug.registerWarnHandler = function () {}; 27438 } 27439 27440 _emberMetalCore.default.create = _emberMetalDebug.deprecateFunc('Ember.create is deprecated in favor of Object.create', { id: 'ember-metal.ember-create', until: '3.0.0' }, Object.create); 27441 _emberMetalCore.default.keys = _emberMetalDebug.deprecateFunc('Ember.keys is deprecated in favor of Object.keys', { id: 'ember-metal.ember.keys', until: '3.0.0' }, Object.keys); 27442 27443 exports.default = _emberMetalCore.default; 27444}); 27445enifed('ember-metal/injected_property', ['exports', 'ember-metal/debug', 'ember-metal/computed', 'ember-metal/alias', 'ember-metal/properties', 'container/owner'], function (exports, _emberMetalDebug, _emberMetalComputed, _emberMetalAlias, _emberMetalProperties, _containerOwner) { 27446 'use strict'; 27447 27448 /** 27449 Read-only property that returns the result of a container lookup. 27450 27451 @class InjectedProperty 27452 @namespace Ember 27453 @constructor 27454 @param {String} type The container type the property will lookup 27455 @param {String} name (optional) The name the property will lookup, defaults 27456 to the property's name 27457 @private 27458 */ 27459 function InjectedProperty(type, name) { 27460 this.type = type; 27461 this.name = name; 27462 27463 this._super$Constructor(injectedPropertyGet); 27464 AliasedPropertyPrototype.oneWay.call(this); 27465 } 27466 27467 function injectedPropertyGet(keyName) { 27468 var desc = this[keyName]; 27469 var owner = _containerOwner.getOwner(this) || this.container; // fallback to `container` for backwards compat 27470 27471 _emberMetalDebug.assert('InjectedProperties should be defined with the Ember.inject computed property macros.', desc && desc.isDescriptor && desc.type); 27472 _emberMetalDebug.assert('Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.', owner); 27473 27474 return owner.lookup(desc.type + ':' + (desc.name || keyName)); 27475 } 27476 27477 InjectedProperty.prototype = Object.create(_emberMetalProperties.Descriptor.prototype); 27478 27479 var InjectedPropertyPrototype = InjectedProperty.prototype; 27480 var ComputedPropertyPrototype = _emberMetalComputed.ComputedProperty.prototype; 27481 var AliasedPropertyPrototype = _emberMetalAlias.AliasedProperty.prototype; 27482 27483 InjectedPropertyPrototype._super$Constructor = _emberMetalComputed.ComputedProperty; 27484 27485 InjectedPropertyPrototype.get = ComputedPropertyPrototype.get; 27486 InjectedPropertyPrototype.readOnly = ComputedPropertyPrototype.readOnly; 27487 27488 InjectedPropertyPrototype.teardown = ComputedPropertyPrototype.teardown; 27489 27490 exports.default = InjectedProperty; 27491}); 27492enifed('ember-metal/instrumentation', ['exports', 'ember-metal/core'], function (exports, _emberMetalCore) { 27493 'use strict'; 27494 27495 exports.instrument = instrument; 27496 exports._instrumentStart = _instrumentStart; 27497 exports.subscribe = subscribe; 27498 exports.unsubscribe = unsubscribe; 27499 exports.reset = reset; 27500 27501 /** 27502 The purpose of the Ember Instrumentation module is 27503 to provide efficient, general-purpose instrumentation 27504 for Ember. 27505 27506 Subscribe to a listener by using `Ember.subscribe`: 27507 27508 ```javascript 27509 Ember.subscribe("render", { 27510 before: function(name, timestamp, payload) { 27511 27512 }, 27513 27514 after: function(name, timestamp, payload) { 27515 27516 } 27517 }); 27518 ``` 27519 27520 If you return a value from the `before` callback, that same 27521 value will be passed as a fourth parameter to the `after` 27522 callback. 27523
27524 Instrument a block of code by using `Ember.instrument`: 27525 27526 ```javascript 27527 Ember.instrument("render.handlebars", payload, function() { 27528 // rendering logic 27529 }, binding); 27530 ``` 27531 27532 Event names passed to `Ember.instrument` are namespaced 27533 by periods, from more general to more specific. Subscribers 27534 can listen for events by whatever level of granularity they 27535 are interested in. 27536 27537 In the above example, the event is `render.handlebars`, 27538 and the subscriber listened for all events beginning with 27539 `render`. It would receive callbacks for events named 27540 `render`, `render.handlebars`, `render.container`, or 27541 even `render.handlebars.layout`. 27542 27543 @class Instrumentation 27544 @namespace Ember 27545 @static 27546 @private 27547 */ 27548 var subscribers = []; 27549 exports.subscribers = subscribers; 27550 var cache = {}; 27551 27552 var populateListeners = function (name) { 27553 var listeners = []; 27554 var subscriber; 27555 27556 for (var i = 0, l = subscribers.length; i < l; i++) { 27557 subscriber = subscribers[i]; 27558 if (subscriber.regex.test(name)) { 27559 listeners.push(subscriber.object); 27560 } 27561 } 27562 27563 cache[name] = listeners; 27564 return listeners; 27565 }; 27566 27567 var time = (function () { 27568 var perf = 'undefined' !== typeof window ? window.performance || {} : {}; 27569 var fn = perf.now || perf.mozNow || perf.webkitNow || perf.msNow || perf.oNow; 27570 // fn.bind will be available in all the browsers that support the advanced window.performance... ;-) 27571 return fn ? fn.bind(perf) : function () { 27572 return +new Date(); 27573 }; 27574 })(); 27575 27576 /** 27577 Notifies event's subscribers, calls `before` and `after` hooks. 27578 27579 @method instrument 27580 @namespace Ember.Instrumentation 27581 27582 @param {String} [name] Namespaced event name. 27583 @param {Object} _payload 27584 @param {Function} callback Function that you're instrumenting. 27585 @param {Object} binding Context that instrument function is called with. 27586 @private 27587 */ 27588 27589 function instrument(name, _payload, callback, binding) { 27590 if (arguments.length <= 3 && typeof _payload === 'function') { 27591 binding = callback; 27592 callback = _payload; 27593 _payload = undefined; 27594 } 27595 if (subscribers.length === 0) { 27596 return callback.call(binding); 27597 } 27598 var payload = _payload || {}; 27599 var finalizer = _instrumentStart(name, function () { 27600 return payload; 27601 }); 27602 27603 if (finalizer) { 27604 return withFinalizer(callback, finalizer, payload, binding); 27605 } else { 27606 return callback.call(binding); 27607 } 27608 } 27609 27610 function withFinalizer(callback, finalizer, payload, binding) { 27611 try { 27612 return callback.call(binding); 27613 } catch (e) { 27614 payload.exception = e; 27615 return payload; 27616 } finally { 27617 return finalizer(); 27618 } 27619 } 27620 27621 // private for now 27622 27623 function _instrumentStart(name, _payload) { 27624 var listeners = cache[name]; 27625 27626 if (!listeners) { 27627 listeners = populateListeners(name); 27628 } 27629 27630 if (listeners.length === 0) { 27631 return; 27632 } 27633 27634 var payload = _payload(); 27635 27636 var STRUCTURED_PROFILE = _emberMetalCore.default.STRUCTURED_PROFILE; 27637 var timeName; 27638 if (STRUCTURED_PROFILE) { 27639 timeName = name + ': ' + payload.object; 27640 console.time(timeName); 27641 } 27642 27643 var l = listeners.length; 27644 var beforeValues = new Array(l); 27645 var i, listener; 27646 var timestamp = time(); 27647 for (i = 0; i < l; i++) { 27648 listener = listeners[i]; 27649 beforeValues[i] = listener.before(name, timestamp, payload); 27650 } 27651 27652 return function _instrumentEnd() { 27653 var i, l, listener; 27654 var timestamp = time(); 27655 for (i = 0, l = listeners.length; i < l; i++) { 27656 listener = listeners[i]; 27657 listener.after(name, timestamp, payload, beforeValues[i]); 27658 } 27659 27660 if (STRUCTURED_PROFILE) { 27661 console.timeEnd(timeName); 27662 } 27663 }; 27664 } 27665 27666 /** 27667 Subscribes to a particular event or instrumented block of code. 27668 27669 @method subscribe 27670 @namespace Ember.Instrumentation 27671 27672 @param {String} [pattern] Namespaced event name. 27673 @param {Object} [object] Before and After hooks. 27674 27675 @return {Subscriber} 27676 @private 27677 */ 27678 27679 function subscribe(pattern, object) { 27680 var paths = pattern.split('.'); 27681 var path; 27682 var regex = []; 27683 27684 for (var i = 0, l = paths.length; i < l; i++) { 27685 path = paths[i]; 27686 if (path === '*') { 27687 regex.push('[^\\.]*'); 27688 } else { 27689 regex.push(path); 27690 } 27691 } 27692 27693 regex = regex.join('\\.'); 27694 regex = regex + '(\\..*)?'; 27695 27696 var subscriber = { 27697 pattern: pattern, 27698 regex: new RegExp('^' + regex + '$'), 27699 object: object 27700 }; 27701 27702 subscribers.push(subscriber); 27703 cache = {}; 27704 27705 return subscriber; 27706 } 27707 27708 /** 27709 Unsubscribes from a particular event or instrumented block of code. 27710 27711 @method unsubscribe 27712 @namespace Ember.Instrumentation 27713 27714 @param {Object} [subscriber] 27715 @private 27716 */ 27717 27718 function unsubscribe(subscriber) { 27719 var index; 27720 27721 for (var i = 0, l = subscribers.length; i < l; i++) { 27722 if (subscribers[i] === subscriber) { 27723 index = i; 27724 } 27725 } 27726 27727 subscribers.splice(index, 1); 27728 cache = {}; 27729 } 27730 27731 /** 27732 Resets `Ember.Instrumentation` by flushing list of subscribers. 27733 27734 @method reset 27735 @namespace Ember.Instrumentation 27736 @private 27737 */ 27738 27739 function reset() { 27740 subscribers.length = 0; 27741 cache = {}; 27742 } 27743}); 27744enifed('ember-metal/is_blank', ['exports', 'ember-metal/is_empty'], function (exports, _emberMetalIs_empty) { 27745 'use strict'; 27746 27747 exports.default = isBlank; 27748 27749 /** 27750 A value is blank if it is empty or a whitespace string. 27751 27752 ```javascript 27753 Ember.isBlank(); // true 27754 Ember.isBlank(null); // true 27755 Ember.isBlank(undefined); // true 27756 Ember.isBlank(''); // true 27757 Ember.isBlank([]); // true 27758 Ember.isBlank('\n\t'); // true 27759 Ember.isBlank(' '); // true 27760 Ember.isBlank({}); // false 27761 Ember.isBlank('\n\t Hello'); // false 27762 Ember.isBlank('Hello world'); // false 27763 Ember.isBlank([1,2,3]); // false 27764 ``` 27765 27766 @method isBlank 27767 @for Ember 27768 @param {Object} obj Value to test 27769 @return {Boolean} 27770 @since 1.5.0 27771 @public 27772 */ 27773 27774 function isBlank(obj) { 27775 return _emberMetalIs_empty.default(obj) || typeof obj === 'string' && obj.match(/\S/) === null; 27776 } 27777}); 27778enifed('ember-metal/is_empty', ['exports', 'ember-metal/property_get', 'ember-metal/is_none'], function (exports, _emberMetalProperty_get, _emberMetalIs_none) { 27779 'use strict'; 27780 27781 /** 27782 Verifies that a value is `null` or an empty string, empty array, 27783 or empty function. 27784 27785 Constrains the rules on `Ember.isNone` by returning true for empty 27786 string and empty arrays. 27787 27788 ```javascript 27789 Ember.isEmpty(); // true 27790 Ember.isEmpty(null); // true 27791 Ember.isEmpty(undefined); // true 27792 Ember.isEmpty(''); // true 27793 Ember.isEmpty([]); // true 27794 Ember.isEmpty({}); // false 27795 Ember.isEmpty('Adam Hawkins'); // false 27796 Ember.isEmpty([0,1,2]); // false 27797 Ember.isEmpty('\n\t'); // false 27798 Ember.isEmpty(' '); // false 27799 ``` 27800 27801 @method isEmpty 27802 @for Ember 27803 @param {Object} obj Value to test 27804 @return {Boolean} 27805 @public 27806 */ 27807 function isEmpty(obj) { 27808 var none = _emberMetalIs_none.default(obj); 27809 if (none) { 27810 return none; 27811 } 27812 27813 if (typeof obj.size === 'number') { 27814 return !obj.size; 27815 } 27816 27817 var objectType = typeof obj; 27818 27819 if (objectType === 'object') { 27820 var size = _emberMetalProperty_get.get(obj, 'size'); 27821 if (typeof size === 'number') { 27822 return !size; 27823 } 27824 } 27825 27826 if (typeof obj.length === 'number' && objectType !== 'function') { 27827 return !obj.length; 27828 } 27829 27830 if (objectType === 'object') { 27831 var length = _emberMetalProperty_get.get(obj, 'length'); 27832 if (typeof length === 'number') { 27833 return !length; 27834 } 27835 } 27836 27837 return false;
27838 } 27839 27840 exports.default = isEmpty; 27841}); 27842enifed("ember-metal/is_none", ["exports"], function (exports) { 27843 /** 27844 Returns true if the passed value is null or undefined. This avoids errors 27845 from JSLint complaining about use of ==, which can be technically 27846 confusing. 27847 27848 ```javascript 27849 Ember.isNone(); // true 27850 Ember.isNone(null); // true 27851 Ember.isNone(undefined); // true 27852 Ember.isNone(''); // false 27853 Ember.isNone([]); // false 27854 Ember.isNone(function() {}); // false 27855 ``` 27856 27857 @method isNone 27858 @for Ember 27859 @param {Object} obj Value to test 27860 @return {Boolean} 27861 @public 27862 */ 27863 "use strict"; 27864 27865 exports.default = isNone; 27866 27867 function isNone(obj) { 27868 return obj === null || obj === undefined; 27869 } 27870}); 27871enifed('ember-metal/is_present', ['exports', 'ember-metal/is_blank'], function (exports, _emberMetalIs_blank) { 27872 'use strict'; 27873 27874 exports.default = isPresent; 27875 27876 /** 27877 A value is present if it not `isBlank`. 27878 27879 ```javascript 27880 Ember.isPresent(); // false 27881 Ember.isPresent(null); // false 27882 Ember.isPresent(undefined); // false 27883 Ember.isPresent(''); // false 27884 Ember.isPresent(' '); // false 27885 Ember.isPresent('\n\t'); // false 27886 Ember.isPresent([]); // false 27887 Ember.isPresent({ length: 0 }) // false 27888 Ember.isPresent(false); // true 27889 Ember.isPresent(true); // true 27890 Ember.isPresent('string'); // true 27891 Ember.isPresent(0); // true 27892 Ember.isPresent(function() {}) // true 27893 Ember.isPresent({}); // true 27894 Ember.isPresent(false); // true 27895 Ember.isPresent('\n\t Hello'); // true 27896 Ember.isPresent([1,2,3]); // true 27897 ``` 27898 27899 @method isPresent 27900 @for Ember 27901 @param {Object} obj Value to test 27902 @return {Boolean} 27903 @since 1.8.0 27904 @public 27905 */ 27906 27907 function isPresent(obj) { 27908 return !_emberMetalIs_blank.default(obj); 27909 } 27910}); 27911enifed('ember-metal/libraries', ['exports', 'ember-metal/debug', 'ember-metal/features'], function (exports, _emberMetalDebug, _emberMetalFeatures) { 27912 'use strict'; 27913 27914 /** 27915 Helper class that allows you to register your library with Ember. 27916 27917 Singleton created at `Ember.libraries`. 27918 27919 @class Libraries 27920 @constructor 27921 @private 27922 */ 27923 function Libraries() { 27924 this._registry = []; 27925 this._coreLibIndex = 0; 27926 } 27927 27928 Libraries.prototype = { 27929 constructor: Libraries, 27930 27931 _getLibraryByName: function (name) { 27932 var libs = this._registry; 27933 var count = libs.length; 27934 27935 for (var i = 0; i < count; i++) { 27936 if (libs[i].name === name) { 27937 return libs[i]; 27938 } 27939 } 27940 }, 27941 27942 register: function (name, version, isCoreLibrary) { 27943 var index = this._registry.length; 27944 27945 if (!this._getLibraryByName(name)) { 27946 if (isCoreLibrary) { 27947 index = this._coreLibIndex++; 27948 } 27949 this._registry.splice(index, 0, { name: name, version: version }); 27950 } else { 27951 _emberMetalDebug.warn('Library "' + name + '" is already registered with Ember.', false, { id: 'ember-metal.libraries-register' }); 27952 } 27953 }, 27954 27955 registerCoreLibrary: function (name, version) { 27956 this.register(name, version, true); 27957 }, 27958 27959 deRegister: function (name) { 27960 var lib = this._getLibraryByName(name); 27961 var index; 27962 27963 if (lib) { 27964 index = this._registry.indexOf(lib); 27965 this._registry.splice(index, 1); 27966 } 27967 } 27968 }; 27969 27970 exports.default = Libraries; 27971}); 27972enifed('ember-metal/logger', ['exports', 'ember-metal/core', 'ember-metal/error'], function (exports, _emberMetalCore, _emberMetalError) { 27973 'use strict'; 27974 27975 function K() { 27976 return this; 27977 } 27978 27979 function consoleMethod(name) { 27980 var consoleObj, logToConsole; 27981 if (_emberMetalCore.default.imports.console) { 27982 consoleObj = _emberMetalCore.default.imports.console; 27983 } else if (typeof console !== 'undefined') { 27984 consoleObj = console; 27985 } 27986 27987 var method = typeof consoleObj === 'object' ? consoleObj[name] : null; 27988 27989 if (method) { 27990 // Older IE doesn't support bind, but Chrome needs it 27991 if (typeof method.bind === 'function') { 27992 logToConsole = method.bind(consoleObj); 27993 logToConsole.displayName = 'console.' + name; 27994 return logToConsole; 27995 } else if (typeof method.apply === 'function') { 27996 logToConsole = function () { 27997 method.apply(consoleObj, arguments); 27998 }; 27999 logToConsole.displayName = 'console.' + name; 28000 return logToConsole; 28001 } else { 28002 return function () { 28003 var message = Array.prototype.join.call(arguments, ', '); 28004 method(message); 28005 }; 28006 } 28007 } 28008 } 28009 28010 function assertPolyfill(test, message) { 28011 if (!test) {
28012 try { 28013 // attempt to preserve the stack 28014 throw new _emberMetalError.default('assertion failed: ' + message); 28015 } catch (error) { 28016 setTimeout(function () { 28017 throw error; 28018 }, 0); 28019 } 28020 } 28021 } 28022 28023 /** 28024 Inside Ember-Metal, simply uses the methods from `imports.console`. 28025 Override this to provide more robust logging functionality. 28026 28027 @class Logger 28028 @namespace Ember 28029 @public 28030 */ 28031 exports.default = { 28032 /** 28033 Logs the arguments to the console. 28034 You can pass as many arguments as you want and they will be joined together with a space. 28035 ```javascript 28036 var foo = 1; 28037 Ember.Logger.log('log value of foo:', foo); 28038 // "log value of foo: 1" will be printed to the console 28039 ``` 28040 @method log 28041 @for Ember.Logger 28042 @param {*} arguments 28043 @public 28044 */ 28045 log: consoleMethod('log') || K, 28046 28047 /** 28048 Prints the arguments to the console with a warning icon. 28049 You can pass as many arguments as you want and they will be joined together with a space. 28050 ```javascript 28051 Ember.Logger.warn('Something happened!'); 28052 // "Something happened!" will be printed to the console with a warning icon. 28053 ``` 28054 @method warn 28055 @for Ember.Logger 28056 @param {*} arguments 28057 @public 28058 */ 28059 warn: consoleMethod('warn') || K, 28060 28061 /** 28062 Prints the arguments to the console with an error icon, red text and a stack trace. 28063 You can pass as many arguments as you want and they will be joined together with a space. 28064 ```javascript 28065 Ember.Logger.error('Danger! Danger!'); 28066 // "Danger! Danger!" will be printed to the console in red text. 28067 ``` 28068 @method error 28069 @for Ember.Logger 28070 @param {*} arguments 28071 @public 28072 */ 28073 error: consoleMethod('error') || K, 28074 28075 /** 28076 Logs the arguments to the console. 28077 You can pass as many arguments as you want and they will be joined together with a space. 28078 ```javascript 28079 var foo = 1; 28080 Ember.Logger.info('log value of foo:', foo); 28081 // "log value of foo: 1" will be printed to the console 28082 ``` 28083 @method info 28084 @for Ember.Logger 28085 @param {*} arguments 28086 @public 28087 */ 28088 info: consoleMethod('info') || K, 28089 28090 /** 28091 Logs the arguments to the console in blue text. 28092 You can pass as many arguments as you want and they will be joined together with a space. 28093 ```javascript 28094 var foo = 1; 28095 Ember.Logger.debug('log value of foo:', foo); 28096 // "log value of foo: 1" will be printed to the console 28097 ``` 28098 @method debug 28099 @for Ember.Logger 28100 @param {*} arguments 28101 @public 28102 */ 28103 debug: consoleMethod('debug') || consoleMethod('info') || K, 28104 28105 /** 28106 If the value passed into `Ember.Logger.assert` is not truthy it will throw an error with a stack trace. 28107 ```javascript 28108 Ember.Logger.assert(true); // undefined 28109 Ember.Logger.assert(true === false); // Throws an Assertion failed error. 28110 ``` 28111 @method assert 28112 @for Ember.Logger 28113 @param {Boolean} bool Value to test 28114 @public 28115 */ 28116 assert: consoleMethod('assert') || assertPolyfill 28117 }; 28118}); 28119// Ember.imports 28120enifed('ember-metal/map', ['exports', 'ember-metal/core', 'ember-metal/utils', 'ember-metal/empty_object'], function (exports, _emberMetalCore, _emberMetalUtils, _emberMetalEmpty_object) { 28121 /** 28122 @module ember 28123 @submodule ember-metal 28124 */ 28125 28126 /* 28127 JavaScript (before ES6) does not have a Map implementation. Objects, 28128 which are often used as dictionaries, may only have Strings as keys. 28129 28130 Because Ember has a way to get a unique identifier for every object 28131 via `Ember.guidFor`, we can implement a performant Map with arbitrary 28132 keys. Because it is commonly used in low-level bookkeeping, Map is 28133 implemented as a pure JavaScript object for performance. 28134 28135 This implementation follows the current iteration of the ES6 proposal for 28136 maps (http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets), 28137 with one exception: as we do not have the luxury of in-VM iteration, we implement a
28138 forEach method for iteration. 28139 28140 Map is mocked out to look like an Ember object, so you can do 28141 `Ember.Map.create()` for symmetry with other Ember classes. 28142 */ 28143 28144 'use strict'; 28145 28146 function missingFunction(fn) { 28147 throw new TypeError(Object.prototype.toString.call(fn) + ' is not a function'); 28148 } 28149 28150 function missingNew(name) { 28151 throw new TypeError('Constructor ' + name + ' requires \'new\''); 28152 } 28153 28154 function copyNull(obj) { 28155 var output = new _emberMetalEmpty_object.default(); 28156 28157 for (var prop in obj) { 28158 // hasOwnPropery is not needed because obj is new EmptyObject(); 28159 output[prop] = obj[prop]; 28160 } 28161 28162 return output; 28163 } 28164 28165 function copyMap(original, newObject) { 28166 var keys = original._keys.copy(); 28167 var values = copyNull(original._values); 28168 28169 newObject._keys = keys; 28170 newObject._values = values; 28171 newObject.size = original.size; 28172 28173 return newObject; 28174 } 28175 28176 /** 28177 This class is used internally by Ember and Ember Data. 28178 Please do not use it at this time. We plan to clean it up 28179 and add many tests soon. 28180 28181 @class OrderedSet 28182 @namespace Ember 28183 @constructor 28184 @private 28185 */ 28186 function OrderedSet() { 28187 if (this instanceof OrderedSet) { 28188 this.clear(); 28189 this._silenceRemoveDeprecation = false; 28190 } else { 28191 missingNew('OrderedSet'); 28192 } 28193 } 28194 28195 /** 28196 @method create 28197 @static 28198 @return {Ember.OrderedSet} 28199 @private 28200 */ 28201 OrderedSet.create = function () { 28202 var Constructor = this; 28203 28204 return new Constructor(); 28205 }; 28206 28207 OrderedSet.prototype = { 28208 constructor: OrderedSet, 28209 /** 28210 @method clear 28211 @private 28212 */ 28213 clear: function () { 28214 this.presenceSet = new _emberMetalEmpty_object.default(); 28215 this.list = []; 28216 this.size = 0; 28217 }, 28218 28219 /** 28220 @method add 28221 @param obj 28222 @param guid (optional, and for internal use) 28223 @return {Ember.OrderedSet} 28224 @private 28225 */ 28226 add: function (obj, _guid) { 28227 var guid = _guid || _emberMetalUtils.guidFor(obj); 28228 var presenceSet = this.presenceSet; 28229 var list = this.list; 28230 28231 if (presenceSet[guid] !== true) { 28232 presenceSet[guid] = true; 28233 this.size = list.push(obj); 28234 } 28235 28236 return this; 28237 }, 28238 28239 /** 28240 @since 1.8.0 28241 @method delete 28242 @param obj 28243 @param _guid (optional and for internal use only) 28244 @return {Boolean} 28245 @private 28246 */ 28247 delete: function (obj, _guid) { 28248 var guid = _guid || _emberMetalUtils.guidFor(obj); 28249 var presenceSet = this.presenceSet; 28250 var list = this.list; 28251 28252 if (presenceSet[guid] === true) { 28253 delete presenceSet[guid]; 28254 var index = list.indexOf(obj); 28255 if (index > -1) { 28256 list.splice(index, 1); 28257 } 28258 this.size = list.length; 28259 return true; 28260 } else { 28261 return false; 28262 } 28263 }, 28264 28265 /** 28266 @method isEmpty 28267 @return {Boolean} 28268 @private 28269 */ 28270 isEmpty: function () { 28271 return this.size === 0; 28272 }, 28273 28274 /** 28275 @method has 28276 @param obj 28277 @return {Boolean} 28278 @private 28279 */ 28280 has: function (obj) { 28281 if (this.size === 0) { 28282 return false; 28283 } 28284 28285 var guid = _emberMetalUtils.guidFor(obj); 28286 var presenceSet = this.presenceSet; 28287 28288 return presenceSet[guid] === true; 28289 }, 28290 28291 /** 28292 @method forEach 28293 @param {Function} fn 28294 @param self 28295 @private 28296 */ 28297 forEach: function (fn /*, ...thisArg*/) { 28298 if (typeof fn !== 'function') { 28299 missingFunction(fn); 28300 } 28301 28302 if (this.size === 0) { 28303 return; 28304 } 28305 28306 var list = this.list; 28307 var length = arguments.length; 28308 var i; 28309 28310 if (length === 2) { 28311 for (i = 0; i < list.length; i++) { 28312 fn.call(arguments[1], list[i]); 28313 } 28314 } else { 28315 for (i = 0; i < list.length; i++) { 28316 fn(list[i]); 28317 } 28318 } 28319 }, 28320 28321 /** 28322 @method toArray 28323 @return {Array} 28324 @private 28325 */ 28326 toArray: function () { 28327 return this.list.slice(); 28328 }, 28329 28330 /** 28331 @method copy 28332 @return {Ember.OrderedSet} 28333 @private 28334 */ 28335 copy: function () { 28336 var Constructor = this.constructor; 28337 var set = new Constructor(); 28338 28339 set._silenceRemoveDeprecation = this._silenceRemoveDeprecation; 28340 set.presenceSet = copyNull(this.presenceSet); 28341 set.list = this.toArray(); 28342 set.size = this.size; 28343 28344 return set; 28345 } 28346 }; 28347 28348 /** 28349 A Map stores values indexed by keys. Unlike JavaScript's 28350 default Objects, the keys of a Map can be any JavaScript 28351 object. 28352 28353 Internally, a Map has two data structures: 28354 28355 1. `keys`: an OrderedSet of all of the existing keys 28356 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)` 28357 28358 When a key/value pair is added for the first time, we 28359 add the key to the `keys` OrderedSet, and create or 28360 replace an entry in `values`. When an entry is deleted, 28361 we delete its entry in `keys` and `values`. 28362 28363 @class Map 28364 @namespace Ember 28365 @private 28366 @constructor 28367 */ 28368 function Map() { 28369 if (this instanceof this.constructor) { 28370 this._keys = OrderedSet.create(); 28371 this._keys._silenceRemoveDeprecation = true; 28372 this._values = new _emberMetalEmpty_object.default(); 28373 this.size = 0; 28374 } else { 28375 missingNew('OrderedSet'); 28376 } 28377 } 28378 28379 _emberMetalCore.default.Map = Map; 28380 28381 /** 28382 @method create 28383 @static 28384 @private 28385 */ 28386 Map.create = function () { 28387 var Constructor = this; 28388 return new Constructor(); 28389 }; 28390 28391 Map.prototype = { 28392 constructor: Map, 28393 28394 /** 28395 This property will change as the number of objects in the map changes. 28396 @since 1.8.0 28397 @property size 28398 @type number 28399 @default 0 28400 @private 28401 */ 28402 size: 0, 28403 28404 /** 28405 Retrieve the value associated with a given key. 28406 @method get 28407 @param {*} key 28408 @return {*} the value associated with the key, or `undefined` 28409 @private 28410 */ 28411 get: function (key) { 28412 if (this.size === 0) { 28413 return; 28414 } 28415 28416 var values = this._values; 28417 var guid = _emberMetalUtils.guidFor(key); 28418 28419 return values[guid]; 28420 }, 28421 28422 /** 28423 Adds a value to the map. If a value for the given key has already been 28424 provided, the new value will replace the old value. 28425 @method set 28426 @param {*} key 28427 @param {*} value 28428 @return {Ember.Map} 28429 @private 28430 */ 28431 set: function (key, value) { 28432 var keys = this._keys; 28433 var values = this._values; 28434 var guid = _emberMetalUtils.guidFor(key); 28435 28436 // ensure we don't store -0 28437 var k = key === -0 ? 0 : key; 28438 28439 keys.add(k, guid); 28440 28441 values[guid] = value; 28442
28443 this.size = keys.size; 28444 28445 return this; 28446 }, 28447 28448 /** 28449 Removes a value from the map for an associated key. 28450 @since 1.8.0 28451 @method delete 28452 @param {*} key 28453 @return {Boolean} true if an item was removed, false otherwise 28454 @private 28455 */ 28456 delete: function (key) { 28457 if (this.size === 0) { 28458 return false; 28459 } 28460 // don't use ES6 "delete" because it will be annoying 28461 // to use in browsers that are not ES6 friendly; 28462 var keys = this._keys; 28463 var values = this._values; 28464 var guid = _emberMetalUtils.guidFor(key); 28465 28466 if (keys.delete(key, guid)) { 28467 delete values[guid]; 28468 this.size = keys.size; 28469 return true; 28470 } else { 28471 return false; 28472 } 28473 }, 28474 28475 /** 28476 Check whether a key is present. 28477 @method has 28478 @param {*} key 28479 @return {Boolean} true if the item was present, false otherwise 28480 @private 28481 */ 28482 has: function (key) { 28483 return this._keys.has(key); 28484 }, 28485 28486 /** 28487 Iterate over all the keys and values. Calls the function once 28488 for each key, passing in value, key, and the map being iterated over, 28489 in that order. 28490 The keys are guaranteed to be iterated over in insertion order. 28491 @method forEach 28492 @param {Function} callback 28493 @param {*} self if passed, the `this` value inside the 28494 callback. By default, `this` is the map. 28495 @private 28496 */ 28497 forEach: function (callback /*, ...thisArg*/) { 28498 if (typeof callback !== 'function') { 28499 missingFunction(callback); 28500 } 28501 28502 if (this.size === 0) { 28503 return; 28504 } 28505 28506 var length = arguments.length; 28507 var map = this; 28508 var cb, thisArg; 28509 28510 if (length === 2) { 28511 thisArg = arguments[1]; 28512 cb = function (key) { 28513 callback.call(thisArg, map.get(key), key, map); 28514 }; 28515 } else { 28516 cb = function (key) { 28517 callback(map.get(key), key, map); 28518 }; 28519 } 28520 28521 this._keys.forEach(cb); 28522 }, 28523 28524 /** 28525 @method clear 28526 @private 28527 */ 28528 clear: function () { 28529 this._keys.clear(); 28530 this._values = new _emberMetalEmpty_object.default(); 28531 this.size = 0; 28532 }, 28533 28534 /** 28535 @method copy 28536 @return {Ember.Map} 28537 @private 28538 */ 28539 copy: function () { 28540 return copyMap(this, new Map()); 28541 } 28542 }; 28543 28544 /** 28545 @class MapWithDefault 28546 @namespace Ember 28547 @extends Ember.Map 28548 @private 28549 @constructor 28550 @param [options] 28551 @param {*} [options.defaultValue] 28552 */ 28553 function MapWithDefault(options) { 28554 this._super$constructor(); 28555 this.defaultValue = options.defaultValue; 28556 } 28557 28558 /** 28559 @method create 28560 @static 28561 @param [options] 28562 @param {*} [options.defaultValue] 28563 @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns 28564 `Ember.MapWithDefault` otherwise returns `Ember.Map` 28565 @private 28566 */ 28567 MapWithDefault.create = function (options) { 28568 if (options) { 28569 return new MapWithDefault(options); 28570 } else { 28571 return new Map(); 28572 } 28573 }; 28574 28575 MapWithDefault.prototype = Object.create(Map.prototype); 28576 MapWithDefault.prototype.constructor = MapWithDefault; 28577 MapWithDefault.prototype._super$constructor = Map; 28578 MapWithDefault.prototype._super$get = Map.prototype.get; 28579 28580 /** 28581 Retrieve the value associated with a given key. 28582 28583 @method get 28584 @param {*} key 28585 @return {*} the value associated with the key, or the default value 28586 @private 28587 */ 28588 MapWithDefault.prototype.get = function (key) { 28589 var hasValue = this.has(key); 28590 28591 if (hasValue) { 28592 return this._super$get(key); 28593 } else { 28594 var defaultValue = this.defaultValue(key); 28595 this.set(key, defaultValue); 28596 return defaultValue; 28597 } 28598 }; 28599 28600 /** 28601 @method copy 28602 @return {Ember.MapWithDefault} 28603 @private 28604 */ 28605 MapWithDefault.prototype.copy = function () { 28606 var Constructor = this.constructor; 28607 return copyMap(this, new Constructor({ 28608 defaultValue: this.defaultValue 28609 })); 28610 }; 28611 28612 exports.default = Map; 28613 exports.OrderedSet = OrderedSet; 28614 exports.Map = Map; 28615 exports.MapWithDefault = MapWithDefault; 28616}); 28617enifed('ember-metal/merge', ['exports'], function (exports) { 28618 /** 28619 Merge the contents of two objects together into the first object. 28620 28621 ```javascript 28622 Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'} 28623 var a = {first: 'Yehuda'}; 28624 var b = {last: 'Katz'}; 28625 Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'} 28626 ``` 28627 28628 @method merge 28629 @for Ember 28630 @param {Object} original The object to merge into 28631 @param {Object} updates The object to copy properties from 28632 @return {Object} 28633 @public 28634 */ 28635 'use strict'; 28636 28637 exports.default = merge; 28638 28639 function merge(original, updates) { 28640 if (!updates || typeof updates !== 'object') { 28641 return original; 28642 } 28643 28644 var props = Object.keys(updates); 28645 var prop; 28646 var length = props.length; 28647 28648 for (var i = 0; i < length; i++) { 28649 prop = props[i]; 28650 original[prop] = updates[prop]; 28651 } 28652 28653 return original; 28654 } 28655}); 28656enifed('ember-metal/meta', ['exports', 'ember-metal/meta_listeners', 'ember-metal/empty_object'], function (exports, _emberMetalMeta_listeners, _emberMetalEmpty_object) { 28657 'no use strict'; 28658 // Remove "use strict"; from transpiled module until 28659 // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed 28660 28661 exports.meta = meta; 28662 exports.peekMeta = peekMeta; 28663 exports.deleteMeta = deleteMeta; 28664 28665 /** 28666 @module ember-metal 28667 */ 28668 28669 /* 28670 This declares several meta-programmed members on the Meta class. Such 28671 meta! 28672 28673 In general, the `readable` variants will give you an object (if it 28674 already exists) that you can read but should not modify. The 28675 `writable` variants will give you a mutable object, and they will 28676 create it if it didn't already exist. 28677 28678 The following methods will get generated metaprogrammatically, and 28679 I'm including them here for greppability: 28680 28681 writableCache, readableCache, writeWatching, 28682 peekWatching, clearWatching, writeMixins, 28683 peekMixins, clearMixins, writeBindings, 28684 peekBindings, clearBindings, writeValues,
28685 peekValues, clearValues, writeDeps, forEachInDeps 28686 writableChainWatchers, readableChainWatchers, writableChains, 28687 readableChains 28688 28689 */ 28690 var members = { 28691 cache: ownMap, 28692 weak: ownMap, 28693 watching: inheritedMap, 28694 mixins: inheritedMap, 28695 bindings: inheritedMap, 28696 values: inheritedMap, 28697 deps: inheritedMapOfMaps, 28698 chainWatchers: ownCustomObject, 28699 chains: inheritedCustomObject 28700 }; 28701 28702 var memberNames = Object.keys(members); 28703 var META_FIELD = '__ember_meta__'; 28704 28705 function Meta(obj, parentMeta) { 28706 this._cache = undefined; 28707 this._weak = undefined; 28708 this._watching = undefined; 28709 this._mixins = undefined; 28710 this._bindings = undefined; 28711 this._values = undefined; 28712 this._deps = undefined; 28713 this._chainWatchers = undefined; 28714 this._chains = undefined; 28715 // used only internally 28716 this.source = obj; 28717 28718 // when meta(obj).proto === obj, the object is intended to be only a 28719 // prototype and doesn't need to actually be observable itself 28720 this.proto = undefined; 28721 28722 // The next meta in our inheritance chain. We (will) track this 28723 // explicitly instead of using prototypical inheritance because we 28724 // have detailed knowledge of how each property should really be 28725 // inherited, and we can optimize it much better than JS runtimes. 28726 this.parent = parentMeta; 28727 28728 this._initializeListeners(); 28729 } 28730 28731 for (var _name in _emberMetalMeta_listeners.protoMethods) { 28732 Meta.prototype[_name] = _emberMetalMeta_listeners.protoMethods[_name]; 28733 } 28734 memberNames.forEach(function (name) { 28735 return members[name](name, Meta); 28736 }); 28737 28738 // Implements a member that is a lazily created, non-inheritable 28739 // POJO. 28740 function ownMap(name, Meta) { 28741 var key = memberProperty(name); 28742 var capitalized = capitalize(name); 28743 Meta.prototype['writable' + capitalized] = function () { 28744 return this._getOrCreateOwnMap(key); 28745 }; 28746 Meta.prototype['readable' + capitalized] = function () { 28747 return this[key]; 28748 }; 28749 } 28750 28751 Meta.prototype._getOrCreateOwnMap = function (key) { 28752 var ret = this[key]; 28753 if (!ret) { 28754 ret = this[key] = new _emberMetalEmpty_object.default(); 28755 } 28756 return ret; 28757 }; 28758 28759 // Implements a member that is a lazily created POJO with inheritable 28760 // values. 28761 function inheritedMap(name, Meta) { 28762 var key = memberProperty(name); 28763 var capitalized = capitalize(name); 28764 28765 Meta.prototype['write' + capitalized] = function (subkey, value) { 28766 var map = this._getOrCreateOwnMap(key); 28767 map[subkey] = value; 28768 }; 28769 28770 Meta.prototype['peek' + capitalized] = function (subkey) { 28771 return this._findInherited(key, subkey); 28772 }; 28773 28774 Meta.prototype['forEach' + capitalized] = function (fn) { 28775 var pointer = this; 28776 var seen = new _emberMetalEmpty_object.default(); 28777 while (pointer !== undefined) { 28778 var map = pointer[key]; 28779 if (map) { 28780 for (var _key in map) { 28781 if (!seen[_key]) { 28782 seen[_key] = true; 28783 fn(_key, map[_key]); 28784 } 28785 } 28786 } 28787 pointer = pointer.parent; 28788 } 28789 }; 28790 28791 Meta.prototype['clear' + capitalized] = function () { 28792 this[key] = undefined; 28793 }; 28794 28795 Meta.prototype['deleteFrom' + capitalized] = function (subkey) { 28796 delete this._getOrCreateOwnMap(key)[subkey]; 28797 }; 28798 28799 Meta.prototype['hasIn' + capitalized] = function (subkey) { 28800 return this._findInherited(key, subkey) !== undefined; 28801 }; 28802 } 28803 28804 Meta.prototype._getInherited = function (key) { 28805 var pointer = this; 28806 while (pointer !== undefined) { 28807 if (pointer[key]) { 28808 return pointer[key]; 28809 } 28810 pointer = pointer.parent; 28811 } 28812 }; 28813 28814 Meta.prototype._findInherited = function (key, subkey) { 28815 var pointer = this; 28816 while (pointer !== undefined) { 28817 var map = pointer[key]; 28818 if (map) { 28819 var value = map[subkey]; 28820 if (value !== undefined) { 28821 return value; 28822 } 28823 } 28824 pointer = pointer.parent; 28825 } 28826 }; 28827 28828 // Implements a member that provides a lazily created map of maps, 28829 // with inheritance at both levels. 28830 function inheritedMapOfMaps(name, Meta) { 28831 var key = memberProperty(name); 28832 var capitalized = capitalize(name); 28833 28834 Meta.prototype['write' + capitalized] = function (subkey, itemkey, value) { 28835 var outerMap = this._getOrCreateOwnMap(key); 28836 var innerMap = outerMap[subkey]; 28837 if (!innerMap) { 28838 innerMap = outerMap[subkey] = new _emberMetalEmpty_object.default(); 28839 } 28840 innerMap[itemkey] = value; 28841 }; 28842 28843 Meta.prototype['peek' + capitalized] = function (subkey, itemkey) { 28844 var pointer = this; 28845 while (pointer !== undefined) { 28846 var map = pointer[key]; 28847 if (map) { 28848 var value = map[subkey]; 28849 if (value) { 28850 if (value[itemkey] !== undefined) { 28851 return value[itemkey]; 28852 } 28853 } 28854 } 28855 pointer = pointer.parent; 28856 } 28857 }; 28858 28859 Meta.prototype['has' + capitalized] = function (subkey) { 28860 var pointer = this; 28861 while (pointer !== undefined) { 28862 if (pointer[key] && pointer[key][subkey]) { 28863 return true; 28864 } 28865 pointer = pointer.parent; 28866 } 28867 return false;
28868 }; 28869 28870 Meta.prototype['forEachIn' + capitalized] = function (subkey, fn) { 28871 return this._forEachIn(key, subkey, fn); 28872 }; 28873 } 28874 28875 Meta.prototype._forEachIn = function (key, subkey, fn) { 28876 var pointer = this; 28877 var seen = new _emberMetalEmpty_object.default(); 28878 var calls = []; 28879 while (pointer !== undefined) { 28880 var map = pointer[key]; 28881 if (map) { 28882 var innerMap = map[subkey]; 28883 if (innerMap) { 28884 for (var innerKey in innerMap) { 28885 if (!seen[innerKey]) { 28886 seen[innerKey] = true; 28887 calls.push([innerKey, innerMap[innerKey]]); 28888 } 28889 } 28890 } 28891 } 28892 pointer = pointer.parent; 28893 } 28894 for (var i = 0; i < calls.length; i++) { 28895 var _calls$i = calls[i]; 28896 var innerKey = _calls$i[0]; 28897 var value = _calls$i[1]; 28898 28899 fn(innerKey, value); 28900 } 28901 }; 28902 28903 // Implements a member that provides a non-heritable, lazily-created 28904 // object using the method you provide. 28905 function ownCustomObject(name, Meta) { 28906 var key = memberProperty(name); 28907 var capitalized = capitalize(name); 28908 Meta.prototype['writable' + capitalized] = function (create) { 28909 var ret = this[key]; 28910 if (!ret) { 28911 ret = this[key] = create(this.source); 28912 } 28913 return ret; 28914 }; 28915 Meta.prototype['readable' + capitalized] = function () { 28916 return this[key]; 28917 }; 28918 } 28919 28920 // Implements a member that provides an inheritable, lazily-created 28921 // object using the method you provide. We will derived children from 28922 // their parents by calling your object's `copy()` method. 28923 function inheritedCustomObject(name, Meta) { 28924 var key = memberProperty(name); 28925 var capitalized = capitalize(name); 28926 Meta.prototype['writable' + capitalized] = function (create) { 28927 var ret = this[key]; 28928 if (!ret) { 28929 if (this.parent) { 28930 ret = this[key] = this.parent['writable' + capitalized](create).copy(this.source); 28931 } else { 28932 ret = this[key] = create(this.source); 28933 } 28934 } 28935 return ret; 28936 }; 28937 Meta.prototype['readable' + capitalized] = function () { 28938 return this._getInherited(key); 28939 }; 28940 } 28941 28942 function memberProperty(name) { 28943 return '_' + name; 28944 } 28945 28946 // there's a more general-purpose capitalize in ember-runtime, but we 28947 // don't want to make ember-metal depend on ember-runtime. 28948 function capitalize(name) { 28949 return name.replace(/^\w/, function (m) { 28950 return m.toUpperCase(); 28951 }); 28952 } 28953 28954 var META_DESC = { 28955 writable: true, 28956 configurable: true, 28957 enumerable: false, 28958 value: null 28959 }; 28960 28961 exports.META_DESC = META_DESC; 28962 var EMBER_META_PROPERTY = { 28963 name: META_FIELD, 28964 descriptor: META_DESC 28965 }; 28966 28967 // choose the one appropriate for given platform 28968 var setMeta = function (obj, meta) { 28969 // if `null` already, just set it to the new value 28970 // otherwise define property first 28971 if (obj[META_FIELD] !== null) { 28972 if (obj.__defineNonEnumerable) { 28973 obj.__defineNonEnumerable(EMBER_META_PROPERTY); 28974 } else { 28975 Object.defineProperty(obj, META_FIELD, META_DESC); 28976 } 28977 } 28978 28979 obj[META_FIELD] = meta; 28980 }; 28981 28982 /** 28983 Retrieves the meta hash for an object. If `writable` is true ensures the 28984 hash is writable for this object as well. 28985 28986 The meta object contains information about computed property descriptors as 28987 well as any watched properties and other information. You generally will 28988 not access this information directly but instead work with higher level 28989 methods that manipulate this hash indirectly. 28990 28991 @method meta 28992 @for Ember 28993 @private 28994 28995 @param {Object} obj The object to retrieve meta for 28996 @param {Boolean} [writable=true] Pass `false` if you do not intend to modify 28997 the meta hash, allowing the method to avoid making an unnecessary copy. 28998 @return {Object} the meta hash for an object 28999 */ 29000 29001 function meta(obj) { 29002 var maybeMeta = peekMeta(obj); 29003 var parent = undefined; 29004 29005 // remove this code, in-favor of explicit parent 29006 if (maybeMeta) { 29007 if (maybeMeta.source === obj) { 29008 return maybeMeta; 29009 } 29010 parent = maybeMeta; 29011 } 29012 29013 var newMeta = new Meta(obj, parent); 29014 setMeta(obj, newMeta); 29015 return newMeta; 29016 } 29017 29018 function peekMeta(obj) { 29019 return obj[META_FIELD]; 29020 } 29021 29022 function deleteMeta(obj) { 29023 if (typeof obj[META_FIELD] !== 'object') { 29024 return; 29025 } 29026 obj[META_FIELD] = null; 29027 } 29028}); 29029enifed('ember-metal/meta_listeners', ['exports'], function (exports) { 29030 /*
29031 When we render a rich template hierarchy, the set of events that 29032 *might* happen tends to be much larger than the set of events that 29033 actually happen. This implies that we should make listener creation & 29034 destruction cheap, even at the cost of making event dispatch more 29035 expensive. 29036 29037 Thus we store a new listener with a single push and no new 29038 allocations, without even bothering to do deduplication -- we can 29039 save that for dispatch time, if an event actually happens. 29040 */ 29041 29042 /* listener flags */ 29043 'use strict'; 29044 29045 var ONCE = 1; 29046 exports.ONCE = ONCE; 29047 var SUSPENDED = 2; 29048 29049 exports.SUSPENDED = SUSPENDED; 29050 var protoMethods = { 29051 29052 addToListeners: function (eventName, target, method, flags) { 29053 if (!this._listeners) { 29054 this._listeners = []; 29055 } 29056 this._listeners.push(eventName, target, method, flags); 29057 }, 29058 29059 _finalizeListeners: function () { 29060 if (this._listenersFinalized) { 29061 return; 29062 } 29063 if (!this._listeners) { 29064 this._listeners = []; 29065 } 29066 var pointer = this.parent; 29067 while (pointer) { 29068 var listeners = pointer._listeners; 29069 if (listeners) { 29070 this._listeners = this._listeners.concat(listeners); 29071 } 29072 if (pointer._listenersFinalized) { 29073 break; 29074 } 29075 pointer = pointer.parent; 29076 } 29077 this._listenersFinalized = true; 29078 }, 29079 29080 removeFromListeners: function (eventName, target, method, didRemove) { 29081 var pointer = this; 29082 while (pointer) { 29083 var listeners = pointer._listeners; 29084 if (listeners) { 29085 for (var index = listeners.length - 4; index >= 0; index -= 4) { 29086 if (listeners[index] === eventName && (!method || listeners[index + 1] === target && listeners[index + 2] === method)) { 29087 if (pointer === this) { 29088 // we are modifying our own list, so we edit directly 29089 if (typeof didRemove === 'function') { 29090 didRemove(eventName, target, listeners[index + 2]); 29091 } 29092 listeners.splice(index, 4); 29093 } else { 29094 // we are trying to remove an inherited listener, so we do 29095 // just-in-time copying to detach our own listeners from 29096 // our inheritance chain. 29097 this._finalizeListeners(); 29098 return this.removeFromListeners(eventName, target, method); 29099 } 29100 } 29101 } 29102 } 29103 if (pointer._listenersFinalized) { 29104 break; 29105 } 29106 pointer = pointer.parent; 29107 } 29108 }, 29109 29110 matchingListeners: function (eventName) { 29111 var pointer = this; 29112 var result = []; 29113 while (pointer) { 29114 var listeners = pointer._listeners; 29115 if (listeners) { 29116 for (var index = 0; index < listeners.length - 3; index += 4) { 29117 if (listeners[index] === eventName) { 29118 pushUniqueListener(result, listeners, index); 29119 } 29120 } 29121 } 29122 if (pointer._listenersFinalized) { 29123 break; 29124 } 29125 pointer = pointer.parent; 29126 } 29127 var sus = this._suspendedListeners; 29128 if (sus) { 29129 for (var susIndex = 0; susIndex < sus.length - 2; susIndex += 3) { 29130 if (eventName === sus[susIndex]) { 29131 for (var resultIndex = 0; resultIndex < result.length - 2; resultIndex += 3) { 29132 if (result[resultIndex] === sus[susIndex + 1] && result[resultIndex + 1] === sus[susIndex + 2]) { 29133 result[resultIndex + 2] |= SUSPENDED; 29134 } 29135 } 29136 } 29137 } 29138 } 29139 return result; 29140 }, 29141 29142 suspendListeners: function (eventNames, target, method, callback) { 29143 var sus = this._suspendedListeners; 29144 if (!sus) { 29145 sus = this._suspendedListeners = []; 29146 } 29147 for (var i = 0; i < eventNames.length; i++) { 29148 sus.push(eventNames[i], target, method); 29149 } 29150 try { 29151 return callback.call(target); 29152 } finally { 29153 if (sus.length === eventNames.length) { 29154 this._suspendedListeners = undefined; 29155 } else { 29156 for (var i = sus.length - 3; i >= 0; i -= 3) { 29157 if (sus[i + 1] === target && sus[i + 2] === method && eventNames.indexOf(sus[i]) !== -1) { 29158 sus.splice(i, 3); 29159 } 29160 } 29161 } 29162 } 29163 }, 29164 29165 watchedEvents: function () { 29166 var pointer = this; 29167 var names = {}; 29168 while (pointer) { 29169 var listeners = pointer._listeners; 29170 if (listeners) { 29171 for (var index = 0; index < listeners.length - 3; index += 4) { 29172 names[listeners[index]] = true; 29173 } 29174 } 29175 if (pointer._listenersFinalized) { 29176 break; 29177 } 29178 pointer = pointer.parent; 29179 } 29180 return Object.keys(names); 29181 }, 29182 29183 _initializeListeners: function () { 29184 this._listeners = undefined; 29185 this._listenersFinalized = undefined; 29186 this._suspendedListeners = undefined; 29187 } 29188 }; 29189 29190 exports.protoMethods = protoMethods; 29191 function pushUniqueListener(destination, source, index) { 29192 var target = source[index + 1]; 29193 var method = source[index + 2]; 29194 for (var destinationIndex = 0; destinationIndex < destination.length - 2; destinationIndex += 3) { 29195 if (destination[destinationIndex] === target && destination[destinationIndex + 1] === method) { 29196 return; 29197 } 29198 } 29199 destination.push(target, method, source[index + 3]); 29200 } 29201}); 29202enifed('ember-metal/mixin', ['exports', 'ember-metal/core', 'ember-metal/error', 'ember-metal/debug', 'ember-metal/assign', 'ember-metal/empty_object', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/expand_properties', 'ember-metal/properties', 'ember-metal/computed', 'ember-metal/binding', 'ember-metal/observer', 'ember-metal/events', 'ember-metal/stream
29202s/utils'], function (exports, _emberMetalCore, _emberMetalError, _emberMetalDebug, _emberMetalAssign, _emberMetalEmpty_object, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalUtils, _emberMetalMeta, _emberMetalExpand_properties, _emberMetalProperties, _emberMetalComputed, _emberMetalBinding, _emberMetalObserver, _emberMetalEvents, _emberMetalStreamsUtils) { 29203 'no use strict'; 29204 // Remove "use strict"; from transpiled module until 29205 // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed 29206 29207 /** 29208 @module ember 29209 @submodule ember-metal 29210 */ 29211 exports.mixin = mixin; 29212 exports.default = Mixin; 29213 exports.required = required; 29214 exports.aliasMethod = aliasMethod; 29215 exports.observer = observer; 29216 exports._immediateObserver = _immediateObserver; 29217 exports._beforeObserver = _beforeObserver; 29218 29219 function ROOT() {} 29220 ROOT.__hasSuper = false; 29221 29222 var REQUIRED; 29223 var a_slice = [].slice; 29224 29225 function isMethod(obj) { 29226 return 'function' === typeof obj && obj.isMethod !== false && obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String; 29227 } 29228 29229 var CONTINUE = {}; 29230 29231 function mixinProperties(mixinsMeta, mixin) { 29232 var guid; 29233 29234 if (mixin instanceof Mixin) { 29235 guid = _emberMetalUtils.guidFor(mixin); 29236 if (mixinsMeta.peekMixins(guid)) { 29237 return CONTINUE; 29238 } 29239 mixinsMeta.writeMixins(guid, mixin); 29240 return mixin.properties; 29241 } else { 29242 return mixin; // apply anonymous mixin properties 29243 } 29244 } 29245 29246 function concatenatedMixinProperties(concatProp, props, values, base) { 29247 var concats; 29248 29249 // reset before adding each new mixin to pickup concats from previous 29250 concats = values[concatProp] || base[concatProp]; 29251 if (props[concatProp]) { 29252 concats = concats ? concats.concat(props[concatProp]) : props[concatProp]; 29253 } 29254 29255 return concats; 29256 } 29257 29258 function giveDescriptorSuper(meta, key, property, values, descs, base) { 29259 var superProperty; 29260 29261 // Computed properties override methods, and do not call super to them 29262 if (values[key] === undefined) { 29263 // Find the original descriptor in a parent mixin 29264 superProperty = descs[key]; 29265 } 29266 29267 // If we didn't find the original descriptor in a parent mixin, find 29268 // it on the original object. 29269 if (!superProperty) { 29270 var possibleDesc = base[key]; 29271 var superDesc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 29272 29273 superProperty = superDesc; 29274 } 29275 29276 if (superProperty === undefined || !(superProperty instanceof _emberMetalComputed.ComputedProperty)) { 29277 return property; 29278 } 29279 29280 // Since multiple mixins may inherit from the same parent, we need 29281 // to clone the computed property so that other mixins do not receive 29282 // the wrapped version. 29283 property = Object.create(property); 29284 property._getter = _emberMetalUtils.wrap(property._getter, superProperty._getter); 29285 if (superProperty._setter) { 29286 if (property._setter) { 29287 property._setter = _emberMetalUtils.wrap(property._setter, superProperty._setter); 29288 } else { 29289 property._setter = superProperty._setter; 29290 } 29291 } 29292 29293 return property; 29294 } 29295 29296 function giveMethodSuper(obj, key, method, values, descs) { 29297 var superMethod; 29298 29299 // Methods overwrite computed properties, and do not call super to them. 29300 if (descs[key] === undefined) { 29301 // Find the original method in a parent mixin 29302 superMethod = values[key]; 29303 } 29304 29305 // If we didn't find the original value in a parent mixin, find it in 29306 // the original object 29307 superMethod = superMethod || obj[key]; 29308 29309 // Only wrap the new method if the original method was a function 29310 if (superMethod === undefined || 'function' !== typeof superMethod) { 29311 return method; 29312 } 29313 29314 return _emberMetalUtils.wrap(method, superMethod); 29315 } 29316 29317 function applyConcatenatedProperties(obj, key, value, values) { 29318 var baseValue = values[key] || obj[key]; 29319 29320 if (baseValue) { 29321 if ('function' === typeof baseValue.concat) { 29322 if (value === null || value === undefined) { 29323 return baseValue; 29324 } else { 29325 return baseValue.concat(value); 29326 } 29327 } else { 29328 return _emberMetalUtils.makeArray(baseValue).concat(value); 29329 } 29330 } else { 29331 return _emberMetalUtils.makeArray(value); 29332 } 29333 } 29334 29335 function applyMergedProperties(obj, key, value, values) { 29336 var baseValue = values[key] || obj[key]; 29337 29338 _emberMetalDebug.runInDebug(function () { 29339 if (Array.isArray(value)) { 29340 // use conditional to avoid stringifying every time 29341 _emberMetalDebug.assert('You passed in `' + JSON.stringify(value) + '` as the value for `' + key + '` but `' + key + '` cannot be an Array', false); 29342 } 29343 }); 29344 29345 if (!baseValue) { 29346 return value; 29347 } 29348 29349 var newBase = _emberMetalAssign.default({}, baseValue); 29350 var hasFunction = false;
29351 29352 for (var prop in value) { 29353 if (!value.hasOwnProperty(prop)) { 29354 continue; 29355 } 29356 29357 var propValue = value[prop]; 29358 if (isMethod(propValue)) { 29359 // TODO: support for Computed Properties, etc? 29360 hasFunction = true; 29361 newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {}); 29362 } else { 29363 newBase[prop] = propValue; 29364 } 29365 } 29366 29367 if (hasFunction) { 29368 newBase._super = ROOT; 29369 } 29370 29371 return newBase; 29372 } 29373 29374 function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) { 29375 if (value instanceof _emberMetalProperties.Descriptor) { 29376 if (value === REQUIRED && descs[key]) { 29377 return CONTINUE; 29378 } 29379 29380 // Wrap descriptor function to implement 29381 // _super() if needed 29382 if (value._getter) { 29383 value = giveDescriptorSuper(meta, key, value, values, descs, base); 29384 } 29385 29386 descs[key] = value; 29387 values[key] = undefined; 29388 } else { 29389 if (concats && concats.indexOf(key) >= 0 || key === 'concatenatedProperties' || key === 'mergedProperties') { 29390 value = applyConcatenatedProperties(base, key, value, values); 29391 } else if (mergings && mergings.indexOf(key) >= 0) { 29392 value = applyMergedProperties(base, key, value, values); 29393 } else if (isMethod(value)) { 29394 value = giveMethodSuper(base, key, value, values, descs); 29395 } 29396 29397 descs[key] = undefined; 29398 values[key] = value; 29399 } 29400 } 29401 29402 function mergeMixins(mixins, m, descs, values, base, keys) { 29403 var currentMixin, props, key, concats, mergings, meta; 29404 29405 function removeKeys(keyName) { 29406 delete descs[keyName]; 29407 delete values[keyName]; 29408 } 29409 29410 for (var i = 0, l = mixins.length; i < l; i++) { 29411 currentMixin = mixins[i]; 29412 _emberMetalDebug.assert('Expected hash or Mixin instance, got ' + Object.prototype.toString.call(currentMixin), typeof currentMixin === 'object' && currentMixin !== null && Object.prototype.toString.call(currentMixin) !== '[object Array]'); 29413 29414 props = mixinProperties(m, currentMixin); 29415 if (props === CONTINUE) { 29416 continue; 29417 } 29418 29419 if (props) { 29420 meta = _emberMetalMeta.meta(base); 29421 if (base.willMergeMixin) { 29422 base.willMergeMixin(props); 29423 } 29424 concats = concatenatedMixinProperties('concatenatedProperties', props, values, base); 29425 mergings = concatenatedMixinProperties('mergedProperties', props, values, base); 29426 29427 for (key in props) { 29428 if (!props.hasOwnProperty(key)) { 29429 continue; 29430 } 29431 keys.push(key); 29432 addNormalizedProperty(base, key, props[key], meta, descs, values, concats, mergings); 29433 } 29434 29435 // manually copy toString() because some JS engines do not enumerate it 29436 if (props.hasOwnProperty('toString')) { 29437 base.toString = props.toString; 29438 } 29439 } else if (currentMixin.mixins) { 29440 mergeMixins(currentMixin.mixins, m, descs, values, base, keys); 29441 if (currentMixin._without) { 29442 currentMixin._without.forEach(removeKeys); 29443 } 29444 } 29445 } 29446 } 29447 29448 var IS_BINDING = /^.+Binding$/; 29449 29450 function detectBinding(obj, key, value, m) { 29451 if (IS_BINDING.test(key)) { 29452 m.writeBindings(key, value); 29453 } 29454 } 29455 29456 function connectStreamBinding(obj, key, stream) { 29457 var onNotify = function (stream) { 29458 _emberMetalObserver._suspendObserver(obj, key, null, didChange, function () { 29459 _emberMetalProperty_set.trySet(obj, key, stream.value()); 29460 }); 29461 }; 29462 29463 var didChange = function () { 29464 stream.setValue(_emberMetalProperty_get.get(obj, key), onNotify); 29465 }; 29466 29467 // Initialize value 29468 _emberMetalProperty_set.set(obj, key, stream.value()); 29469 29470 _emberMetalObserver.addObserver(obj, key, null, didChange); 29471 29472 stream.subscribe(onNotify); 29473 29474 if (obj._streamBindingSubscriptions === undefined) { 29475 obj._streamBindingSubscriptions = new _emberMetalEmpty_object.default(); 29476 } 29477 29478 obj._streamBindingSubscriptions[key] = onNotify; 29479 } 29480 29481 function connectBindings(obj, m) { 29482 // TODO Mixin.apply(instance) should disconnect binding if exists 29483 m.forEachBindings(function (key, binding) { 29484 if (binding) { 29485 var to = key.slice(0, -7); // strip Binding off end 29486 if (_emberMetalStreamsUtils.isStream(binding)) { 29487 connectStreamBinding(obj, to, binding); 29488 return; 29489 } else if (binding instanceof _emberMetalBinding.Binding) { 29490 binding = binding.copy(); // copy prototypes' instance 29491 binding.to(to); 29492 } else { 29493 // binding is string path 29494 binding = new _emberMetalBinding.Binding(to, binding); 29495 } 29496 binding.connect(obj); 29497 obj[key] = binding; 29498 } 29499 }); 29500 // mark as applied 29501 m.clearBindings(); 29502 } 29503 29504 function finishPartial(obj, m) { 29505 connectBindings(obj, m || _emberMetalMeta.meta(obj)); 29506 return obj; 29507 } 29508 29509 function followAlias(obj, desc, m, descs, values) { 29510 var altKey = desc.methodName; 29511 var value; 29512 var possibleDesc; 29513 if (descs[altKey] || values[altKey]) { 29514 value = values[altKey]; 29515 desc = descs[altKey]; 29516 } else if ((possibleDesc = obj[altKey]) && possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) { 29517 desc = possibleDesc; 29518 value = undefined; 29519 } else { 29520 desc = undefined; 29521 value = obj[altKey]; 29522 } 29523 29524 return { desc: desc, value: value }; 29525 } 29526 29527 function updateObserversAndListeners(obj, key, observerOrListener, pathsKey, updateMethod) { 29528 var paths = observerOrListener[pathsKey]; 29529 29530 if (paths) { 29531 for (var i = 0, l = paths.length; i < l; i++) { 29532 updateMethod(obj, paths[i], null, key); 29533 } 29534 } 29535 } 29536 29537 function replaceObserversAndListeners(obj, key, observerOrListener) { 29538 var prev = obj[key]; 29539 29540 if ('function' === typeof prev) { 29541 updateObserversAndListeners(obj, key, prev, '__ember_observesBefore__', _emberMetalObserver._removeBeforeObserver); 29542 updateObserversAndListeners(obj, key, prev, '__ember_observes__', _emberMetalObserver.removeObserver); 29543 updateObserversAndListeners(obj, key, prev, '__ember_listens__', _emberMetalEvents.removeListener); 29544 } 29545 29546 if ('function' === typeof observerOrListener) { 29547 updateObserversAndListeners(obj, key, observerOrListener, '__ember_observesBefore__', _emberMetalObserver._addBeforeObserver); 29548 updateObserversAndListeners(obj, key, observerOrListener, '__ember_observes__', _emberMetalObserver.addObserver); 29549 updateObserversAndListeners(obj, key, observerOrListener, '__ember_listens__', _emberMetalEvents.addListener); 29550 } 29551 } 29552 29553 function applyMixin(obj, mixins, partial) { 29554 var descs = {}; 29555 var values = {}; 29556 var m = _emberMetalMeta.meta(obj); 29557 var keys = []; 29558 var key, value, desc; 29559 29560 obj._super = ROOT; 29561 29562 // Go through all mixins and hashes passed in, and: 29563 // 29564 // * Handle concatenated properties 29565 // * Handle merged properties 29566 // * Set up _super wrapping if necessary 29567 // * Set up computed property descriptors 29568 // * Copying `toString` in broken browsers 29569 mergeMixins(mixins, m, descs, values, obj, keys); 29570
29571 for (var i = 0, l = keys.length; i < l; i++) { 29572 key = keys[i]; 29573 if (key === 'constructor' || !values.hasOwnProperty(key)) { 29574 continue; 29575 } 29576 29577 desc = descs[key]; 29578 value = values[key]; 29579 29580 if (desc === REQUIRED) { 29581 continue; 29582 } 29583 29584 while (desc && desc instanceof Alias) { 29585 var followed = followAlias(obj, desc, m, descs, values); 29586 desc = followed.desc; 29587 value = followed.value; 29588 } 29589 29590 if (desc === undefined && value === undefined) { 29591 continue; 29592 } 29593 29594 replaceObserversAndListeners(obj, key, value); 29595 detectBinding(obj, key, value, m); 29596 _emberMetalProperties.defineProperty(obj, key, desc, value, m); 29597 } 29598 29599 if (!partial) { 29600 // don't apply to prototype 29601 finishPartial(obj, m); 29602 } 29603 29604 return obj; 29605 } 29606 29607 /** 29608 @method mixin 29609 @for Ember 29610 @param obj 29611 @param mixins* 29612 @return obj 29613 @private 29614 */ 29615 29616 function mixin(obj) { 29617 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 29618 args[_key - 1] = arguments[_key]; 29619 } 29620 29621 applyMixin(obj, args, false); 29622 return obj; 29623 } 29624 29625 /** 29626 The `Ember.Mixin` class allows you to create mixins, whose properties can be 29627 added to other classes. For instance, 29628 29629 ```javascript 29630 App.Editable = Ember.Mixin.create({ 29631 edit: function() { 29632 console.log('starting to edit'); 29633 this.set('isEditing', true); 29634 }, 29635 isEditing: false 29636 }); 29637 29638 // Mix mixins into classes by passing them as the first arguments to 29639 // .extend. 29640 App.CommentView = Ember.View.extend(App.Editable, { 29641 template: Ember.Handlebars.compile('{{#if view.isEditing}}...{{else}}...{{/if}}') 29642 }); 29643 29644 commentView = App.CommentView.create(); 29645 commentView.edit(); // outputs 'starting to edit' 29646 ``` 29647 29648 Note that Mixins are created with `Ember.Mixin.create`, not 29649 `Ember.Mixin.extend`. 29650 29651 Note that mixins extend a constructor's prototype so arrays and object literals 29652 defined as properties will be shared amongst objects that implement the mixin. 29653 If you want to define a property in a mixin that is not shared, you can define 29654 it either as a computed property or have it be created on initialization of the object. 29655 29656 ```javascript 29657 //filters array will be shared amongst any object implementing mixin 29658 App.Filterable = Ember.Mixin.create({ 29659 filters: Ember.A() 29660 }); 29661 29662 //filters will be a separate array for every object implementing the mixin 29663 App.Filterable = Ember.Mixin.create({ 29664 filters: Ember.computed(function() {return Ember.A();}) 29665 }); 29666 29667 //filters will be created as a separate array during the object's initialization 29668 App.Filterable = Ember.Mixin.create({ 29669 init: function() { 29670 this._super(...arguments); 29671 this.set("filters", Ember.A()); 29672 } 29673 }); 29674 ``` 29675 29676 @class Mixin 29677 @namespace Ember 29678 @public 29679 */ 29680 29681 function Mixin(args, properties) { 29682 this.properties = properties; 29683 29684 var length = args && args.length; 29685 29686 if (length > 0) { 29687 var m = new Array(length); 29688 29689 for (var i = 0; i < length; i++) { 29690 var x = args[i]; 29691 if (x instanceof Mixin) { 29692 m[i] = x; 29693 } else { 29694 m[i] = new Mixin(undefined, x); 29695 } 29696 } 29697 29698 this.mixins = m; 29699 } else { 29700 this.mixins = undefined; 29701 } 29702 this.ownerConstructor = undefined; 29703 this._without = undefined; 29704 this[_emberMetalUtils.GUID_KEY] = null; 29705 this[_emberMetalUtils.GUID_KEY + '_name'] = null; 29706 _emberMetalDebug.debugSeal(this); 29707 } 29708 29709 Mixin._apply = applyMixin; 29710 29711 Mixin.applyPartial = function (obj) { 29712 var args = a_slice.call(arguments, 1); 29713 return applyMixin(obj, args, true); 29714 }; 29715 29716 Mixin.finishPartial = finishPartial; 29717 29718 // ES6TODO: this relies on a global state? 29719 _emberMetalCore.default.anyUnprocessedMixins = false; 29720 29721 /** 29722 @method create 29723 @static 29724 @param arguments* 29725 @public 29726 */ 29727 Mixin.create = function () { 29728 // ES6TODO: this relies on a global state? 29729 _emberMetalCore.default.anyUnprocessedMixins = true; 29730 var M = this; 29731 29732 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 29733 args[_key2] = arguments[_key2]; 29734 } 29735 29736 return new M(args, undefined); 29737 }; 29738 29739 var MixinPrototype = Mixin.prototype; 29740 29741 /** 29742 @method reopen 29743 @param arguments* 29744 @private 29745 */ 29746 MixinPrototype.reopen = function () { 29747 var currentMixin; 29748 29749 if (this.properties) { 29750 currentMixin = new Mixin(undefined, this.properties); 29751 this.properties = undefined; 29752 this.mixins = [currentMixin]; 29753 } else if (!this.mixins) { 29754 this.mixins = []; 29755 } 29756 29757 var len = arguments.length; 29758 var mixins = this.mixins; 29759 var idx; 29760 29761 for (idx = 0; idx < len; idx++) { 29762 currentMixin = arguments[idx]; 29763 _emberMetalDebug.assert('Expected hash or Mixin instance, got ' + Object.prototype.toString.call(currentMixin), typeof currentMixin === 'object' && currentMixin !== null && Object.prototype.toString.call(currentMixin) !== '[object Array]'); 29764 29765 if (currentMixin instanceof Mixin) { 29766 mixins.push(currentMixin); 29767 } else { 29768 mixins.push(new Mixin(undefined, currentMixin)); 29769 } 29770 } 29771 29772 return this; 29773 }; 29774 29775 /** 29776 @method apply 29777 @param obj 29778 @return applied object 29779 @private 29780 */ 29781 MixinPrototype.apply = function (obj) { 29782 return applyMixin(obj, [this], false); 29783 }; 29784 29785 MixinPrototype.applyPartial = function (obj) { 29786 return applyMixin(obj, [this], true); 29787 }; 29788 29789 MixinPrototype.toString = function Mixin_toString() { 29790 return '(unknown mixin)'; 29791 }; 29792 29793 function _detect(curMixin, targetMixin, seen) { 29794 var guid = _emberMetalUtils.guidFor(curMixin); 29795 29796 if (seen[guid]) { 29797 return false;
29798 } 29799 seen[guid] = true; 29800 29801 if (curMixin === targetMixin) { 29802 return true; 29803 } 29804 var mixins = curMixin.mixins; 29805 var loc = mixins ? mixins.length : 0; 29806 while (--loc >= 0) { 29807 if (_detect(mixins[loc], targetMixin, seen)) { 29808 return true; 29809 } 29810 } 29811 return false; 29812 } 29813 29814 /** 29815 @method detect 29816 @param obj 29817 @return {Boolean} 29818 @private 29819 */ 29820 MixinPrototype.detect = function (obj) { 29821 if (!obj) { 29822 return false; 29823 } 29824 if (obj instanceof Mixin) { 29825 return _detect(obj, this, {}); 29826 } 29827 var m = _emberMetalMeta.peekMeta(obj); 29828 if (!m) { 29829 return false; 29830 } 29831 return !!m.peekMixins(_emberMetalUtils.guidFor(this)); 29832 }; 29833 29834 MixinPrototype.without = function () { 29835 var ret = new Mixin([this]); 29836 29837 for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { 29838 args[_key3] = arguments[_key3]; 29839 } 29840 29841 ret._without = args; 29842 return ret; 29843 }; 29844 29845 function _keys(ret, mixin, seen) { 29846 if (seen[_emberMetalUtils.guidFor(mixin)]) { 29847 return; 29848 } 29849 seen[_emberMetalUtils.guidFor(mixin)] = true; 29850 29851 if (mixin.properties) { 29852 var props = Object.keys(mixin.properties); 29853 for (var i = 0; i < props.length; i++) { 29854 var key = props[i]; 29855 ret[key] = true; 29856 } 29857 } else if (mixin.mixins) { 29858 mixin.mixins.forEach(function (x) { 29859 return _keys(ret, x, seen); 29860 }); 29861 } 29862 } 29863 29864 MixinPrototype.keys = function () { 29865 var keys = {}; 29866 var seen = {}; 29867 29868 _keys(keys, this, seen); 29869 var ret = Object.keys(keys); 29870 return ret; 29871 }; 29872 29873 _emberMetalDebug.debugSeal(MixinPrototype); 29874 29875 // returns the mixins currently applied to the specified object 29876 // TODO: Make Ember.mixin 29877 Mixin.mixins = function (obj) { 29878 var m = _emberMetalMeta.peekMeta(obj); 29879 var ret = []; 29880 if (!m) { 29881 return ret; 29882 } 29883 29884 m.forEachMixins(function (key, currentMixin) { 29885 // skip primitive mixins since these are always anonymous 29886 if (!currentMixin.properties) { 29887 ret.push(currentMixin); 29888 } 29889 }); 29890 29891 return ret; 29892 }; 29893 29894 exports.REQUIRED = REQUIRED = new _emberMetalProperties.Descriptor(); 29895 REQUIRED.toString = function () { 29896 return '(Required Property)'; 29897 }; 29898 29899 /** 29900 Denotes a required property for a mixin 29901 29902 @method required 29903 @for Ember 29904 @private 29905 */ 29906 29907 function required() { 29908 _emberMetalDebug.deprecate('Ember.required is deprecated as its behavior is inconsistent and unreliable.', false, { id: 'ember-metal.required', until: '3.0.0' }); 29909 return REQUIRED; 29910 } 29911 29912 function Alias(methodName) { 29913 this.isDescriptor = true; 29914 this.methodName = methodName; 29915 } 29916 29917 Alias.prototype = new _emberMetalProperties.Descriptor(); 29918 29919 /** 29920 Makes a method available via an additional name. 29921 29922 ```javascript 29923 App.Person = Ember.Object.extend({ 29924 name: function() { 29925 return 'Tomhuda Katzdale'; 29926 }, 29927 moniker: Ember.aliasMethod('name') 29928 }); 29929 29930 var goodGuy = App.Person.create(); 29931 29932 goodGuy.name(); // 'Tomhuda Katzdale' 29933 goodGuy.moniker(); // 'Tomhuda Katzdale' 29934 ``` 29935 29936 @method aliasMethod 29937 @for Ember 29938 @param {String} methodName name of the method to alias 29939 @public 29940 */ 29941 29942 function aliasMethod(methodName) { 29943 return new Alias(methodName); 29944 } 29945 29946 // .......................................................... 29947 // OBSERVER HELPER 29948 // 29949 29950 /** 29951 Specify a method that observes property changes. 29952 29953 ```javascript 29954 Ember.Object.extend({ 29955 valueObserver: Ember.observer('value', function() { 29956 // Executes whenever the "value" property changes 29957 }) 29958 }); 29959 ``` 29960 29961 Also available as `Function.prototype.observes` if prototype extensions are 29962 enabled. 29963 29964 @method observer 29965 @for Ember 29966 @param {String} propertyNames* 29967 @param {Function} func 29968 @return func 29969 @public 29970 */ 29971 29972 function observer() { 29973 for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { 29974 args[_key4] = arguments[_key4]; 29975 } 29976 29977 var func = args.slice(-1)[0]; 29978 var paths; 29979 29980 var addWatchedProperty = function (path) { 29981 paths.push(path); 29982 }; 29983 var _paths = args.slice(0, -1); 29984 29985 if (typeof func !== 'function') { 29986 // revert to old, soft-deprecated argument ordering 29987 _emberMetalDebug.deprecate('Passing the dependentKeys after the callback function in Ember.observer is deprecated. Ensure the callback function is the last argument.', false, { id: 'ember-metal.observer-argument-order', until: '3.0.0' }); 29988 29989 func = args[0]; 29990 _paths = args.slice(1); 29991 } 29992 29993 paths = []; 29994 29995 for (var i = 0; i < _paths.length; ++i) { 29996 _emberMetalExpand_properties.default(_paths[i], addWatchedProperty); 29997 } 29998 29999 if (typeof func !== 'function') { 30000 throw new _emberMetalError.default('Ember.observer called without a function'); 30001 } 30002 30003 func.__ember_observes__ = paths; 30004 return func; 30005 } 30006 30007 /** 30008 Specify a method that observes property changes. 30009 30010 ```javascript 30011 Ember.Object.extend({ 30012 valueObserver: Ember.immediateObserver('value', function() { 30013 // Executes whenever the "value" property changes 30014 }) 30015 }); 30016 ``` 30017 30018 In the future, `Ember.observer` may become asynchronous. In this event, 30019 `Ember.immediateObserver` will maintain the synchronous behavior. 30020 30021 Also available as `Function.prototype.observesImmediately` if prototype extensions are 30022 enabled. 30023
30024 @method _immediateObserver 30025 @for Ember 30026 @param {String} propertyNames* 30027 @param {Function} func 30028 @deprecated Use `Ember.observer` instead. 30029 @return func 30030 @private 30031 */ 30032 30033 function _immediateObserver() { 30034 _emberMetalDebug.deprecate('Usage of `Ember.immediateObserver` is deprecated, use `Ember.observer` instead.', false, { id: 'ember-metal.immediate-observer', until: '3.0.0' }); 30035 30036 for (var i = 0, l = arguments.length; i < l; i++) { 30037 var arg = arguments[i]; 30038 _emberMetalDebug.assert('Immediate observers must observe internal properties only, not properties on other objects.', typeof arg !== 'string' || arg.indexOf('.') === -1); 30039 } 30040 30041 return observer.apply(this, arguments); 30042 } 30043 30044 /** 30045 When observers fire, they are called with the arguments `obj`, `keyName`. 30046 30047 Note, `@each.property` observer is called per each add or replace of an element 30048 and it's not called with a specific enumeration item. 30049 30050 A `_beforeObserver` fires before a property changes. 30051 30052 A `_beforeObserver` is an alternative form of `.observesBefore()`. 30053 30054 ```javascript 30055 App.PersonView = Ember.View.extend({ 30056 friends: [{ name: 'Tom' }, { name: 'Stefan' }, { name: 'Kris' }], 30057 30058 valueDidChange: Ember.observer('content.value', function(obj, keyName) { 30059 // only run if updating a value already in the DOM 30060 if (this.get('state') === 'inDOM') { 30061 var color = obj.get(keyName) > this.changingFrom ? 'green' : 'red'; 30062 // logic 30063 } 30064 }), 30065 30066 friendsDidChange: Ember.observer('[email protected]', function(obj, keyName) { 30067 // some logic 30068 // obj.get(keyName) returns friends array 30069 }) 30070 }); 30071 ``` 30072 30073 Also available as `Function.prototype.observesBefore` if prototype extensions are 30074 enabled. 30075 30076 @method beforeObserver 30077 @for Ember 30078 @param {String} propertyNames* 30079 @param {Function} func 30080 @return func 30081 @deprecated 30082 @private 30083 */ 30084 30085 function _beforeObserver() { 30086 for (var _len5 = arguments.length, args = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { 30087 args[_key5] = arguments[_key5]; 30088 } 30089 30090 var func = args.slice(-1)[0]; 30091 var paths; 30092 30093 var addWatchedProperty = function (path) { 30094 paths.push(path); 30095 }; 30096 30097 var _paths = args.slice(0, -1); 30098 30099 if (typeof func !== 'function') { 30100 // revert to old, soft-deprecated argument ordering 30101 30102 func = args[0]; 30103 _paths = args.slice(1); 30104 } 30105 30106 paths = []; 30107 30108 for (var i = 0; i < _paths.length; ++i) { 30109 _emberMetalExpand_properties.default(_paths[i], addWatchedProperty); 30110 } 30111 30112 if (typeof func !== 'function') { 30113 throw new _emberMetalCore.default.Error('Ember.beforeObserver called without a function'); 30114 } 30115 30116 func.__ember_observesBefore__ = paths; 30117 return func; 30118 } 30119 30120 exports.IS_BINDING = IS_BINDING; 30121 exports.Mixin = Mixin; 30122 exports.required = required; 30123 exports.REQUIRED = REQUIRED; 30124}); 30125// warn, assert, wrap, et; 30126enifed('ember-metal/observer', ['exports', 'ember-metal/watching', 'ember-metal/events'], function (exports, _emberMetalWatching, _emberMetalEvents) { 30127 'use strict'; 30128 30129 exports.addObserver = addObserver; 30130 exports.observersFor = observersFor; 30131 exports.removeObserver = removeObserver; 30132 exports._addBeforeObserver = _addBeforeObserver; 30133 exports._suspendObserver = _suspendObserver; 30134 exports._suspendObservers = _suspendObservers; 30135 exports._removeBeforeObserver = _removeBeforeObserver; 30136 30137 /** 30138 @module ember-metal 30139 */ 30140 30141 var AFTER_OBSERVERS = ':change'; 30142 var BEFORE_OBSERVERS = ':before'; 30143 30144 function changeEvent(keyName) { 30145 return keyName + AFTER_OBSERVERS; 30146 } 30147 30148 function beforeEvent(keyName) { 30149 return keyName + BEFORE_OBSERVERS; 30150 } 30151 30152 /** 30153 @method addObserver 30154 @for Ember 30155 @param obj 30156 @param {String} _path 30157 @param {Object|Function} target 30158 @param {Function|String} [method] 30159 @public 30160 */ 30161 30162 function addObserver(obj, _path, target, method) { 30163 _emberMetalEvents.addListener(obj, changeEvent(_path), target, method); 30164 _emberMetalWatching.watch(obj, _path); 30165 30166 return this; 30167 } 30168 30169 function observersFor(obj, path) { 30170 return _emberMetalEvents.listenersFor(obj, changeEvent(path)); 30171 } 30172 30173 /** 30174 @method removeObserver 30175 @for Ember 30176 @param obj 30177 @param {String} path 30178 @param {Object|Function} target 30179 @param {Function|String} [method] 30180 @public 30181 */ 30182 30183 function removeObserver(obj, path, target, method) { 30184 _emberMetalWatching.unwatch(obj, path); 30185 _emberMetalEvents.removeListener(obj, changeEvent(path), target, method); 30186 30187 return this; 30188 } 30189 30190 /** 30191 @method _addBeforeObserver 30192 @for Ember 30193 @param obj 30194 @param {String} path 30195 @param {Object|Function} target 30196 @param {Function|String} [method] 30197 @deprecated 30198 @private 30199 */ 30200 30201 function _addBeforeObserver(obj, path, target, method) { 30202 _emberMetalEvents.addListener(obj, beforeEvent(path), target, method); 30203 _emberMetalWatching.watch(obj, path); 30204 30205 return this; 30206 } 30207 30208 // Suspend observer during callback. 30209 // 30210 // This should only be used by the target of the observer 30211 // while it is setting the observed path. 30212 30213 function _suspendObserver(obj, path, target, method, callback) { 30214 return _emberMetalEvents.suspendListener(obj, changeEvent(path), target, method, callback); 30215 } 30216 30217 function _suspendObservers(obj, paths, target, method, callback) { 30218 var events = paths.map(changeEvent); 30219 return _emberMetalEvents.suspendListeners(obj, events, target, method, callback); 30220 } 30221 30222 /** 30223 @method removeBeforeObserver 30224 @for Ember 30225 @param obj 30226 @param {String} path 30227 @param {Object|Function} target 30228 @param {Function|String} [method] 30229 @deprecated 30230 @private 30231 */ 30232 30233 function _removeBeforeObserver(obj, path, target, method) { 30234 _emberMetalWatching.unwatch(obj, path); 30235 _emberMetalEvents.removeListener(obj, beforeEvent(path), target, method); 30236 30237 return this; 30238 } 30239}); 30240enifed('ember-metal/observer_set', ['exports', 'ember-metal/utils', 'ember-metal/events'], function (exports, _emberMetalUtils, _emberMetalEvents) { 30241 'use strict'; 30242 30243 /* 30244 this.observerSet = { 30245 [senderGuid]: { // variable name: `keySet` 30246 [keyName]: listIndex 30247 } 30248 }, 30249 this.observers = [ 30250 { 30251 sender: obj, 30252 keyName: keyName, 30253 eventName: eventName, 30254 listeners: [ 30255 [target, method, flags] 30256 ] 30257 }, 30258 ... 30259 ] 30260 */ 30261 exports.default = ObserverSet; 30262 30263 function ObserverSet() { 30264 this.clear(); 30265 } 30266 30267 ObserverSet.prototype.add = function (sender, keyName, eventName) { 30268 var observerSet = this.observerSet; 30269 var observers = this.observers; 30270 var senderGuid = _emberMetalUtils.guidFor(sender); 30271 var keySet = observerSet[senderGuid]; 30272 var index; 30273 30274 if (!keySet) { 30275 observerSet[senderGuid] = keySet = {}; 30276 } 30277 index = keySet[keyName]; 30278 if (index === undefined) { 30279 index = observers.push({ 30280 sender: sender, 30281 keyName: keyName, 30282 eventName: eventName, 30283 listeners: [] 30284 }) - 1; 30285 keySet[keyName] = index; 30286 } 30287 return observers[index].listeners; 30288 }; 30289 30290 ObserverSet.prototype.flush = function () { 30291 var observers = this.observers; 30292 var i, len, observer, sender; 30293 this.clear(); 30294 for (i = 0, len = observers.length; i < len; ++i) { 30295 observer = observers[i]; 30296 sender = observer.sender; 30297 if (sender.isDestroying || sender.isDestroyed) { 30298 continue; 30299 } 30300 _emberMetalEvents.sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); 30301 } 30302 }; 30303 30304 ObserverSet.prototype.clear = function () { 30305 this.observerSet = {}; 30306 this.observers = []; 30307 }; 30308}); 30309enifed('ember-metal/path_cache', ['exports', 'ember-metal/cache'], function (exports, _emberMetalCache) { 30310 'use strict'; 30311 30312 exports.isGlobal = isGlobal; 30313 exports.isGlobalPath = isGlobalPath;
30314 exports.hasThis = hasThis; 30315 exports.isPath = isPath; 30316 exports.getFirstKey = getFirstKey; 30317 exports.getTailPath = getTailPath; 30318 30319 var IS_GLOBAL = /^[A-Z$]/; 30320 var IS_GLOBAL_PATH = /^[A-Z$].*[\.]/; 30321 var HAS_THIS = 'this.'; 30322 30323 var isGlobalCache = new _emberMetalCache.default(1000, function (key) { 30324 return IS_GLOBAL.test(key); 30325 }); 30326 30327 var isGlobalPathCache = new _emberMetalCache.default(1000, function (key) { 30328 return IS_GLOBAL_PATH.test(key); 30329 }); 30330 30331 var hasThisCache = new _emberMetalCache.default(1000, function (key) { 30332 return key.lastIndexOf(HAS_THIS, 0) === 0; 30333 }); 30334 30335 var firstDotIndexCache = new _emberMetalCache.default(1000, function (key) { 30336 return key.indexOf('.'); 30337 }); 30338 30339 var firstKeyCache = new _emberMetalCache.default(1000, function (path) { 30340 var index = firstDotIndexCache.get(path); 30341 if (index === -1) { 30342 return path; 30343 } else { 30344 return path.slice(0, index); 30345 } 30346 }); 30347 30348 var tailPathCache = new _emberMetalCache.default(1000, function (path) { 30349 var index = firstDotIndexCache.get(path); 30350 if (index !== -1) { 30351 return path.slice(index + 1); 30352 } 30353 }); 30354 30355 var caches = { 30356 isGlobalCache: isGlobalCache, 30357 isGlobalPathCache: isGlobalPathCache, 30358 hasThisCache: hasThisCache, 30359 firstDotIndexCache: firstDotIndexCache, 30360 firstKeyCache: firstKeyCache, 30361 tailPathCache: tailPathCache 30362 }; 30363 30364 exports.caches = caches; 30365 30366 function isGlobal(path) { 30367 return isGlobalCache.get(path); 30368 } 30369 30370 function isGlobalPath(path) { 30371 return isGlobalPathCache.get(path); 30372 } 30373 30374 function hasThis(path) { 30375 return hasThisCache.get(path); 30376 } 30377 30378 function isPath(path) { 30379 return firstDotIndexCache.get(path) !== -1; 30380 } 30381 30382 function getFirstKey(path) { 30383 return firstKeyCache.get(path); 30384 } 30385 30386 function getTailPath(path) { 30387 return tailPathCache.get(path); 30388 } 30389}); 30390enifed('ember-metal/properties', ['exports', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/meta', 'ember-metal/property_events'], function (exports, _emberMetalDebug, _emberMetalFeatures, _emberMetalMeta, _emberMetalProperty_events) { 30391 /** 30392 @module ember-metal 30393 */ 30394 30395 'use strict'; 30396 30397 exports.Descriptor = Descriptor; 30398 exports.MANDATORY_SETTER_FUNCTION = MANDATORY_SETTER_FUNCTION; 30399 exports.DEFAULT_GETTER_FUNCTION = DEFAULT_GETTER_FUNCTION; 30400 exports.INHERITING_GETTER_FUNCTION = INHERITING_GETTER_FUNCTION; 30401 exports.defineProperty = defineProperty; 30402 30403 // .......................................................... 30404 // DESCRIPTOR 30405 // 30406 30407 /** 30408 Objects of this type can implement an interface to respond to requests to 30409 get and set. The default implementation handles simple properties. 30410 30411 @class Descriptor 30412 @private 30413 */ 30414 30415 function Descriptor() { 30416 this.isDescriptor = true; 30417 } 30418 30419 var REDEFINE_SUPPORTED = (function () { 30420 // https://github.com/spalger/kibana/commit/b7e35e6737df585585332857a4c397dc206e7ff9 30421 var a = Object.create(Object.prototype, { 30422 prop: { 30423 configurable: true, 30424 value: 1 30425 } 30426 }); 30427 30428 Object.defineProperty(a, 'prop', { 30429 configurable: true, 30430 value: 2 30431 }); 30432 30433 return a.prop === 2; 30434 })(); 30435 // .......................................................... 30436 // DEFINING PROPERTIES API 30437 // 30438 30439 function MANDATORY_SETTER_FUNCTION(name) { 30440 function SETTER_FUNCTION(value) { 30441 _emberMetalDebug.assert('You must use Ember.set() to set the `' + name + '` property (of ' + this + ') to `' + value + '`.', false); 30442 } 30443 30444 SETTER_FUNCTION.isMandatorySetter = true; 30445 return SETTER_FUNCTION; 30446 } 30447 30448 function DEFAULT_GETTER_FUNCTION(name) { 30449 return function GETTER_FUNCTION() { 30450 var meta = this['__ember_meta__']; 30451 return meta && meta.peekValues(name); 30452 }; 30453 } 30454 30455 function INHERITING_GETTER_FUNCTION(name) { 30456 function IGETTER_FUNCTION() { 30457 var proto = Object.getPrototypeOf(this); 30458 return proto && proto[name]; 30459 } 30460 30461 IGETTER_FUNCTION.isInheritingGetter = true; 30462 return IGETTER_FUNCTION; 30463 } 30464 30465 /** 30466 NOTE: This is a low-level method used by other parts of the API. You almost 30467 never want to call this method directly. Instead you should use 30468 `Ember.mixin()` to define new properties. 30469 30470 Defines a property on an object. This method works much like the ES5
30471 `Object.defineProperty()` method except that it can also accept computed 30472 properties and other special descriptors. 30473 30474 Normally this method takes only three parameters. However if you pass an 30475 instance of `Descriptor` as the third param then you can pass an 30476 optional value as the fourth parameter. This is often more efficient than 30477 creating new descriptor hashes for each property. 30478 30479 ## Examples 30480 30481 ```javascript 30482 // ES5 compatible mode 30483 Ember.defineProperty(contact, 'firstName', { 30484 writable: true, 30485 configurable: false, 30486 enumerable: true, 30487 value: 'Charles' 30488 }); 30489 30490 // define a simple property 30491 Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); 30492 30493 // define a computed property 30494 Ember.defineProperty(contact, 'fullName', Ember.computed('firstName', 'lastName', function() { 30495 return this.firstName+' '+this.lastName; 30496 })); 30497 ``` 30498 30499 @private 30500 @method defineProperty 30501 @for Ember 30502 @param {Object} obj the object to define this property on. This may be a prototype. 30503 @param {String} keyName the name of the property 30504 @param {Descriptor} [desc] an instance of `Descriptor` (typically a 30505 computed property) or an ES5 descriptor. 30506 You must provide this or `data` but not both. 30507 @param {*} [data] something other than a descriptor, that will 30508 become the explicit value of this property. 30509 */ 30510 30511 function defineProperty(obj, keyName, desc, data, meta) { 30512 var possibleDesc, existingDesc, watching, value; 30513 30514 if (!meta) { 30515 meta = _emberMetalMeta.meta(obj); 30516 } 30517 var watchEntry = meta.peekWatching(keyName); 30518 possibleDesc = obj[keyName]; 30519 existingDesc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 30520 30521 watching = watchEntry !== undefined && watchEntry > 0; 30522 30523 if (existingDesc) { 30524 existingDesc.teardown(obj, keyName); 30525 } 30526 30527 if (desc instanceof Descriptor) { 30528 value = desc; 30529 30530 if (watching) { 30531 Object.defineProperty(obj, keyName, { 30532 configurable: true, 30533 enumerable: true, 30534 writable: true, 30535 value: value 30536 }); 30537 } else { 30538 obj[keyName] = value; 30539 } 30540 30541 if (desc.setup) { 30542 desc.setup(obj, keyName); 30543 } 30544 } else { 30545 if (desc == null) { 30546 value = data; 30547 30548 if (watching) { 30549 meta.writeValues(keyName, data); 30550 30551 var defaultDescriptor = { 30552 configurable: true, 30553 enumerable: true, 30554 set: MANDATORY_SETTER_FUNCTION(keyName), 30555 get: DEFAULT_GETTER_FUNCTION(keyName) 30556 }; 30557 30558 if (REDEFINE_SUPPORTED) { 30559 Object.defineProperty(obj, keyName, defaultDescriptor); 30560 } else { 30561 handleBrokenPhantomDefineProperty(obj, keyName, defaultDescriptor); 30562 } 30563 } else { 30564 obj[keyName] = data; 30565 } 30566 } else { 30567 value = desc; 30568 30569 // fallback to ES5 30570 Object.defineProperty(obj, keyName, desc); 30571 } 30572 } 30573 30574 // if key is being watched, override chains that 30575 // were initialized with the prototype 30576 if (watching) { 30577 _emberMetalProperty_events.overrideChains(obj, keyName, meta); 30578 } 30579 30580 // The `value` passed to the `didDefineProperty` hook is 30581 // either the descriptor or data, whichever was passed. 30582 if (obj.didDefineProperty) { 30583 obj.didDefineProperty(obj, keyName, value); 30584 } 30585 30586 return this; 30587 } 30588 30589 function handleBrokenPhantomDefineProperty(obj, keyName, desc) { 30590 // https://github.com/ariya/phantomjs/issues/11856 30591 Object.defineProperty(obj, keyName, { configurable: true, writable: true, value: 'iCry' }); 30592 Object.defineProperty(obj, keyName, desc); 30593 } 30594}); 30595enifed('ember-metal/property_events', ['exports', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/events', 'ember-metal/observer_set', 'ember-metal/symbol'], function (exports, _emberMetalUtils, _emberMetalMeta, _emberMetalEvents, _emberMetalObserver_set, _emberMetalSymbol) { 30596 'use strict'; 30597 30598 var PROPERTY_DID_CHANGE = _emberMetalSymbol.default('PROPERTY_DID_CHANGE'); 30599 30600 exports.PROPERTY_DID_CHANGE = PROPERTY_DID_CHANGE; 30601 var beforeObserverSet = new _emberMetalObserver_set.default(); 30602 var observerSet = new _emberMetalObserver_set.default(); 30603 var deferred = 0; 30604 30605 // .......................................................... 30606 // PROPERTY CHANGES 30607 // 30608 30609 /** 30610 This function is called just before an object property is about to change. 30611 It will notify any before observers and prepare caches among other things. 30612 30613 Normally you will not need to call this method directly but if for some 30614 reason you can't directly watch a property you can invoke this method 30615 manually along with `Ember.propertyDidChange()` which you should call just 30616 after the property value changes. 30617 30618 @method propertyWillChange 30619 @for Ember 30620 @param {Object} obj The object with the property that will change 30621 @param {String} keyName The property key (or path) that will change. 30622 @return {void} 30623 @private 30624 */ 30625 function propertyWillChange(obj, keyName) { 30626 var m = _emberMetalMeta.peekMeta(obj); 30627 var watching = m && m.peekWatching(keyName) > 0 || keyName === 'length'; 30628 var proto = m && m.proto; 30629 var possibleDesc = obj[keyName]; 30630 var desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 30631 30632 if (!watching) { 30633 return; 30634 } 30635 30636 if (proto === obj) { 30637 return; 30638 } 30639 30640 if (desc && desc.willChange) { 30641 desc.willChange(obj, keyName); 30642 } 30643 30644 dependentKeysWillChange(obj, keyName, m); 30645 chainsWillChange(obj, keyName, m); 30646 notifyBeforeObservers(obj, keyName); 30647 } 30648 30649 /** 30650 This function is called just after an object property has changed. 30651 It will notify any observers and clear caches among other things. 30652 30653 Normally you will not need to call this method directly but if for some 30654 reason you can't directly watch a property you can invoke this method 30655 manually along with `Ember.propertyWillChange()` which you should call just 30656 before the property value changes. 30657 30658 @method propertyDidChange 30659 @for Ember 30660 @param {Object} obj The object with the property that will change 30661 @param {String} keyName The property key (or path) that will change. 30662 @return {void} 30663 @private 30664 */ 30665 function propertyDidChange(obj, keyName) { 30666 var m = _emberMetalMeta.peekMeta(obj); 30667 var watching = m && m.peekWatching(keyName) > 0 || keyName === 'length'; 30668 var proto = m && m.proto; 30669 var possibleDesc = obj[keyName]; 30670 var desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 30671 30672 if (proto === obj) { 30673 return; 30674 } 30675 30676 // shouldn't this mean that we're watching this key? 30677 if (desc && desc.didChange) { 30678 desc.didChange(obj, keyName); 30679 } 30680 30681 if (obj[PROPERTY_DID_CHANGE]) { 30682 obj[PROPERTY_DID_CHANGE](keyName); 30683 } 30684 30685 if (!watching && keyName !== 'length') { 30686 return; 30687 } 30688 30689 if (m && m.hasDeps(keyName)) { 30690 dependentKeysDidChange(obj, keyName, m); 30691 } 30692 30693 chainsDidChange(obj, keyName, m, false); 30694 notifyObservers(obj, keyName); 30695 } 30696 30697 var WILL_SEEN, DID_SEEN; 30698 // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) 30699 function dependentKeysWillChange(obj, depKey, meta) { 30700 if (obj.isDestroying) { 30701 return; 30702 } 30703 30704 if (meta && meta.hasDeps(depKey)) { 30705 var seen = WILL_SEEN; 30706 var top = !seen; 30707 30708 if (top) { 30709 seen = WILL_SEEN = {}; 30710 } 30711 30712 iterDeps(propertyWillChange, obj, depKey, seen, meta); 30713 30714 if (top) { 30715 WILL_SEEN = null; 30716 } 30717 } 30718 } 30719 30720 // called whenever a property has just changed to update dependent keys 30721 function dependentKeysDidChange(obj, depKey, meta) { 30722 if (obj.isDestroying) { 30723 return; 30724 } 30725 30726 if (meta && meta.hasDeps(depKey)) { 30727 var seen = DID_SEEN; 30728 var top = !seen; 30729 30730 if (top) { 30731 seen = DID_SEEN = {}; 30732 } 30733 30734 iterDeps(propertyDidChange, obj, depKey, seen, meta); 30735 30736 if (top) { 30737 DID_SEEN = null; 30738 } 30739 } 30740 } 30741 30742 function iterDeps(method, obj, depKey, seen, meta) { 30743 var possibleDesc, desc; 30744 var guid = _emberMetalUtils.guidFor(obj); 30745 var current = seen[guid]; 30746 30747 if (!current) { 30748 current = seen[guid] = {}; 30749 } 30750 30751 if (current[depKey]) { 30752 return; 30753 } 30754 30755 current[depKey] = true; 30756 30757 meta.forEachInDeps(depKey, function (key, value) { 30758 if (!value) { 30759 return; 30760 } 30761 30762 possibleDesc = obj[key]; 30763 desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 30764 30765 if (desc && desc._suspended === obj) { 30766 return; 30767 } 30768 30769 method(obj, key); 30770 }); 30771 } 30772 30773 function chainsWillChange(obj, keyName, m) { 30774 var c = m.readableChainWatchers(); 30775 if (c) { 30776 c.notify(keyName, false, propertyWillChange); 30777 } 30778 } 30779 30780 function chainsDidChange(obj, keyName, m) { 30781 var c = m.readableChainWatchers(); 30782 if (c) { 30783 c.notify(keyName, true, propertyDidChange); 30784 } 30785 } 30786 30787 function overrideChains(obj, keyName, m) { 30788 var c = m.readableChainWatchers(); 30789 if (c) { 30790 c.revalidate(keyName); 30791 } 30792 } 30793 30794 /** 30795 @method beginPropertyChanges 30796 @chainable 30797 @private 30798 */ 30799 function beginPropertyChanges() { 30800 deferred++; 30801 } 30802 30803 /** 30804 @method endPropertyChanges 30805 @private 30806 */ 30807 function endPropertyChanges() { 30808 deferred--; 30809 if (deferred <= 0) { 30810 beforeObserverSet.clear(); 30811 observerSet.flush(); 30812 } 30813 } 30814 30815 /** 30816 Make a series of property changes together in an 30817 exception-safe way. 30818
30819 ```javascript 30820 Ember.changeProperties(function() { 30821 obj1.set('foo', mayBlowUpWhenSet); 30822 obj2.set('bar', baz); 30823 }); 30824 ``` 30825 30826 @method changeProperties 30827 @param {Function} callback 30828 @param [binding] 30829 @private 30830 */ 30831 function changeProperties(callback, binding) { 30832 beginPropertyChanges(); 30833 try { 30834 callback.call(binding); 30835 } finally { 30836 endPropertyChanges.call(binding); 30837 } 30838 } 30839 30840 function notifyBeforeObservers(obj, keyName) { 30841 if (obj.isDestroying) { 30842 return; 30843 } 30844 30845 var eventName = keyName + ':before'; 30846 var listeners, added; 30847 if (deferred) { 30848 listeners = beforeObserverSet.add(obj, keyName, eventName); 30849 added = _emberMetalEvents.accumulateListeners(obj, eventName, listeners); 30850 _emberMetalEvents.sendEvent(obj, eventName, [obj, keyName], added); 30851 } else { 30852 _emberMetalEvents.sendEvent(obj, eventName, [obj, keyName]); 30853 } 30854 } 30855 30856 function notifyObservers(obj, keyName) { 30857 if (obj.isDestroying) { 30858 return; 30859 } 30860 30861 var eventName = keyName + ':change'; 30862 var listeners; 30863 if (deferred) { 30864 listeners = observerSet.add(obj, keyName, eventName); 30865 _emberMetalEvents.accumulateListeners(obj, eventName, listeners); 30866 } else { 30867 _emberMetalEvents.sendEvent(obj, eventName, [obj, keyName]); 30868 } 30869 } 30870 30871 exports.propertyWillChange = propertyWillChange; 30872 exports.propertyDidChange = propertyDidChange; 30873 exports.overrideChains = overrideChains; 30874 exports.beginPropertyChanges = beginPropertyChanges; 30875 exports.endPropertyChanges = endPropertyChanges; 30876 exports.changeProperties = changeProperties; 30877}); 30878enifed('ember-metal/property_get', ['exports', 'ember-metal/debug', 'ember-metal/path_cache'], function (exports, _emberMetalDebug, _emberMetalPath_cache) { 30879 /** 30880 @module ember-metal 30881 */ 30882 30883 'use strict'; 30884 30885 exports.get = get; 30886 exports._getPath = _getPath; 30887 exports.getWithDefault = getWithDefault; 30888 30889 // .......................................................... 30890 // GET AND SET 30891 // 30892 // If we are on a platform that supports accessors we can use those. 30893 // Otherwise simulate accessors by looking up the property directly on the 30894 // object. 30895 30896 /** 30897 Gets the value of a property on an object. If the property is computed, 30898 the function will be invoked. If the property is not defined but the 30899 object implements the `unknownProperty` method then that will be invoked. 30900 30901 If you plan to run on IE8 and older browsers then you should use this 30902 method anytime you want to retrieve a property on an object that you don't 30903 know for sure is private. (Properties beginning with an underscore '_' 30904 are considered private.) 30905 30906 On all newer browsers, you only need to use this method to retrieve 30907 properties if the property might not be defined on the object and you want 30908 to respect the `unknownProperty` handler. Otherwise you can ignore this 30909 method. 30910 30911 Note that if the object itself is `undefined`, this method will throw 30912 an error. 30913 30914 @method get 30915 @for Ember 30916 @param {Object} obj The object to retrieve from. 30917 @param {String} keyName The property key to retrieve 30918 @return {Object} the property value or `null`. 30919 @public 30920 */ 30921 30922 function get(obj, keyName) { 30923 _emberMetalDebug.assert('Get must be called with two arguments; an object and a property key', arguments.length === 2); 30924 _emberMetalDebug.assert('Cannot call get with \'' + keyName + '\' on an undefined object.', obj !== undefined && obj !== null); 30925 _emberMetalDebug.assert('The key provided to get must be a string, you passed ' + keyName, typeof keyName === 'string'); 30926 _emberMetalDebug.assert('\'this\' in paths is not supported', !_emberMetalPath_cache.hasThis(keyName)); 30927 30928 // Helpers that operate with 'this' within an #each 30929 if (keyName === '') { 30930 return obj; 30931 } 30932 30933 var value = obj[keyName]; 30934 var desc = value !== null && typeof value === 'object' && value.isDescriptor ? value : undefined; 30935 var ret; 30936 30937 if (desc === undefined && _emberMetalPath_cache.isPath(keyName)) { 30938 return _getPath(obj, keyName); 30939 } 30940 30941 if (desc) { 30942 return desc.get(obj, keyName); 30943 } else { 30944 ret = value; 30945 30946 if (ret === undefined && 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { 30947 return obj.unknownProperty(keyName); 30948 } 30949 30950 return ret; 30951 } 30952 } 30953 30954 function _getPath(root, path) { 30955 var obj = root; 30956 var parts = path.split('.'); 30957 var len = parts.length; 30958 30959 for (var i = 0; i < len; i++) { 30960 if (obj == null) { 30961 return obj; 30962 } 30963 30964 obj = get(obj, parts[i]); 30965 30966 if (obj && obj.isDestroyed) { 30967 return undefined; 30968 } 30969 } 30970 30971 return obj; 30972 } 30973 30974 /** 30975 Retrieves the value of a property from an Object, or a default value in the 30976 case that the property returns `undefined`. 30977 30978 ```javascript 30979 Ember.getWithDefault(person, 'lastName', 'Doe'); 30980 ``` 30981 30982 @method getWithDefault 30983 @for Ember 30984 @param {Object} obj The object to retrieve from. 30985 @param {String} keyName The name of the property to retrieve 30986 @param {Object} defaultValue The value to return if the property value is undefined 30987 @return {Object} The property value or the defaultValue. 30988 @public 30989 */ 30990 30991 function getWithDefault(root, key, defaultValue) { 30992 var value = get(root, key); 30993 30994 if (value === undefined) { 30995 return defaultValue; 30996 } 30997 return value; 30998 } 30999 31000 exports.default = get; 31001}); 31002enifed('ember-metal/property_set', ['exports', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/property_get', 'ember-metal/property_events', 'ember-metal/properties', 'ember-metal/error', 'ember-metal/path_cache', 'ember-metal/meta', 'ember-metal/utils'], function (exports, _emberMetalDebug, _emberMetalFeatures, _emberMetalProperty_get, _emberMetalProperty_events, _emberMetalProperties, _emberMetalError, _emberMetalPath_cache, _emberMetalMeta, _emberMetalUtils) { 31003 'use strict'; 31004 31005 exports.set = set; 31006 exports.trySet = trySet; 31007 31008 /** 31009 Sets the value of a property on an object, respecting computed properties 31010 and notifying observers and other listeners of the change. If the 31011 property is not defined but the object implements the `setUnknownProperty` 31012 method then that will be invoked as well. 31013 31014 @method set 31015 @for Ember 31016 @param {Object} obj The object to modify. 31017 @param {String} keyName The property key to set 31018 @param {Object} value The value to set 31019 @return {Object} the passed value. 31020 @public 31021 */ 31022 31023 function set(obj, keyName, value, tolerant) { 31024 _emberMetalDebug.assert('Set must be called with three or four arguments; an object, a property key, a value and tolerant true/false', arguments.length === 3 || arguments.length === 4); 31025 _emberMetalDebug.assert('Cannot call set with \'' + keyName + '\' on an undefined object.', obj !== undefined && obj !== null); 31026 _emberMetalDebug.assert('The key provided to set must be a string, you passed ' + keyName, typeof keyName === 'string'); 31027 _emberMetalDebug.assert('\'this\' in paths is not supported', !_emberMetalPath_cache.hasThis(keyName)); 31028 31029 var meta, possibleDesc, desc; 31030 if (obj) { 31031 meta = _emberMetalMeta.peekMeta(obj); 31032 possibleDesc = obj[keyName]; 31033 desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 31034 } 31035 31036 var isUnknown, currentValue; 31037 if (desc === undefined && _emberMetalPath_cache.isPath(keyName)) { 31038 return setPath(obj, keyName, value, tolerant); 31039 } 31040 31041 _emberMetalDebug.assert('calling set on destroyed object: ' + _emberMetalUtils.toString(obj) + '.' + keyName + ' = ' + _emberMetalUtils.toString(value), !obj.isDestroyed); 31042 31043 if (desc) { 31044 desc.set(obj, keyName, value); 31045 } else { 31046 if (value !== undefined && typeof obj === 'object' && obj[keyName] === value) { 31047 return value; 31048 } 31049 31050 isUnknown = 'object' === typeof obj && !(keyName in obj); 31051
31052 // setUnknownProperty is called if `obj` is an object, 31053 // the property does not already exist, and the 31054 // `setUnknownProperty` method exists on the object 31055 if (isUnknown && 'function' === typeof obj.setUnknownProperty) { 31056 obj.setUnknownProperty(keyName, value); 31057 } else if (meta && meta.peekWatching(keyName) > 0) { 31058 if (meta.proto !== obj) { 31059 currentValue = obj[keyName]; 31060 } 31061 // only trigger a change if the value has changed 31062 if (value !== currentValue) { 31063 _emberMetalProperty_events.propertyWillChange(obj, keyName); 31064 31065 if (currentValue === undefined && !(keyName in obj) || !Object.prototype.propertyIsEnumerable.call(obj, keyName)) { 31066 _emberMetalProperties.defineProperty(obj, keyName, null, value); // setup mandatory setter 31067 } else { 31068 var descriptor = _emberMetalUtils.lookupDescriptor(obj, keyName); 31069 var isMandatorySetter = descriptor && descriptor.set && descriptor.set.isMandatorySetter; 31070 if (isMandatorySetter) { 31071 meta.writeValues(keyName, value); 31072 } else { 31073 obj[keyName] = value; 31074 } 31075 } 31076 31077 _emberMetalProperty_events.propertyDidChange(obj, keyName); 31078 } 31079 } else { 31080 obj[keyName] = value; 31081 if (obj[_emberMetalProperty_events.PROPERTY_DID_CHANGE]) { 31082 obj[_emberMetalProperty_events.PROPERTY_DID_CHANGE](keyName); 31083 } 31084 } 31085 } 31086 return value; 31087 } 31088 31089 function setPath(root, path, value, tolerant) { 31090 var keyName; 31091 31092 // get the last part of the path 31093 keyName = path.slice(path.lastIndexOf('.') + 1); 31094 31095 // get the first part of the part 31096 path = path === keyName ? keyName : path.slice(0, path.length - (keyName.length + 1)); 31097 31098 // unless the path is this, look up the first part to 31099 // get the root 31100 if (path !== 'this') { 31101 root = _emberMetalProperty_get._getPath(root, path); 31102 } 31103 31104 if (!keyName || keyName.length === 0) { 31105 throw new _emberMetalError.default('Property set failed: You passed an empty path'); 31106 } 31107 31108 if (!root) { 31109 if (tolerant) { 31110 return; 31111 } else { 31112 throw new _emberMetalError.default('Property set failed: object in path "' + path + '" could not be found or was destroyed.'); 31113 } 31114 } 31115 31116 return set(root, keyName, value); 31117 } 31118 31119 /** 31120 Error-tolerant form of `Ember.set`. Will not blow up if any part of the 31121 chain is `undefined`, `null`, or destroyed. 31122 31123 This is primarily used when syncing bindings, which may try to update after 31124 an object has been destroyed. 31125 31126 @method trySet 31127 @for Ember 31128 @param {Object} root The object to modify. 31129 @param {String} path The property path to set 31130 @param {Object} value The value to set 31131 @public 31132 */ 31133 31134 function trySet(root, path, value) { 31135 return set(root, path, value, true); 31136 } 31137}); 31138enifed("ember-metal/replace", ["exports"], function (exports) { 31139 "use strict"; 31140 31141 exports._replace = _replace; 31142 exports.default = replace; 31143 var splice = Array.prototype.splice; 31144 31145 function _replace(array, idx, amt, objects) { 31146 var args = [].concat(objects); 31147 var ret = []; 31148 // https://code.google.com/p/chromium/issues/detail?id=56588 31149 var size = 60000; 31150 var start = idx; 31151 var ends = amt; 31152 var count, chunk; 31153 31154 while (args.length) { 31155 count = ends > size ? size : ends; 31156 if (count <= 0) { 31157 count = 0; 31158 } 31159 31160 chunk = args.splice(0, size); 31161 chunk = [start, count].concat(chunk); 31162 31163 start += size; 31164 ends -= count; 31165 31166 ret = ret.concat(splice.apply(array, chunk)); 31167 } 31168 return ret; 31169 } 31170 31171 /** 31172 Replaces objects in an array with the passed objects. 31173 31174 ```javascript 31175 var array = [1,2,3]; 31176 Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] 31177 31178 var array = [1,2,3]; 31179 Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] 31180 31181 var array = [1,2,3]; 31182 Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] 31183 ``` 31184 31185 @method replace 31186 @deprecated 31187 @param {Array} array The array the objects should be inserted into. 31188 @param {Number} idx Starting index in the array to replace. If *idx* >= 31189 length, then append to the end of the array. 31190 @param {Number} amt Number of elements that should be removed from the array, 31191 starting at *idx* 31192 @param {Array} objects An array of zero or more objects that should be 31193 inserted into the array at *idx* 31194 31195 @return {Array} The modified array.
31196 @public 31197 */ 31198 31199 function replace(array, idx, amt, objects) { 31200 if (array.replace) { 31201 return array.replace(idx, amt, objects); 31202 } else { 31203 return _replace(array, idx, amt, objects); 31204 } 31205 } 31206}); 31207enifed('ember-metal/run_loop', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-metal/utils', 'ember-metal/property_events', 'backburner'], function (exports, _emberMetalCore, _emberMetalDebug, _emberMetalUtils, _emberMetalProperty_events, _backburner) { 31208 'use strict'; 31209 31210 exports.default = run; 31211 31212 function onBegin(current) { 31213 run.currentRunLoop = current; 31214 } 31215 31216 function onEnd(current, next) { 31217 run.currentRunLoop = next; 31218 } 31219 31220 // ES6TODO: should Backburner become es6? 31221 var backburner = new _backburner.default(['sync', 'actions', 'destroy'], { 31222 GUID_KEY: _emberMetalUtils.GUID_KEY, 31223 sync: { 31224 before: _emberMetalProperty_events.beginPropertyChanges, 31225 after: _emberMetalProperty_events.endPropertyChanges 31226 }, 31227 defaultQueue: 'actions', 31228 onBegin: onBegin, 31229 onEnd: onEnd, 31230 onErrorTarget: _emberMetalCore.default, 31231 onErrorMethod: 'onerror' 31232 }); 31233 31234 // .......................................................... 31235 // run - this is ideally the only public API the dev sees 31236 // 31237 31238 /** 31239 Runs the passed target and method inside of a RunLoop, ensuring any 31240 deferred actions including bindings and views updates are flushed at the 31241 end. 31242 31243 Normally you should not need to invoke this method yourself. However if 31244 you are implementing raw event handlers when interfacing with other 31245 libraries or plugins, you should probably wrap all of your code inside this 31246 call. 31247 31248 ```javascript 31249 run(function() { 31250 // code to be executed within a RunLoop 31251 }); 31252 ``` 31253 31254 @class run 31255 @namespace Ember 31256 @static 31257 @constructor 31258 @param {Object} [target] target of method to call 31259 @param {Function|String} method Method to invoke. 31260 May be a function or a string. If you pass a string 31261 then it will be looked up on the passed target. 31262 @param {Object} [args*] Any additional arguments you wish to pass to the method. 31263 @return {Object} return value from invoking the passed function. 31264 @public 31265 */ 31266 31267 function run() { 31268 return backburner.run.apply(backburner, arguments); 31269 } 31270 31271 /** 31272 If no run-loop is present, it creates a new one. If a run loop is 31273 present it will queue itself to run on the existing run-loops action 31274 queue. 31275 31276 Please note: This is not for normal usage, and should be used sparingly. 31277 31278 If invoked when not within a run loop: 31279 31280 ```javascript 31281 run.join(function() { 31282 // creates a new run-loop 31283 }); 31284 ``` 31285 31286 Alternatively, if called within an existing run loop: 31287 31288 ```javascript 31289 run(function() { 31290 // creates a new run-loop 31291 run.join(function() { 31292 // joins with the existing run-loop, and queues for invocation on 31293 // the existing run-loops action queue. 31294 }); 31295 }); 31296 ``` 31297 31298 @method join 31299 @namespace Ember 31300 @param {Object} [target] target of method to call 31301 @param {Function|String} method Method to invoke. 31302 May be a function or a string. If you pass a string 31303 then it will be looked up on the passed target. 31304 @param {Object} [args*] Any additional arguments you wish to pass to the method. 31305 @return {Object} Return value from invoking the passed function. Please note, 31306 when called within an existing loop, no return value is possible. 31307 @public 31308 */ 31309 run.join = function () { 31310 return backburner.join.apply(backburner, arguments); 31311 }; 31312 31313 /** 31314 Allows you to specify which context to call the specified function in while 31315 adding the execution of that function to the Ember run loop. This ability 31316 makes this method a great way to asynchronously integrate third-party libraries 31317 into your Ember application. 31318 31319 `run.bind` takes two main arguments, the desired context and the function to 31320 invoke in that context. Any additional arguments will be supplied as arguments 31321 to the function that is passed in. 31322 31323 Let's use the creation of a TinyMCE component as an example. Currently, 31324 TinyMCE provides a setup configuration option we can use to do some processing 31325 after the TinyMCE instance is initialized but before it is actually rendered. 31326 We can use that setup option to do some additional setup for our component. 31327 The component itself could look something like the following: 31328 31329 ```javascript 31330 App.RichTextEditorComponent = Ember.Component.extend({ 31331 initializeTinyMCE: Ember.on('didInsertElement', function() { 31332 tinymce.init({ 31333 selector: '#' + this.$().prop('id'), 31334 setup: Ember.run.bind(this, this.setupEditor) 31335 }); 31336 }), 31337 31338 setupEditor: function(editor) { 31339 this.set('editor', editor); 31340 31341 editor.on('change', function() { 31342 console.log('content changed!'); 31343 }); 31344 } 31345 }); 31346 ``` 31347 31348 In this example, we use Ember.run.bind to bind the setupEditor method to the 31349 context of the App.RichTextEditorComponent and to have the invocation of that 31350 method be safely handled and executed by the Ember run loop. 31351 31352 @method bind 31353 @namespace Ember 31354 @param {Object} [target] target of method to call 31355 @param {Function|String} method Method to invoke. 31356 May be a function or a string. If you pass a string 31357 then it will be looked up on the passed target. 31358 @param {Object} [args*] Any additional arguments you wish to pass to the method. 31359 @return {Function} returns a new function that will always have a particular context 31360 @since 1.4.0 31361 @public 31362 */ 31363 run.bind = function () { 31364 for (var _len = arguments.length, curried = Array(_len), _key = 0; _key < _len; _key++) { 31365 curried[_key] = arguments[_key]; 31366 } 31367 31368 return function () { 31369 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 31370 args[_key2] = arguments[_key2]; 31371 } 31372
31373 return run.join.apply(run, curried.concat(args)); 31374 }; 31375 }; 31376 31377 run.backburner = backburner; 31378 run.currentRunLoop = null; 31379 run.queues = backburner.queueNames; 31380 31381 /** 31382 Begins a new RunLoop. Any deferred actions invoked after the begin will 31383 be buffered until you invoke a matching call to `run.end()`. This is 31384 a lower-level way to use a RunLoop instead of using `run()`. 31385 31386 ```javascript 31387 run.begin(); 31388 // code to be executed within a RunLoop 31389 run.end(); 31390 ``` 31391 31392 @method begin 31393 @return {void} 31394 @public 31395 */ 31396 run.begin = function () { 31397 backburner.begin(); 31398 }; 31399 31400 /** 31401 Ends a RunLoop. This must be called sometime after you call 31402 `run.begin()` to flush any deferred actions. This is a lower-level way 31403 to use a RunLoop instead of using `run()`. 31404 31405 ```javascript 31406 run.begin(); 31407 // code to be executed within a RunLoop 31408 run.end(); 31409 ``` 31410 31411 @method end 31412 @return {void} 31413 @public 31414 */ 31415 run.end = function () { 31416 backburner.end(); 31417 }; 31418 31419 /** 31420 Array of named queues. This array determines the order in which queues 31421 are flushed at the end of the RunLoop. You can define your own queues by 31422 simply adding the queue name to this array. Normally you should not need 31423 to inspect or modify this property. 31424 31425 @property queues 31426 @type Array 31427 @default ['sync', 'actions', 'destroy'] 31428 @private 31429 */ 31430 31431 /** 31432 Adds the passed target/method and any optional arguments to the named 31433 queue to be executed at the end of the RunLoop. If you have not already 31434 started a RunLoop when calling this method one will be started for you 31435 automatically. 31436 31437 At the end of a RunLoop, any methods scheduled in this way will be invoked. 31438 Methods will be invoked in an order matching the named queues defined in 31439 the `run.queues` property. 31440 31441 ```javascript 31442 run.schedule('sync', this, function() { 31443 // this will be executed in the first RunLoop queue, when bindings are synced 31444 console.log('scheduled on sync queue'); 31445 }); 31446 31447 run.schedule('actions', this, function() { 31448 // this will be executed in the 'actions' queue, after bindings have synced. 31449 console.log('scheduled on actions queue'); 31450 }); 31451 31452 // Note the functions will be run in order based on the run queues order. 31453 // Output would be: 31454 // scheduled on sync queue 31455 // scheduled on actions queue 31456 ``` 31457 31458 @method schedule 31459 @param {String} queue The name of the queue to schedule against. 31460 Default queues are 'sync' and 'actions' 31461 @param {Object} [target] target object to use as the context when invoking a method. 31462 @param {String|Function} method The method to invoke. If you pass a string it 31463 will be resolved on the target object at the time the scheduled item is 31464 invoked allowing you to change the target function. 31465 @param {Object} [arguments*] Optional arguments to be passed to the queued method. 31466 @return {void} 31467 @public 31468 */ 31469 run.schedule = function () /* queue, target, method */{ 31470 checkAutoRun(); 31471 backburner.schedule.apply(backburner, arguments); 31472 }; 31473 31474 // Used by global test teardown 31475 run.hasScheduledTimers = function () { 31476 return backburner.hasTimers(); 31477 }; 31478 31479 // Used by global test teardown 31480 run.cancelTimers = function () { 31481 backburner.cancelTimers(); 31482 }; 31483 31484 /** 31485 Immediately flushes any events scheduled in the 'sync' queue. Bindings 31486 use this queue so this method is a useful way to immediately force all 31487 bindings in the application to sync. 31488 31489 You should call this method anytime you need any changed state to propagate 31490 throughout the app immediately without repainting the UI (which happens 31491 in the later 'render' queue added by the `ember-views` package). 31492 31493 ```javascript 31494 run.sync(); 31495 ``` 31496 31497 @method sync 31498 @return {void} 31499 @private 31500 */ 31501 run.sync = function () { 31502 if (backburner.currentInstance) { 31503 backburner.currentInstance.queues.sync.flush(); 31504 } 31505 }; 31506 31507 /** 31508 Invokes the passed target/method and optional arguments after a specified
31509 period of time. The last parameter of this method must always be a number 31510 of milliseconds. 31511 31512 You should use this method whenever you need to run some action after a 31513 period of time instead of using `setTimeout()`. This method will ensure that 31514 items that expire during the same script execution cycle all execute 31515 together, which is often more efficient than using a real setTimeout. 31516 31517 ```javascript 31518 run.later(myContext, function() { 31519 // code here will execute within a RunLoop in about 500ms with this == myContext 31520 }, 500); 31521 ``` 31522 31523 @method later 31524 @param {Object} [target] target of method to invoke 31525 @param {Function|String} method The method to invoke. 31526 If you pass a string it will be resolved on the 31527 target at the time the method is invoked. 31528 @param {Object} [args*] Optional arguments to pass to the timeout. 31529 @param {Number} wait Number of milliseconds to wait. 31530 @return {*} Timer information for use in cancelling, see `run.cancel`. 31531 @public 31532 */ 31533 run.later = function () /*target, method*/{ 31534 return backburner.later.apply(backburner, arguments); 31535 }; 31536 31537 /** 31538 Schedule a function to run one time during the current RunLoop. This is equivalent 31539 to calling `scheduleOnce` with the "actions" queue. 31540 31541 @method once 31542 @param {Object} [target] The target of the method to invoke. 31543 @param {Function|String} method The method to invoke. 31544 If you pass a string it will be resolved on the 31545 target at the time the method is invoked. 31546 @param {Object} [args*] Optional arguments to pass to the timeout. 31547 @return {Object} Timer information for use in cancelling, see `run.cancel`. 31548 @public 31549 */ 31550 run.once = function () { 31551 checkAutoRun(); 31552 31553 for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { 31554 args[_key3] = arguments[_key3]; 31555 } 31556 31557 args.unshift('actions'); 31558 return backburner.scheduleOnce.apply(backburner, args); 31559 }; 31560 31561 /** 31562 Schedules a function to run one time in a given queue of the current RunLoop. 31563 Calling this method with the same queue/target/method combination will have 31564 no effect (past the initial call). 31565 31566 Note that although you can pass optional arguments these will not be 31567 considered when looking for duplicates. New arguments will replace previous 31568 calls. 31569 31570 ```javascript 31571 function sayHi() { 31572 console.log('hi'); 31573 } 31574 31575 run(function() { 31576 run.scheduleOnce('afterRender', myContext, sayHi); 31577 run.scheduleOnce('afterRender', myContext, sayHi); 31578 // sayHi will only be executed once, in the afterRender queue of the RunLoop 31579 }); 31580 ``` 31581 31582 Also note that passing an anonymous function to `run.scheduleOnce` will 31583 not prevent additional calls with an identical anonymous function from 31584 scheduling the items multiple times, e.g.: 31585 31586 ```javascript 31587 function scheduleIt() { 31588 run.scheduleOnce('actions', myContext, function() { 31589 console.log('Closure'); 31590 }); 31591 } 31592 31593 scheduleIt(); 31594 scheduleIt(); 31595 31596 // "Closure" will print twice, even though we're using `run.scheduleOnce`, 31597 // because the function we pass to it is anonymous and won't match the 31598 // previously scheduled operation. 31599 ``` 31600 31601 Available queues, and their order, can be found at `run.queues` 31602 31603 @method scheduleOnce 31604 @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'. 31605 @param {Object} [target] The target of the method to invoke. 31606 @param {Function|String} method The method to invoke. 31607 If you pass a string it will be resolved on the 31608 target at the time the method is invoked. 31609 @param {Object} [args*] Optional arguments to pass to the timeout. 31610 @return {Object} Timer information for use in cancelling, see `run.cancel`. 31611 @public 31612 */ 31613 run.scheduleOnce = function () /*queue, target, method*/{ 31614 checkAutoRun(); 31615 return backburner.scheduleOnce.apply(backburner, arguments); 31616 }; 31617 31618 /** 31619 Schedules an item to run from within a separate run loop, after 31620 control has been returned to the system. This is equivalent to calling 31621 `run.later` with a wait time of 1ms. 31622 31623 ```javascript 31624 run.next(myContext, function() { 31625 // code to be executed in the next run loop, 31626 // which will be scheduled after the current one 31627 }); 31628 ``` 31629 31630 Multiple operations scheduled with `run.next` will coalesce 31631 into the same later run loop, along with any other operations 31632 scheduled by `run.later` that expire right around the same 31633 time that `run.next` operations will fire. 31634 31635 Note that there are often alternatives to using `run.next`. 31636 For instance, if you'd like to schedule an operation to happen 31637 after all DOM element operations have completed within the current 31638 run loop, you can make use of the `afterRender` run loop queue (added 31639 by the `ember-views` package, along with the preceding `render` queue 31640 where all the DOM element operations happen). Example: 31641 31642 ```javascript 31643 App.MyCollectionView = Ember.CollectionView.extend({ 31644 didInsertElement: function() { 31645 run.scheduleOnce('afterRender', this, 'processChildElements'); 31646 }, 31647 processChildElements: function() { 31648 // ... do something with collectionView's child view 31649 // elements after they've finished rendering, which 31650 // can't be done within the CollectionView's 31651 // `didInsertElement` hook because that gets run 31652 // before the child elements have been added to the DOM. 31653 } 31654 }); 31655 ``` 31656
31657 One benefit of the above approach compared to using `run.next` is 31658 that you will be able to perform DOM/CSS operations before unprocessed 31659 elements are rendered to the screen, which may prevent flickering or 31660 other artifacts caused by delaying processing until after rendering. 31661 31662 The other major benefit to the above approach is that `run.next` 31663 introduces an element of non-determinism, which can make things much 31664 harder to test, due to its reliance on `setTimeout`; it's much harder 31665 to guarantee the order of scheduled operations when they are scheduled 31666 outside of the current run loop, i.e. with `run.next`. 31667 31668 @method next 31669 @param {Object} [target] target of method to invoke 31670 @param {Function|String} method The method to invoke. 31671 If you pass a string it will be resolved on the 31672 target at the time the method is invoked. 31673 @param {Object} [args*] Optional arguments to pass to the timeout. 31674 @return {Object} Timer information for use in cancelling, see `run.cancel`. 31675 @public 31676 */ 31677 run.next = function () { 31678 for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { 31679 args[_key4] = arguments[_key4]; 31680 } 31681 31682 args.push(1); 31683 return backburner.later.apply(backburner, args); 31684 }; 31685 31686 /** 31687 Cancels a scheduled item. Must be a value returned by `run.later()`, 31688 `run.once()`, `run.scheduleOnce()`, `run.next()`, `run.debounce()`, or 31689 `run.throttle()`. 31690 31691 ```javascript 31692 var runNext = run.next(myContext, function() { 31693 // will not be executed 31694 }); 31695 31696 run.cancel(runNext); 31697 31698 var runLater = run.later(myContext, function() { 31699 // will not be executed 31700 }, 500); 31701 31702 run.cancel(runLater); 31703 31704 var runScheduleOnce = run.scheduleOnce('afterRender', myContext, function() { 31705 // will not be executed 31706 }); 31707 31708 run.cancel(runScheduleOnce); 31709 31710 var runOnce = run.once(myContext, function() { 31711 // will not be executed 31712 }); 31713 31714 run.cancel(runOnce); 31715 31716 var throttle = run.throttle(myContext, function() { 31717 // will not be executed 31718 }, 1, false); 31719 31720 run.cancel(throttle); 31721 31722 var debounce = run.debounce(myContext, function() { 31723 // will not be executed 31724 }, 1); 31725 31726 run.cancel(debounce); 31727 31728 var debounceImmediate = run.debounce(myContext, function() { 31729 // will be executed since we passed in true (immediate) 31730 }, 100, true); 31731 31732 // the 100ms delay until this method can be called again will be cancelled 31733 run.cancel(debounceImmediate); 31734 ``` 31735 31736 @method cancel 31737 @param {Object} timer Timer object to cancel 31738 @return {Boolean} true if cancelled or false/undefined if it wasn't found 31739 @public 31740 */ 31741 run.cancel = function (timer) { 31742 return backburner.cancel(timer); 31743 }; 31744 31745 /** 31746 Delay calling the target method until the debounce period has elapsed 31747 with no additional debounce calls. If `debounce` is called again before 31748 the specified time has elapsed, the timer is reset and the entire period 31749 must pass again before the target method is called. 31750 31751 This method should be used when an event may be called multiple times 31752 but the action should only be called once when the event is done firing. 31753 A common example is for scroll events where you only want updates to 31754 happen once scrolling has ceased. 31755 31756 ```javascript 31757 function whoRan() { 31758 console.log(this.name + ' ran.'); 31759 } 31760 31761 var myContext = { name: 'debounce' }; 31762 31763 run.debounce(myContext, whoRan, 150); 31764 31765 // less than 150ms passes 31766 run.debounce(myContext, whoRan, 150); 31767 31768 // 150ms passes 31769 // whoRan is invoked with context myContext 31770 // console logs 'debounce ran.' one time. 31771 ``` 31772 31773 Immediate allows you to run the function immediately, but debounce 31774 other calls for this function until the wait time has elapsed. If 31775 `debounce` is called again before the specified time has elapsed, 31776 the timer is reset and the entire period must pass again before 31777 the method can be called again. 31778 31779 ```javascript 31780 function whoRan() { 31781 console.log(this.name + ' ran.'); 31782 } 31783 31784 var myContext = { name: 'debounce' }; 31785 31786 run.debounce(myContext, whoRan, 150, true); 31787 31788 // console logs 'debounce ran.' one time immediately. 31789 // 100ms passes 31790 run.debounce(myContext, whoRan, 150, true); 31791 31792 // 150ms passes and nothing else is logged to the console and 31793 // the debouncee is no longer being watched 31794 run.debounce(myContext, whoRan, 150, true); 31795 31796 // console logs 'debounce ran.' one time immediately. 31797 // 150ms passes and nothing else is logged to the console and 31798 // the debouncee is no longer being watched 31799 31800 ``` 31801 31802 @method debounce 31803 @param {Object} [target] target of method to invoke 31804 @param {Function|String} method The method to invoke. 31805 May be a function or a string. If you pass a string 31806 then it will be looked up on the passed target. 31807 @param {Object} [args*] Optional arguments to pass to the timeout. 31808 @param {Number} wait Number of milliseconds to wait. 31809 @param {Boolean} immediate Trigger the function on the leading instead 31810 of the trailing edge of the wait interval. Defaults to false. 31811 @return {Array} Timer information for use in cancelling, see `run.cancel`. 31812 @public 31813 */ 31814 run.debounce = function () {
31815 return backburner.debounce.apply(backburner, arguments); 31816 }; 31817 31818 /** 31819 Ensure that the target method is never called more frequently than 31820 the specified spacing period. The target method is called immediately. 31821 31822 ```javascript 31823 function whoRan() { 31824 console.log(this.name + ' ran.'); 31825 } 31826 31827 var myContext = { name: 'throttle' }; 31828 31829 run.throttle(myContext, whoRan, 150); 31830 // whoRan is invoked with context myContext 31831 // console logs 'throttle ran.' 31832 31833 // 50ms passes 31834 run.throttle(myContext, whoRan, 150); 31835 31836 // 50ms passes 31837 run.throttle(myContext, whoRan, 150); 31838 31839 // 150ms passes 31840 run.throttle(myContext, whoRan, 150); 31841 // whoRan is invoked with context myContext 31842 // console logs 'throttle ran.' 31843 ``` 31844 31845 @method throttle 31846 @param {Object} [target] target of method to invoke 31847 @param {Function|String} method The method to invoke. 31848 May be a function or a string. If you pass a string 31849 then it will be looked up on the passed target. 31850 @param {Object} [args*] Optional arguments to pass to the timeout. 31851 @param {Number} spacing Number of milliseconds to space out requests. 31852 @param {Boolean} immediate Trigger the function on the leading instead 31853 of the trailing edge of the wait interval. Defaults to true. 31854 @return {Array} Timer information for use in cancelling, see `run.cancel`. 31855 @public 31856 */ 31857 run.throttle = function () { 31858 return backburner.throttle.apply(backburner, arguments); 31859 }; 31860 31861 // Make sure it's not an autorun during testing 31862 function checkAutoRun() { 31863 if (!run.currentRunLoop) { 31864 _emberMetalDebug.assert('You have turned on testing mode, which disabled the run-loop\'s autorun. ' + 'You will need to wrap any code with asynchronous side-effects in a run', !_emberMetalCore.default.testing); 31865 } 31866 } 31867 31868 /** 31869 Add a new named queue after the specified queue. 31870 31871 The queue to add will only be added once. 31872 31873 @method _addQueue 31874 @param {String} name the name of the queue to add. 31875 @param {String} after the name of the queue to add after. 31876 @private 31877 */ 31878 run._addQueue = function (name, after) { 31879 if (run.queues.indexOf(name) === -1) { 31880 run.queues.splice(run.queues.indexOf(after) + 1, 0, name); 31881 } 31882 }; 31883}); 31884enifed('ember-metal/set_properties', ['exports', 'ember-metal/property_events', 'ember-metal/property_set'], function (exports, _emberMetalProperty_events, _emberMetalProperty_set) { 31885 'use strict'; 31886 31887 exports.default = setProperties; 31888 31889 /** 31890 Set a list of properties on an object. These properties are set inside 31891 a single `beginPropertyChanges` and `endPropertyChanges` batch, so 31892 observers will be buffered. 31893 31894 ```javascript 31895 var anObject = Ember.Object.create(); 31896 31897 anObject.setProperties({ 31898 firstName: 'Stanley', 31899 lastName: 'Stuart', 31900 age: 21 31901 }); 31902 ``` 31903 31904 @method setProperties 31905 @param obj 31906 @param {Object} properties 31907 @return properties 31908 @public 31909 */ 31910 31911 function setProperties(obj, properties) { 31912 if (!properties || typeof properties !== 'object') { 31913 return properties; 31914 } 31915 _emberMetalProperty_events.changeProperties(function () { 31916 var props = Object.keys(properties); 31917 var propertyName; 31918 31919 for (var i = 0, l = props.length; i < l; i++) { 31920 propertyName = props[i]; 31921 31922 _emberMetalProperty_set.set(obj, propertyName, properties[propertyName]); 31923 } 31924 }); 31925 return properties; 31926 } 31927}); 31928enifed('ember-metal/streams/dependency', ['exports', 'ember-metal/debug', 'ember-metal/assign', 'ember-metal/streams/utils'], function (exports, _emberMetalDebug, _emberMetalAssign, _emberMetalStreamsUtils) { 31929 'use strict'; 31930 31931 /** 31932 @module ember-metal 31933 */ 31934 31935 /** 31936 @private 31937 @class Dependency 31938 @namespace Ember.streams 31939 @constructor 31940 */ 31941 function Dependency(depender, dependee) { 31942 _emberMetalDebug.assert('Dependency error: Depender must be a stream', _emberMetalStreamsUtils.isStream(depender)); 31943 31944 this.next = null; 31945 this.prev = null; 31946 this.depender = depender; 31947 this.dependee = dependee; 31948 this.unsubscription = null; 31949 } 31950 31951 _emberMetalAssign.default(Dependency.prototype, { 31952 subscribe: function () { 31953 _emberMetalDebug.assert('Dependency error: Dependency tried to subscribe while already subscribed', !this.unsubscription); 31954 31955 this.unsubscription = _emberMetalStreamsUtils.subscribe(this.dependee, this.depender.notify, this.depender); 31956 }, 31957 31958 unsubscribe: function () { 31959 if (this.unsubscription) { 31960 this.unsubscription(); 31961 this.unsubscription = null; 31962 } 31963 }, 31964 31965 replace: function (dependee) { 31966 if (this.dependee !== dependee) { 31967 this.dependee = dependee; 31968 31969 if (this.unsubscription) { 31970 this.unsubscribe(); 31971 this.subscribe(); 31972 } 31973 return true; 31974 } 31975 return false;
31976 }, 31977 31978 getValue: function () { 31979 return _emberMetalStreamsUtils.read(this.dependee); 31980 }, 31981 31982 setValue: function (value) { 31983 return _emberMetalStreamsUtils.setValue(this.dependee, value); 31984 } 31985 31986 // destroy() { 31987 // var next = this.next; 31988 // var prev = this.prev; 31989 31990 // if (prev) { 31991 // prev.next = next; 31992 // } else { 31993 // this.depender.dependencyHead = next; 31994 // } 31995 31996 // if (next) { 31997 // next.prev = prev; 31998 // } else { 31999 // this.depender.dependencyTail = prev; 32000 // } 32001 32002 // this.unsubscribe(); 32003 // } 32004 }); 32005 32006 exports.default = Dependency; 32007}); 32008enifed('ember-metal/streams/key-stream', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/observer', 'ember-metal/streams/stream', 'ember-metal/streams/utils'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalObserver, _emberMetalStreamsStream, _emberMetalStreamsUtils) { 32009 'use strict'; 32010 32011 function labelFor(source, key) { 32012 return source.label ? source.label + '.' + key : key; 32013 } 32014 32015 exports.default = _emberMetalStreamsStream.default.extend({ 32016 init: function (source, key) { 32017 _emberMetalDebug.assert('KeyStream error: source must be a stream', _emberMetalStreamsUtils.isStream(source)); // TODO: This isn't necessary. 32018 _emberMetalDebug.assert('KeyStream error: key must be a non-empty string', typeof key === 'string' && key.length > 0); 32019 _emberMetalDebug.assert('KeyStream error: key must not have a \'.\'', key.indexOf('.') === -1); 32020 32021 var label = labelFor(source, key); 32022 32023 this.path = label; 32024 this.observedObject = null; 32025 this.key = key; 32026 this.sourceDep = this.addMutableDependency(source); 32027 this.label = label; 32028 }, 32029 32030 compute: function () { 32031 var object = this.sourceDep.getValue(); 32032 var type = typeof object; 32033 32034 if (!object || type === 'boolean') { 32035 return; 32036 } 32037 32038 if (type === 'object') { 32039 return _emberMetalProperty_get.get(object, this.key); 32040 } 32041 32042 return object[this.key]; 32043 }, 32044 32045 setValue: function (value) { 32046 var object = this.sourceDep.getValue(); 32047 if (object) { 32048 _emberMetalProperty_set.set(object, this.key, value); 32049 } 32050 }, 32051 32052 setSource: function (source) { 32053 this.sourceDep.replace(source); 32054 this.notify(); 32055 }, 32056 32057 _super$revalidate: _emberMetalStreamsStream.default.prototype.revalidate, 32058 32059 revalidate: function (value) { 32060 this._super$revalidate(value); 32061 32062 var object = this.sourceDep.getValue(); 32063 if (object !== this.observedObject) { 32064 this._clearObservedObject(); 32065 32066 if (object && typeof object === 'object') { 32067 _emberMetalObserver.addObserver(object, this.key, this, this.notify); 32068 this.observedObject = object; 32069 } 32070 } 32071 }, 32072 32073 _super$deactivate: _emberMetalStreamsStream.default.prototype.deactivate, 32074 32075 _clearObservedObject: function () { 32076 if (this.observedObject) { 32077 _emberMetalObserver.removeObserver(this.observedObject, this.key, this, this.notify); 32078 this.observedObject = null; 32079 } 32080 }, 32081 32082 deactivate: function () { 32083 this._super$deactivate(); 32084 this._clearObservedObject(); 32085 } 32086 }); 32087}); 32088enifed('ember-metal/streams/proxy-stream', ['exports', 'ember-runtime/system/object', 'ember-metal/streams/stream'], function (exports, _emberRuntimeSystemObject, _emberMetalStreamsStream) { 32089 'use strict'; 32090 32091 var ProxyStream = _emberMetalStreamsStream.default.extend({ 32092 init: function (source, label) { 32093 this.label = label; 32094 this.sourceDep = this.addMutableDependency(source); 32095 }, 32096 32097 compute: function () { 32098 return this.sourceDep.getValue(); 32099 }, 32100 32101 setValue: function (value) { 32102 this.sourceDep.setValue(value); 32103 }, 32104 32105 setSource: function (source) { 32106 var didChange = this.sourceDep.replace(source); 32107 if (didChange || !(source instanceof _emberRuntimeSystemObject.default)) { 32108 // If the source changed, we must notify. If the source is not
32109 // an Ember.Object, we must also notify, because it could have 32110 // interior mutability that is otherwise not being observed. 32111 this.notify(); 32112 } 32113 } 32114 }); 32115 32116 ProxyStream.extend = _emberMetalStreamsStream.default.extend; 32117 32118 exports.default = ProxyStream; 32119}); 32120enifed('ember-metal/streams/stream', ['exports', 'ember-metal/assign', 'ember-metal/debug', 'ember-metal/path_cache', 'ember-metal/observer', 'ember-metal/streams/utils', 'ember-metal/empty_object', 'ember-metal/streams/subscriber', 'ember-metal/streams/dependency', 'ember-metal/utils', 'require', 'ember-metal/symbol'], function (exports, _emberMetalAssign, _emberMetalDebug, _emberMetalPath_cache, _emberMetalObserver, _emberMetalStreamsUtils, _emberMetalEmpty_object, _emberMetalStreamsSubscriber, _emberMetalStreamsDependency, _emberMetalUtils, _require, _emberMetalSymbol) { 32121 'use strict'; 32122 32123 exports.wrap = wrap; 32124 var IS_STREAM = _emberMetalSymbol.default('IS_STREAM'); 32125 32126 exports.IS_STREAM = IS_STREAM; 32127 /** 32128 @module ember-metal 32129 */ 32130 32131 /** 32132 @private 32133 @class Stream 32134 @namespace Ember.stream 32135 @constructor 32136 */ 32137 function BasicStream(label) { 32138 this._init(label); 32139 } 32140 32141 var KeyStream; 32142 var ProxyMixin; 32143 32144 BasicStream.prototype = { 32145 _init: function (label) { 32146 this[IS_STREAM] = true; 32147 this.label = makeLabel(label); 32148 this.isActive = false; 32149 this.isDirty = true; 32150 this.isDestroyed = false; 32151 this.cache = undefined; 32152 this.children = undefined; 32153 this.subscriberHead = null; 32154 this.subscriberTail = null; 32155 this.dependencyHead = null; 32156 this.dependencyTail = null; 32157 this.observedProxy = null; 32158 this.__ember_meta__ = null; 32159 this[_emberMetalUtils.GUID_KEY] = null; 32160 }, 32161 32162 _makeChildStream: function (key) { 32163 KeyStream = KeyStream || _require.default('ember-metal/streams/key-stream').default; 32164 return new KeyStream(this, key); 32165 }, 32166 32167 removeChild: function (key) { 32168 delete this.children[key]; 32169 }, 32170 32171 getKey: function (key) { 32172 if (this.children === undefined) { 32173 this.children = new _emberMetalEmpty_object.default(); 32174 } 32175 32176 var keyStream = this.children[key]; 32177 32178 if (keyStream === undefined) { 32179 keyStream = this._makeChildStream(key); 32180 this.children[key] = keyStream; 32181 } 32182 32183 return keyStream; 32184 }, 32185 32186 get: function (path) { 32187 var firstKey = _emberMetalPath_cache.getFirstKey(path); 32188 var tailPath = _emberMetalPath_cache.getTailPath(path); 32189 32190 if (this.children === undefined) { 32191 this.children = new _emberMetalEmpty_object.default(); 32192 } 32193 32194 var keyStream = this.children[firstKey]; 32195 32196 if (keyStream === undefined) { 32197 keyStream = this._makeChildStream(firstKey, path); 32198 this.children[firstKey] = keyStream; 32199 } 32200 32201 if (tailPath === undefined) { 32202 return keyStream; 32203 } else { 32204 return keyStream.get(tailPath); 32205 } 32206 }, 32207 32208 value: function () { 32209 // TODO: Ensure value is never called on a destroyed stream 32210 // so that we can uncomment this assertion. 32211 // 32212 // assert("Stream error: value was called after the stream was destroyed", !this.isDestroyed); 32213 32214 // TODO: Remove this block. This will require ensuring we are 32215 // not treating streams as "volatile" anywhere. 32216 if (!this.isActive) { 32217 this.isDirty = true; 32218 } 32219 32220 var willRevalidate = false; 32221 32222 if (!this.isActive && this.subscriberHead) { 32223 this.activate(); 32224 willRevalidate = true; 32225 } 32226 32227 if (this.isDirty) { 32228 if (this.isActive) { 32229 willRevalidate = true; 32230 } 32231 32232 this.cache = this.compute(); 32233 this.isDirty = false; 32234 } 32235 32236 if (willRevalidate) { 32237 this.revalidate(this.cache); 32238 } 32239 32240 return this.cache; 32241 }, 32242 32243 addMutableDependency: function (object) { 32244 var dependency = new _emberMetalStreamsDependency.default(this, object); 32245 32246 if (this.isActive) { 32247 dependency.subscribe(); 32248 } 32249 32250 if (this.dependencyHead === null) { 32251 this.dependencyHead = this.dependencyTail = dependency; 32252 } else { 32253 var tail = this.dependencyTail; 32254 tail.next = dependency; 32255 dependency.prev = tail; 32256 this.dependencyTail = dependency; 32257 } 32258
32259 return dependency; 32260 }, 32261 32262 addDependency: function (object) { 32263 if (_emberMetalStreamsUtils.isStream(object)) { 32264 this.addMutableDependency(object); 32265 } 32266 }, 32267 32268 subscribeDependencies: function () { 32269 var dependency = this.dependencyHead; 32270 while (dependency) { 32271 var next = dependency.next; 32272 dependency.subscribe(); 32273 dependency = next; 32274 } 32275 }, 32276 32277 unsubscribeDependencies: function () { 32278 var dependency = this.dependencyHead; 32279 while (dependency) { 32280 var next = dependency.next; 32281 dependency.unsubscribe(); 32282 dependency = next; 32283 } 32284 }, 32285 32286 maybeDeactivate: function () { 32287 if (!this.subscriberHead && this.isActive) { 32288 this.isActive = false; 32289 this.unsubscribeDependencies(); 32290 this.deactivate(); 32291 } 32292 }, 32293 32294 activate: function () { 32295 this.isActive = true; 32296 this.subscribeDependencies(); 32297 }, 32298 32299 revalidate: function (value) { 32300 if (value !== this.observedProxy) { 32301 this._clearObservedProxy(); 32302 32303 ProxyMixin = ProxyMixin || _require.default('ember-runtime/mixins/-proxy').default; 32304 32305 if (ProxyMixin.detect(value)) { 32306 _emberMetalObserver.addObserver(value, 'content', this, this.notify); 32307 this.observedProxy = value; 32308 } 32309 } 32310 }, 32311 32312 _clearObservedProxy: function () { 32313 if (this.observedProxy) { 32314 _emberMetalObserver.removeObserver(this.observedProxy, 'content', this, this.notify); 32315 this.observedProxy = null; 32316 } 32317 }, 32318 32319 deactivate: function () { 32320 this._clearObservedProxy(); 32321 }, 32322 32323 compute: function () { 32324 throw new Error('Stream error: compute not implemented'); 32325 }, 32326 32327 setValue: function () { 32328 throw new Error('Stream error: setValue not implemented'); 32329 }, 32330 32331 notify: function () { 32332 this.notifyExcept(); 32333 }, 32334 32335 notifyExcept: function (callbackToSkip, contextToSkip) { 32336 if (!this.isDirty) { 32337 this.isDirty = true; 32338 this.notifySubscribers(callbackToSkip, contextToSkip); 32339 } 32340 }, 32341 32342 subscribe: function (callback, context) { 32343 _emberMetalDebug.assert('You tried to subscribe to a stream but the callback provided was not a function.', typeof callback === 'function'); 32344 32345 var subscriber = new _emberMetalStreamsSubscriber.default(callback, context, this); 32346 if (this.subscriberHead === null) { 32347 this.subscriberHead = this.subscriberTail = subscriber; 32348 } else { 32349 var tail = this.subscriberTail; 32350 tail.next = subscriber; 32351 subscriber.prev = tail; 32352 this.subscriberTail = subscriber; 32353 } 32354 32355 var stream = this; 32356 return function (prune) { 32357 subscriber.removeFrom(stream); 32358 if (prune) { 32359 stream.prune(); 32360 } 32361 }; 32362 }, 32363 32364 prune: function () { 32365 if (this.subscriberHead === null) { 32366 this.destroy(true); 32367 } 32368 }, 32369 32370 unsubscribe: function (callback, context) { 32371 var subscriber = this.subscriberHead; 32372 32373 while (subscriber) { 32374 var next = subscriber.next; 32375 if (subscriber.callback === callback && subscriber.context === context) { 32376 subscriber.removeFrom(this); 32377 } 32378 subscriber = next; 32379 } 32380 }, 32381 32382 notifySubscribers: function (callbackToSkip, contextToSkip) { 32383 var subscriber = this.subscriberHead; 32384 32385 while (subscriber) { 32386 var next = subscriber.next; 32387 32388 var callback = subscriber.callback; 32389 var context = subscriber.context; 32390 32391 subscriber = next; 32392 32393 if (callback === callbackToSkip && context === contextToSkip) { 32394 continue; 32395 } 32396 32397 if (context === undefined) { 32398 callback(this); 32399 } else { 32400 callback.call(context, this); 32401 } 32402 } 32403 }, 32404 32405 destroy: function (prune) { 32406 if (!this.isDestroyed) { 32407 this.isDestroyed = true; 32408 32409 this.subscriberHead = this.subscriberTail = null; 32410 this.maybeDeactivate(); 32411 32412 var dependencies = this.dependencies; 32413 32414 if (dependencies) { 32415 for (var i = 0, l = dependencies.length; i < l; i++) { 32416 dependencies[i](prune); 32417 } 32418 } 32419 32420 return true; 32421 } 32422 } 32423 }; 32424 32425 BasicStream.extend = function (object) { 32426 var Child = function () { 32427 this._init(); 32428 this.init.apply(this, arguments); 32429 32430 _emberMetalDebug.debugSeal(this); 32431 }; 32432 32433 Child.prototype = Object.create(this.prototype); 32434 32435 _emberMetalAssign.default(Child.prototype, object); 32436 Child.extend = BasicStream.extend; 32437 return Child; 32438 }; 32439 32440 var Stream = BasicStream.extend({ 32441 init: function (fn, label) { 32442 this._compute = fn; 32443 this.label = label; 32444 }, 32445 32446 compute: function () { 32447 return this._compute(); 32448 } 32449 }); 32450 32451 function wrap(value, Kind, param) { 32452 if (_emberMetalStreamsUtils.isStream(value)) { 32453 return value; 32454 } else { 32455 return new Kind(value, param); 32456 } 32457 } 32458 32459 function makeLabel(label) { 32460 if (label === undefined) { 32461 return '(no label)'; 32462 } else { 32463 return label; 32464 } 32465 } 32466 32467 exports.default = BasicStream; 32468 exports.Stream = Stream; 32469});
32470enifed('ember-metal/streams/subscriber', ['exports', 'ember-metal/assign'], function (exports, _emberMetalAssign) { 32471 'use strict'; 32472 32473 /** 32474 @module ember-metal 32475 */ 32476 32477 /** 32478 @private 32479 @class Subscriber 32480 @namespace Ember.streams 32481 @constructor 32482 */ 32483 function Subscriber(callback, context) { 32484 this.next = null; 32485 this.prev = null; 32486 this.callback = callback; 32487 this.context = context; 32488 } 32489 32490 _emberMetalAssign.default(Subscriber.prototype, { 32491 removeFrom: function (stream) { 32492 var next = this.next; 32493 var prev = this.prev; 32494 32495 if (prev) { 32496 prev.next = next; 32497 } else { 32498 stream.subscriberHead = next; 32499 } 32500 32501 if (next) { 32502 next.prev = prev; 32503 } else { 32504 stream.subscriberTail = prev; 32505 } 32506 32507 stream.maybeDeactivate(); 32508 } 32509 }); 32510 32511 exports.default = Subscriber; 32512}); 32513enifed('ember-metal/streams/utils', ['exports', 'ember-metal/debug', 'ember-metal/streams/stream'], function (exports, _emberMetalDebug, _emberMetalStreamsStream) { 32514 'use strict'; 32515 32516 exports.isStream = isStream; 32517 exports.subscribe = subscribe; 32518 exports.unsubscribe = unsubscribe; 32519 exports.read = read; 32520 exports.readArray = readArray; 32521 exports.readHash = readHash; 32522 exports.scanArray = scanArray; 32523 exports.scanHash = scanHash; 32524 exports.concat = concat; 32525 exports.labelsFor = labelsFor; 32526 exports.labelsForObject = labelsForObject; 32527 exports.labelFor = labelFor; 32528 exports.or = or; 32529 exports.addDependency = addDependency; 32530 exports.zip = zip; 32531 exports.zipHash = zipHash; 32532 exports.chain = chain; 32533 exports.setValue = setValue; 32534 32535 /* 32536 Check whether an object is a stream or not. 32537 32538 @private 32539 @for Ember.stream 32540 @function isStream 32541 @param {Object|Stream} object Object to check whether it is a stream. 32542 @return {Boolean} `true` if the object is a stream, `false` otherwise. 32543 */ 32544 32545 function isStream(object) { 32546 return object && object[_emberMetalStreamsStream.IS_STREAM]; 32547 } 32548 32549 /* 32550 A method of subscribing to a stream which is safe for use with a non-stream 32551 object. If a non-stream object is passed, the function does nothing. 32552 32553 @public 32554 @for Ember.stream 32555 @function subscribe 32556 @param {Object|Stream} object Object or stream to potentially subscribe to. 32557 @param {Function} callback Function to run when stream value changes. 32558 @param {Object} [context] the callback will be executed with this context if it 32559 is provided. 32560 */ 32561 32562 function subscribe(object, callback, context) { 32563 if (object && object[_emberMetalStreamsStream.IS_STREAM]) { 32564 return object.subscribe(callback, context); 32565 } 32566 } 32567 32568 /* 32569 A method of unsubscribing from a stream which is safe for use with a non-stream 32570 object. If a non-stream object is passed, the function does nothing. 32571 32572 @private 32573 @for Ember.stream 32574 @function unsubscribe 32575 @param {Object|Stream} object Object or stream to potentially unsubscribe from. 32576 @param {Function} callback Function originally passed to `subscribe()`. 32577 @param {Object} [context] Object originally passed to `subscribe()`. 32578 */ 32579 32580 function unsubscribe(object, callback, context) { 32581 if (object && object[_emberMetalStreamsStream.IS_STREAM]) { 32582 object.unsubscribe(callback, context); 32583 } 32584 } 32585 32586 /* 32587 Retrieve the value of a stream, or in the case where a non-stream object is passed, 32588 return the object itself. 32589 32590 @private 32591 @for Ember.stream 32592 @function read 32593 @param {Object|Stream} object Object to return the value of. 32594 @return The stream's current value, or the non-stream object itself. 32595 */ 32596 32597 function read(object) { 32598 if (object && object[_emberMetalStreamsStream.IS_STREAM]) { 32599 return object.value(); 32600 } else { 32601 return object; 32602 } 32603 } 32604 32605 /* 32606 Map an array, replacing any streams with their values. 32607 32608 @private 32609 @for Ember.stream 32610 @function readArray 32611 @param {Array} array The array to read values from 32612 @return {Array} A new array of the same length with the values of non-stream 32613 objects mapped from their original positions untouched, and 32614 the values of stream objects retaining their original position 32615 and replaced with the stream's current value. 32616 */ 32617 32618 function readArray(array) { 32619 var length = array.length; 32620 var ret = new Array(length); 32621 for (var i = 0; i < length; i++) { 32622 ret[i] = read(array[i]); 32623 } 32624 return ret; 32625 } 32626 32627 /* 32628 Map a hash, replacing any stream property values with the current value of that 32629 stream. 32630 32631 @private 32632 @for Ember.stream 32633 @function readHash 32634 @param {Object} object The hash to read keys and values from. 32635 @return {Object} A new object with the same keys as the passed object. The 32636 property values in the new object are the original values in 32637 the case of non-stream objects, and the streams' current 32638 values in the case of stream objects. 32639 */ 32640 32641 function readHash(object) { 32642 var ret = {}; 32643 for (var key in object) { 32644 ret[key] = read(object[key]); 32645 } 32646 return ret; 32647 } 32648 32649 /* 32650 Check whether an array contains any stream values. 32651 32652 @private 32653 @for Ember.stream 32654 @function scanArray 32655 @param {Array} array Array given to a handlebars helper. 32656 @return {Boolean} `true` if the array contains a stream/bound value, `false` 32657 otherwise. 32658 */ 32659 32660 function scanArray(array) { 32661 var length = array.length; 32662 var containsStream = false;
32663 32664 for (var i = 0; i < length; i++) { 32665 if (isStream(array[i])) { 32666 containsStream = true; 32667 break; 32668 } 32669 } 32670 32671 return containsStream; 32672 } 32673 32674 /* 32675 Check whether a hash has any stream property values. 32676 32677 @private 32678 @for Ember.stream 32679 @function scanHash 32680 @param {Object} hash "hash" argument given to a handlebars helper. 32681 @return {Boolean} `true` if the object contains a stream/bound value, `false` 32682 otherwise. 32683 */ 32684 32685 function scanHash(hash) { 32686 var containsStream = false; 32687 32688 for (var prop in hash) { 32689 if (isStream(hash[prop])) { 32690 containsStream = true; 32691 break; 32692 } 32693 } 32694 32695 return containsStream; 32696 } 32697 32698 var ConcatStream = _emberMetalStreamsStream.default.extend({ 32699 init: function (array, separator) { 32700 this.array = array; 32701 this.separator = separator; 32702 32703 // Used by angle bracket components to detect an attribute was provided 32704 // as a string literal. 32705 this.isConcat = true; 32706 }, 32707 32708 label: function () { 32709 var labels = labelsFor(this.array); 32710 return 'concat([' + labels.join(', ') + ']; separator=' + inspect(this.separator) + ')'; 32711 }, 32712 32713 compute: function () { 32714 return concat(readArray(this.array), this.separator); 32715 } 32716 }); 32717 32718 /* 32719 Join an array, with any streams replaced by their current values. 32720 32721 @private 32722 @for Ember.stream 32723 @function concat 32724 @param {Array} array An array containing zero or more stream objects and 32725 zero or more non-stream objects. 32726 @param {String} separator String to be used to join array elements. 32727 @return {String} String with array elements concatenated and joined by the 32728 provided separator, and any stream array members having been 32729 replaced by the current value of the stream. 32730 */ 32731 32732 function concat(array, separator) { 32733 // TODO: Create subclass ConcatStream < Stream. Defer 32734 // subscribing to streams until the value() is called. 32735 var hasStream = scanArray(array); 32736 if (hasStream) { 32737 var stream = new ConcatStream(array, separator); 32738 32739 for (var i = 0, l = array.length; i < l; i++) { 32740 addDependency(stream, array[i]); 32741 } 32742 32743 return stream; 32744 } else { 32745 return array.join(separator); 32746 } 32747 } 32748 32749 function labelsFor(streams) { 32750 var labels = []; 32751 32752 for (var i = 0, l = streams.length; i < l; i++) { 32753 var stream = streams[i]; 32754 labels.push(labelFor(stream)); 32755 } 32756 32757 return labels; 32758 } 32759 32760 function labelsForObject(streams) { 32761 var labels = []; 32762 32763 for (var prop in streams) { 32764 labels.push(prop + ': ' + inspect(streams[prop])); 32765 } 32766 32767 return labels.length ? '{ ' + labels.join(', ') + ' }' : '{}'; 32768 } 32769 32770 function labelFor(maybeStream) { 32771 if (isStream(maybeStream)) { 32772 var stream = maybeStream; 32773 return typeof stream.label === 'function' ? stream.label() : stream.label; 32774 } else { 32775 return inspect(maybeStream); 32776 } 32777 } 32778 32779 function inspect(value) { 32780 switch (typeof value) { 32781 case 'string': 32782 return '"' + value + '"'; 32783 case 'object': 32784 return '{ ... }'; 32785 case 'function': 32786 return 'function() { ... }'; 32787 default: 32788 return String(value); 32789 } 32790 } 32791 32792 function or(first, second) { 32793 var stream = new _emberMetalStreamsStream.Stream(function () { 32794 return first.value() || second.value(); 32795 }, function () { 32796 return labelFor(first) + ' || ' + labelFor(second); 32797 }); 32798 32799 stream.addDependency(first); 32800 stream.addDependency(second); 32801 32802 return stream; 32803 } 32804 32805 function addDependency(stream, dependency) { 32806 _emberMetalDebug.assert('Cannot add a stream as a dependency to a non-stream', isStream(stream) || !isStream(dependency)); 32807 if (isStream(stream)) { 32808 stream.addDependency(dependency); 32809 } 32810 } 32811 32812 function zip(streams, callback, label) { 32813 _emberMetalDebug.assert('Must call zip with a label', !!label); 32814 32815 var stream = new _emberMetalStreamsStream.Stream(function () { 32816 var array = readArray(streams); 32817 return callback ? callback(array) : array; 32818 }, function () { 32819 return label + '(' + labelsFor(streams) + ')'; 32820 }); 32821 32822 for (var i = 0, l = streams.length; i < l; i++) { 32823 stream.addDependency(streams[i]); 32824 } 32825 32826 return stream; 32827 } 32828 32829 function zipHash(object, callback, label) { 32830 _emberMetalDebug.assert('Must call zipHash with a label', !!label); 32831 32832 var stream = new _emberMetalStreamsStream.Stream(function () { 32833 var hash = readHash(object); 32834 return callback ? callback(hash) : hash; 32835 }, function () { 32836 return label + '(' + labelsForObject(object) + ')'; 32837 }); 32838 32839 for (var prop in object) { 32840 stream.addDependency(object[prop]); 32841 } 32842 32843 return stream; 32844 } 32845 32846 /** 32847 Generate a new stream by providing a source stream and a function that can 32848 be used to transform the stream's value. In the case of a non-stream object, 32849 returns the result of the function. 32850 32851 The value to transform would typically be available to the function you pass 32852 to `chain()` via scope. For example: 32853 32854 ```javascript 32855 var source = ...; // stream returning a number 32856 // or a numeric (non-stream) object 32857 var result = chain(source, function() { 32858 var currentValue = read(source); 32859 return currentValue + 1; 32860 }); 32861 ``` 32862 32863 In the example, result is a stream if source is a stream, or a number of 32864 source was numeric. 32865 32866 @private 32867 @for Ember.stream 32868 @function chain 32869 @param {Object|Stream} value A stream or non-stream object. 32870 @param {Function} fn Function to be run when the stream value changes, or to 32871 be run once in the case of a non-stream object. 32872 @return {Object|Stream} In the case of a stream `value` parameter, a new 32873 stream that will be updated with the return value of 32874 the provided function `fn`. In the case of a 32875 non-stream object, the return value of the provided 32876 function `fn`. 32877 */ 32878 32879 function chain(value, fn, label) { 32880 _emberMetalDebug.assert('Must call chain with a label', !!label); 32881 if (isStream(value)) { 32882 var stream = new _emberMetalStreamsStream.Stream(fn, function () { 32883 return label + '(' + labelFor(value) + ')'; 32884 }); 32885 stream.addDependency(value); 32886 return stream; 32887 } else { 32888 return fn(); 32889 } 32890 } 32891 32892 function setValue(object, value) { 32893 if (object && object[_emberMetalStreamsStream.IS_STREAM]) { 32894 object.setValue(value); 32895 } 32896 } 32897}); 32898enifed('ember-metal/symbol', ['exports', 'ember-metal/utils'], function (exports, _emberMetalUtils) { 32899 'use strict'; 32900 32901 exports.default = symbol; 32902 32903 function symbol(debugName) { 32904 // TODO: Investigate using platform symbols, but we do not 32905 // want to require non-enumerability for this API, which 32906 // would introduce a large cost. 32907 32908 return _emberMetalUtils.intern(debugName + ' [id=' + _emberMetalUtils.GUID_KEY + Math.floor(Math.random() * new Date()) + ']'); 32909 } 32910}); 32911enifed('ember-metal/utils', ['exports'], function (exports) { 32912 'no use strict'; 32913 // Remove "use strict"; from transpiled module until 32914 // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed 32915 32916 /** 32917 @module ember-metal 32918 */ 32919 32920 /** 32921 Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from 32922 jQuery master. We'll just bootstrap our own uuid now. 32923 32924 @private 32925 @return {Number} the uuid 32926 */ 32927 exports.uuid = uuid; 32928 exports.intern = intern; 32929 exports.generateGuid = generateGuid; 32930 exports.guidFor = guidFor; 32931 exports.wrap = wrap; 32932 exports.tryInvoke = tryInvoke; 32933 exports.makeArray = makeArray; 32934 exports.inspect = inspect; 32935 exports.apply = apply; 32936 exports.applyStr = applyStr; 32937 exports.lookupDescriptor = lookupDescriptor; 32938 exports.toString = toString; 32939 var _uuid = 0; 32940 32941 /** 32942 Generates a universally unique identifier. This method 32943 is used internally by Ember for assisting with 32944 the generation of GUID's and other unique identifiers. 32945 32946 @public 32947 @return {Number} [description] 32948 */ 32949 32950 function uuid() { 32951 return ++_uuid; 32952 } 32953 32954 /** 32955 Prefix used for guids through out Ember. 32956 @private 32957 @property GUID_PREFIX 32958 @for Ember
32959 @type String 32960 @final 32961 */ 32962 var GUID_PREFIX = 'ember'; 32963 32964 // Used for guid generation... 32965 var numberCache = []; 32966 var stringCache = {}; 32967 32968 /** 32969 Strongly hint runtimes to intern the provided string. 32970 32971 When do I need to use this function? 32972 32973 For the most part, never. Pre-mature optimization is bad, and often the 32974 runtime does exactly what you need it to, and more often the trade-off isn't 32975 worth it. 32976 32977 Why? 32978 32979 Runtimes store strings in at least 2 different representations: 32980 Ropes and Symbols (interned strings). The Rope provides a memory efficient 32981 data-structure for strings created from concatenation or some other string 32982 manipulation like splitting. 32983 32984 Unfortunately checking equality of different ropes can be quite costly as 32985 runtimes must resort to clever string comparison algorithms. These 32986 algorithms typically cost in proportion to the length of the string. 32987 Luckily, this is where the Symbols (interned strings) shine. As Symbols are 32988 unique by their string content, equality checks can be done by pointer 32989 comparison. 32990 32991 How do I know if my string is a rope or symbol? 32992 32993 Typically (warning general sweeping statement, but truthy in runtimes at 32994 present) static strings created as part of the JS source are interned. 32995 Strings often used for comparisons can be interned at runtime if some 32996 criteria are met. One of these criteria can be the size of the entire rope. 32997 For example, in chrome 38 a rope longer then 12 characters will not 32998 intern, nor will segments of that rope. 32999 33000 Some numbers: http://jsperf.com/eval-vs-keys/8 33001 33002 Known Trick⢠33003 33004 @private 33005 @return {String} interned version of the provided string 33006 */ 33007 33008 function intern(str) { 33009 var obj = {}; 33010 obj[str] = 1; 33011 for (var key in obj) { 33012 if (key === str) { 33013 return key; 33014 } 33015 } 33016 return str; 33017 } 33018 33019 /** 33020 A unique key used to assign guids and other private metadata to objects. 33021 If you inspect an object in your browser debugger you will often see these. 33022 They can be safely ignored. 33023 33024 On browsers that support it, these properties are added with enumeration 33025 disabled so they won't show up when you iterate over your properties. 33026 33027 @private 33028 @property GUID_KEY 33029 @for Ember 33030 @type String 33031 @final 33032 */ 33033 var GUID_KEY = intern('__ember' + +new Date()); 33034 33035 var GUID_DESC = { 33036 writable: true, 33037 configurable: true, 33038 enumerable: false, 33039 value: null 33040 }; 33041 33042 exports.GUID_DESC = GUID_DESC; 33043 var nullDescriptor = { 33044 configurable: true, 33045 writable: true, 33046 enumerable: false, 33047 value: null 33048 }; 33049 33050 var GUID_KEY_PROPERTY = { 33051 name: GUID_KEY, 33052 descriptor: nullDescriptor 33053 }; 33054 33055 exports.GUID_KEY_PROPERTY = GUID_KEY_PROPERTY; 33056 /** 33057 Generates a new guid, optionally saving the guid to the object that you 33058 pass in. You will rarely need to use this method. Instead you should 33059 call `Ember.guidFor(obj)`, which return an existing guid if available. 33060 33061 @private 33062 @method generateGuid 33063 @for Ember 33064 @param {Object} [obj] Object the guid will be used for. If passed in, the guid will 33065 be saved on the object and reused whenever you pass the same object 33066 again. 33067 33068 If no object is passed, just generate a new guid. 33069 @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to 33070 separate the guid into separate namespaces. 33071 @return {String} the guid 33072 */ 33073 33074 function generateGuid(obj, prefix) { 33075 if (!prefix) { 33076 prefix = GUID_PREFIX; 33077 } 33078 33079 var ret = prefix + uuid(); 33080 if (obj) { 33081 if (obj[GUID_KEY] === null) { 33082 obj[GUID_KEY] = ret; 33083 } else { 33084 GUID_DESC.value = ret; 33085 if (obj.__defineNonEnumerable) { 33086 obj.__defineNonEnumerable(GUID_KEY_PROPERTY); 33087 } else { 33088 Object.defineProperty(obj, GUID_KEY, GUID_DESC); 33089 } 33090 } 33091 } 33092 return ret; 33093 } 33094 33095 /** 33096 Returns a unique id for the object. If the object does not yet have a guid, 33097 one will be assigned to it. You can call this on any object, 33098 `Ember.Object`-based or not, but be aware that it will add a `_guid` 33099 property. 33100 33101 You can also use this method on DOM Element objects. 33102 33103 @public 33104 @method guidFor 33105 @for Ember 33106 @param {Object} obj any object, string, number, Element, or primitive 33107 @return {String} the unique guid for this instance. 33108 */ 33109 33110 function guidFor(obj) { 33111 if (obj && obj[GUID_KEY]) { 33112 return obj[GUID_KEY]; 33113 } 33114 33115 // special cases where we don't want to add a key to object 33116 if (obj === undefined) { 33117 return '(undefined)'; 33118 } 33119 33120 if (obj === null) { 33121 return '(null)'; 33122 } 33123 33124 var ret; 33125 var type = typeof obj; 33126 33127 // Don't allow prototype changes to String etc. to change the guidFor 33128 switch (type) { 33129 case 'number': 33130 ret = numberCache[obj]; 33131 33132 if (!ret) { 33133 ret = numberCache[obj] = 'nu' + obj; 33134 } 33135 33136 return ret; 33137 33138 case 'string': 33139 ret = stringCache[obj]; 33140 33141 if (!ret) { 33142 ret = stringCache[obj] = 'st' + uuid(); 33143 } 33144 33145 return ret; 33146 33147 case 'boolean': 33148 return obj ? '(true)' : '(false)'; 33149 33150 default: 33151 if (obj === Object) { 33152 return '(Object)'; 33153 } 33154 33155 if (obj === Array) { 33156 return '(Array)'; 33157 } 33158 33159 ret = GUID_PREFIX + uuid(); 33160 33161 if (obj[GUID_KEY] === null) { 33162 obj[GUID_KEY] = ret; 33163 } else { 33164 GUID_DESC.value = ret; 33165 33166 if (obj.__defineNonEnumerable) { 33167 obj.__defineNonEnumerable(GUID_KEY_PROPERTY); 33168 } else { 33169 Object.defineProperty(obj, GUID_KEY, GUID_DESC); 33170 } 33171 } 33172 return ret; 33173 } 33174 } 33175 33176 var HAS_SUPER_PATTERN = /\.(_super|call\(this|apply\(this)/; 33177 33178 var checkHasSuper = (function () { 33179 var sourceAvailable = (function () { 33180 return this; 33181 }).toString().indexOf('return this') > -1; 33182 33183 if (sourceAvailable) { 33184 return function checkHasSuper(func) { 33185 return HAS_SUPER_PATTERN.test(func.toString()); 33186 }; 33187 } 33188 33189 return function checkHasSuper() { 33190 return true; 33191 }; 33192 })(); 33193 33194 exports.checkHasSuper = checkHasSuper; 33195 function ROOT() {} 33196 ROOT.__hasSuper = false;
33197 33198 function hasSuper(func) { 33199 if (func.__hasSuper === undefined) { 33200 func.__hasSuper = checkHasSuper(func); 33201 } 33202 return func.__hasSuper; 33203 } 33204 33205 /** 33206 Wraps the passed function so that `this._super` will point to the superFunc 33207 when the function is invoked. This is the primitive we use to implement 33208 calls to super. 33209 33210 @private 33211 @method wrap 33212 @for Ember 33213 @param {Function} func The function to call 33214 @param {Function} superFunc The super function. 33215 @return {Function} wrapped function. 33216 */ 33217 33218 function wrap(func, superFunc) { 33219 if (!hasSuper(func)) { 33220 return func; 33221 } 33222 // ensure an unwrapped super that calls _super is wrapped with a terminal _super 33223 if (!superFunc.wrappedFunction && hasSuper(superFunc)) { 33224 return _wrap(func, _wrap(superFunc, ROOT)); 33225 } 33226 return _wrap(func, superFunc); 33227 } 33228 33229 function _wrap(func, superFunc) { 33230 function superWrapper() { 33231 var orig = this._super; 33232 var length = arguments.length; 33233 var ret = undefined; 33234 this._super = superFunc; 33235 switch (length) { 33236 case 0: 33237 ret = func.call(this);break; 33238 case 1: 33239 ret = func.call(this, arguments[0]);break; 33240 case 2: 33241 ret = func.call(this, arguments[0], arguments[1]);break; 33242 case 3: 33243 ret = func.call(this, arguments[0], arguments[1], arguments[2]);break; 33244 case 4: 33245 ret = func.call(this, arguments[0], arguments[1], arguments[2], arguments[3]);break; 33246 case 5: 33247 ret = func.call(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);break; 33248 default: 33249 // v8 bug potentially incorrectly deopts this function: https://code.google.com/p/v8/issues/detail?id=3709 33250 // we may want to keep this around till this ages out on mobile 33251 var args = new Array(length); 33252 for (var x = 0; x < length; x++) { 33253 args[x] = arguments[x]; 33254 } 33255 ret = func.apply(this, args); 33256 break; 33257 } 33258 this._super = orig; 33259 return ret; 33260 } 33261 33262 superWrapper.wrappedFunction = func; 33263 superWrapper.__ember_observes__ = func.__ember_observes__; 33264 superWrapper.__ember_observesBefore__ = func.__ember_observesBefore__; 33265 superWrapper.__ember_listens__ = func.__ember_listens__; 33266 33267 return superWrapper; 33268 } 33269 33270 /** 33271 Checks to see if the `methodName` exists on the `obj`. 33272 33273 ```javascript 33274 var foo = { bar: function() { return 'bar'; }, baz: null }; 33275 33276 Ember.canInvoke(foo, 'bar'); // true 33277 Ember.canInvoke(foo, 'baz'); // false 33278 Ember.canInvoke(foo, 'bat'); // false 33279 ``` 33280 33281 @method canInvoke 33282 @for Ember 33283 @param {Object} obj The object to check for the method 33284 @param {String} methodName The method name to check for 33285 @return {Boolean} 33286 @private 33287 */ 33288 function canInvoke(obj, methodName) { 33289 return !!(obj && typeof obj[methodName] === 'function'); 33290 } 33291 33292 /** 33293 Checks to see if the `methodName` exists on the `obj`, 33294 and if it does, invokes it with the arguments passed. 33295 33296 ```javascript 33297 var d = new Date('03/15/2013'); 33298 33299 Ember.tryInvoke(d, 'getTime'); // 1363320000000 33300 Ember.tryInvoke(d, 'setFullYear', [2014]); // 1394856000000 33301 Ember.tryInvoke(d, 'noSuchMethod', [2014]); // undefined 33302 ``` 33303 33304 @method tryInvoke 33305 @for Ember 33306 @param {Object} obj The object to check for the method 33307 @param {String} methodName The method name to check for 33308 @param {Array} [args] The arguments to pass to the method 33309 @return {*} the return value of the invoked method or undefined if it cannot be invoked 33310 @public 33311 */ 33312 33313 function tryInvoke(obj, methodName, args) { 33314 if (canInvoke(obj, methodName)) { 33315 return args ? applyStr(obj, methodName, args) : applyStr(obj, methodName); 33316 } 33317 } 33318 33319 // ........................................ 33320 // TYPING & ARRAY MESSAGING 33321 // 33322 33323 var objectToString = Object.prototype.toString; 33324 33325 /** 33326 Forces the passed object to be part of an array. If the object is already 33327 an array, it will return the object. Otherwise, it will add the object to 33328 an array. If obj is `null` or `undefined`, it will return an empty array. 33329 33330 ```javascript 33331 Ember.makeArray(); // [] 33332 Ember.makeArray(null); // [] 33333 Ember.makeArray(undefined); // [] 33334 Ember.makeArray('lindsay'); // ['lindsay'] 33335 Ember.makeArray([1, 2, 42]); // [1, 2, 42] 33336 33337 var controller = Ember.ArrayProxy.create({ content: [] }); 33338 33339 Ember.makeArray(controller) === controller; // true 33340 ``` 33341 33342 @method makeArray 33343 @for Ember 33344 @param {Object} obj the object 33345 @return {Array} 33346 @private 33347 */ 33348 33349 function makeArray(obj) { 33350 if (obj === null || obj === undefined) { 33351 return []; 33352 } 33353 return Array.isArray(obj) ? obj : [obj]; 33354 } 33355 33356 /** 33357 Convenience method to inspect an object. This method will attempt to 33358 convert the object into a useful string description. 33359 33360 It is a pretty simple implementation. If you want something more robust, 33361 use something like JSDump: https://github.com/NV/jsDump 33362 33363 @method inspect 33364 @for Ember 33365 @param {Object} obj The object you want to inspect. 33366 @return {String} A description of the object 33367 @since 1.4.0 33368 @private 33369 */ 33370 33371 function inspect(obj) { 33372 if (obj === null) { 33373 return 'null';
33374 } 33375 if (obj === undefined) { 33376 return 'undefined'; 33377 } 33378 if (Array.isArray(obj)) { 33379 return '[' + obj + ']'; 33380 } 33381 // for non objects 33382 var type = typeof obj; 33383 if (type !== 'object' && type !== 'symbol') { 33384 return '' + obj; 33385 } 33386 // overridden toString 33387 if (typeof obj.toString === 'function' && obj.toString !== objectToString) { 33388 return obj.toString(); 33389 } 33390 33391 // Object.prototype.toString === {}.toString 33392 var v; 33393 var ret = []; 33394 for (var key in obj) { 33395 if (obj.hasOwnProperty(key)) { 33396 v = obj[key]; 33397 if (v === 'toString') { 33398 continue; 33399 } // ignore useless items 33400 if (typeof v === 'function') { 33401 v = 'function() { ... }'; 33402 } 33403 33404 if (v && typeof v.toString !== 'function') { 33405 ret.push(key + ': ' + objectToString.call(v)); 33406 } else { 33407 ret.push(key + ': ' + v); 33408 } 33409 } 33410 } 33411 return '{' + ret.join(', ') + '}'; 33412 } 33413 33414 // The following functions are intentionally minified to keep the functions 33415 // below Chrome's function body size inlining limit of 600 chars. 33416 /** 33417 @param {Object} t target 33418 @param {Function} m method 33419 @param {Array} a args 33420 @private 33421 */ 33422 33423 function apply(t, m, a) { 33424 var l = a && a.length; 33425 if (!a || !l) { 33426 return m.call(t); 33427 } 33428 switch (l) { 33429 case 1: 33430 return m.call(t, a[0]); 33431 case 2: 33432 return m.call(t, a[0], a[1]); 33433 case 3: 33434 return m.call(t, a[0], a[1], a[2]); 33435 case 4: 33436 return m.call(t, a[0], a[1], a[2], a[3]); 33437 case 5: 33438 return m.call(t, a[0], a[1], a[2], a[3], a[4]); 33439 default: 33440 return m.apply(t, a); 33441 } 33442 } 33443 33444 /** 33445 @param {Object} t target 33446 @param {String} m method 33447 @param {Array} a args 33448 @private 33449 */ 33450 33451 function applyStr(t, m, a) { 33452 var l = a && a.length; 33453 if (!a || !l) { 33454 return t[m](); 33455 } 33456 switch (l) { 33457 case 1: 33458 return t[m](a[0]); 33459 case 2: 33460 return t[m](a[0], a[1]); 33461 case 3: 33462 return t[m](a[0], a[1], a[2]); 33463 case 4: 33464 return t[m](a[0], a[1], a[2], a[3]); 33465 case 5: 33466 return t[m](a[0], a[1], a[2], a[3], a[4]); 33467 default: 33468 return t[m].apply(t, a); 33469 } 33470 } 33471 33472 function lookupDescriptor(obj, keyName) { 33473 var current = obj; 33474 while (current) { 33475 var descriptor = Object.getOwnPropertyDescriptor(current, keyName); 33476 33477 if (descriptor) { 33478 return descriptor; 33479 } 33480 33481 current = Object.getPrototypeOf(current); 33482 } 33483 33484 return null; 33485 } 33486 33487 // A `toString` util function that supports objects without a `toString` 33488 // method, e.g. an object created with `Object.create(null)`. 33489 33490 function toString(obj) { 33491 if (obj && obj.toString) { 33492 return obj.toString(); 33493 } else { 33494 return objectToString.call(obj); 33495 } 33496 } 33497 33498 exports.GUID_KEY = GUID_KEY; 33499 exports.makeArray = makeArray; 33500 exports.canInvoke = canInvoke; 33501}); 33502enifed('ember-metal/watch_key', ['exports', 'ember-metal/features', 'ember-metal/meta', 'ember-metal/properties', 'ember-metal/utils'], function (exports, _emberMetalFeatures, _emberMetalMeta, _emberMetalProperties, _emberMetalUtils) { 33503 'use strict'; 33504 33505 exports.watchKey = watchKey; 33506 exports.unwatchKey = unwatchKey; 33507 33508 var handleMandatorySetter = undefined; 33509 33510 function watchKey(obj, keyName, meta) { 33511 // can't watch length on Array - it is special... 33512 if (keyName === 'length' && Array.isArray(obj)) { 33513 return; 33514 } 33515 33516 var m = meta || _emberMetalMeta.meta(obj); 33517 33518 // activate watching first time 33519 if (!m.peekWatching(keyName)) { 33520 m.writeWatching(keyName, 1); 33521 33522 var possibleDesc = obj[keyName]; 33523 var desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 33524 if (desc && desc.willWatch) { 33525 desc.willWatch(obj, keyName); 33526 } 33527 33528 if ('function' === typeof obj.willWatchProperty) { 33529 obj.willWatchProperty(keyName); 33530 } 33531 33532 // NOTE: this is dropped for prod + minified builds 33533 handleMandatorySetter(m, obj, keyName); 33534 } else { 33535 m.writeWatching(keyName, (m.peekWatching(keyName) || 0) + 1); 33536 } 33537 } 33538 33539 // Future traveler, although this code looks scary. It merely exists in 33540 // development to aid in development asertions. Production builds of 33541 // ember strip this entire block out 33542 handleMandatorySetter = function handleMandatorySetter(m, obj, keyName) { 33543 var descriptor = _emberMetalUtils.lookupDescriptor(obj, keyName); 33544 var configurable = descriptor ? descriptor.configurable : true; 33545 var isWritable = descriptor ? descriptor.writable : true; 33546 var hasValue = descriptor ? 'value' in descriptor : true; 33547 var possibleDesc = descriptor && descriptor.value; 33548 var isDescriptor = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor; 33549 33550 if (isDescriptor) { 33551 return; 33552 } 33553 33554 // this x in Y deopts, so keeping it in this function is better; 33555 if (configurable && isWritable && hasValue && keyName in obj) { 33556 var desc = { 33557 configurable: true, 33558 enumerable: Object.prototype.propertyIsEnumerable.call(obj, keyName), 33559 set: _emberMetalProperties.MANDATORY_SETTER_FUNCTION(keyName), 33560 get: undefined 33561 }; 33562 33563 if (Object.prototype.hasOwnProperty.call(obj, keyName)) { 33564 m.writeValues(keyName, obj[keyName]); 33565 desc.get = _emberMetalProperties.DEFAULT_GETTER_FUNCTION(keyName); 33566 } else { 33567 desc.get = _emberMetalProperties.INHERITING_GETTER_FUNCTION(keyName); 33568 } 33569 33570 Object.defineProperty(obj, keyName, desc); 33571 } 33572 }; 33573 33574 function unwatchKey(obj, keyName, meta) { 33575 var m = meta || _emberMetalMeta.meta(obj); 33576 var count = m.peekWatching(keyName); 33577 if (count === 1) { 33578 m.writeWatching(keyName, 0); 33579 33580 var possibleDesc = obj[keyName]; 33581 var desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 33582 33583 if (desc && desc.didUnwatch) { 33584 desc.didUnwatch(obj, keyName); 33585 } 33586 33587 if ('function' === typeof obj.didUnwatchProperty) { 33588 obj.didUnwatchProperty(keyName); 33589 } 33590 33591 // It is true, the following code looks quite WAT. But have no fear, It 33592 // exists purely to improve development ergonomics and is removed from 33593 // ember.min.js and ember.prod.js builds. 33594 // 33595 // Some further context: Once a property is watched by ember, bypassing `set` 33596 // for mutation, will bypass observation. This code exists to assert when 33597 // that occurs, and attempt to provide more helpful feedback. The alternative 33598 // is tricky to debug partially observable properties. 33599 if (!desc && keyName in obj) { 33600 var maybeMandatoryDescriptor = _emberMetalUtils.lookupDescriptor(obj, keyName); 33601 33602 if (maybeMandatoryDescriptor.set && maybeMandatoryDescriptor.set.isMandatorySetter) { 33603 if (maybeMandatoryDescriptor.get && maybeMandatoryDescriptor.get.isInheritingGetter) { 33604 delete obj[keyName]; 33605 } else { 33606 Object.defineProperty(obj, keyName, { 33607 configurable: true, 33608 enumerable: Object.prototype.propertyIsEnumerable.call(obj, keyName), 33609 writable: true, 33610 value: m.peekValues(keyName) 33611 }); 33612 m.deleteFromValues(keyName); 33613 } 33614 } 33615 } 33616 } else if (count > 1) { 33617 m.writeWatching(keyName, count - 1); 33618 } 33619 } 33620}); 33621enifed('ember-metal/watch_path', ['exports', 'ember-metal/meta', 'ember-metal/chains'], function (exports, _emberMetalMeta, _emberMetalChains) { 33622 'use strict'; 33623 33624 exports.watchPath = watchPath; 33625 exports.unwatchPath = unwatchPath; 33626 33627 // get the chains for the current object. If the current object has 33628 // chains inherited from the proto they will be cloned and reconfigured for 33629 // the current object. 33630 function chainsFor(obj, meta) { 33631 return (meta || _emberMetalMeta.meta(obj)).writableChains(makeChainNode); 33632 } 33633 33634 function makeChainNode(obj) { 33635 return new _emberMetalChains.ChainNode(null, null, obj); 33636 } 33637 33638 function watchPath(obj, keyPath, meta) { 33639 // can't watch length on Array - it is special... 33640 if (keyPath === 'length' && Array.isArray(obj)) { 33641 return; 33642 } 33643 33644 var m = meta || _emberMetalMeta.meta(obj); 33645 var counter = m.peekWatching(keyPath) || 0; 33646 if (!counter) { 33647 // activate watching first time 33648 m.writeWatching(keyPath, 1); 33649 chainsFor(obj, m).add(keyPath); 33650 } else { 33651 m.writeWatching(keyPath, counter + 1); 33652 } 33653 } 33654 33655 function unwatchPath(obj, keyPath, meta) { 33656 var m = meta || _emberMetalMeta.meta(obj); 33657 var counter = m.peekWatching(keyPath) || 0; 33658 33659 if (counter === 1) { 33660 m.writeWatching(keyPath, 0); 33661 chainsFor(obj, m).remove(keyPath); 33662 } else if (counter > 1) { 33663 m.writeWatching(keyPath, counter - 1); 33664 } 33665 } 33666}); 33667enifed('ember-metal/watching', ['exports', 'ember-metal/chains', 'ember-metal/watch_key', 'ember-metal/watch_path', 'ember-metal/path_cache', 'ember-metal/meta'], function (exports, _emberMetalChains, _emberMetalWatch_key, _emberMetalWatch_path, _emberMetalPath_cache, _emberMetalMeta) { 33668 /** 33669 @module ember-metal 33670 */ 33671 33672 'use strict'; 33673 33674 exports.isWatching = isWatching; 33675 exports.watcherCount = watcherCount; 33676 exports.unwatch = unwatch; 33677 exports.destroy = destroy; 33678 33679 /** 33680 Starts watching a property on an object. Whenever the property changes, 33681 invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the 33682 primitive used by observers and dependent keys; usually you will never call 33683 this method directly but instead use higher level methods like 33684 `Ember.addObserver()` 33685 33686 @private 33687 @method watch 33688 @for Ember 33689 @param obj 33690 @param {String} _keyPath 33691 */ 33692 function watch(obj, _keyPath, m) { 33693 // can't watch length on Array - it is special... 33694 if (_keyPath === 'length' && Array.isArray(obj)) { 33695 return; 33696 } 33697 33698 if (!_emberMetalPath_cache.isPath(_keyPath)) { 33699 _emberMetalWatch_key.watchKey(obj, _keyPath, m); 33700 } else { 33701 _emberMetalWatch_path.watchPath(obj, _keyPath, m); 33702 } 33703 } 33704 33705 exports.watch = watch; 33706 33707 function isWatching(obj, key) { 33708 var meta = _emberMetalMeta.peekMeta(obj);
33709 return (meta && meta.peekWatching(key)) > 0; 33710 } 33711 33712 function watcherCount(obj, key) { 33713 var meta = _emberMetalMeta.peekMeta(obj); 33714 return meta && meta.peekWatching(key) || 0; 33715 } 33716 33717 function unwatch(obj, _keyPath, m) { 33718 // can't watch length on Array - it is special... 33719 if (_keyPath === 'length' && Array.isArray(obj)) { 33720 return; 33721 } 33722 33723 if (!_emberMetalPath_cache.isPath(_keyPath)) { 33724 _emberMetalWatch_key.unwatchKey(obj, _keyPath, m); 33725 } else { 33726 _emberMetalWatch_path.unwatchPath(obj, _keyPath, m); 33727 } 33728 } 33729 33730 var NODE_STACK = []; 33731 33732 /** 33733 Tears down the meta on an object so that it can be garbage collected. 33734 Multiple calls will have no effect. 33735 33736 @method destroy 33737 @for Ember 33738 @param {Object} obj the object to destroy 33739 @return {void} 33740 @private 33741 */ 33742 33743 function destroy(obj) { 33744 var meta = _emberMetalMeta.peekMeta(obj); 33745 var node, nodes, key, nodeObject; 33746 33747 if (meta) { 33748 _emberMetalMeta.deleteMeta(obj); 33749 // remove chainWatchers to remove circular references that would prevent GC 33750 node = meta.readableChains(); 33751 if (node) { 33752 NODE_STACK.push(node); 33753 // process tree 33754 while (NODE_STACK.length > 0) { 33755 node = NODE_STACK.pop(); 33756 // push children 33757 nodes = node._chains; 33758 if (nodes) { 33759 for (key in nodes) { 33760 if (nodes[key] !== undefined) { 33761 NODE_STACK.push(nodes[key]); 33762 } 33763 } 33764 } 33765 // remove chainWatcher in node object 33766 if (node._watching) { 33767 nodeObject = node._object; 33768 if (nodeObject) { 33769 _emberMetalChains.removeChainWatcher(nodeObject, node._key, node); 33770 } 33771 } 33772 } 33773 } 33774 } 33775 } 33776}); 33777enifed('ember-metal/weak_map', ['exports', 'ember-metal/debug', 'ember-metal/utils', 'ember-metal/meta'], function (exports, _emberMetalDebug, _emberMetalUtils, _emberMetalMeta) { 33778 'use strict'; 33779 33780 exports.default = WeakMap; 33781 33782 var id = 0; 33783 function UNDEFINED() {} 33784 33785 /* 33786 * @private 33787 * @class Ember.WeakMap 33788 * 33789 * A partial polyfill for [WeakMap](http://www.ecma-international.org/ecma-262/6.0/#sec-weakmap-objects). 33790 * 33791 * There is a small but important caveat. This implementation assumes that the 33792 * weak map will live longer (in the sense of garbage collection) than all of its 33793 * keys, otherwise it is possible to leak the values stored in the weak map. In 33794 * practice, most use cases satisfy this limitation which is why it is included 33795 * in ember-metal. 33796 */ 33797 33798 function WeakMap() { 33799 _emberMetalDebug.assert('Invoking the WeakMap constructor with arguments is not supported at this time', arguments.length === 0); 33800 33801 this._id = _emberMetalUtils.GUID_KEY + id++; 33802 } 33803 33804 /* 33805 * @method get 33806 * @param key {Object | Function} 33807 * @return {Any} stored value 33808 */ 33809 WeakMap.prototype.get = function (obj) { 33810 var meta = _emberMetalMeta.peekMeta(obj); 33811 if (meta) { 33812 var map = meta.readableWeak(); 33813 if (map) { 33814 if (map[this._id] === UNDEFINED) { 33815 return undefined; 33816 } 33817 33818 return map[this._id]; 33819 } 33820 } 33821 }; 33822 33823 /* 33824 * @method set 33825 * @param key {Object | Function} 33826 * @param value {Any} 33827 * @return {WeakMap} the weak map 33828 */ 33829 WeakMap.prototype.set = function (obj, value) { 33830 _emberMetalDebug.assert('Uncaught TypeError: Invalid value used as weak map key', obj && (typeof obj === 'object' || typeof obj === 'function')); 33831 33832 if (value === undefined) { 33833 value = UNDEFINED; 33834 } 33835 33836 _emberMetalMeta.meta(obj).writableWeak()[this._id] = value; 33837 33838 return this; 33839 }; 33840 33841 /* 33842 * @method has 33843 * @param key {Object | Function} 33844 * @return {boolean} if the key exists 33845 */ 33846 WeakMap.prototype.has = function (obj) { 33847 var meta = _emberMetalMeta.peekMeta(obj); 33848 if (meta) { 33849 var map = meta.readableWeak(); 33850 if (map) { 33851 return map[this._id] !== undefined; 33852 } 33853 } 33854 33855 return false; 33856 }; 33857 33858 /* 33859 * @method delete 33860 * @param key {Object | Function} 33861 * @return {boolean} if the key was deleted 33862 */ 33863 WeakMap.prototype.delete = function (obj) { 33864 if (this.has(obj)) { 33865 delete _emberMetalMeta.meta(obj).writableWeak()[this._id]; 33866 return true; 33867 } else { 33868 return false;
33869 } 33870 }; 33871}); 33872enifed('ember-metal-views/htmlbars-renderer', ['exports', 'ember-metal/run_loop', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/assign', 'ember-metal/set_properties', 'ember-views/system/build-component-template', 'ember-metal/environment', 'htmlbars-runtime'], function (exports, _emberMetalRun_loop, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalAssign, _emberMetalSet_properties, _emberViewsSystemBuildComponentTemplate, _emberMetalEnvironment, _htmlbarsRuntime) { 33873 'use strict'; 33874 33875 exports.Renderer = Renderer; 33876 exports.MorphSet = MorphSet; 33877 33878 function Renderer(domHelper) { 33879 var _ref = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 33880 33881 var destinedForDOM = _ref.destinedForDOM; 33882 33883 this._dom = domHelper; 33884 33885 // This flag indicates whether the resulting rendered element will be 33886 // inserted into the DOM. This should be set to `false` if the rendered 33887 // element is going to be serialized to HTML without being inserted into 33888 // the DOM (e.g., in FastBoot mode). By default, this flag is the same 33889 // as whether we are running in an environment with DOM, but may be 33890 // overridden. 33891 this._destinedForDOM = destinedForDOM === undefined ? _emberMetalEnvironment.default.hasDOM : destinedForDOM; 33892 } 33893 33894 Renderer.prototype.prerenderTopLevelView = function Renderer_prerenderTopLevelView(view, renderNode) { 33895 if (view._state === 'inDOM') { 33896 throw new Error('You cannot insert a View that has already been rendered'); 33897 } 33898 view.ownerView = renderNode.emberView = view; 33899 view._renderNode = renderNode; 33900 33901 var layout = _emberMetalProperty_get.get(view, 'layout'); 33902 var template = _emberMetalProperty_get.get(view, 'template'); 33903 33904 var componentInfo = { component: view, layout: layout }; 33905 33906 var block = _emberViewsSystemBuildComponentTemplate.default(componentInfo, {}, { 33907 self: view, 33908 templates: template ? { default: template.raw } : undefined 33909 }).block; 33910 33911 view.renderBlock(block, renderNode); 33912 view.lastResult = renderNode.lastResult; 33913 this.clearRenderedViews(view.env); 33914 }; 33915 33916 Renderer.prototype.renderTopLevelView = function Renderer_renderTopLevelView(view, renderNode) { 33917 // Check to see if insertion has been canceled. 33918 if (view._willInsert) { 33919 view._willInsert = false; 33920 this.prerenderTopLevelView(view, renderNode); 33921 this.dispatchLifecycleHooks(view.env); 33922 } 33923 }; 33924 33925 Renderer.prototype.revalidateTopLevelView = function Renderer_revalidateTopLevelView(view) { 33926 // This guard prevents revalidation on an already-destroyed view. 33927 if (view._renderNode.lastResult) { 33928 view._renderNode.lastResult.revalidate(view.env); 33929 // supports createElement, which operates without moving the view into 33930 // the inDOM state. 33931 if (view._state === 'inDOM') { 33932 this.dispatchLifecycleHooks(view.env); 33933 } 33934 this.clearRenderedViews(view.env); 33935 } 33936 }; 33937 33938 Renderer.prototype.dispatchLifecycleHooks = function Renderer_dispatchLifecycleHooks(env) { 33939 var ownerView = env.view; 33940 33941 var lifecycleHooks = env.lifecycleHooks; 33942 var i, hook; 33943 33944 for (i = 0; i < lifecycleHooks.length; i++) { 33945 hook = lifecycleHooks[i]; 33946 ownerView._dispatching = hook.type; 33947 33948 switch (hook.type) { 33949 case 'didInsertElement': 33950 this.didInsertElement(hook.view);break; 33951 case 'didUpdate': 33952 this.didUpdate(hook.view);break; 33953 } 33954 33955 this.didRender(hook.view); 33956 } 33957 33958 ownerView._dispatching = null; 33959 env.lifecycleHooks.length = 0; 33960 }; 33961 33962 Renderer.prototype.ensureViewNotRendering = function Renderer_ensureViewNotRendering(view) { 33963 var env = view.ownerView.env; 33964 if (env && env.renderedViews.indexOf(view.elementId) !== -1) { 33965 throw new Error('Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.'); 33966 } 33967 }; 33968 33969 function MorphSet() { 33970 this.morphs = []; 33971 } 33972 33973 MorphSet.prototype.add = function (morph) { 33974 this.morphs.push(morph); 33975 morph.seen = true; 33976 }; 33977 33978 MorphSet.prototype.has = function (morph) { 33979 return morph.seen; 33980 }; 33981 33982 MorphSet.prototype.clear = function () { 33983 var morphs = this.morphs; 33984 for (var i = 0, l = morphs.length; i < l; i++) { 33985 morphs[i].seen = false;
33986 } 33987 33988 this.morphs = []; 33989 }; 33990 33991 Renderer.prototype.clearRenderedViews = function Renderer_clearRenderedViews(env) { 33992 env.renderedNodes.clear(); 33993 env.renderedViews.length = 0; 33994 }; 33995 33996 // This entry point is called from top-level `view.appendTo`. 33997 Renderer.prototype.appendTo = function Renderer_appendTo(view, target) { 33998 var morph = this._dom.appendMorph(target); 33999 morph.ownerNode = morph; 34000 view._willInsert = true; 34001 _emberMetalRun_loop.default.schedule('render', this, this.renderTopLevelView, view, morph); 34002 }; 34003 34004 Renderer.prototype.replaceIn = function Renderer_replaceIn(view, target) { 34005 var morph = this._dom.replaceContentWithMorph(target); 34006 morph.ownerNode = morph; 34007 view._willInsert = true; 34008 _emberMetalRun_loop.default.scheduleOnce('render', this, this.renderTopLevelView, view, morph); 34009 }; 34010 34011 Renderer.prototype.createElement = function Renderer_createElement(view) { 34012 var morph = this._dom.createFragmentMorph(); 34013 morph.ownerNode = morph; 34014 this.prerenderTopLevelView(view, morph); 34015 }; 34016 34017 Renderer.prototype.didCreateElement = function (view, element) { 34018 if (element) { 34019 view.element = element; 34020 } 34021 34022 if (view._transitionTo) { 34023 view._transitionTo('hasElement'); 34024 } 34025 }; // hasElement 34026 34027 Renderer.prototype.willInsertElement = function (view) { 34028 if (view.trigger) { 34029 view.trigger('willInsertElement'); 34030 } 34031 }; // Will place into DOM. 34032 34033 Renderer.prototype.setAttrs = function (view, attrs) { 34034 _emberMetalProperty_set.set(view, 'attrs', attrs); 34035 }; // Set attrs the first time. 34036 34037 Renderer.prototype.componentInitAttrs = function (component, attrs) { 34038 component.trigger('didInitAttrs', { attrs: attrs }); 34039 component.trigger('didReceiveAttrs', { newAttrs: attrs }); 34040 }; // Set attrs the first time. 34041 34042 Renderer.prototype.didInsertElement = function (view) { 34043 if (view._transitionTo) { 34044 view._transitionTo('inDOM'); 34045 } 34046 34047 if (view.trigger) { 34048 view.trigger('didInsertElement'); 34049 } 34050 }; // inDOM // Placed into DOM. 34051 34052 Renderer.prototype.didUpdate = function (view) { 34053 if (view.trigger) { 34054 view.trigger('didUpdate'); 34055 } 34056 }; 34057 34058 Renderer.prototype.didRender = function (view) { 34059 if (view.trigger) { 34060 view.trigger('didRender'); 34061 } 34062 }; 34063 34064 Renderer.prototype.updateAttrs = function (view, attrs) { 34065 this.setAttrs(view, attrs); 34066 }; // Setting new attrs. 34067 34068 Renderer.prototype.componentUpdateAttrs = function (component, newAttrs) { 34069 var oldAttrs = null; 34070 34071 if (component.attrs) { 34072 oldAttrs = _emberMetalAssign.default({}, component.attrs); 34073 _emberMetalSet_properties.default(component.attrs, newAttrs); 34074 } else { 34075 _emberMetalProperty_set.set(component, 'attrs', newAttrs); 34076 } 34077 34078 component.trigger('didUpdateAttrs', { oldAttrs: oldAttrs, newAttrs: newAttrs }); 34079 component.trigger('didReceiveAttrs', { oldAttrs: oldAttrs, newAttrs: newAttrs }); 34080 }; 34081 34082 Renderer.prototype.willUpdate = function (view, attrs) { 34083 if (view._willUpdate) { 34084 view._willUpdate(attrs); 34085 } 34086 }; 34087 34088 Renderer.prototype.componentWillUpdate = function (component) { 34089 component.trigger('willUpdate'); 34090 }; 34091 34092 Renderer.prototype.willRender = function (view) { 34093 if (view._willRender) { 34094 view._willRender(); 34095 } 34096 }; 34097 34098 Renderer.prototype.componentWillRender = function (component) { 34099 component.trigger('willRender'); 34100 }; 34101 34102 Renderer.prototype.rerender = function (view) { 34103 var renderNode = view._renderNode; 34104 34105 renderNode.isDirty = true; 34106 _htmlbarsRuntime.internal.visitChildren(renderNode.childNodes, function (node) { 34107 if (node.getState().manager) { 34108 node.shouldReceiveAttrs = true; 34109 } 34110 node.isDirty = true; 34111 }); 34112 34113 renderNode.ownerNode.emberView.scheduleRevalidate(renderNode, view.toString(), 'rerendering'); 34114 }; 34115 34116 Renderer.prototype.remove = function (view, shouldDestroy) { 34117 this.willDestroyElement(view); 34118 34119 view._willRemoveElement = true; 34120 _emberMetalRun_loop.default.schedule('render', this, this.renderElementRemoval, view); 34121 }; 34122
34123 Renderer.prototype.renderElementRemoval = function Renderer_renderElementRemoval(view) { 34124 // Use the _willRemoveElement flag to avoid mulitple removal attempts in 34125 // case many have been scheduled. This should be more performant than using 34126 // `scheduleOnce`. 34127 if (view._willRemoveElement) { 34128 view._willRemoveElement = false; 34129 34130 if (view._renderNode && view.element && view.element.parentNode) { 34131 view._renderNode.clear(); 34132 } 34133 this.didDestroyElement(view); 34134 } 34135 }; 34136 34137 Renderer.prototype.willRemoveElement = function () /*view*/{}; 34138 34139 Renderer.prototype.willDestroyElement = function (view) { 34140 if (view._willDestroyElement) { 34141 view._willDestroyElement(); 34142 } 34143 if (view.trigger) { 34144 view.trigger('willDestroyElement'); 34145 view.trigger('willClearRender'); 34146 } 34147 34148 if (view._transitionTo) { 34149 view._transitionTo('destroying'); 34150 } 34151 }; 34152 34153 Renderer.prototype.didDestroyElement = function (view) { 34154 view.element = null; 34155 34156 // Views that are being destroyed should never go back to the preRender state. 34157 // However if we're just destroying an element on a view (as is the case when 34158 // using View#remove) then the view should go to a preRender state so that 34159 // it can be rendered again later. 34160 if (view._state !== 'destroying' && view._transitionTo) { 34161 view._transitionTo('preRender'); 34162 } 34163 34164 if (view.trigger) { 34165 view.trigger('didDestroyElement'); 34166 } 34167 }; // Element destroyed so view.destroy shouldn't try to remove it removedFromDOM 34168 34169 exports.default = Renderer; 34170}); 34171enifed('ember-metal-views/index', ['exports', 'ember-metal-views/htmlbars-renderer'], function (exports, _emberMetalViewsHtmlbarsRenderer) { 34172 'use strict'; 34173 34174 function _interopExportWildcard(obj, defaults) { var newObj = defaults({}, obj); delete newObj['default']; return newObj; } 34175 34176 function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } 34177 34178 _defaults(exports, _interopExportWildcard(_emberMetalViewsHtmlbarsRenderer, _defaults)); 34179}); 34180enifed('ember-routing/ext/controller', ['exports', 'ember-metal/property_get', 'ember-runtime/mixins/controller'], function (exports, _emberMetalProperty_get, _emberRuntimeMixinsController) { 34181 'use strict'; 34182 34183 /** 34184 @module ember 34185 @submodule ember-routing 34186 */ 34187 34188 _emberRuntimeMixinsController.default.reopen({ 34189 concatenatedProperties: ['queryParams'], 34190 34191 /** 34192 Defines which query parameters the controller accepts. 34193 If you give the names `['category','page']` it will bind 34194 the values of these query parameters to the variables 34195 `this.category` and `this.page` 34196 @property queryParams 34197 @public 34198 */ 34199 queryParams: null, 34200 34201 /** 34202 @property _qpDelegate 34203 @private 34204 */ 34205 _qpDelegate: null, // set by route 34206 34207 /** 34208 @method _qpChanged 34209 @private 34210 */ 34211 _qpChanged: function (controller, _prop) { 34212 var prop = _prop.substr(0, _prop.length - 3); 34213 34214 var delegate = controller._qpDelegate; 34215 var value = _emberMetalProperty_get.get(controller, prop); 34216 delegate(prop, value); 34217 }, 34218 34219 /** 34220 Transition the application into another route. The route may 34221 be either a single route or route path: 34222 ```javascript 34223 aController.transitionToRoute('blogPosts'); 34224 aController.transitionToRoute('blogPosts.recentEntries'); 34225 ``` 34226 Optionally supply a model for the route in question. The model 34227 will be serialized into the URL using the `serialize` hook of 34228 the route: 34229 ```javascript 34230 aController.transitionToRoute('blogPost', aPost); 34231 ``` 34232 If a literal is passed (such as a number or a string), it will 34233 be treated as an identifier instead. In this case, the `model` 34234 hook of the route will be triggered: 34235 ```javascript 34236 aController.transitionToRoute('blogPost', 1); 34237 ``` 34238 Multiple models will be applied last to first recursively up the 34239 route tree. 34240 ```javascript 34241 App.Router.map(function() { 34242 this.route('blogPost', { path: ':blogPostId' }, function() { 34243 this.route('blogComment', { path: ':blogCommentId', resetNamespace: true }); 34244 }); 34245 }); 34246 aController.transitionToRoute('blogComment', aPost, aComment); 34247 aController.transitionToRoute('blogComment', 1, 13); 34248 ``` 34249 It is also possible to pass a URL (a string that starts with a 34250 `/`). This is intended for testing and debugging purposes and 34251 should rarely be used in production code. 34252 ```javascript 34253 aController.transitionToRoute('/'); 34254 aController.transitionToRoute('/blog/post/1/comment/13'); 34255 aController.transitionToRoute('/blog/posts?sort=title'); 34256 ``` 34257 An options hash with a `queryParams` property may be provided as 34258 the final argument to add query parameters to the destination URL. 34259 ```javascript 34260 aController.transitionToRoute('blogPost', 1, { 34261 queryParams: {showComments: 'true'} 34262 }); 34263 // if you just want to transition the query parameters without changing the route 34264 aController.transitionToRoute({queryParams: {sort: 'date'}}); 34265 ``` 34266 See also [replaceRoute](/api/classes/Ember.ControllerMixin.html#method_replaceRoute). 34267 @param {String} name the name of the route or a URL 34268 @param {...Object} models the model(s) or identifier(s) to be used 34269 while transitioning to the route. 34270 @param {Object} [options] optional hash with a queryParams property 34271 containing a mapping of query parameters 34272 @for Ember.ControllerMixin 34273 @method transitionToRoute 34274 @public 34275 */ 34276 transitionToRoute: function () { 34277 // target may be either another controller or a router 34278 var target = _emberMetalProperty_get.get(this, 'target'); 34279 var method = target.transitionToRoute || target.transitionTo; 34280 return method.apply(target, arguments); 34281 }, 34282 34283 /** 34284 Transition into another route while replacing the current URL, if possible. 34285 This will replace the current history entry instead of adding a new one. 34286 Beside that, it is identical to `transitionToRoute` in all other respects. 34287 ```javascript 34288 aController.replaceRoute('blogPosts'); 34289 aController.replaceRoute('blogPosts.recentEntries'); 34290 ``` 34291 Optionally supply a model for the route in question. The model 34292 will be serialized into the URL using the `serialize` hook of 34293 the route: 34294 ```javascript 34295 aController.replaceRoute('blogPost', aPost); 34296 ``` 34297 If a literal is passed (such as a number or a string), it will 34298 be treated as an identifier instead. In this case, the `model` 34299 hook of the route will be triggered: 34300 ```javascript 34301 aController.replaceRoute('blogPost', 1); 34302 ``` 34303 Multiple models will be applied last to first recursively up the 34304 route tree. 34305 ```javascript 34306 App.Router.map(function() { 34307 this.route('blogPost', { path: ':blogPostId' }, function() { 34308 this.route('blogComment', { path: ':blogCommentId', resetNamespace: true }); 34309 }); 34310 }); 34311 aController.replaceRoute('blogComment', aPost, aComment); 34312 aController.replaceRoute('blogComment', 1, 13); 34313 ``` 34314 It is also possible to pass a URL (a string that starts with a 34315 `/`). This is intended for testing and debugging purposes and 34316 should rarely be used in production code. 34317 ```javascript 34318 aController.replaceRoute('/'); 34319 aController.replaceRoute('/blog/post/1/comment/13'); 34320 ``` 34321 @param {String} name the name of the route or a URL 34322 @param {...Object} models the model(s) or identifier(s) to be used 34323 while transitioning to the route. 34324 @for Ember.ControllerMixin 34325 @method replaceRoute 34326 @private 34327 */ 34328 replaceRoute: function () { 34329 // target may be either another controller or a router 34330 var target = _emberMetalProperty_get.get(this, 'target'); 34331 var method = target.replaceRoute || target.replaceWith; 34332 return method.apply(target, arguments); 34333 } 34334 }); 34335 34336 exports.default = _emberRuntimeMixinsController.default; 34337}); 34338enifed('ember-routing/ext/run_loop', ['exports', 'ember-metal/run_loop'], function (exports, _emberMetalRun_loop) { 34339 'use strict'; 34340 34341 /** 34342 @module ember 34343 @submodule ember-views 34344 */ 34345 34346 // Add a new named queue after the 'actions' queue (where RSVP promises 34347 // resolve), which is used in router transitions to prevent unnecessary
34348 // loading state entry if all context promises resolve on the 34349 // 'actions' queue first. 34350 _emberMetalRun_loop.default._addQueue('routerTransitions', 'actions'); 34351}); 34352enifed('ember-routing/index', ['exports', 'ember-metal/core', 'ember-routing/ext/run_loop', 'ember-routing/ext/controller', 'ember-routing/location/api', 'ember-routing/location/none_location', 'ember-routing/location/hash_location', 'ember-routing/location/history_location', 'ember-routing/location/auto_location', 'ember-routing/system/generate_controller', 'ember-routing/system/controller_for', 'ember-routing/system/dsl', 'ember-routing/system/router', 'ember-routing/system/route'], function (exports, _emberMetalCore, _emberRoutingExtRun_loop, _emberRoutingExtController, _emberRoutingLocationApi, _emberRoutingLocationNone_location, _emberRoutingLocationHash_location, _emberRoutingLocationHistory_location, _emberRoutingLocationAuto_location, _emberRoutingSystemGenerate_controller, _emberRoutingSystemController_for, _emberRoutingSystemDsl, _emberRoutingSystemRouter, _emberRoutingSystemRoute) { 34353 /** 34354 @module ember 34355 @submodule ember-routing 34356 */ 34357 34358 'use strict'; 34359 34360 _emberMetalCore.default.Location = _emberRoutingLocationApi.default; 34361 _emberMetalCore.default.AutoLocation = _emberRoutingLocationAuto_location.default; 34362 _emberMetalCore.default.HashLocation = _emberRoutingLocationHash_location.default; 34363 _emberMetalCore.default.HistoryLocation = _emberRoutingLocationHistory_location.default; 34364 _emberMetalCore.default.NoneLocation = _emberRoutingLocationNone_location.default; 34365 34366 _emberMetalCore.default.controllerFor = _emberRoutingSystemController_for.default; 34367 _emberMetalCore.default.generateControllerFactory = _emberRoutingSystemGenerate_controller.generateControllerFactory; 34368 _emberMetalCore.default.generateController = _emberRoutingSystemGenerate_controller.default; 34369 _emberMetalCore.default.RouterDSL = _emberRoutingSystemDsl.default; 34370 _emberMetalCore.default.Router = _emberRoutingSystemRouter.default; 34371 _emberMetalCore.default.Route = _emberRoutingSystemRoute.default; 34372 34373 exports.default = _emberMetalCore.default; 34374}); 34375 34376// ES6TODO: Cleanup modules with side-effects below 34377enifed('ember-routing/location/api', ['exports', 'ember-metal/debug', 'ember-metal/environment', 'ember-routing/location/util'], function (exports, _emberMetalDebug, _emberMetalEnvironment, _emberRoutingLocationUtil) { 34378 'use strict'; 34379 34380 /** 34381 @module ember 34382 @submodule ember-routing 34383 */ 34384 34385 /** 34386 Ember.Location returns an instance of the correct implementation of 34387 the `location` API. 34388 34389 ## Implementations 34390 34391 You can pass an implementation name (`hash`, `history`, `none`) to force a 34392 particular implementation to be used in your application. 34393 34394 ### HashLocation 34395 34396 Using `HashLocation` results in URLs with a `#` (hash sign) separating the 34397 server side URL portion of the URL from the portion that is used by Ember. 34398 This relies upon the `hashchange` event existing in the browser. 34399 34400 Example: 34401 34402 ```javascript 34403 App.Router.map(function() { 34404 this.route('posts', function() { 34405 this.route('new'); 34406 }); 34407 }); 34408 34409 App.Router.reopen({ 34410 location: 'hash' 34411 }); 34412 ``` 34413 34414 This will result in a posts.new url of `/#/posts/new`. 34415 34416 ### HistoryLocation 34417 34418 Using `HistoryLocation` results in URLs that are indistinguishable from a 34419 standard URL. This relies upon the browser's `history` API. 34420 34421 Example: 34422 34423 ```javascript 34424 App.Router.map(function() { 34425 this.route('posts', function() { 34426 this.route('new'); 34427 }); 34428 }); 34429 34430 App.Router.reopen({ 34431 location: 'history' 34432 }); 34433 ``` 34434 34435 This will result in a posts.new url of `/posts/new`. 34436 34437 Keep in mind that your server must serve the Ember app at all the routes you 34438 define. 34439 34440 ### AutoLocation 34441 34442 Using `AutoLocation`, the router will use the best Location class supported by 34443 the browser it is running in. 34444 34445 Browsers that support the `history` API will use `HistoryLocation`, those that 34446 do not, but still support the `hashchange` event will use `HashLocation`, and 34447 in the rare case neither is supported will use `NoneLocation`. 34448 34449 Example: 34450 34451 ```javascript 34452 App.Router.map(function() { 34453 this.route('posts', function() { 34454 this.route('new'); 34455 }); 34456 }); 34457 34458 App.Router.reopen({ 34459 location: 'auto' 34460 }); 34461 ``` 34462 34463 This will result in a posts.new url of `/posts/new` for modern browsers that 34464 support the `history` api or `/#/posts/new` for older ones, like Internet 34465 Explorer 9 and below. 34466 34467 When a user visits a link to your application, they will be automatically 34468 upgraded or downgraded to the appropriate `Location` class, with the URL 34469 transformed accordingly, if needed. 34470 34471 Keep in mind that since some of your users will use `HistoryLocation`, your 34472 server must serve the Ember app at all the routes you define. 34473 34474 ### NoneLocation 34475 34476 Using `NoneLocation` causes Ember to not store the applications URL state 34477 in the actual URL. This is generally used for testing purposes, and is one 34478 of the changes made when calling `App.setupForTesting()`. 34479 34480 ## Location API 34481 34482 Each location implementation must provide the following methods: 34483 34484 * implementation: returns the string name used to reference the implementation. 34485 * getURL: returns the current URL. 34486 * setURL(path): sets the current URL. 34487 * replaceURL(path): replace the current URL (optional). 34488 * onUpdateURL(callback): triggers the callback when the URL changes. 34489 * formatURL(url): formats `url` to be placed into `href` attribute. 34490 * detect() (optional): instructs the location to do any feature detection 34491 necessary. If the location needs to redirect to a different URL, it 34492 can cancel routing by setting the `cancelRouterSetup` property on itself 34493 to `false`. 34494 34495 Calling setURL or replaceURL will not trigger onUpdateURL callbacks. 34496 34497 @class Location 34498 @namespace Ember 34499 @static 34500 @private 34501 */ 34502 exports.default = { 34503 /**
34504 This is deprecated in favor of using the container to lookup the location 34505 implementation as desired. 34506 For example: 34507 ```javascript 34508 // Given a location registered as follows: 34509 container.register('location:history-test', HistoryTestLocation); 34510 // You could create a new instance via: 34511 container.lookup('location:history-test'); 34512 ``` 34513 @method create 34514 @param {Object} options 34515 @return {Object} an instance of an implementation of the `location` API 34516 @deprecated Use the container to lookup the location implementation that you 34517 need. 34518 @private 34519 */ 34520 create: function (options) { 34521 var implementation = options && options.implementation; 34522 _emberMetalDebug.assert('Ember.Location.create: you must specify a \'implementation\' option', !!implementation); 34523 34524 var implementationClass = this.implementations[implementation]; 34525 _emberMetalDebug.assert('Ember.Location.create: ' + implementation + ' is not a valid implementation', !!implementationClass); 34526 34527 return implementationClass.create.apply(implementationClass, arguments); 34528 }, 34529 34530 implementations: {}, 34531 _location: _emberMetalEnvironment.default.location, 34532 34533 /** 34534 Returns the current `location.hash` by parsing location.href since browsers 34535 inconsistently URL-decode `location.hash`. 34536 https://bugzilla.mozilla.org/show_bug.cgi?id=483304 34537 @private 34538 @method getHash 34539 @since 1.4.0 34540 */ 34541 _getHash: function () { 34542 return _emberRoutingLocationUtil.getHash(this.location); 34543 } 34544 }; 34545}); 34546enifed('ember-routing/location/auto_location', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/utils', 'container/owner', 'ember-runtime/system/object', 'ember-metal/environment', 'ember-routing/location/util'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalUtils, _containerOwner, _emberRuntimeSystemObject, _emberMetalEnvironment, _emberRoutingLocationUtil) { 34547 'use strict'; 34548 34549 exports.getHistoryPath = getHistoryPath; 34550 exports.getHashPath = getHashPath; 34551 34552 /** 34553 @module ember 34554 @submodule ember-routing 34555 */ 34556 34557 /** 34558 Ember.AutoLocation will select the best location option based off browser 34559 support with the priority order: history, hash, none. 34560 34561 Clean pushState paths accessed by hashchange-only browsers will be redirected 34562 to the hash-equivalent and vice versa so future transitions are consistent. 34563 34564 Keep in mind that since some of your users will use `HistoryLocation`, your 34565 server must serve the Ember app at all the routes you define. 34566 34567 @class AutoLocation 34568 @namespace Ember 34569 @static 34570 @private 34571 */ 34572 exports.default = _emberRuntimeSystemObject.default.extend({ 34573 /** 34574 @private 34575 The browser's `location` object. This is typically equivalent to 34576 `window.location`, but may be overridden for testing. 34577 @property location 34578 @default environment.location 34579 */ 34580 location: _emberMetalEnvironment.default.location, 34581 34582 /** 34583 @private 34584 The browser's `history` object. This is typically equivalent to 34585 `window.history`, but may be overridden for testing. 34586 @since 1.5.1 34587 @property history 34588 @default environment.history 34589 */ 34590 history: _emberMetalEnvironment.default.history, 34591 34592 /** 34593 @private 34594 The user agent's global variable. In browsers, this will be `window`. 34595 @since 1.11 34596 @property global 34597 @default environment.global 34598 */ 34599 global: _emberMetalEnvironment.default.global, 34600 34601 /** 34602 @private 34603 The browser's `userAgent`. This is typically equivalent to 34604 `navigator.userAgent`, but may be overridden for testing. 34605 @since 1.5.1 34606 @property userAgent 34607 @default environment.history 34608 */ 34609 userAgent: _emberMetalEnvironment.default.userAgent, 34610 34611 /** 34612 @private 34613 This property is used by the router to know whether to cancel the routing 34614 setup process, which is needed while we redirect the browser. 34615 @since 1.5.1 34616 @property cancelRouterSetup 34617 @default false 34618 */ 34619 cancelRouterSetup: false, 34620 34621 /** 34622 @private 34623 Will be pre-pended to path upon state change. 34624 @since 1.5.1 34625 @property rootURL 34626 @default '/' 34627 */ 34628 rootURL: '/', 34629 34630 /** 34631 Called by the router to instruct the location to do any feature detection 34632 necessary. In the case of AutoLocation, we detect whether to use history 34633 or hash concrete implementations. 34634 @private 34635 */ 34636 detect: function () { 34637 var rootURL = this.rootURL; 34638 34639 _emberMetalDebug.assert('rootURL must end with a trailing forward slash e.g. "/app/"', rootURL.charAt(rootURL.length - 1) === '/'); 34640 34641 var implementation = detectImplementation({ 34642 location: this.location, 34643 history: this.history, 34644 userAgent: this.userAgent, 34645 rootURL: rootURL, 34646 documentMode: this.documentMode, 34647 global: this.global 34648 }); 34649 34650 if (implementation === false) { 34651 _emberMetalProperty_set.set(this, 'cancelRouterSetup', true);
34652 implementation = 'none'; 34653 } 34654 34655 var concrete = _containerOwner.getOwner(this).lookup('location:' + implementation); 34656 _emberMetalProperty_set.set(concrete, 'rootURL', rootURL); 34657 34658 _emberMetalDebug.assert('Could not find location \'' + implementation + '\'.', !!concrete); 34659 34660 _emberMetalProperty_set.set(this, 'concreteImplementation', concrete); 34661 }, 34662 34663 initState: delegateToConcreteImplementation('initState'), 34664 getURL: delegateToConcreteImplementation('getURL'), 34665 setURL: delegateToConcreteImplementation('setURL'), 34666 replaceURL: delegateToConcreteImplementation('replaceURL'), 34667 onUpdateURL: delegateToConcreteImplementation('onUpdateURL'), 34668 formatURL: delegateToConcreteImplementation('formatURL'), 34669 34670 willDestroy: function () { 34671 var concreteImplementation = _emberMetalProperty_get.get(this, 'concreteImplementation'); 34672 34673 if (concreteImplementation) { 34674 concreteImplementation.destroy(); 34675 } 34676 } 34677 }); 34678 34679 function delegateToConcreteImplementation(methodName) { 34680 return function () { 34681 var concreteImplementation = _emberMetalProperty_get.get(this, 'concreteImplementation'); 34682 _emberMetalDebug.assert('AutoLocation\'s detect() method should be called before calling any other hooks.', !!concreteImplementation); 34683 34684 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 34685 args[_key] = arguments[_key]; 34686 } 34687 34688 return _emberMetalUtils.tryInvoke(concreteImplementation, methodName, args); 34689 }; 34690 } 34691 34692 /* 34693 Given the browser's `location`, `history` and `userAgent`, and a configured 34694 root URL, this function detects whether the browser supports the [History 34695 API](https://developer.mozilla.org/en-US/docs/Web/API/History) and returns a 34696 string representing the Location object to use based on its determination. 34697 34698 For example, if the page loads in an evergreen browser, this function would 34699 return the string "history", meaning the history API and thus HistoryLocation 34700 should be used. If the page is loaded in IE8, it will return the string 34701 "hash," indicating that the History API should be simulated by manipulating the 34702 hash portion of the location. 34703 34704 */ 34705 34706 function detectImplementation(options) { 34707 var location = options.location; 34708 var userAgent = options.userAgent; 34709 var history = options.history; 34710 var documentMode = options.documentMode; 34711 var global = options.global; 34712 var rootURL = options.rootURL; 34713 34714 var implementation = 'none'; 34715 var cancelRouterSetup = false; 34716 var currentPath = _emberRoutingLocationUtil.getFullPath(location); 34717 34718 if (_emberRoutingLocationUtil.supportsHistory(userAgent, history)) { 34719 var historyPath = getHistoryPath(rootURL, location); 34720 34721 // If the browser supports history and we have a history path, we can use 34722 // the history location with no redirects. 34723 if (currentPath === historyPath) { 34724 return 'history'; 34725 } else { 34726 if (currentPath.substr(0, 2) === '/#') { 34727 history.replaceState({ path: historyPath }, null, historyPath); 34728 implementation = 'history'; 34729 } else { 34730 cancelRouterSetup = true; 34731 _emberRoutingLocationUtil.replacePath(location, historyPath); 34732 } 34733 } 34734 } else if (_emberRoutingLocationUtil.supportsHashChange(documentMode, global)) { 34735 var hashPath = getHashPath(rootURL, location); 34736 34737 // Be sure we're using a hashed path, otherwise let's switch over it to so 34738 // we start off clean and consistent. We'll count an index path with no 34739 // hash as "good enough" as well. 34740 if (currentPath === hashPath || currentPath === '/' && hashPath === '/#/') { 34741 implementation = 'hash'; 34742 } else { 34743 // Our URL isn't in the expected hash-supported format, so we want to 34744 // cancel the router setup and replace the URL to start off clean 34745 cancelRouterSetup = true; 34746 _emberRoutingLocationUtil.replacePath(location, hashPath); 34747 } 34748 } 34749 34750 if (cancelRouterSetup) { 34751 return false; 34752 } 34753 34754 return implementation; 34755 } 34756 34757 /** 34758 @private 34759 34760 Returns the current path as it should appear for HistoryLocation supported 34761 browsers. This may very well differ from the real current path (e.g. if it 34762 starts off as a hashed URL) 34763 */ 34764 34765 function getHistoryPath(rootURL, location) { 34766 var path = _emberRoutingLocationUtil.getPath(location); 34767 var hash = _emberRoutingLocationUtil.getHash(location); 34768 var query = _emberRoutingLocationUtil.getQuery(location); 34769 var rootURLIndex = path.indexOf(rootURL); 34770 var routeHash, hashParts; 34771 34772 _emberMetalDebug.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0); 34773 34774 // By convention, Ember.js routes using HashLocation are required to start 34775 // with `#/`. Anything else should NOT be considered a route and should 34776 // be passed straight through, without transformation. 34777 if (hash.substr(0, 2) === '#/') { 34778 // There could be extra hash segments after the route 34779 hashParts = hash.substr(1).split('#'); 34780 // The first one is always the route url 34781 routeHash = hashParts.shift(); 34782 34783 // If the path already has a trailing slash, remove the one 34784 // from the hashed route so we don't double up. 34785 if (path.slice(-1) === '/') { 34786 routeHash = routeHash.substr(1); 34787 } 34788 34789 // This is the "expected" final order 34790 path = path + routeHash + query; 34791 34792 if (hashParts.length) { 34793 path += '#' + hashParts.join('#'); 34794 } 34795 } else { 34796 path = path + query + hash; 34797 } 34798 34799 return path; 34800 } 34801 34802 /** 34803 @private 34804 34805 Returns the current path as it should appear for HashLocation supported 34806 browsers. This may very well differ from the real current path. 34807 34808 @method _getHashPath 34809 */ 34810 34811 function getHashPath(rootURL, location) { 34812 var path = rootURL; 34813 var historyPath = getHistoryPath(rootURL, location); 34814 var routePath = historyPath.substr(rootURL.length); 34815 34816 if (routePath !== '') { 34817 if (routePath.charAt(0) !== '/') { 34818 routePath = '/' + routePath; 34819 } 34820 34821 path += '#' + routePath; 34822 } 34823 34824 return path; 34825 } 34826}); 34827enifed('ember-routing/location/hash_location', ['exports', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/run_loop', 'ember-metal/utils', 'ember-runtime/system/object', 'ember-routing/location/api', 'ember-views/system/jquery'], function (exports, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalRun_loop, _emberMetalUtils, _emberRuntimeSystemObject, _emberRoutingLocationApi, _emberViewsSystemJquery) { 34828 'use strict'; 34829 34830 /** 34831 @module ember 34832 @submodule ember-routing 34833 */ 34834 34835 /** 34836 `Ember.HashLocation` implements the location API using the browser's 34837 hash. At present, it relies on a `hashchange` event existing in the 34838 browser. 34839 34840 @class HashLocation 34841 @namespace Ember
34842 @extends Ember.Object 34843 @private 34844 */ 34845 exports.default = _emberRuntimeSystemObject.default.extend({ 34846 implementation: 'hash', 34847 34848 init: function () { 34849 _emberMetalProperty_set.set(this, 'location', _emberMetalProperty_get.get(this, '_location') || window.location); 34850 }, 34851 34852 /** 34853 @private 34854 Returns normalized location.hash 34855 @since 1.5.1 34856 @method getHash 34857 */ 34858 getHash: _emberRoutingLocationApi.default._getHash, 34859 34860 /** 34861 Returns the normalized URL, constructed from `location.hash`. 34862 e.g. `#/foo` => `/foo` as well as `#/foo#bar` => `/foo#bar`. 34863 By convention, hashed paths must begin with a forward slash, otherwise they 34864 are not treated as a path so we can distinguish intent. 34865 @private 34866 @method getURL 34867 */ 34868 getURL: function () { 34869 var originalPath = this.getHash().substr(1); 34870 var outPath = originalPath; 34871 34872 if (outPath.charAt(0) !== '/') { 34873 outPath = '/'; 34874 34875 // Only add the # if the path isn't empty. 34876 // We do NOT want `/#` since the ampersand 34877 // is only included (conventionally) when 34878 // the location.hash has a value 34879 if (originalPath) { 34880 outPath += '#' + originalPath; 34881 } 34882 } 34883 34884 return outPath; 34885 }, 34886 34887 /** 34888 Set the `location.hash` and remembers what was set. This prevents 34889 `onUpdateURL` callbacks from triggering when the hash was set by 34890 `HashLocation`. 34891 @private 34892 @method setURL 34893 @param path {String} 34894 */ 34895 setURL: function (path) { 34896 _emberMetalProperty_get.get(this, 'location').hash = path; 34897 _emberMetalProperty_set.set(this, 'lastSetURL', path); 34898 }, 34899 34900 /** 34901 Uses location.replace to update the url without a page reload 34902 or history modification. 34903 @private 34904 @method replaceURL 34905 @param path {String} 34906 */ 34907 replaceURL: function (path) { 34908 _emberMetalProperty_get.get(this, 'location').replace('#' + path); 34909 _emberMetalProperty_set.set(this, 'lastSetURL', path); 34910 }, 34911 34912 /** 34913 Register a callback to be invoked when the hash changes. These 34914 callbacks will execute when the user presses the back or forward 34915 button, but not after `setURL` is invoked. 34916 @private 34917 @method onUpdateURL 34918 @param callback {Function} 34919 */ 34920 onUpdateURL: function (callback) { 34921 var _this = this; 34922 34923 var guid = _emberMetalUtils.guidFor(this); 34924 34925 _emberViewsSystemJquery.default(window).on('hashchange.ember-location-' + guid, function () { 34926 _emberMetalRun_loop.default(function () { 34927 var path = _this.getURL(); 34928 if (_emberMetalProperty_get.get(_this, 'lastSetURL') === path) { 34929 return; 34930 } 34931 34932 _emberMetalProperty_set.set(_this, 'lastSetURL', null); 34933 34934 callback(path); 34935 }); 34936 }); 34937 }, 34938 34939 /** 34940 Given a URL, formats it to be placed into the page as part 34941 of an element's `href` attribute. 34942 This is used, for example, when using the {{action}} helper 34943 to generate a URL based on an event. 34944 @private 34945 @method formatURL 34946 @param url {String} 34947 */ 34948 formatURL: function (url) { 34949 return '#' + url; 34950 }, 34951 34952 /** 34953 Cleans up the HashLocation event listener. 34954 @private 34955 @method willDestroy 34956 */ 34957 willDestroy: function () { 34958 var guid = _emberMetalUtils.guidFor(this); 34959 34960 _emberViewsSystemJquery.default(window).off('hashchange.ember-location-' + guid); 34961 } 34962 }); 34963}); 34964enifed('ember-routing/location/history_location', ['exports', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/utils', 'ember-runtime/system/object', 'ember-routing/location/api', 'ember-views/system/jquery'], function (exports, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalUtils, _emberRuntimeSystemObject, _emberRoutingLocationApi, _emberViewsSystemJquery) { 34965 'use strict'; 34966 34967 /** 34968 @module ember 34969 @submodule ember-routing 34970 */ 34971 34972 var popstateFired = false; 34973 34974 /** 34975 Ember.HistoryLocation implements the location API using the browser's 34976 history.pushState API. 34977 34978 @class HistoryLocation 34979 @namespace Ember
34980 @extends Ember.Object 34981 @private 34982 */ 34983 exports.default = _emberRuntimeSystemObject.default.extend({ 34984 implementation: 'history', 34985 34986 init: function () { 34987 _emberMetalProperty_set.set(this, 'location', _emberMetalProperty_get.get(this, 'location') || window.location); 34988 _emberMetalProperty_set.set(this, 'baseURL', _emberViewsSystemJquery.default('base').attr('href') || ''); 34989 }, 34990 34991 /** 34992 Used to set state on first call to setURL 34993 @private 34994 @method initState 34995 */ 34996 initState: function () { 34997 var history = _emberMetalProperty_get.get(this, 'history') || window.history; 34998 _emberMetalProperty_set.set(this, 'history', history); 34999 35000 if (history && 'state' in history) { 35001 this.supportsHistory = true; 35002 } 35003 35004 this.replaceState(this.formatURL(this.getURL())); 35005 }, 35006 35007 /** 35008 Will be pre-pended to path upon state change 35009 @property rootURL 35010 @default '/' 35011 @private 35012 */ 35013 rootURL: '/', 35014 35015 /** 35016 Returns the current `location.pathname` without `rootURL` or `baseURL` 35017 @private 35018 @method getURL 35019 @return url {String} 35020 */ 35021 getURL: function () { 35022 var rootURL = _emberMetalProperty_get.get(this, 'rootURL'); 35023 var location = _emberMetalProperty_get.get(this, 'location'); 35024 var path = location.pathname; 35025 var baseURL = _emberMetalProperty_get.get(this, 'baseURL'); 35026 35027 rootURL = rootURL.replace(/\/$/, ''); 35028 baseURL = baseURL.replace(/\/$/, ''); 35029 35030 var url = path.replace(baseURL, '').replace(rootURL, ''); 35031 var search = location.search || ''; 35032 35033 url += search; 35034 url += this.getHash(); 35035 35036 return url; 35037 }, 35038 35039 /** 35040 Uses `history.pushState` to update the url without a page reload. 35041 @private 35042 @method setURL 35043 @param path {String} 35044 */ 35045 setURL: function (path) { 35046 var state = this.getState(); 35047 path = this.formatURL(path); 35048 35049 if (!state || state.path !== path) { 35050 this.pushState(path); 35051 } 35052 }, 35053 35054 /** 35055 Uses `history.replaceState` to update the url without a page reload 35056 or history modification. 35057 @private 35058 @method replaceURL 35059 @param path {String} 35060 */ 35061 replaceURL: function (path) { 35062 var state = this.getState(); 35063 path = this.formatURL(path); 35064 35065 if (!state || state.path !== path) { 35066 this.replaceState(path); 35067 } 35068 }, 35069 35070 /** 35071 Get the current `history.state`. Checks for if a polyfill is 35072 required and if so fetches this._historyState. The state returned 35073 from getState may be null if an iframe has changed a window's 35074 history. 35075 @private 35076 @method getState 35077 @return state {Object} 35078 */ 35079 getState: function () { 35080 if (this.supportsHistory) { 35081 return _emberMetalProperty_get.get(this, 'history').state; 35082 } 35083 35084 return this._historyState; 35085 }, 35086 35087 /** 35088 Pushes a new state. 35089 @private 35090 @method pushState 35091 @param path {String} 35092 */ 35093 pushState: function (path) { 35094 var state = { path: path }; 35095 35096 _emberMetalProperty_get.get(this, 'history').pushState(state, null, path); 35097 35098 this._historyState = state; 35099 35100 // used for webkit workaround 35101 this._previousURL = this.getURL(); 35102 }, 35103 35104 /** 35105 Replaces the current state. 35106 @private 35107 @method replaceState 35108 @param path {String} 35109 */ 35110 replaceState: function (path) { 35111 var state = { path: path }; 35112 _emberMetalProperty_get.get(this, 'history').replaceState(state, null, path); 35113 35114 this._historyState = state; 35115 35116 // used for webkit workaround 35117 this._previousURL = this.getURL(); 35118 }, 35119 35120 /** 35121 Register a callback to be invoked whenever the browser 35122 history changes, including using forward and back buttons. 35123 @private 35124 @method onUpdateURL 35125 @param callback {Function} 35126 */ 35127 onUpdateURL: function (callback) { 35128 var _this = this; 35129 35130 var guid = _emberMetalUtils.guidFor(this); 35131 35132 _emberViewsSystemJquery.default(window).on('popstate.ember-location-' + guid, function (e) { 35133 // Ignore initial page load popstate event in Chrome 35134 if (!popstateFired) { 35135 popstateFired = true; 35136 if (_this.getURL() === _this._previousURL) { 35137 return; 35138 } 35139 } 35140 callback(_this.getURL()); 35141 }); 35142 }, 35143 35144 /** 35145 Used when using `{{action}}` helper. The url is always appended to the rootURL. 35146 @private 35147 @method formatURL 35148 @param url {String} 35149 @return formatted url {String} 35150 */ 35151 formatURL: function (url) { 35152 var rootURL = _emberMetalProperty_get.get(this, 'rootURL'); 35153 var baseURL = _emberMetalProperty_get.get(this, 'baseURL'); 35154 35155 if (url !== '') { 35156 rootURL = rootURL.replace(/\/$/, ''); 35157 baseURL = baseURL.replace(/\/$/, ''); 35158 } else if (baseURL.match(/^\//) && rootURL.match(/^\//)) { 35159 baseURL = baseURL.replace(/\/$/, ''); 35160 } 35161 35162 return baseURL + rootURL + url; 35163 }, 35164 35165 /** 35166 Cleans up the HistoryLocation event listener. 35167 @private 35168 @method willDestroy 35169 */ 35170 willDestroy: function () { 35171 var guid = _emberMetalUtils.guidFor(this); 35172 35173 _emberViewsSystemJquery.default(window).off('popstate.ember-location-' + guid); 35174 }, 35175 35176 /** 35177 @private 35178 Returns normalized location.hash 35179 @method getHash 35180 */ 35181 getHash: _emberRoutingLocationApi.default._getHash 35182 }); 35183}); 35184enifed('ember-routing/location/none_location', ['exports', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-runtime/system/object'], function (exports, _emberMetalProperty_get, _emberMetalProperty_set, _emberRuntimeSystemObject) { 35185 'use strict'; 35186 35187 /** 35188 @module ember 35189 @submodule ember-routing 35190 */ 35191 35192 /** 35193 Ember.NoneLocation does not interact with the browser. It is useful for 35194 testing, or when you need to manage state with your Router, but temporarily 35195 don't want it to muck with the URL (for example when you embed your 35196 application in a larger page). 35197
35198 @class NoneLocation 35199 @namespace Ember 35200 @extends Ember.Object 35201 @private 35202 */ 35203 exports.default = _emberRuntimeSystemObject.default.extend({ 35204 implementation: 'none', 35205 path: '', 35206 35207 /** 35208 Returns the current path. 35209 @private 35210 @method getURL 35211 @return {String} path 35212 */ 35213 getURL: function () { 35214 return _emberMetalProperty_get.get(this, 'path'); 35215 }, 35216 35217 /** 35218 Set the path and remembers what was set. Using this method 35219 to change the path will not invoke the `updateURL` callback. 35220 @private 35221 @method setURL 35222 @param path {String} 35223 */ 35224 setURL: function (path) { 35225 _emberMetalProperty_set.set(this, 'path', path); 35226 }, 35227 35228 /** 35229 Register a callback to be invoked when the path changes. These 35230 callbacks will execute when the user presses the back or forward 35231 button, but not after `setURL` is invoked. 35232 @private 35233 @method onUpdateURL 35234 @param callback {Function} 35235 */ 35236 onUpdateURL: function (callback) { 35237 this.updateCallback = callback; 35238 }, 35239 35240 /** 35241 Sets the path and calls the `updateURL` callback. 35242 @private 35243 @method handleURL 35244 @param callback {Function} 35245 */ 35246 handleURL: function (url) { 35247 _emberMetalProperty_set.set(this, 'path', url); 35248 this.updateCallback(url); 35249 }, 35250 35251 /** 35252 Given a URL, formats it to be placed into the page as part 35253 of an element's `href` attribute. 35254 This is used, for example, when using the {{action}} helper 35255 to generate a URL based on an event. 35256 @private 35257 @method formatURL 35258 @param url {String} 35259 @return {String} url 35260 */ 35261 formatURL: function (url) { 35262 // The return value is not overly meaningful, but we do not want to throw 35263 // errors when test code renders templates containing {{action href=true}} 35264 // helpers. 35265 return url; 35266 } 35267 }); 35268}); 35269enifed('ember-routing/location/util', ['exports'], function (exports) { 35270 /** 35271 @private 35272 35273 Returns the current `location.pathname`, normalized for IE inconsistencies. 35274 */ 35275 'use strict'; 35276 35277 exports.getPath = getPath; 35278 exports.getQuery = getQuery; 35279 exports.getHash = getHash; 35280 exports.getFullPath = getFullPath; 35281 exports.getOrigin = getOrigin; 35282 exports.supportsHashChange = supportsHashChange; 35283 exports.supportsHistory = supportsHistory; 35284 exports.replacePath = replacePath; 35285 35286 function getPath(location) { 35287 var pathname = location.pathname; 35288 // Various versions of IE/Opera don't always return a leading slash 35289 if (pathname.charAt(0) !== '/') { 35290 pathname = '/' + pathname; 35291 } 35292 35293 return pathname; 35294 } 35295 35296 /** 35297 @private 35298 35299 Returns the current `location.search`. 35300 */ 35301 35302 function getQuery(location) { 35303 return location.search; 35304 } 35305 35306 /** 35307 @private 35308 35309 Returns the current `location.hash` by parsing location.href since browsers 35310 inconsistently URL-decode `location.hash`. 35311 35312 Should be passed the browser's `location` object as the first argument. 35313 35314 https://bugzilla.mozilla.org/show_bug.cgi?id=483304 35315 */ 35316 35317 function getHash(location) { 35318 var href = location.href; 35319 var hashIndex = href.indexOf('#'); 35320 35321 if (hashIndex === -1) { 35322 return ''; 35323 } else { 35324 return href.substr(hashIndex); 35325 } 35326 } 35327 35328 function getFullPath(location) { 35329 return getPath(location) + getQuery(location) + getHash(location); 35330 } 35331 35332 function getOrigin(location) { 35333 var origin = location.origin; 35334 35335 // Older browsers, especially IE, don't have origin 35336 if (!origin) { 35337 origin = location.protocol + '//' + location.hostname; 35338 35339 if (location.port) { 35340 origin += ':' + location.port; 35341 } 35342 } 35343 35344 return origin; 35345 } 35346 35347 /* 35348 `documentMode` only exist in Internet Explorer, and it's tested because IE8 running in 35349 IE7 compatibility mode claims to support `onhashchange` but actually does not. 35350 35351 `global` is an object that may have an `onhashchange` property. 35352 35353 @private 35354 @function supportsHashChange 35355 */ 35356 35357 function supportsHashChange(documentMode, global) { 35358 return 'onhashchange' in global && (documentMode === undefined || documentMode > 7); 35359 } 35360 35361 /* 35362 `userAgent` is a user agent string. We use user agent testing here, because 35363 the stock Android browser is known to have buggy versions of the History API, 35364 in some Android versions. 35365 35366 @private 35367 @function supportsHistory 35368 */ 35369 35370 function supportsHistory(userAgent, history) { 35371 // Boosted from Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js 35372 // The stock browser on Android 2.2 & 2.3, and 4.0.x returns positive on history support 35373 // Unfortunately support is really buggy and there is no clean way to detect 35374 // these bugs, so we fall back to a user agent sniff :( 35375
35376 // We only want Android 2 and 4.0, stock browser, and not Chrome which identifies 35377 // itself as 'Mobile Safari' as well, nor Windows Phone. 35378 if ((userAgent.indexOf('Android 2.') !== -1 || userAgent.indexOf('Android 4.0') !== -1) && userAgent.indexOf('Mobile Safari') !== -1 && userAgent.indexOf('Chrome') === -1 && userAgent.indexOf('Windows Phone') === -1) { 35379 return false; 35380 } 35381 35382 return !!(history && 'pushState' in history); 35383 } 35384 35385 /** 35386 Replaces the current location, making sure we explicitly include the origin 35387 to prevent redirecting to a different origin. 35388 35389 @private 35390 */ 35391 35392 function replacePath(location, path) { 35393 location.replace(getOrigin(location) + path); 35394 } 35395}); 35396enifed('ember-routing/services/routing', ['exports', 'ember-runtime/system/service', 'ember-metal/property_get', 'ember-metal/computed_macros', 'ember-routing/utils', 'ember-metal/assign'], function (exports, _emberRuntimeSystemService, _emberMetalProperty_get, _emberMetalComputed_macros, _emberRoutingUtils, _emberMetalAssign) { 35397 /** 35398 @module ember 35399 @submodule ember-routing 35400 */ 35401 35402 'use strict'; 35403 35404 /** 35405 The Routing service is used by LinkComponent, and provides facilities for 35406 the component/view layer to interact with the router. 35407 35408 While still private, this service can eventually be opened up, and provides
35409 the set of API needed for components to control routing without interacting 35410 with router internals. 35411 35412 @private 35413 @class RoutingService 35414 */ 35415 exports.default = _emberRuntimeSystemService.default.extend({ 35416 router: null, 35417 35418 targetState: _emberMetalComputed_macros.readOnly('router.targetState'), 35419 currentState: _emberMetalComputed_macros.readOnly('router.currentState'), 35420 currentRouteName: _emberMetalComputed_macros.readOnly('router.currentRouteName'), 35421 currentPath: _emberMetalComputed_macros.readOnly('router.currentPath'), 35422 35423 availableRoutes: function () { 35424 return Object.keys(_emberMetalProperty_get.get(this, 'router').router.recognizer.names); 35425 }, 35426 35427 hasRoute: function (routeName) { 35428 return _emberMetalProperty_get.get(this, 'router').hasRoute(routeName); 35429 }, 35430 35431 transitionTo: function (routeName, models, queryParams, shouldReplace) { 35432 var router = _emberMetalProperty_get.get(this, 'router'); 35433 35434 var transition = router._doTransition(routeName, models, queryParams); 35435 35436 if (shouldReplace) { 35437 transition.method('replace'); 35438 } 35439 }, 35440 35441 normalizeQueryParams: function (routeName, models, queryParams) { 35442 var router = _emberMetalProperty_get.get(this, 'router'); 35443 router._prepareQueryParams(routeName, models, queryParams); 35444 }, 35445 35446 generateURL: function (routeName, models, queryParams) { 35447 var router = _emberMetalProperty_get.get(this, 'router'); 35448 if (!router.router) { 35449 return; 35450 } 35451 35452 var visibleQueryParams = {}; 35453 _emberMetalAssign.default(visibleQueryParams, queryParams); 35454 35455 this.normalizeQueryParams(routeName, models, visibleQueryParams); 35456 35457 var args = _emberRoutingUtils.routeArgs(routeName, models, visibleQueryParams); 35458 return router.generate.apply(router, args); 35459 }, 35460 35461 isActiveForRoute: function (contexts, queryParams, routeName, routerState, isCurrentWhenSpecified) { 35462 var router = _emberMetalProperty_get.get(this, 'router'); 35463 35464 var handlers = router.router.recognizer.handlersFor(routeName); 35465 var leafName = handlers[handlers.length - 1].handler; 35466 var maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); 35467 35468 // NOTE: any ugliness in the calculation of activeness is largely 35469 // due to the fact that we support automatic normalizing of 35470 // `resource` -> `resource.index`, even though there might be 35471 // dynamic segments / query params defined on `resource.index` 35472 // which complicates (and makes somewhat ambiguous) the calculation 35473 // of activeness for links that link to `resource` instead of 35474 // directly to `resource.index`. 35475 35476 // if we don't have enough contexts revert back to full route name 35477 // this is because the leaf route will use one of the contexts 35478 if (contexts.length > maximumContexts) { 35479 routeName = leafName; 35480 } 35481 35482 return routerState.isActiveIntent(routeName, contexts, queryParams, !isCurrentWhenSpecified); 35483 } 35484 }); 35485 35486 function numberOfContextsAcceptedByHandler(handler, handlerInfos) { 35487 var req = 0; 35488 for (var i = 0, l = handlerInfos.length; i < l; i++) { 35489 req = req + handlerInfos[i].names.length; 35490 if (handlerInfos[i].handler === handler) { 35491 break; 35492 } 35493 } 35494 35495 return req; 35496 } 35497}); 35498enifed('ember-routing/system/cache', ['exports', 'ember-runtime/system/object'], function (exports, _emberRuntimeSystemObject) { 35499 'use strict'; 35500 35501 exports.default = _emberRuntimeSystemObject.default.extend({ 35502 init: function () { 35503 this.cache = {}; 35504 }, 35505 has: function (bucketKey) { 35506 return bucketKey in this.cache; 35507 }, 35508 stash: function (bucketKey, key, value) { 35509 var bucket = this.cache[bucketKey]; 35510 if (!bucket) { 35511 bucket = this.cache[bucketKey] = {}; 35512 } 35513 bucket[key] = value; 35514 }, 35515 lookup: function (bucketKey, prop, defaultValue) { 35516 var cache = this.cache; 35517 if (!(bucketKey in cache)) { 35518 return defaultValue; 35519 } 35520 var bucket = cache[bucketKey]; 35521 if (prop in bucket) { 35522 return bucket[prop]; 35523 } else { 35524 return defaultValue; 35525 } 35526 }, 35527 cache: null 35528 }); 35529}); 35530enifed("ember-routing/system/controller_for", ["exports"], function (exports) { 35531 /** 35532 @module ember 35533 @submodule ember-routing 35534 */ 35535 35536 /** 35537 35538 Finds a controller instance. 35539 35540 @for Ember 35541 @method controllerFor 35542 @private 35543 */ 35544 "use strict"; 35545 35546 exports.default = controllerFor; 35547 35548 function controllerFor(container, controllerName, lookupOptions) {
35549 return container.lookup("controller:" + controllerName, lookupOptions); 35550 } 35551}); 35552enifed('ember-routing/system/dsl', ['exports', 'ember-metal/debug'], function (exports, _emberMetalDebug) { 35553 'use strict'; 35554 35555 /** 35556 @module ember 35557 @submodule ember-routing 35558 */ 35559 35560 function DSL(name, options) { 35561 this.parent = name; 35562 this.enableLoadingSubstates = options && options.enableLoadingSubstates; 35563 this.matches = []; 35564 this.explicitIndex = undefined; 35565 this.options = options; 35566 } 35567 35568 exports.default = DSL; 35569 35570 DSL.prototype = { 35571 route: function (name, options, callback) { 35572 var dummyErrorRoute = '/_unused_dummy_error_path_route_' + name + '/:error'; 35573 if (arguments.length === 2 && typeof options === 'function') { 35574 callback = options; 35575 options = {}; 35576 } 35577 35578 if (arguments.length === 1) { 35579 options = {}; 35580 } 35581 35582 _emberMetalDebug.assert('\'' + name + '\' cannot be used as a route name.', (function () { 35583 if (options.overrideNameAssertion === true) { 35584 return true; 35585 } 35586 35587 return ['array', 'basic', 'object', 'application'].indexOf(name) === -1; 35588 })()); 35589 35590 _emberMetalDebug.warn('Using a route named \'select\' (and defining a App.SelectView) will prevent you from using {{view \'select\'}}', name !== 'select', { id: 'ember-routing.dsl-select-route' }); 35591 35592 if (this.enableLoadingSubstates) { 35593 createRoute(this, name + '_loading', { resetNamespace: options.resetNamespace }); 35594 createRoute(this, name + '_error', { path: dummyErrorRoute }); 35595 } 35596 35597 if (callback) { 35598 var fullName = getFullName(this, name, options.resetNamespace); 35599 var dsl = new DSL(fullName, this.options); 35600 35601 createRoute(dsl, 'loading'); 35602 createRoute(dsl, 'error', { path: dummyErrorRoute }); 35603 35604 callback.call(dsl); 35605 35606 createRoute(this, name, options, dsl.generate()); 35607 } else { 35608 createRoute(this, name, options); 35609 } 35610 }, 35611 35612 push: function (url, name, callback) { 35613 var parts = name.split('.'); 35614 if (url === '' || url === '/' || parts[parts.length - 1] === 'index') { 35615 this.explicitIndex = true; 35616 } 35617 35618 this.matches.push([url, name, callback]); 35619 }, 35620 35621 resource: function (name, options, callback) { 35622 if (arguments.length === 2 && typeof options === 'function') { 35623 callback = options; 35624 options = {}; 35625 } 35626 35627 if (arguments.length === 1) { 35628 options = {}; 35629 } 35630 35631 options.resetNamespace = true; 35632 _emberMetalDebug.deprecate('this.resource() is deprecated. Use this.route(\'name\', { resetNamespace: true }, function () {}) instead.', false, { id: 'ember-routing.router-resource', until: '3.0.0' }); 35633 this.route(name, options, callback); 35634 }, 35635 35636 generate: function () { 35637 var dslMatches = this.matches; 35638 35639 if (!this.explicitIndex) { 35640 this.route('index', { path: '/' }); 35641 } 35642 35643 return function (match) { 35644 for (var i = 0, l = dslMatches.length; i < l; i++) { 35645 var dslMatch = dslMatches[i]; 35646 match(dslMatch[0]).to(dslMatch[1], dslMatch[2]); 35647 } 35648 }; 35649 } 35650 }; 35651 35652 function canNest(dsl) { 35653 return dsl.parent && dsl.parent !== 'application'; 35654 } 35655 35656 function getFullName(dsl, name, resetNamespace) { 35657 if (canNest(dsl) && resetNamespace !== true) { 35658 return dsl.parent + '.' + name; 35659 } else { 35660 return name; 35661 } 35662 } 35663 35664 function createRoute(dsl, name, options, callback) { 35665 options = options || {}; 35666 35667 var fullName = getFullName(dsl, name, options.resetNamespace); 35668 35669 if (typeof options.path !== 'string') { 35670 options.path = '/' + name; 35671 } 35672 35673 dsl.push(options.path, fullName, callback); 35674 } 35675 35676 DSL.map = function (callback) { 35677 var dsl = new DSL(); 35678 callback.call(dsl); 35679 return dsl; 35680 }; 35681}); 35682enifed('ember-routing/system/generate_controller', ['exports', 'ember-metal/debug', 'ember-metal/property_get'], function (exports, _emberMetalDebug, _emberMetalProperty_get) { 35683 'use strict'; 35684 35685 exports.generateControllerFactory = generateControllerFactory; 35686 exports.default = generateController; 35687 35688 /** 35689 @module ember 35690 @submodule ember-routing 35691 */ 35692 35693 /** 35694 Generates a controller factory 35695 35696 @for Ember 35697 @method generateControllerFactory 35698 @private 35699 */ 35700 35701 function generateControllerFactory(owner, controllerName, context) { 35702 var Factory, fullName; 35703 35704 Factory = owner._lookupFactory('controller:basic').extend({ 35705 isGenerated: true, 35706 toString: function () { 35707 return '(generated ' + controllerName + ' controller)'; 35708 } 35709 }); 35710 35711 fullName = 'controller:' + controllerName; 35712 35713 owner.register(fullName, Factory); 35714 35715 return Factory; 35716 } 35717 35718 /** 35719 Generates and instantiates a controller. 35720 35721 The type of the generated controller factory is derived 35722 from the context. If the context is an array an array controller
35723 is generated, if an object, an object controller otherwise, a basic 35724 controller is generated. 35725 35726 @for Ember 35727 @method generateController 35728 @private 35729 @since 1.3.0 35730 */ 35731 35732 function generateController(owner, controllerName, context) { 35733 generateControllerFactory(owner, controllerName, context); 35734 35735 var fullName = 'controller:' + controllerName; 35736 var instance = owner.lookup(fullName); 35737 35738 if (_emberMetalProperty_get.get(instance, 'namespace.LOG_ACTIVE_GENERATION')) { 35739 _emberMetalDebug.info('generated -> ' + fullName, { fullName: fullName }); 35740 } 35741 35742 return instance; 35743 } 35744}); 35745enifed('ember-routing/system/query_params', ['exports', 'ember-runtime/system/object'], function (exports, _emberRuntimeSystemObject) { 35746 'use strict'; 35747 35748 exports.default = _emberRuntimeSystemObject.default.extend({ 35749 isQueryParams: true, 35750 values: null 35751 }); 35752}); 35753enifed('ember-routing/system/route', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/error', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/get_properties', 'ember-metal/is_none', 'ember-metal/computed', 'ember-metal/assign', 'ember-runtime/utils', 'ember-metal/run_loop', 'ember-runtime/copy', 'ember-runtime/system/string', 'ember-runtime/system/object', 'ember-runtime/system/native_array', 'ember-runtime/mixins/evented', 'ember-runtime/mixins/action_handler', 'ember-routing/system/generate_controller', 'ember-routing/utils', 'container/owner', 'ember-metal/is_empty'], function (exports, _emberMetalCore, _emberMetalDebug, _emberMetalFeatures, _emberMetalError, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalGet_properties, _emberMetalIs_none, _emberMetalComputed, _emberMetalAssign, _emberRuntimeUtils, _emberMetalRun_loop, _emberRuntimeCopy, _emberRuntimeSystemString, _emberRuntimeSystemObject, _emberRuntimeSystemNative_array, _emberRuntimeMixinsEvented, _emberRuntimeMixinsAction_handler, _emberRoutingSystemGenerate_controller, _emberRoutingUtils, _containerOwner, _emberMetalIs_empty) { 35754 'use strict'; 35755 35756 var slice = Array.prototype.slice; 35757 35758 function K() { 35759 return this; 35760 } 35761 35762 /** 35763 @module ember 35764 @submodule ember-routing 35765 */ 35766 35767 /** 35768 The `Ember.Route` class is used to define individual routes. Refer to 35769 the [routing guide](http://emberjs.com/guides/routing/) for documentation. 35770 35771 @class Route 35772 @namespace Ember 35773 @extends Ember.Object 35774 @uses Ember.ActionHandler 35775 @uses Ember.Evented 35776 @public 35777 */ 35778 var Route = _emberRuntimeSystemObject.default.extend(_emberRuntimeMixinsAction_handler.default, _emberRuntimeMixinsEvented.default, { 35779 /** 35780 Configuration hash for this route's queryParams. The possible 35781 configuration options and their defaults are as follows 35782 (assuming a query param whose controller property is `page`): 35783 ```javascript 35784 queryParams: { 35785 page: { 35786 // By default, controller query param properties don't 35787 // cause a full transition when they are changed, but 35788 // rather only cause the URL to update. Setting 35789 // `refreshModel` to true will cause an "in-place" 35790 // transition to occur, whereby the model hooks for 35791 // this route (and any child routes) will re-fire, allowing 35792 // you to reload models (e.g., from the server) using the 35793 // updated query param values. 35794 refreshModel: false, 35795 // By default, changes to controller query param properties 35796 // cause the URL to update via `pushState`, which means an 35797 // item will be added to the browser's history, allowing 35798 // you to use the back button to restore the app to the 35799 // previous state before the query param property was changed. 35800 // Setting `replace` to true will use `replaceState` (or its 35801 // hash location equivalent), which causes no browser history 35802 // item to be added. This options name and default value are 35803 // the same as the `link-to` helper's `replace` option. 35804 replace: false, 35805 // By default, the query param URL key is the same name as 35806 // the controller property name. Use `as` to specify a 35807 // different URL key. 35808 as: 'page' 35809 } 35810 } 35811 ``` 35812 @property queryParams 35813 @for Ember.Route 35814 @type Object 35815 @public 35816 */ 35817 queryParams: {}, 35818 35819 /** 35820 The name of the route, dot-delimited. 35821 For example, a route found at `app/routes/posts/post.js` or 35822 `app/posts/post/route.js` (with pods) will have a `routeName` of 35823 `posts.post`. 35824 @property routeName 35825 @for Ember.Route
35826 @type String 35827 @public 35828 */ 35829 35830 /** 35831 @private 35832 @property _qp 35833 */ 35834 _qp: _emberMetalComputed.computed(function () { 35835 var _this = this; 35836 35837 var controllerProto, combinedQueryParameterConfiguration; 35838 35839 var controllerName = this.controllerName || this.routeName; 35840 var definedControllerClass = _containerOwner.getOwner(this)._lookupFactory('controller:' + controllerName); 35841 var queryParameterConfiguraton = _emberMetalProperty_get.get(this, 'queryParams'); 35842 var hasRouterDefinedQueryParams = !!Object.keys(queryParameterConfiguraton).length; 35843 35844 if (definedControllerClass) { 35845 // the developer has authored a controller class in their application for this route 35846 // access the prototype, find its query params and normalize their object shape 35847 // them merge in the query params for the route. As a mergedProperty, Route#queryParams is always 35848 // at least `{}` 35849 controllerProto = definedControllerClass.proto(); 35850 35851 var controllerDefinedQueryParameterConfiguration = _emberMetalProperty_get.get(controllerProto, 'queryParams'); 35852 var normalizedControllerQueryParameterConfiguration = _emberRoutingUtils.normalizeControllerQueryParams(controllerDefinedQueryParameterConfiguration); 35853 combinedQueryParameterConfiguration = mergeEachQueryParams(normalizedControllerQueryParameterConfiguration, queryParameterConfiguraton); 35854 } else if (hasRouterDefinedQueryParams) { 35855 // the developer has not defined a controller but *has* supplied route query params. 35856 // Generate a class for them so we can later insert default values 35857 var generatedControllerClass = _emberRoutingSystemGenerate_controller.generateControllerFactory(_containerOwner.getOwner(this), controllerName); 35858 controllerProto = generatedControllerClass.proto(); 35859 combinedQueryParameterConfiguration = queryParameterConfiguraton; 35860 } 35861 35862 var qps = []; 35863 var map = {}; 35864 var propertyNames = []; 35865 35866 for (var propName in combinedQueryParameterConfiguration) { 35867 if (!combinedQueryParameterConfiguration.hasOwnProperty(propName)) { 35868 continue; 35869 } 35870 35871 // to support the dubious feature of using unknownProperty 35872 // on queryParams configuration 35873 if (propName === 'unknownProperty' || propName === '_super') { 35874 // possible todo: issue deprecation warning? 35875 continue; 35876 } 35877 35878 var desc = combinedQueryParameterConfiguration[propName]; 35879 35880 var scope = desc.scope || 'model'; 35881 var parts; 35882 35883 if (scope === 'controller') { 35884 parts = []; 35885 } 35886 35887 var urlKey = desc.as || this.serializeQueryParamKey(propName); 35888 var defaultValue = _emberMetalProperty_get.get(controllerProto, propName); 35889 35890 if (Array.isArray(defaultValue)) { 35891 defaultValue = _emberRuntimeSystemNative_array.A(defaultValue.slice()); 35892 } 35893 35894 var type = desc.type || _emberRuntimeUtils.typeOf(defaultValue); 35895 35896 var defaultValueSerialized = this.serializeQueryParam(defaultValue, urlKey, type); 35897 var scopedPropertyName = controllerName + ':' + propName; 35898 var qp = { 35899 undecoratedDefaultValue: _emberMetalProperty_get.get(controllerProto, propName), 35900 defaultValue: defaultValue, 35901 serializedDefaultValue: defaultValueSerialized, 35902 serializedValue: defaultValueSerialized, 35903 35904 type: type, 35905 urlKey: urlKey, 35906 prop: propName, 35907 scopedPropertyName: scopedPropertyName, 35908 ctrl: controllerName, 35909 route: this, 35910 parts: parts, // provided later when stashNames is called if 'model' scope 35911 values: null, // provided later when setup is called. no idea why. 35912 scope: scope, 35913 prefix: '' 35914 }; 35915 35916 map[propName] = map[urlKey] = map[scopedPropertyName] = qp; 35917 qps.push(qp); 35918 propertyNames.push(propName); 35919 } 35920 35921 return { 35922 qps: qps, 35923 map: map, 35924 propertyNames: propertyNames, 35925 states: { 35926 /* 35927 Called when a query parameter changes in the URL, this route cares 35928 about that query parameter, but the route is not currently 35929 in the active route hierarchy. 35930 */ 35931 inactive: function (prop, value) { 35932 var qp = map[prop]; 35933 _this._qpChanged(prop, value, qp); 35934 }, 35935 /* 35936 Called when a query parameter changes in the URL, this route cares 35937 about that query parameter, and the route is currently 35938 in the active route hierarchy. 35939 */ 35940 active: function (prop, value) { 35941 var qp = map[prop]; 35942 _this._qpChanged(prop, value, qp); 35943 return _this._activeQPChanged(map[prop], value); 35944 }, 35945 /* 35946 Called when a value of a query parameter this route handles changes in a controller 35947 and the route is currently in the active route hierarchy. 35948 */ 35949 allowOverrides: function (prop, value) { 35950 var qp = map[prop]; 35951 _this._qpChanged(prop, value, qp); 35952 return _this._updatingQPChanged(map[prop]); 35953 } 35954 } 35955 }; 35956 }), 35957 35958 /** 35959 @private 35960 @property _names 35961 */ 35962 _names: null, 35963 35964 /** 35965 @private 35966 @method _stashNames 35967 */ 35968 _stashNames: function (_handlerInfo, dynamicParent) { 35969 var handlerInfo = _handlerInfo; 35970 if (this._names) { 35971 return; 35972 } 35973 var names = this._names = handlerInfo._names; 35974 35975 if (!names.length) { 35976 handlerInfo = dynamicParent; 35977 names = handlerInfo && handlerInfo._names || []; 35978 } 35979 35980 var qps = _emberMetalProperty_get.get(this, '_qp.qps'); 35981 var len = qps.length; 35982 35983 var namePaths = new Array(names.length); 35984 for (var a = 0, nlen = names.length; a < nlen; ++a) { 35985 namePaths[a] = handlerInfo.name + '.' + names[a]; 35986 } 35987 35988 for (var i = 0; i < len; ++i) { 35989 var qp = qps[i]; 35990 if (qp.scope === 'model') { 35991 qp.parts = namePaths; 35992 } 35993 qp.prefix = qp.ctrl; 35994 } 35995 }, 35996 35997 /** 35998 @private 35999 @property _activeQPChanged 36000 */ 36001 _activeQPChanged: function (qp, value) { 36002 var router = this.router; 36003 router._activeQPChanged(qp.scopedPropertyName, value); 36004 }, 36005 36006 /** 36007 @private 36008 @method _updatingQPChanged 36009 */ 36010 _updatingQPChanged: function (qp) { 36011 var router = this.router;
36012 router._updatingQPChanged(qp.urlKey); 36013 }, 36014 36015 mergedProperties: ['queryParams'], 36016 36017 /** 36018 Retrieves parameters, for current route using the state.params 36019 variable and getQueryParamsFor, using the supplied routeName. 36020 @method paramsFor 36021 @param {String} name 36022 @public 36023 */ 36024 paramsFor: function (name) { 36025 var route = _containerOwner.getOwner(this).lookup('route:' + name); 36026 36027 if (!route) { 36028 return {}; 36029 } 36030 36031 var transition = this.router.router.activeTransition; 36032 var state = transition ? transition.state : this.router.router.state; 36033 36034 var params = {}; 36035 _emberMetalAssign.default(params, state.params[name]); 36036 _emberMetalAssign.default(params, getQueryParamsFor(route, state)); 36037 36038 return params; 36039 }, 36040 36041 /** 36042 Serializes the query parameter key 36043 @method serializeQueryParamKey 36044 @param {String} controllerPropertyName 36045 @private 36046 */ 36047 serializeQueryParamKey: function (controllerPropertyName) { 36048 return controllerPropertyName; 36049 }, 36050 36051 /** 36052 Serializes value of the query parameter based on defaultValueType 36053 @method serializeQueryParam 36054 @param {Object} value 36055 @param {String} urlKey 36056 @param {String} defaultValueType 36057 @private 36058 */ 36059 serializeQueryParam: function (value, urlKey, defaultValueType) { 36060 // urlKey isn't used here, but anyone overriding 36061 // can use it to provide serialization specific 36062 // to a certain query param. 36063 if (defaultValueType === 'array') { 36064 return JSON.stringify(value); 36065 } 36066 return '' + value; 36067 }, 36068 36069 /** 36070 Deserializes value of the query parameter based on defaultValueType 36071 @method deserializeQueryParam 36072 @param {Object} value 36073 @param {String} urlKey 36074 @param {String} defaultValueType 36075 @private 36076 */ 36077 deserializeQueryParam: function (value, urlKey, defaultValueType) { 36078 // urlKey isn't used here, but anyone overriding 36079 // can use it to provide deserialization specific 36080 // to a certain query param. 36081 36082 // Use the defaultValueType of the default value (the initial value assigned to a 36083 // controller query param property), to intelligently deserialize and cast. 36084 if (defaultValueType === 'boolean') { 36085 return value === 'true' ? true : false; 36086 } else if (defaultValueType === 'number') { 36087 return Number(value).valueOf(); 36088 } else if (defaultValueType === 'array') { 36089 return _emberRuntimeSystemNative_array.A(JSON.parse(value)); 36090 } 36091 return value; 36092 }, 36093 36094 /** 36095 @private 36096 @property _optionsForQueryParam 36097 */ 36098 _optionsForQueryParam: function (qp) { 36099 return _emberMetalProperty_get.get(this, 'queryParams.' + qp.urlKey) || _emberMetalProperty_get.get(this, 'queryParams.' + qp.prop) || {}; 36100 }, 36101 36102 /** 36103 A hook you can use to reset controller values either when the model 36104 changes or the route is exiting. 36105 ```javascript 36106 App.ArticlesRoute = Ember.Route.extend({ 36107 // ... 36108 resetController: function(controller, isExiting, transition) { 36109 if (isExiting) { 36110 controller.set('page', 1); 36111 } 36112 } 36113 }); 36114 ``` 36115 @method resetController 36116 @param {Controller} controller instance 36117 @param {Boolean} isExiting 36118 @param {Object} transition 36119 @since 1.7.0 36120 @public 36121 */ 36122 resetController: K, 36123 36124 /** 36125 @private 36126 @method exit 36127 */ 36128 exit: function () { 36129 this.deactivate(); 36130 this.trigger('deactivate'); 36131 this.teardownViews(); 36132 }, 36133 36134 /** 36135 @private 36136 @method _reset 36137 @since 1.7.0 36138 */ 36139 _reset: function (isExiting, transition) { 36140 var controller = this.controller; 36141 controller._qpDelegate = _emberMetalProperty_get.get(this, '_qp.states.inactive'); 36142 36143 this.resetController(controller, isExiting, transition); 36144 }, 36145 36146 /** 36147 @private 36148 @method enter 36149 */ 36150 enter: function () { 36151 this.connections = []; 36152 this.activate(); 36153 this.trigger('activate'); 36154 }, 36155 36156 /** 36157 The name of the view to use by default when rendering this routes template. 36158 When rendering a template, the route will, by default, determine the 36159 template and view to use from the name of the route itself. If you need to 36160 define a specific view, set this property. 36161 This is useful when multiple routes would benefit from using the same view 36162 because it doesn't require a custom `renderTemplate` method. For example, 36163 the following routes will all render using the `App.PostsListView` view: 36164 ```javascript 36165 var PostsList = Ember.Route.extend({ 36166 viewName: 'postsList' 36167 }); 36168 App.PostsIndexRoute = PostsList.extend(); 36169 App.PostsArchivedRoute = PostsList.extend(); 36170 ``` 36171 @property viewName
36172 @type String 36173 @default null 36174 @since 1.4.0 36175 @public 36176 */ 36177 viewName: null, 36178 36179 /** 36180 The name of the template to use by default when rendering this routes 36181 template. 36182 This is similar with `viewName`, but is useful when you just want a custom 36183 template without a view. 36184 ```javascript 36185 var PostsList = Ember.Route.extend({ 36186 templateName: 'posts/list' 36187 }); 36188 App.PostsIndexRoute = PostsList.extend(); 36189 App.PostsArchivedRoute = PostsList.extend(); 36190 ``` 36191 @property templateName 36192 @type String 36193 @default null 36194 @since 1.4.0 36195 @public 36196 */ 36197 templateName: null, 36198 36199 /** 36200 The name of the controller to associate with this route. 36201 By default, Ember will lookup a route's controller that matches the name 36202 of the route (i.e. `App.PostController` for `App.PostRoute`). However, 36203 if you would like to define a specific controller to use, you can do so 36204 using this property. 36205 This is useful in many ways, as the controller specified will be: 36206 * passed to the `setupController` method. 36207 * used as the controller for the view being rendered by the route. 36208 * returned from a call to `controllerFor` for the route. 36209 @property controllerName 36210 @type String 36211 @default null 36212 @since 1.4.0 36213 @public 36214 */ 36215 controllerName: null, 36216 36217 /** 36218 The `willTransition` action is fired at the beginning of any 36219 attempted transition with a `Transition` object as the sole 36220 argument. This action can be used for aborting, redirecting, 36221 or decorating the transition from the currently active routes. 36222 A good example is preventing navigation when a form is 36223 half-filled out: 36224 ```javascript 36225 App.ContactFormRoute = Ember.Route.extend({ 36226 actions: { 36227 willTransition: function(transition) { 36228 if (this.controller.get('userHasEnteredData')) { 36229 this.controller.displayNavigationConfirm(); 36230 transition.abort(); 36231 } 36232 } 36233 } 36234 }); 36235 ``` 36236 You can also redirect elsewhere by calling 36237 `this.transitionTo('elsewhere')` from within `willTransition`. 36238 Note that `willTransition` will not be fired for the 36239 redirecting `transitionTo`, since `willTransition` doesn't 36240 fire when there is already a transition underway. If you want 36241 subsequent `willTransition` actions to fire for the redirecting 36242 transition, you must first explicitly call 36243 `transition.abort()`. 36244 To allow the `willTransition` event to continue bubbling to the parent 36245 route, use `return true;`. When the `willTransition` method has a 36246 return value of `true` then the parent route's `willTransition` method 36247 will be fired, enabling "bubbling" behavior for the event. 36248 @event willTransition 36249 @param {Transition} transition 36250 @public 36251 */ 36252 36253 /** 36254 The `didTransition` action is fired after a transition has 36255 successfully been completed. This occurs after the normal model 36256 hooks (`beforeModel`, `model`, `afterModel`, `setupController`) 36257 have resolved. The `didTransition` action has no arguments, 36258 however, it can be useful for tracking page views or resetting 36259 state on the controller. 36260 ```javascript 36261 App.LoginRoute = Ember.Route.extend({ 36262 actions: { 36263 didTransition: function() { 36264 this.controller.get('errors.base').clear(); 36265 return true; // Bubble the didTransition event 36266 } 36267 } 36268 }); 36269 ``` 36270 @event didTransition 36271 @since 1.2.0 36272 @public 36273 */ 36274 36275 /** 36276 The `loading` action is fired on the route when a route's `model` 36277 hook returns a promise that is not already resolved. The current 36278 `Transition` object is the first parameter and the route that 36279 triggered the loading event is the second parameter. 36280 ```javascript 36281 App.ApplicationRoute = Ember.Route.extend({ 36282 actions: { 36283 loading: function(transition, route) { 36284 var view = Ember.View.create({ 36285 classNames: ['app-loading'] 36286 }) 36287 .append(); 36288 this.router.one('didTransition', function() { 36289 view.destroy(); 36290 }); 36291 return true; // Bubble the loading event 36292 } 36293 } 36294 }); 36295 ``` 36296 @event loading 36297 @param {Transition} transition 36298 @param {Ember.Route} route The route that triggered the loading event 36299 @since 1.2.0 36300 @public 36301 */ 36302 36303 /** 36304 When attempting to transition into a route, any of the hooks 36305 may return a promise that rejects, at which point an `error` 36306 action will be fired on the partially-entered routes, allowing 36307 for per-route error handling logic, or shared error handling 36308 logic defined on a parent route. 36309 Here is an example of an error handler that will be invoked 36310 for rejected promises from the various hooks on the route, 36311 as well as any unhandled errors from child routes: 36312 ```javascript 36313 App.AdminRoute = Ember.Route.extend({ 36314 beforeModel: function() { 36315 return Ember.RSVP.reject('bad things!'); 36316 }, 36317 actions: { 36318 error: function(error, transition) { 36319 // Assuming we got here due to the error in `beforeModel`, 36320 // we can expect that error === "bad things!", 36321 // but a promise model rejecting would also 36322 // call this hook, as would any errors encountered 36323 // in `afterModel`. 36324 // The `error` hook is also provided the failed 36325 // `transition`, which can be stored and later 36326 // `.retry()`d if desired. 36327 this.transitionTo('login'); 36328 } 36329 } 36330 }); 36331 ``` 36332 `error` actions that bubble up all the way to `ApplicationRoute` 36333 will fire a default error handler that logs the error. You can 36334 specify your own global default error handler by overriding the 36335 `error` handler on `ApplicationRoute`: 36336 ```javascript 36337 App.ApplicationRoute = Ember.Route.extend({ 36338 actions: { 36339 error: function(error, transition) { 36340 this.controllerFor('banner').displayError(error.message); 36341 } 36342 } 36343 }); 36344 ``` 36345 @event error 36346 @param {Error} error 36347 @param {Transition} transition 36348 @public 36349 */ 36350 36351 /** 36352 This event is triggered when the router enters the route. It is 36353 not executed when the model for the route changes. 36354 ```javascript 36355 App.ApplicationRoute = Ember.Route.extend({ 36356 collectAnalytics: function(){ 36357 collectAnalytics(); 36358 }.on('activate') 36359 }); 36360 ``` 36361 @event activate 36362 @since 1.9.0 36363 @public 36364 */ 36365 36366 /** 36367 This event is triggered when the router completely exits this 36368 route. It is not executed when the model for the route changes. 36369 ```javascript 36370 App.IndexRoute = Ember.Route.extend({ 36371 trackPageLeaveAnalytics: function(){ 36372 trackPageLeaveAnalytics(); 36373 }.on('deactivate') 36374 }); 36375 ``` 36376 @event deactivate 36377 @since 1.9.0 36378 @public 36379 */ 36380 36381 /** 36382 The controller associated with this route. 36383 Example 36384 ```javascript 36385 App.FormRoute = Ember.Route.extend({ 36386 actions: { 36387 willTransition: function(transition) { 36388 if (this.controller.get('userHasEnteredData') && 36389 !confirm('Are you sure you want to abandon progress?')) { 36390 transition.abort(); 36391 } else { 36392 // Bubble the `willTransition` action so that 36393 // parent routes can decide whether or not to abort. 36394 return true; 36395 } 36396 } 36397 } 36398 }); 36399 ``` 36400 @property controller 36401 @type Ember.Controller 36402 @since 1.6.0 36403 @public 36404 */ 36405 36406 actions: { 36407 36408 queryParamsDidChange: function (changed, totalPresent, removed) { 36409 var qpMap = _emberMetalProperty_get.get(this, '_qp').map; 36410 36411 var totalChanged = Object.keys(changed).concat(Object.keys(removed)); 36412 for (var i = 0, len = totalChanged.length; i < len; ++i) { 36413 var qp = qpMap[totalChanged[i]]; 36414 if (qp && _emberMetalProperty_get.get(this._optionsForQueryParam(qp), 'refreshModel') && this.router.currentState) { 36415 this.refresh(); 36416 } 36417 } 36418 36419 return true; 36420 }, 36421 36422 finalizeQueryParamChange: function (params, finalParams, transition) { 36423 if (this.routeName !== 'application') { 36424 return true; 36425 } 36426 36427 // Transition object is absent for intermediate transitions. 36428 if (!transition) { 36429 return; 36430 } 36431 36432 var handlerInfos = transition.state.handlerInfos; 36433 var router = this.router; 36434 var qpMeta = router._queryParamsFor(handlerInfos[handlerInfos.length - 1].name); 36435 var changes = router._qpUpdates; 36436 var replaceUrl; 36437 36438 _emberRoutingUtils.stashParamNames(router, handlerInfos); 36439 36440 for (var i = 0, len = qpMeta.qps.length; i < len; ++i) { 36441 var qp = qpMeta.qps[i]; 36442 var route = qp.route; 36443 var controller = route.controller; 36444 var presentKey = qp.urlKey in params && qp.urlKey; 36445 36446 // Do a reverse lookup to see if the changed query 36447 // param URL key corresponds to a QP property on 36448 // this controller. 36449 var value, svalue; 36450 if (changes && qp.urlKey in changes) { 36451 // Value updated in/before setupController 36452 value = _emberMetalProperty_get.get(controller, qp.prop); 36453 svalue = route.serializeQueryParam(value, qp.urlKey, qp.type); 36454 } else { 36455 if (presentKey) { 36456 svalue = params[presentKey]; 36457 value = route.deserializeQueryParam(svalue, qp.urlKey, qp.type); 36458 } else { 36459 // No QP provided; use default value. 36460 svalue = qp.serializedDefaultValue; 36461 value = copyDefaultValue(qp.defaultValue); 36462 } 36463 } 36464 36465 controller._qpDelegate = _emberMetalProperty_get.get(route, '_qp.states.inactive'); 36466 36467 var thisQueryParamChanged = svalue !== qp.serializedValue; 36468 if (thisQueryParamChanged) { 36469 if (transition.queryParamsOnly && replaceUrl !== false) { 36470 var options = route._optionsForQueryParam(qp); 36471 var replaceConfigValue = _emberMetalProperty_get.get(options, 'replace'); 36472 if (replaceConfigValue) { 36473 replaceUrl = true; 36474 } else if (replaceConfigValue === false) { 36475 // Explicit pushState wins over any other replaceStates. 36476 replaceUrl = false;
36477 } 36478 } 36479 36480 _emberMetalProperty_set.set(controller, qp.prop, value); 36481 } 36482 36483 // Stash current serialized value of controller. 36484 qp.serializedValue = svalue; 36485 36486 var thisQueryParamHasDefaultValue = qp.serializedDefaultValue === svalue; 36487 if (!thisQueryParamHasDefaultValue) { 36488 finalParams.push({ 36489 value: svalue, 36490 visible: true, 36491 key: presentKey || qp.urlKey 36492 }); 36493 } 36494 } 36495 36496 if (replaceUrl) { 36497 transition.method('replace'); 36498 } 36499 36500 qpMeta.qps.forEach(function (qp) { 36501 var routeQpMeta = _emberMetalProperty_get.get(qp.route, '_qp'); 36502 var finalizedController = qp.route.controller; 36503 finalizedController._qpDelegate = _emberMetalProperty_get.get(routeQpMeta, 'states.active'); 36504 }); 36505 36506 router._qpUpdates = null; 36507 } 36508 }, 36509 36510 /** 36511 This hook is executed when the router completely exits this route. It is 36512 not executed when the model for the route changes. 36513 @method deactivate 36514 @public 36515 */ 36516 deactivate: K, 36517 36518 /** 36519 This hook is executed when the router enters the route. It is not executed 36520 when the model for the route changes. 36521 @method activate 36522 @public 36523 */ 36524 activate: K, 36525 36526 /** 36527 Transition the application into another route. The route may 36528 be either a single route or route path: 36529 ```javascript 36530 this.transitionTo('blogPosts'); 36531 this.transitionTo('blogPosts.recentEntries'); 36532 ``` 36533 Optionally supply a model for the route in question. The model 36534 will be serialized into the URL using the `serialize` hook of 36535 the route: 36536 ```javascript 36537 this.transitionTo('blogPost', aPost); 36538 ``` 36539 If a literal is passed (such as a number or a string), it will 36540 be treated as an identifier instead. In this case, the `model` 36541 hook of the route will be triggered: 36542 ```javascript 36543 this.transitionTo('blogPost', 1); 36544 ``` 36545 Multiple models will be applied last to first recursively up the 36546 route tree. 36547 ```javascript 36548 App.Router.map(function() { 36549 this.route('blogPost', { path:':blogPostId' }, function() { 36550 this.route('blogComment', { path: ':blogCommentId', resetNamespace: true }); 36551 }); 36552 }); 36553 this.transitionTo('blogComment', aPost, aComment); 36554 this.transitionTo('blogComment', 1, 13); 36555 ``` 36556 It is also possible to pass a URL (a string that starts with a 36557 `/`). This is intended for testing and debugging purposes and 36558 should rarely be used in production code. 36559 ```javascript 36560 this.transitionTo('/'); 36561 this.transitionTo('/blog/post/1/comment/13'); 36562 this.transitionTo('/blog/posts?sort=title'); 36563 ``` 36564 An options hash with a `queryParams` property may be provided as 36565 the final argument to add query parameters to the destination URL. 36566 ```javascript 36567 this.transitionTo('blogPost', 1, { 36568 queryParams: {showComments: 'true'} 36569 }); 36570 // if you just want to transition the query parameters without changing the route 36571 this.transitionTo({queryParams: {sort: 'date'}}); 36572 ``` 36573 See also [replaceWith](#method_replaceWith). 36574 Simple Transition Example 36575 ```javascript 36576 App.Router.map(function() { 36577 this.route('index'); 36578 this.route('secret'); 36579 this.route('fourOhFour', { path: '*:' }); 36580 }); 36581 App.IndexRoute = Ember.Route.extend({ 36582 actions: { 36583 moveToSecret: function(context) { 36584 if (authorized()) { 36585 this.transitionTo('secret', context); 36586 } else { 36587 this.transitionTo('fourOhFour'); 36588 } 36589 } 36590 } 36591 }); 36592 ``` 36593 Transition to a nested route 36594 ```javascript 36595 App.Router.map(function() { 36596 this.route('articles', { path: '/articles' }, function() { 36597 this.route('new'); 36598 }); 36599 }); 36600 App.IndexRoute = Ember.Route.extend({ 36601 actions: { 36602 transitionToNewArticle: function() { 36603 this.transitionTo('articles.new'); 36604 } 36605 } 36606 }); 36607 ``` 36608 Multiple Models Example 36609 ```javascript 36610 App.Router.map(function() { 36611 this.route('index'); 36612 this.route('breakfast', { path: ':breakfastId' }, function() { 36613 this.route('cereal', { path: ':cerealId', resetNamespace: true }); 36614 }); 36615 }); 36616 App.IndexRoute = Ember.Route.extend({ 36617 actions: { 36618 moveToChocolateCereal: function() { 36619 var cereal = { cerealId: 'ChocolateYumminess' }; 36620 var breakfast = { breakfastId: 'CerealAndMilk' }; 36621 this.transitionTo('cereal', breakfast, cereal); 36622 } 36623 } 36624 }); 36625 ``` 36626 Nested Route with Query String Example 36627 ```javascript 36628 App.Router.map(function() { 36629 this.route('fruits', function() { 36630 this.route('apples'); 36631 }); 36632 }); 36633 App.IndexRoute = Ember.Route.extend({ 36634 actions: { 36635 transitionToApples: function() { 36636 this.transitionTo('fruits.apples', {queryParams: {color: 'red'}}); 36637 } 36638 } 36639 }); 36640 ``` 36641 @method transitionTo 36642 @param {String} name the name of the route or a URL 36643 @param {...Object} models the model(s) or identifier(s) to be used while 36644 transitioning to the route. 36645 @param {Object} [options] optional hash with a queryParams property 36646 containing a mapping of query parameters 36647 @return {Transition} the transition object associated with this 36648 attempted transition 36649 @public 36650 */ 36651 transitionTo: function (name, context) { 36652 var router = this.router; 36653 return router.transitionTo.apply(router, arguments); 36654 }, 36655 36656 /** 36657 Perform a synchronous transition into another route without attempting 36658 to resolve promises, update the URL, or abort any currently active 36659 asynchronous transitions (i.e. regular transitions caused by 36660 `transitionTo` or URL changes). 36661 This method is handy for performing intermediate transitions on the
36662 way to a final destination route, and is called internally by the 36663 default implementations of the `error` and `loading` handlers. 36664 @method intermediateTransitionTo 36665 @param {String} name the name of the route 36666 @param {...Object} models the model(s) to be used while transitioning 36667 to the route. 36668 @since 1.2.0 36669 @public 36670 */ 36671 intermediateTransitionTo: function () { 36672 var router = this.router; 36673 router.intermediateTransitionTo.apply(router, arguments); 36674 }, 36675 36676 /** 36677 Refresh the model on this route and any child routes, firing the 36678 `beforeModel`, `model`, and `afterModel` hooks in a similar fashion 36679 to how routes are entered when transitioning in from other route. 36680 The current route params (e.g. `article_id`) will be passed in 36681 to the respective model hooks, and if a different model is returned, 36682 `setupController` and associated route hooks will re-fire as well. 36683 An example usage of this method is re-querying the server for the 36684 latest information using the same parameters as when the route 36685 was first entered. 36686 Note that this will cause `model` hooks to fire even on routes 36687 that were provided a model object when the route was initially 36688 entered. 36689 @method refresh 36690 @return {Transition} the transition object associated with this 36691 attempted transition 36692 @since 1.4.0 36693 @public 36694 */ 36695 refresh: function () { 36696 return this.router.router.refresh(this); 36697 }, 36698 36699 /** 36700 Transition into another route while replacing the current URL, if possible. 36701 This will replace the current history entry instead of adding a new one. 36702 Beside that, it is identical to `transitionTo` in all other respects. See 36703 'transitionTo' for additional information regarding multiple models. 36704 Example 36705 ```javascript 36706 App.Router.map(function() { 36707 this.route('index'); 36708 this.route('secret'); 36709 }); 36710 App.SecretRoute = Ember.Route.extend({ 36711 afterModel: function() { 36712 if (!authorized()){ 36713 this.replaceWith('index'); 36714 } 36715 } 36716 }); 36717 ``` 36718 @method replaceWith 36719 @param {String} name the name of the route or a URL 36720 @param {...Object} models the model(s) or identifier(s) to be used while 36721 transitioning to the route. 36722 @return {Transition} the transition object associated with this 36723 attempted transition 36724 @public 36725 */ 36726 replaceWith: function () { 36727 var router = this.router; 36728 return router.replaceWith.apply(router, arguments); 36729 }, 36730 36731 /** 36732 Sends an action to the router, which will delegate it to the currently 36733 active route hierarchy per the bubbling rules explained under `actions`. 36734 Example 36735 ```javascript 36736 App.Router.map(function() { 36737 this.route('index'); 36738 }); 36739 App.ApplicationRoute = Ember.Route.extend({ 36740 actions: { 36741 track: function(arg) { 36742 console.log(arg, 'was clicked'); 36743 } 36744 } 36745 }); 36746 App.IndexRoute = Ember.Route.extend({ 36747 actions: { 36748 trackIfDebug: function(arg) { 36749 if (debug) { 36750 this.send('track', arg); 36751 } 36752 } 36753 } 36754 }); 36755 ``` 36756 @method send 36757 @param {String} name the name of the action to trigger 36758 @param {...*} args 36759 @public 36760 */ 36761 send: function () { 36762 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 36763 args[_key] = arguments[_key]; 36764 } 36765 36766 if (this.router && this.router.router || !_emberMetalCore.default.testing) { 36767 var _router; 36768 36769 (_router = this.router).send.apply(_router, args); 36770 } else { 36771 var name = args[0]; 36772 args = slice.call(args, 1); 36773 var action = this.actions[name]; 36774 if (action) { 36775 return this.actions[name].apply(this, args); 36776 } 36777 } 36778 }, 36779 36780 /** 36781 This hook is the entry point for router.js 36782 @private 36783 @method setup 36784 */ 36785 setup: function (context, transition) { 36786 var controller; 36787 36788 var controllerName = this.controllerName || this.routeName; 36789 var definedController = this.controllerFor(controllerName, true); 36790 36791 if (!definedController) { 36792 controller = this.generateController(controllerName, context); 36793 } else { 36794 controller = definedController; 36795 } 36796 36797 // Assign the route's controller so that it can more easily be 36798 // referenced in action handlers. Side effects. Side effects everywhere. 36799 if (!this.controller) { 36800 var propNames = _emberMetalProperty_get.get(this, '_qp.propertyNames'); 36801 addQueryParamsObservers(controller, propNames); 36802 this.controller = controller; 36803 } 36804 36805 var queryParams = _emberMetalProperty_get.get(this, '_qp'); 36806 36807 var states = queryParams.states; 36808 if (transition) { 36809 // Update the model dep values used to calculate cache keys. 36810 _emberRoutingUtils.stashParamNames(this.router, transition.state.handlerInfos); 36811 36812 var params = transition.params;
36813 var allParams = queryParams.propertyNames; 36814 var cache = this._bucketCache; 36815 36816 allParams.forEach(function (prop) { 36817 var aQp = queryParams.map[prop]; 36818 36819 aQp.values = params; 36820 var cacheKey = _emberRoutingUtils.calculateCacheKey(aQp.prefix, aQp.parts, aQp.values); 36821 36822 if (cache) { 36823 var value = cache.lookup(cacheKey, prop, aQp.undecoratedDefaultValue); 36824 _emberMetalProperty_set.set(controller, prop, value); 36825 } 36826 }); 36827 } 36828 36829 controller._qpDelegate = states.allowOverrides; 36830 36831 if (transition) { 36832 var qpValues = getQueryParamsFor(this, transition.state); 36833 controller.setProperties(qpValues); 36834 } 36835 36836 this.setupController(controller, context, transition); 36837 36838 if (!this._environment || this._environment.options.shouldRender) { 36839 this.renderTemplate(controller, context); 36840 } 36841 }, 36842 36843 /* 36844 Called when a query parameter for this route changes, regardless of whether the route 36845 is currently part of the active route hierarchy. This will update the query parameter's 36846 value in the cache so if this route becomes active, the cache value has been updated. 36847 */ 36848 _qpChanged: function (prop, value, qp) { 36849 if (!qp) { 36850 return; 36851 } 36852 36853 var cacheKey = _emberRoutingUtils.calculateCacheKey(qp.prefix || '', qp.parts, qp.values); 36854 36855 // Update model-dep cache 36856 var cache = this._bucketCache; 36857 if (cache) { 36858 cache.stash(cacheKey, prop, value); 36859 } 36860 }, 36861 /** 36862 This hook is the first of the route entry validation hooks 36863 called when an attempt is made to transition into a route 36864 or one of its children. It is called before `model` and 36865 `afterModel`, and is appropriate for cases when: 36866 1) A decision can be made to redirect elsewhere without 36867 needing to resolve the model first. 36868 2) Any async operations need to occur first before the 36869 model is attempted to be resolved. 36870 This hook is provided the current `transition` attempt 36871 as a parameter, which can be used to `.abort()` the transition, 36872 save it for a later `.retry()`, or retrieve values set 36873 on it from a previous hook. You can also just call 36874 `this.transitionTo` to another route to implicitly 36875 abort the `transition`. 36876 You can return a promise from this hook to pause the 36877 transition until the promise resolves (or rejects). This could 36878 be useful, for instance, for retrieving async code from 36879 the server that is required to enter a route. 36880 ```javascript 36881 App.PostRoute = Ember.Route.extend({ 36882 beforeModel: function(transition) { 36883 if (!App.Post) { 36884 return Ember.$.getScript('/models/post.js'); 36885 } 36886 } 36887 }); 36888 ``` 36889 If `App.Post` doesn't exist in the above example, 36890 `beforeModel` will use jQuery's `getScript`, which 36891 returns a promise that resolves after the server has 36892 successfully retrieved and executed the code from the 36893 server. Note that if an error were to occur, it would 36894 be passed to the `error` hook on `Ember.Route`, but 36895 it's also possible to handle errors specific to 36896 `beforeModel` right from within the hook (to distinguish 36897 from the shared error handling behavior of the `error` 36898 hook): 36899 ```javascript 36900 App.PostRoute = Ember.Route.extend({ 36901 beforeModel: function(transition) { 36902 if (!App.Post) { 36903 var self = this; 36904 return Ember.$.getScript('post.js').then(null, function(e) { 36905 self.transitionTo('help'); 36906 // Note that the above transitionTo will implicitly 36907 // halt the transition. If you were to return 36908 // nothing from this promise reject handler, 36909 // according to promise semantics, that would 36910 // convert the reject into a resolve and the 36911 // transition would continue. To propagate the 36912 // error so that it'd be handled by the `error` 36913 // hook, you would have to 36914 return Ember.RSVP.reject(e); 36915 }); 36916 } 36917 } 36918 }); 36919 ``` 36920 @method beforeModel 36921 @param {Transition} transition 36922 @return {Promise} if the value returned from this hook is 36923 a promise, the transition will pause until the transition 36924 resolves. Otherwise, non-promise return values are not 36925 utilized in any way. 36926 @public 36927 */ 36928 beforeModel: K, 36929 36930 /** 36931 This hook is called after this route's model has resolved. 36932 It follows identical async/promise semantics to `beforeModel` 36933 but is provided the route's resolved model in addition to 36934 the `transition`, and is therefore suited to performing 36935 logic that can only take place after the model has already 36936 resolved. 36937 ```javascript 36938 App.PostsRoute = Ember.Route.extend({ 36939 afterModel: function(posts, transition) { 36940 if (posts.get('length') === 1) { 36941 this.transitionTo('post.show', posts.get('firstObject')); 36942 } 36943 } 36944 }); 36945 ``` 36946 Refer to documentation for `beforeModel` for a description 36947 of transition-pausing semantics when a promise is returned 36948 from this hook. 36949 @method afterModel 36950 @param {Object} resolvedModel the value returned from `model`, 36951 or its resolved value if it was a promise 36952 @param {Transition} transition 36953 @return {Promise} if the value returned from this hook is 36954 a promise, the transition will pause until the transition 36955 resolves. Otherwise, non-promise return values are not 36956 utilized in any way. 36957 @public 36958 */ 36959 afterModel: K, 36960 36961 /** 36962 A hook you can implement to optionally redirect to another route. 36963 If you call `this.transitionTo` from inside of this hook, this route 36964 will not be entered in favor of the other hook. 36965 `redirect` and `afterModel` behave very similarly and are 36966 called almost at the same time, but they have an important 36967 distinction in the case that, from one of these hooks, a 36968 redirect into a child route of this route occurs: redirects 36969 from `afterModel` essentially invalidate the current attempt 36970 to enter this route, and will result in this route's `beforeModel`, 36971 `model`, and `afterModel` hooks being fired again within 36972 the new, redirecting transition. Redirects that occur within 36973 the `redirect` hook, on the other hand, will _not_ cause 36974 these hooks to be fired again the second time around; in 36975 other words, by the time the `redirect` hook has been called, 36976 both the resolved model and attempted entry into this route 36977 are considered to be fully validated. 36978 @method redirect 36979 @param {Object} model the model for this route 36980 @param {Transition} transition the transition object associated with the current transition 36981 @public 36982 */ 36983 redirect: K, 36984 36985 /** 36986 Called when the context is changed by router.js. 36987 @private 36988 @method contextDidChange 36989 */ 36990 contextDidChange: function () { 36991 this.currentModel = this.context; 36992 }, 36993 36994 /** 36995 A hook you can implement to convert the URL into the model for 36996 this route. 36997 ```javascript 36998 App.Router.map(function() { 36999 this.route('post', { path: '/posts/:post_id' }); 37000 }); 37001 ``` 37002 The model for the `post` route is `store.findRecord('post', params.post_id)`. 37003 By default, if your route has a dynamic segment ending in `_id`: 37004 * The model class is determined from the segment (`post_id`'s 37005 class is `App.Post`) 37006 * The find method is called on the model class with the value of 37007 the dynamic segment. 37008 Note that for routes with dynamic segments, this hook is not always 37009 executed. If the route is entered through a transition (e.g. when 37010 using the `link-to` Handlebars helper or the `transitionTo` method 37011 of routes), and a model context is already provided this hook 37012 is not called. 37013 A model context does not include a primitive string or number, 37014 which does cause the model hook to be called. 37015 Routes without dynamic segments will always execute the model hook. 37016 ```javascript 37017 // no dynamic segment, model hook always called 37018 this.transitionTo('posts'); 37019 // model passed in, so model hook not called 37020 thePost = store.findRecord('post', 1); 37021 this.transitionTo('post', thePost); 37022 // integer passed in, model hook is called 37023 this.transitionTo('post', 1); 37024 // model id passed in, model hook is called 37025 // useful for forcing the hook to execute 37026 thePost = store.findRecord('post', 1); 37027 this.transitionTo('post', thePost.id); 37028 ``` 37029 This hook follows the asynchronous/promise semantics
37030 described in the documentation for `beforeModel`. In particular, 37031 if a promise returned from `model` fails, the error will be 37032 handled by the `error` hook on `Ember.Route`. 37033 Example 37034 ```javascript 37035 App.PostRoute = Ember.Route.extend({ 37036 model: function(params) { 37037 return this.store.findRecord('post', params.post_id); 37038 } 37039 }); 37040 ``` 37041 @method model 37042 @param {Object} params the parameters extracted from the URL 37043 @param {Transition} transition 37044 @return {Object|Promise} the model for this route. If 37045 a promise is returned, the transition will pause until 37046 the promise resolves, and the resolved value of the promise 37047 will be used as the model for this route. 37048 @public 37049 */ 37050 model: function (params, transition) { 37051 var match, name, sawParams, value; 37052 var queryParams = _emberMetalProperty_get.get(this, '_qp.map'); 37053 37054 for (var prop in params) { 37055 if (prop === 'queryParams' || queryParams && prop in queryParams) { 37056 continue; 37057 } 37058 37059 if (match = prop.match(/^(.*)_id$/)) { 37060 name = match[1]; 37061 value = params[prop]; 37062 } 37063 sawParams = true; 37064 } 37065 37066 if (!name && sawParams) { 37067 return _emberRuntimeCopy.default(params); 37068 } else if (!name) { 37069 if (transition.resolveIndex < 1) { 37070 return; 37071 } 37072 37073 var parentModel = transition.state.handlerInfos[transition.resolveIndex - 1].context; 37074 37075 return parentModel; 37076 } 37077 37078 return this.findModel(name, value); 37079 }, 37080 37081 /** 37082 @private 37083 @method deserialize 37084 @param {Object} params the parameters extracted from the URL 37085 @param {Transition} transition 37086 @return {Object|Promise} the model for this route. 37087 Router.js hook. 37088 */ 37089 deserialize: function (params, transition) { 37090 return this.model(this.paramsFor(this.routeName), transition); 37091 }, 37092 37093 /** 37094 @method findModel 37095 @param {String} type the model type 37096 @param {Object} value the value passed to find 37097 @private 37098 */ 37099 findModel: function () { 37100 var store = _emberMetalProperty_get.get(this, 'store'); 37101 return store.find.apply(store, arguments); 37102 }, 37103 37104 /** 37105 Store property provides a hook for data persistence libraries to inject themselves. 37106 By default, this store property provides the exact same functionality previously 37107 in the model hook. 37108 Currently, the required interface is: 37109 `store.find(modelName, findArguments)` 37110 @method store 37111 @param {Object} store 37112 @private 37113 */ 37114 store: _emberMetalComputed.computed(function () { 37115 var owner = _containerOwner.getOwner(this); 37116 var routeName = this.routeName; 37117 var namespace = _emberMetalProperty_get.get(this, 'router.namespace'); 37118 37119 return { 37120 find: function (name, value) { 37121 var modelClass = owner._lookupFactory('model:' + name); 37122 37123 _emberMetalDebug.assert('You used the dynamic segment ' + name + '_id in your route ' + routeName + ', but ' + namespace + '.' + _emberRuntimeSystemString.classify(name) + ' did not exist and you did not override your route\'s `model` hook.', !!modelClass); 37124 37125 if (!modelClass) { 37126 return; 37127 } 37128 37129 _emberMetalDebug.assert(_emberRuntimeSystemString.classify(name) + ' has no method `find`.', typeof modelClass.find === 'function'); 37130 37131 return modelClass.find(value); 37132 } 37133 }; 37134 }), 37135 37136 /** 37137 A hook you can implement to convert the route's model into parameters 37138 for the URL. 37139 ```javascript 37140 App.Router.map(function() { 37141 this.route('post', { path: '/posts/:post_id' }); 37142 }); 37143 App.PostRoute = Ember.Route.extend({ 37144 model: function(params) { 37145 // the server returns `{ id: 12 }` 37146 return Ember.$.getJSON('/posts/' + params.post_id); 37147 }, 37148 serialize: function(model) { 37149 // this will make the URL `/posts/12` 37150 return { post_id: model.id }; 37151 } 37152 }); 37153 ``` 37154 The default `serialize` method will insert the model's `id` into the 37155 route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'. 37156 If the route has multiple dynamic segments or does not contain '_id', `serialize` 37157 will return `Ember.getProperties(model, params)` 37158 This method is called when `transitionTo` is called with a context 37159 in order to populate the URL. 37160 @method serialize 37161 @param {Object} model the routes model 37162 @param {Array} params an Array of parameter names for the current 37163 route (in the example, `['post_id']`. 37164 @return {Object} the serialized parameters 37165 @public 37166 */ 37167 serialize: function (model, params) { 37168 if (params.length < 1) { 37169 return; 37170 } 37171 if (!model) { 37172 return; 37173 } 37174 37175 var name = params[0]; 37176 var object = {}; 37177 37178 if (params.length === 1) { 37179 if (name in model) { 37180 object[name] = _emberMetalProperty_get.get(model, name); 37181 } else if (/_id$/.test(name)) { 37182 object[name] = _emberMetalProperty_get.get(model, 'id'); 37183 } 37184 } else { 37185 object = _emberMetalGet_properties.default(model, params); 37186 } 37187 37188 return object; 37189 }, 37190 37191 /** 37192 A hook you can use to setup the controller for the current route. 37193 This method is called with the controller for the current route and the 37194 model supplied by the `model` hook. 37195 By default, the `setupController` hook sets the `model` property of 37196 the controller to the `model`. 37197 If you implement the `setupController` hook in your Route, it will 37198 prevent this default behavior. If you want to preserve that behavior 37199 when implementing your `setupController` function, make sure to call 37200 `_super`: 37201 ```javascript 37202 App.PhotosRoute = Ember.Route.extend({ 37203 model: function() { 37204 return this.store.findAll('photo'); 37205 }, 37206 setupController: function(controller, model) { 37207 // Call _super for default behavior 37208 this._super(controller, model); 37209 // Implement your custom setup after 37210 this.controllerFor('application').set('showingPhotos', true); 37211 } 37212 }); 37213 ``` 37214 The provided controller will be one resolved based on the name 37215 of this route. 37216 If no explicit controller is defined, Ember will automatically create one. 37217 As an example, consider the router: 37218 ```javascript 37219 App.Router.map(function() { 37220 this.route('post', { path: '/posts/:post_id' }); 37221 }); 37222 ``` 37223 For the `post` route, a controller named `App.PostController` would 37224 be used if it is defined. If it is not defined, a basic `Ember.Controller` 37225 instance would be used. 37226 Example 37227 ```javascript 37228 App.PostRoute = Ember.Route.extend({ 37229 setupController: function(controller, model) { 37230 controller.set('model', model); 37231 } 37232 }); 37233 ``` 37234 @method setupController 37235 @param {Controller} controller instance 37236 @param {Object} model 37237 @public 37238 */ 37239 setupController: function (controller, context, transition) { 37240 if (controller && context !== undefined) { 37241 _emberMetalProperty_set.set(controller, 'model', context); 37242 } 37243 }, 37244 37245 /** 37246 Returns the controller for a particular route or name. 37247 The controller instance must already have been created, either through entering the 37248 associated route or using `generateController`. 37249 ```javascript 37250 App.PostRoute = Ember.Route.extend({ 37251 setupController: function(controller, post) { 37252 this._super(controller, post); 37253 this.controllerFor('posts').set('currentPost', post); 37254 } 37255 }); 37256 ``` 37257 @method controllerFor 37258 @param {String} name the name of the route or controller 37259 @return {Ember.Controller} 37260 @public 37261 */ 37262 controllerFor: function (name, _skipAssert) { 37263 var owner = _containerOwner.getOwner(this); 37264 var route = owner.lookup('route:' + name); 37265 var controller; 37266 37267 if (route && route.controllerName) { 37268 name = route.controllerName; 37269 } 37270 37271 controller = owner.lookup('controller:' + name); 37272 37273 // NOTE: We're specifically checking that skipAssert is true, because according 37274 // to the old API the second parameter was model. We do not want people who 37275 // passed a model to skip the assertion. 37276 _emberMetalDebug.assert('The controller named \'' + name + '\' could not be found. Make sure that this route exists and has already been entered at least once. If you are accessing a controller not associated with a route, make sure the controller class is explicitly defined.', controller || _skipAssert === true); 37277 37278 return controller; 37279 }, 37280 37281 /** 37282 Generates a controller for a route. 37283 Example 37284 ```javascript 37285 App.PostRoute = Ember.Route.extend({ 37286 setupController: function(controller, post) { 37287 this._super(controller, post); 37288 this.generateController('posts', post); 37289 } 37290 }); 37291 ``` 37292 @method generateController 37293 @param {String} name the name of the controller 37294 @param {Object} model the model to infer the type of the controller (optional) 37295 @private 37296 */ 37297 generateController: function (name, model) { 37298 var owner = _containerOwner.getOwner(this); 37299 37300 model = model || this.modelFor(name); 37301 37302 return _emberRoutingSystemGenerate_controller.default(owner, name, model); 37303 }, 37304 37305 /** 37306 Returns the resolved model of a parent (or any ancestor) route 37307 in a route hierarchy. During a transition, all routes 37308 must resolve a model object, and if a route 37309 needs access to a parent route's model in order to 37310 resolve a model (or just reuse the model from a parent), 37311 it can call `this.modelFor(theNameOfParentRoute)` to 37312 retrieve it. If the ancestor route's model was a promise, 37313 its resolved result is returned. 37314 Example 37315 ```javascript 37316 App.Router.map(function() { 37317 this.route('post', { path: '/post/:post_id' }, function() { 37318 this.route('comments', { resetNamespace: true }); 37319 }); 37320 }); 37321 App.CommentsRoute = Ember.Route.extend({ 37322 afterModel: function() { 37323 this.set('post', this.modelFor('post')); 37324 } 37325 }); 37326 ``` 37327 @method modelFor 37328 @param {String} name the name of the route 37329 @return {Object} the model object 37330 @public 37331 */ 37332 modelFor: function (name) { 37333 var route = _containerOwner.getOwner(this).lookup('route:' + name); 37334 var transition = this.router ? this.router.router.activeTransition : null; 37335 37336 // If we are mid-transition, we want to try and look up 37337 // resolved parent contexts on the current transitionEvent. 37338 if (transition) { 37339 var modelLookupName = route && route.routeName || name; 37340 if (transition.resolvedModels.hasOwnProperty(modelLookupName)) { 37341 return transition.resolvedModels[modelLookupName]; 37342 } 37343 } 37344 37345 return route && route.currentModel; 37346 }, 37347 37348 /** 37349 A hook you can use to render the template for the current route. 37350 This method is called with the controller for the current route and the 37351 model supplied by the `model` hook. By default, it renders the route's 37352 template, configured with the controller for the route. 37353 This method can be overridden to set up and render additional or 37354 alternative templates. 37355 ```javascript 37356 App.PostsRoute = Ember.Route.extend({ 37357 renderTemplate: function(controller, model) { 37358 var favController = this.controllerFor('favoritePost'); 37359 // Render the `favoritePost` template into 37360 // the outlet `posts`, and display the `favoritePost` 37361 // controller. 37362 this.render('favoritePost', { 37363 outlet: 'posts', 37364 controller: favController 37365 }); 37366 } 37367 }); 37368 ``` 37369 @method renderTemplate 37370 @param {Object} controller the route's controller 37371 @param {Object} model the route's model 37372 @public 37373 */ 37374 renderTemplate: function (controller, model) { 37375 this.render(); 37376 }, 37377 37378 /** 37379 `render` is used to render a template into a region of another template 37380 (indicated by an `{{outlet}}`). `render` is used both during the entry 37381 phase of routing (via the `renderTemplate` hook) and later in response to 37382 user interaction. 37383 For example, given the following minimal router and templates: 37384 ```javascript 37385 Router.map(function() { 37386 this.route('photos'); 37387 }); 37388 ``` 37389 ```handlebars 37390 <!-- application.hbs --> 37391 <div class='something-in-the-app-hbs'> 37392 {{outlet "anOutletName"}}
37392 37393 </div> 37394 ``` 37395 ```handlebars 37396 <!-- photos.hbs --> 37397 <h1>Photos</h1> 37398 ``` 37399 You can render `photos.hbs` into the `"anOutletName"` outlet of 37400 `application.hbs` by calling `render`: 37401 ```javascript 37402 // posts route 37403 Ember.Route.extend({ 37404 renderTemplate: function() { 37405 this.render('photos', { 37406 into: 'application', 37407 outlet: 'anOutletName' 37408 }) 37409 } 37410 }); 37411 ``` 37412 `render` additionally allows you to supply which `view`, `controller`, and 37413 `model` objects should be loaded and associated with the rendered template. 37414 ```javascript 37415 // posts route 37416 Ember.Route.extend({ 37417 renderTemplate: function(controller, model){ 37418 this.render('posts', { // the template to render, referenced by name 37419 into: 'application', // the template to render into, referenced by name 37420 outlet: 'anOutletName', // the outlet inside `options.template` to render into. 37421 view: 'aViewName', // the view to use for this template, referenced by name 37422 controller: 'someControllerName', // the controller to use for this template, referenced by name 37423 model: model // the model to set on `options.controller`. 37424 }) 37425 } 37426 }); 37427 ``` 37428 The string values provided for the template name, view, and controller 37429 will eventually pass through to the resolver for lookup. See 37430 Ember.Resolver for how these are mapped to JavaScript objects in your 37431 application. 37432 Not all options need to be passed to `render`. Default values will be used 37433 based on the name of the route specified in the router or the Route's 37434 `controllerName`, `viewName` and `templateName` properties. 37435 For example: 37436 ```javascript 37437 // router 37438 Router.map(function() { 37439 this.route('index'); 37440 this.route('post', { path: '/posts/:post_id' }); 37441 }); 37442 ``` 37443 ```javascript 37444 // post route 37445 PostRoute = App.Route.extend({ 37446 renderTemplate: function() { 37447 this.render(); // all defaults apply 37448 } 37449 }); 37450 ``` 37451 The name of the `PostRoute`, defined by the router, is `post`. 37452 The following equivalent default options will be applied when 37453 the Route calls `render`: 37454 ```javascript 37455 // 37456 this.render('post', { // the template name associated with 'post' Route 37457 into: 'application', // the parent route to 'post' Route 37458 outlet: 'main', // {{outlet}} and {{outlet 'main'}} are synonymous, 37459 view: 'post', // the view associated with the 'post' Route 37460 controller: 'post', // the controller associated with the 'post' Route 37461 }) 37462 ``` 37463 By default the controller's `model` will be the route's model, so it does not 37464 need to be passed unless you wish to change which model is being used. 37465 @method render 37466 @param {String} name the name of the template to render 37467 @param {Object} [options] the options 37468 @param {String} [options.into] the template to render into, 37469 referenced by name. Defaults to the parent template 37470 @param {String} [options.outlet] the outlet inside `options.template` to render into. 37471 Defaults to 'main' 37472 @param {String|Object} [options.controller] the controller to use for this template, 37473 referenced by name or as a controller instance. Defaults to the Route's paired controller 37474 @param {Object} [options.model] the model object to set on `options.controller`. 37475 Defaults to the return value of the Route's model hook 37476 @public 37477 */ 37478 render: function (_name, options) { 37479 _emberMetalDebug.assert('The name in the given arguments is undefined', arguments.length > 0 ? !_emberMetalIs_none.default(arguments[0]) : true); 37480 37481 var namePassed = typeof _name === 'string' && !!_name; 37482 var isDefaultRender = arguments.length === 0 || _emberMetalIs_empty.default(arguments[0]); 37483 var name; 37484 37485 if (typeof _name === 'object' && !options) { 37486 name = this.routeName; 37487 options = _name; 37488 } else { 37489 name = _name; 37490 } 37491 37492 var renderOptions = buildRenderOptions(this, namePassed, isDefaultRender, name, options); 37493 this.connections.push(renderOptions); 37494 _emberMetalRun_loop.default.once(this.router, '_setOutlets'); 37495 }, 37496 37497 /** 37498 Disconnects a view that has been rendered into an outlet. 37499 You may pass any or all of the following options to `disconnectOutlet`: 37500 * `outlet`: the name of the outlet to clear (default: 'main') 37501 * `parentView`: the name of the view containing the outlet to clear 37502 (default: the view rendered by the parent route) 37503 Example: 37504 ```javascript 37505 App.ApplicationRoute = App.Route.extend({ 37506 actions: { 37507 showModal: function(evt) { 37508 this.render(evt.modalName, { 37509 outlet: 'modal', 37510 into: 'application' 37511 }); 37512 }, 37513 hideModal: function(evt) { 37514 this.disconnectOutlet({ 37515 outlet: 'modal', 37516 parentView: 'application' 37517 }); 37518 } 37519 } 37520 }); 37521 ``` 37522 Alternatively, you can pass the `outlet` name directly as a string. 37523 Example: 37524 ```javascript 37525 hideModal: function(evt) { 37526 this.disconnectOutlet('modal'); 37527 } 37528 ``` 37529 @method disconnectOutlet 37530 @param {Object|String} options the options hash or outlet name 37531 @public 37532 */ 37533 disconnectOutlet: function (options) { 37534 var outletName; 37535 var parentView; 37536 if (!options || typeof options === 'string') { 37537 outletName = options; 37538 } else { 37539 outletName = options.outlet; 37540 parentView = options.parentView; 37541 37542 if (options && Object.keys(options).indexOf('outlet') !== -1 && typeof options.outlet === 'undefined') { 37543 throw new _emberMetalError.default('You passed undefined as the outlet name.'); 37544 } 37545 } 37546 parentView = parentView && parentView.replace(/\//g, '.'); 37547 outletName = outletName || 'main'; 37548 this._disconnectOutlet(outletName, parentView); 37549 for (var i = 0; i < this.router.router.currentHandlerInfos.length; i++) { 37550 // This non-local state munging is sadly necessary to maintain 37551 // backward compatibility with our existing semantics, which allow 37552 // any route to disconnectOutlet things originally rendered by any 37553 // other route. This should all get cut in 2.0. 37554 this.router.router.currentHandlerInfos[i].handler._disconnectOutlet(outletName, parentView); 37555 } 37556 }, 37557 37558 _disconnectOutlet: function (outletName, parentView) { 37559 var parent = parentRoute(this); 37560 if (parent && parentView === parent.routeName) { 37561 parentView = undefined; 37562 } 37563 for (var i = 0; i < this.connections.length; i++) { 37564 var connection = this.connections[i]; 37565 if (connection.outlet === outletName && connection.into === parentView) { 37566 // This neuters the disconnected outlet such that it doesn't 37567 // render anything, but it leaves an entry in the outlet 37568 // hierarchy so that any existing other renders that target it 37569 // don't suddenly blow up. They will still stick themselves 37570 // into its outlets, which won't render anywhere. All of this 37571 // statefulness should get the machete in 2.0. 37572 this.connections[i] = { 37573 into: connection.into, 37574 outlet: connection.outlet, 37575 name: connection.name 37576 }; 37577 _emberMetalRun_loop.default.once(this.router, '_setOutlets'); 37578 } 37579 } 37580 }, 37581 37582 willDestroy: function () { 37583 this.teardownViews(); 37584 }, 37585 37586 /** 37587 @private 37588 @method teardownViews 37589 */ 37590 teardownViews: function () { 37591 if (this.connections && this.connections.length > 0) { 37592 this.connections = []; 37593 _emberMetalRun_loop.default.once(this.router, '_setOutlets'); 37594 } 37595 } 37596 }); 37597 37598 _emberRuntimeMixinsAction_handler.deprecateUnderscoreActions(Route); 37599 37600 Route.reopenClass({ 37601 isRouteFactory: true 37602 }); 37603 37604 function parentRoute(route) { 37605 var handlerInfo = handlerInfoFor(route, route.router.router.state.handlerInfos, -1); 37606 return handlerInfo && handlerInfo.handler; 37607 } 37608 37609 function handlerInfoFor(route, handlerInfos, _offset) { 37610 if (!handlerInfos) { 37611 return; 37612 } 37613 37614 var offset = _offset || 0; 37615 var current; 37616 for (var i = 0, l = handlerInfos.length; i < l; i++) { 37617 current = handlerInfos[i].handler; 37618 if (current === route) { 37619 return handlerInfos[i + offset]; 37620 } 37621 } 37622 } 37623 37624 function buildRenderOptions(route, namePassed, isDefaultRender, name, options) { 37625 var controller = options && options.controller; 37626 var templateName; 37627 var viewName; 37628 var ViewClass; 37629 var template; 37630 var LOG_VIEW_LOOKUPS = _emberMetalProperty_get.get(route.router, 'namespace.LOG_VIEW_LOOKUPS'); 37631 var into = options && options.into && options.into.replace(/\//g, '.'); 37632 var outlet = options && options.outlet || 'main'; 37633 var owner = _containerOwner.getOwner(route); 37634 37635 if (name) { 37636 name = name.replace(/\//g, '.'); 37637 templateName = name; 37638 } else { 37639 name = route.routeName; 37640 templateName = route.templateName || name; 37641 } 37642 37643 if (!controller) { 37644 if (namePassed) { 37645 controller = owner.lookup('controller:' + name) || route.controllerName || route.routeName; 37646 } else { 37647 controller = route.controllerName || owner.lookup('controller:' + name); 37648 } 37649 } 37650 37651 if (typeof controller === 'string') { 37652 var controllerName = controller; 37653 controller = owner.lookup('controller:' + controllerName); 37654 if (!controller) { 37655 throw new _emberMetalError.default('You passed `controller: \'' + controllerName + '\'` into the `render` method, but no such controller could be found.'); 37656 } 37657 } 37658 37659 if (options && Object.keys(options).indexOf('outlet') !== -1 && typeof options.outlet === 'undefined') { 37660 throw new _emberMetalError.default('You passed undefined as the outlet name.'); 37661 } 37662 37663 if (options && options.model) { 37664 controller.set('model', options.model); 37665 } 37666 37667 viewName = options && options.view || namePassed && name || route.viewName || name; 37668 ViewClass = owner._lookupFactory('view:' + viewName); 37669 template = owner.lookup('template:' + templateName); 37670 37671 var parent; 37672 if (into && (parent = parentRoute(route)) && into === parentRoute(route).routeName) { 37673 into = undefined; 37674 } 37675 37676 var renderOptions = { 37677 owner: owner, 37678 into: into, 37679 outlet: outlet, 37680 name: name, 37681 controller: controller, 37682 ViewClass: ViewClass, 37683 template: template 37684 }; 37685 37686 var Component = undefined; 37687 37688 if (!ViewClass && !template && !Component) {
37689 _emberMetalDebug.assert('Could not find "' + name + '" template, view, or component.', isDefaultRender); 37690 if (LOG_VIEW_LOOKUPS) { 37691 var fullName = 'template:' + name; 37692 _emberMetalDebug.info('Could not find "' + name + '" template or view. Nothing will be rendered', { fullName: fullName }); 37693 } 37694 } 37695 37696 return renderOptions; 37697 } 37698 37699 function getFullQueryParams(router, state) { 37700 if (state.fullQueryParams) { 37701 return state.fullQueryParams; 37702 } 37703 37704 state.fullQueryParams = {}; 37705 _emberMetalAssign.default(state.fullQueryParams, state.queryParams); 37706 37707 var targetRouteName = state.handlerInfos[state.handlerInfos.length - 1].name; 37708 router._deserializeQueryParams(targetRouteName, state.fullQueryParams); 37709 return state.fullQueryParams; 37710 } 37711 37712 function getQueryParamsFor(route, state) { 37713 state.queryParamsFor = state.queryParamsFor || {}; 37714 var name = route.routeName; 37715 37716 if (state.queryParamsFor[name]) { 37717 return state.queryParamsFor[name]; 37718 } 37719 37720 var fullQueryParams = getFullQueryParams(route.router, state); 37721 37722 var params = state.queryParamsFor[name] = {}; 37723 37724 // Copy over all the query params for this route/controller into params hash. 37725 var qpMeta = _emberMetalProperty_get.get(route, '_qp'); 37726 var qps = qpMeta.qps; 37727 for (var i = 0, len = qps.length; i < len; ++i) { 37728 // Put deserialized qp on params hash. 37729 var qp = qps[i]; 37730 37731 var qpValueWasPassedIn = (qp.prop in fullQueryParams); 37732 params[qp.prop] = qpValueWasPassedIn ? fullQueryParams[qp.prop] : copyDefaultValue(qp.defaultValue); 37733 } 37734 37735 return params; 37736 } 37737 37738 function copyDefaultValue(value) { 37739 if (Array.isArray(value)) { 37740 return _emberRuntimeSystemNative_array.A(value.slice()); 37741 } 37742 return value; 37743 } 37744 37745 /* 37746 Merges all query parameters from a controller with those from 37747 a route, returning a new object and avoiding any mutations to 37748 the existing objects. 37749 */ 37750 function mergeEachQueryParams(controllerQP, routeQP) { 37751 var keysAlreadyMergedOrSkippable; 37752 var qps = {}; 37753 37754 keysAlreadyMergedOrSkippable = { 37755 defaultValue: true, 37756 type: true, 37757 scope: true, 37758 as: true 37759 }; 37760 37761 // first loop over all controller qps, merging them with any matching route qps 37762 // into a new empty object to avoid mutating. 37763 for (var cqpName in controllerQP) { 37764 if (!controllerQP.hasOwnProperty(cqpName)) { 37765 continue; 37766 } 37767 37768 var newControllerParameterConfiguration = {}; 37769 _emberMetalAssign.default(newControllerParameterConfiguration, controllerQP[cqpName]); 37770 _emberMetalAssign.default(newControllerParameterConfiguration, routeQP[cqpName]); 37771 37772 qps[cqpName] = newControllerParameterConfiguration; 37773 37774 // allows us to skip this QP when we check route QPs. 37775 keysAlreadyMergedOrSkippable[cqpName] = true; 37776 } 37777 37778 // loop over all route qps, skipping those that were merged in the first pass 37779 // because they also appear in controller qps 37780 for (var rqpName in routeQP) { 37781 if (!routeQP.hasOwnProperty(rqpName) || keysAlreadyMergedOrSkippable[rqpName]) { 37782 continue; 37783 } 37784 37785 var newRouteParameterConfiguration = {}; 37786 _emberMetalAssign.default(newRouteParameterConfiguration, routeQP[rqpName], controllerQP[rqpName]); 37787 qps[rqpName] = newRouteParameterConfiguration; 37788 } 37789 37790 return qps; 37791 } 37792 37793 function addQueryParamsObservers(controller, propNames) { 37794 propNames.forEach(function (prop) { 37795 controller.addObserver(prop + '.[]', controller, controller._qpChanged); 37796 }); 37797 } 37798 37799 function deprecateQueryParamDefaultValuesSetOnController(controllerName, routeName, propName) { 37800 _emberMetalDebug.deprecate('Configuring query parameter default values on controllers is deprecated. Please move the value for the property \'' + propName + '\' from the \'' + controllerName + '\' controller to the \'' + routeName + '\' route in the format: {queryParams: ' + propName + ': {defaultValue: <default value> }}', false, { id: 'ember-routing.deprecate-query-param-default-values-set-on-controller', until: '3.0.0' }); 37801 } 37802 37803 exports.default = Route; 37804}); 37805// FEATURES, A, deprecate, assert, Logger 37806 37807// apply default values to controllers 37808// detect that default value defined on router config 37809 37810// detect that property was not defined on controller 37811enifed('ember-routing/system/router', ['exports', 'ember-metal/logger', 'ember-metal/debug', 'ember-metal/error', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/properties', 'ember-metal/empty_object', 'ember-metal/computed', 'ember-metal/assign', 'ember-metal/run_loop', 'ember-runtime/system/object', 'ember-runtime/mixins/evented', 'ember-routing/system/dsl', 'ember-routing/location/api', 'ember-routing/utils', 'ember-metal/utils', 'ember-routing/system/router_state', 'container/owner', 'ember-metal/dictionary', 'router', 'router/transition'], function (exports, _emberMetalLogger, _emberMetalDebug, _emberMetalError, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalProperties, _emberMetalEmpty_object, _emberMetalComputed, _emberMetalAssign, _emberMetalRun_loop, _emberRuntimeSystemObject, _emberRuntimeMixinsEvented, _emberRoutingSystemDsl, _emberRoutingLocationApi, _emberRoutingUtils, _emberMetalUtils, _emberRoutingSystemRouter_state, _containerOwner, _emberMetalDictionary, _router4, _routerTransition) { 37812 'use strict'; 37813 37814 exports.triggerEvent = triggerEvent; 37815 37816 function K() { 37817 return this; 37818 } 37819 37820 var slice = [].slice; 37821 37822 /** 37823 The `Ember.Router` class manages the application state and URLs. Refer to 37824 the [routing guide](http://emberjs.com/guides/routing/) for documentation. 37825 37826 @class Router 37827 @namespace Ember
37828 @extends Ember.Object 37829 @uses Ember.Evented 37830 @public 37831 */ 37832 var EmberRouter = _emberRuntimeSystemObject.default.extend(_emberRuntimeMixinsEvented.default, { 37833 /** 37834 The `location` property determines the type of URL's that your 37835 application will use. 37836 The following location types are currently available: 37837 * `history` - use the browser's history API to make the URLs look just like any standard URL 37838 * `hash` - use `#` to separate the server part of the URL from the Ember part: `/blog/#/posts/new` 37839 * `none` - do not store the Ember URL in the actual browser URL (mainly used for testing) 37840 * `auto` - use the best option based on browser capabilites: `history` if possible, then `hash` if possible, otherwise `none` 37841 Note: If using ember-cli, this value is defaulted to `auto` by the `locationType` setting of `/config/environment.js` 37842 @property location 37843 @default 'hash' 37844 @see {Ember.Location} 37845 @public 37846 */ 37847 location: 'hash', 37848 37849 /** 37850 Represents the URL of the root of the application, often '/'. This prefix is 37851 assumed on all routes defined on this router. 37852 @property rootURL 37853 @default '/' 37854 @public 37855 */ 37856 rootURL: '/', 37857 37858 _initRouterJs: function () { 37859 var router = this.router = new _router4.default(); 37860 router.triggerEvent = triggerEvent; 37861 37862 router._triggerWillChangeContext = K; 37863 router._triggerWillLeave = K; 37864 37865 var dslCallbacks = this.constructor.dslCallbacks || [K]; 37866 var dsl = this._buildDSL(); 37867 37868 dsl.route('application', { path: '/', resetNamespace: true, overrideNameAssertion: true }, function () { 37869 for (var i = 0; i < dslCallbacks.length; i++) { 37870 dslCallbacks[i].call(this); 37871 } 37872 }); 37873 37874 if (_emberMetalProperty_get.get(this, 'namespace.LOG_TRANSITIONS_INTERNAL')) { 37875 router.log = _emberMetalLogger.default.debug; 37876 } 37877 37878 router.map(dsl.generate()); 37879 }, 37880 37881 _buildDSL: function () { 37882 var moduleBasedResolver = this._hasModuleBasedResolver(); 37883 37884 return new _emberRoutingSystemDsl.default(null, { 37885 enableLoadingSubstates: !!moduleBasedResolver 37886 }); 37887 }, 37888 37889 init: function () { 37890 this._super.apply(this, arguments); 37891 37892 this._activeViews = {}; 37893 this._qpCache = new _emberMetalEmpty_object.default(); 37894 this._resetQueuedQueryParameterChanges(); 37895 this._handledErrors = _emberMetalDictionary.default(null); 37896 }, 37897 37898 /* 37899 Resets all pending query paramter changes. 37900 Called after transitioning to a new route 37901 based on query parameter changes. 37902 */ 37903 _resetQueuedQueryParameterChanges: function () { 37904 this._queuedQPChanges = {}; 37905 }, 37906 37907 /** 37908 Represents the current URL. 37909 @method url 37910 @return {String} The current URL. 37911 @private 37912 */ 37913 url: _emberMetalComputed.computed(function () { 37914 return _emberMetalProperty_get.get(this, 'location').getURL(); 37915 }), 37916 37917 _hasModuleBasedResolver: function () { 37918 var owner = _containerOwner.getOwner(this); 37919 37920 if (!owner) { 37921 return false; 37922 } 37923 37924 var resolver = owner.application && owner.application.__registry__ && owner.application.__registry__.resolver; 37925 37926 if (!resolver) { 37927 return false; 37928 } 37929 37930 return !!resolver.moduleBasedResolver; 37931 }, 37932 37933 /** 37934 Initializes the current router instance and sets up the change handling 37935 event listeners used by the instances `location` implementation. 37936 A property named `initialURL` will be used to determine the initial URL. 37937 If no value is found `/` will be used. 37938 @method startRouting 37939 @private 37940 */ 37941 startRouting: function () { 37942 var initialURL = _emberMetalProperty_get.get(this, 'initialURL'); 37943 37944 if (this.setupRouter()) { 37945 if (typeof initialURL === 'undefined') { 37946 initialURL = _emberMetalProperty_get.get(this, 'location').getURL(); 37947 } 37948 var initialTransition = this.handleURL(initialURL); 37949 if (initialTransition && initialTransition.error) { 37950 throw initialTransition.error; 37951 } 37952 } 37953 }, 37954 37955 setupRouter: function () { 37956 var _this = this; 37957 37958 this._initRouterJs(); 37959 this._setupLocation(); 37960 37961 var router = this.router; 37962 var location = _emberMetalProperty_get.get(this, 'location'); 37963 37964 // Allow the Location class to cancel the router setup while it refreshes 37965 // the page 37966 if (_emberMetalProperty_get.get(location, 'cancelRouterSetup')) { 37967 return false;
37968 } 37969 37970 this._setupRouter(router, location); 37971 37972 location.onUpdateURL(function (url) { 37973 _this.handleURL(url); 37974 }); 37975 37976 return true; 37977 }, 37978 37979 /** 37980 Handles updating the paths and notifying any listeners of the URL 37981 change. 37982 Triggers the router level `didTransition` hook. 37983 For example, to notify google analytics when the route changes, 37984 you could use this hook. (Note: requires also including GA scripts, etc.) 37985 ```javascript 37986 var Router = Ember.Router.extend({ 37987 location: config.locationType, 37988 didTransition: function() { 37989 this._super(...arguments); 37990 return ga('send', 'pageview', { 37991 'page': this.get('url'), 37992 'title': this.get('url') 37993 }); 37994 } 37995 }); 37996 ``` 37997 @method didTransition 37998 @public 37999 @since 1.2.0 38000 */ 38001 didTransition: function (infos) { 38002 updatePaths(this); 38003 38004 this._cancelSlowTransitionTimer(); 38005 38006 this.notifyPropertyChange('url'); 38007 this.set('currentState', this.targetState); 38008 38009 // Put this in the runloop so url will be accurate. Seems 38010 // less surprising than didTransition being out of sync. 38011 _emberMetalRun_loop.default.once(this, this.trigger, 'didTransition'); 38012 38013 if (_emberMetalProperty_get.get(this, 'namespace').LOG_TRANSITIONS) { 38014 _emberMetalLogger.default.log('Transitioned into \'' + EmberRouter._routePath(infos) + '\''); 38015 } 38016 }, 38017 38018 _setOutlets: function () { 38019 var handlerInfos = this.router.currentHandlerInfos; 38020 var route; 38021 var defaultParentState; 38022 var liveRoutes = null; 38023 38024 if (!handlerInfos) { 38025 return; 38026 } 38027 38028 for (var i = 0; i < handlerInfos.length; i++) { 38029 route = handlerInfos[i].handler; 38030 var connections = route.connections; 38031 var ownState; 38032 for (var j = 0; j < connections.length; j++) { 38033 var appended = appendLiveRoute(liveRoutes, defaultParentState, connections[j]); 38034 liveRoutes = appended.liveRoutes; 38035 if (appended.ownState.render.name === route.routeName || appended.ownState.render.outlet === 'main') { 38036 ownState = appended.ownState; 38037 } 38038 } 38039 if (connections.length === 0) { 38040 ownState = representEmptyRoute(liveRoutes, defaultParentState, route); 38041 } 38042 defaultParentState = ownState; 38043 } 38044 if (!this._toplevelView) { 38045 var owner = _containerOwner.getOwner(this); 38046 var OutletView = owner._lookupFactory('view:-outlet'); 38047 this._toplevelView = OutletView.create(); 38048 var instance = owner.lookup('-application-instance:main'); 38049 instance.didCreateRootView(this._toplevelView); 38050 } 38051 this._toplevelView.setOutletState(liveRoutes); 38052 }, 38053 38054 /** 38055 Handles notifying any listeners of an impending URL 38056 change. 38057 Triggers the router level `willTransition` hook. 38058 @method willTransition 38059 @public 38060 @since 1.11.0 38061 */ 38062 willTransition: function (oldInfos, newInfos, transition) { 38063 _emberMetalRun_loop.default.once(this, this.trigger, 'willTransition', transition); 38064 38065 if (_emberMetalProperty_get.get(this, 'namespace').LOG_TRANSITIONS) { 38066 _emberMetalLogger.default.log('Preparing to transition from \'' + EmberRouter._routePath(oldInfos) + '\' to \'' + EmberRouter._routePath(newInfos) + '\''); 38067 } 38068 }, 38069 38070 handleURL: function (url) { 38071 // Until we have an ember-idiomatic way of accessing #hashes, we need to 38072 // remove it because router.js doesn't know how to handle it. 38073 url = url.split(/#(.+)?/)[0]; 38074 return this._doURLTransition('handleURL', url); 38075 }, 38076 38077 _doURLTransition: function (routerJsMethod, url) { 38078 var transition = this.router[routerJsMethod](url || '/'); 38079 didBeginTransition(transition, this); 38080 return transition; 38081 }, 38082 38083 /** 38084 Transition the application into another route. The route may 38085 be either a single route or route path: 38086 See [Route.transitionTo](http://emberjs.com/api/classes/Ember.Route.html#method_transitionTo) for more info. 38087 @method transitionTo 38088 @param {String} name the name of the route or a URL 38089 @param {...Object} models the model(s) or identifier(s) to be used while 38090 transitioning to the route. 38091 @param {Object} [options] optional hash with a queryParams property 38092 containing a mapping of query parameters 38093 @return {Transition} the transition object associated with this 38094 attempted transition 38095 @public 38096 */ 38097 transitionTo: function () { 38098 var queryParams; 38099 38100 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 38101 args[_key] = arguments[_key]; 38102 } 38103 38104 if (resemblesURL(args[0])) { 38105 return this._doURLTransition('transitionTo', args[0]); 38106 } 38107 38108 var possibleQueryParams = args[args.length - 1]; 38109 if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) { 38110 queryParams = args.pop().queryParams; 38111 } else { 38112 queryParams = {}; 38113 } 38114 38115 var targetRouteName = args.shift(); 38116 return this._doTransition(targetRouteName, args, queryParams); 38117 }, 38118 38119 intermediateTransitionTo: function () { 38120 var _router; 38121 38122 (_router = this.router).intermediateTransitionTo.apply(_router, arguments); 38123 38124 updatePaths(this); 38125 38126 var infos = this.router.currentHandlerInfos; 38127 if (_emberMetalProperty_get.get(this, 'namespace').LOG_TRANSITIONS) { 38128 _emberMetalLogger.default.log('Intermediate-transitioned into \'' + EmberRouter._routePath(infos) + '\''); 38129 } 38130 }, 38131 38132 replaceWith: function () { 38133 return this.transitionTo.apply(this, arguments).method('replace'); 38134 }, 38135 38136 generate: function () { 38137 var _router2; 38138 38139 var url = (_router2 = this.router).generate.apply(_router2, arguments); 38140 return this.location.formatURL(url); 38141 }, 38142 38143 /** 38144 Determines if the supplied route is currently active. 38145 @method isActive 38146 @param routeName 38147 @return {Boolean} 38148 @private 38149 */ 38150 isActive: function (routeName) { 38151 var router = this.router; 38152 return router.isActive.apply(router, arguments); 38153 }, 38154 38155 /** 38156 An alternative form of `isActive` that doesn't require 38157 manual concatenation of the arguments into a single 38158 array. 38159 @method isActiveIntent 38160 @param routeName 38161 @param models 38162 @param queryParams 38163 @return {Boolean} 38164 @private 38165 @since 1.7.0 38166 */ 38167 isActiveIntent: function (routeName, models, queryParams) { 38168 return this.currentState.isActiveIntent(routeName, models, queryParams); 38169 }, 38170 38171 send: function (name, context) { 38172 var _router3; 38173 38174 (_router3 = this.router).trigger.apply(_router3, arguments); 38175 }, 38176 38177 /** 38178 Does this router instance have the given route. 38179 @method hasRoute 38180 @return {Boolean} 38181 @private 38182 */ 38183 hasRoute: function (route) { 38184 return this.router.hasRoute(route); 38185 }, 38186 38187 /** 38188 Resets the state of the router by clearing the current route 38189 handlers and deactivating them. 38190 @private 38191 @method reset 38192 */ 38193 reset: function () { 38194 if (this.router) { 38195 this.router.reset(); 38196 } 38197 }, 38198 38199 willDestroy: function () { 38200 if (this._toplevelView) { 38201 this._toplevelView.destroy(); 38202 this._toplevelView = null; 38203 } 38204 this._super.apply(this, arguments); 38205 this.reset(); 38206 }, 38207 38208 _lookupActiveComponentNode: function (templateName) { 38209 return this._activeViews[templateName]; 38210 }, 38211 38212 /* 38213 Called when an active route's query parameter has changed. 38214 These changes are batched into a runloop run and trigger 38215 a single transition. 38216 */ 38217 _activeQPChanged: function (queryParameterName, newValue) { 38218 this._queuedQPChanges[queryParameterName] = newValue; 38219 _emberMetalRun_loop.default.once(this, this._fireQueryParamTransition); 38220 }, 38221 38222 _updatingQPChanged: function (queryParameterName) { 38223 if (!this._qpUpdates) { 38224 this._qpUpdates = {}; 38225 } 38226 this._qpUpdates[queryParameterName] = true; 38227 }, 38228 38229 /* 38230 Triggers a transition to a route based on query parameter changes. 38231 This is called once per runloop, to batch changes. 38232 e.g. 38233 if these methods are called in succession: 38234 this._activeQPChanged('foo', '10'); 38235 // results in _queuedQPChanges = {foo: '10'} 38236 this._activeQPChanged('bar', false); 38237 // results in _queuedQPChanges = {foo: '10', bar: false} 38238 _queuedQPChanges will represent both of these changes 38239 and the transition using `transitionTo` will be triggered 38240 once. 38241 */ 38242 _fireQueryParamTransition: function () { 38243 this.transitionTo({ queryParams: this._queuedQPChanges }); 38244 this._resetQueuedQueryParameterChanges(); 38245 }, 38246 38247 _connectActiveComponentNode: function (templateName, componentNode) { 38248 _emberMetalDebug.assert('cannot connect an activeView that already exists', !this._activeViews[templateName]); 38249 38250 var _activeViews = this._activeViews; 38251 function disconnectActiveView() { 38252 delete _activeViews[templateName]; 38253 } 38254 38255 this._activeViews[templateName] = componentNode; 38256 componentNode.renderNode.addDestruction({ destroy: disconnectActiveView }); 38257 }, 38258 38259 _setupLocation: function () { 38260 var location = _emberMetalProperty_get.get(this, 'location'); 38261 var rootURL = _emberMetalProperty_get.get(this, 'rootURL'); 38262 var owner = _containerOwner.getOwner(this); 38263 38264 if ('string' === typeof location && owner) { 38265 var resolvedLocation = owner.lookup('location:' + location); 38266 38267 if ('undefined' !== typeof resolvedLocation) { 38268 location = _emberMetalProperty_set.set(this, 'location', resolvedLocation); 38269 } else { 38270 // Allow for deprecated registration of custom location API's 38271 var options = { 38272 implementation: location 38273 }; 38274 38275 location = _emberMetalProperty_set.set(this, 'location', _emberRoutingLocationApi.default.create(options)); 38276 } 38277 } 38278 38279 if (location !== null && typeof location === 'object') { 38280 if (rootURL) { 38281 _emberMetalProperty_set.set(location, 'rootURL', rootURL); 38282 } 38283 38284 // Allow the location to do any feature detection, such as AutoLocation 38285 // detecting history support. This gives it a chance to set its 38286 // `cancelRouterSetup` property which aborts routing. 38287 if (typeof location.detect === 'function') { 38288 location.detect(); 38289 } 38290 38291 // ensure that initState is called AFTER the rootURL is set on 38292 // the location instance 38293 if (typeof location.initState === 'function') { 38294 location.initState(); 38295 } 38296 } 38297 }, 38298 38299 _getHandlerFunction: function () { 38300 var _this2 = this; 38301 38302 var seen = new _emberMetalEmpty_object.default(); 38303 var owner = _containerOwner.getOwner(this); 38304 var DefaultRoute = owner._lookupFactory('route:basic'); 38305 38306 return function (name) { 38307 var routeName = 'route:' + name; 38308 var handler = owner.lookup(routeName); 38309 38310 if (seen[name]) { 38311 return handler; 38312 } 38313 38314 seen[name] = true; 38315 38316 if (!handler) { 38317 owner.register(routeName, DefaultRoute.extend()); 38318 handler = owner.lookup(routeName); 38319 38320 if (_emberMetalProperty_get.get(_this2, 'namespace.LOG_ACTIVE_GENERATION')) { 38321 _emberMetalDebug.info('generated -> ' + routeName, { fullName: routeName }); 38322 } 38323 } 38324 38325 handler.routeName = name; 38326 return handler; 38327 }; 38328 }, 38329 38330 _setupRouter: function (router, location) { 38331 var lastURL; 38332 var emberRouter = this; 38333 38334 router.getHandler = this._getHandlerFunction(); 38335 38336 var doUpdateURL = function () { 38337 location.setURL(lastURL); 38338 }; 38339 38340 router.updateURL = function (path) { 38341 lastURL = path; 38342 _emberMetalRun_loop.default.once(doUpdateURL); 38343 }; 38344 38345 if (location.replaceURL) { 38346 var doReplaceURL = function () { 38347 location.replaceURL(lastURL); 38348 }; 38349 38350 router.replaceURL = function (path) { 38351 lastURL = path; 38352 _emberMetalRun_loop.default.once(doReplaceURL); 38353 }; 38354 } 38355 38356 router.didTransition = function (infos) { 38357 emberRouter.didTransition(infos); 38358 }; 38359 38360 router.willTransition = function (oldInfos, newInfos, transition) { 38361 emberRouter.willTransition(oldInfos, newInfos, transition); 38362 }; 38363 }, 38364 38365 _serializeQueryParams: function (targetRouteName, queryParams) { 38366 var groupedByUrlKey = {}; 38367
38368 forEachQueryParam(this, targetRouteName, queryParams, function (key, value, qp) { 38369 var urlKey = qp.urlKey; 38370 if (!groupedByUrlKey[urlKey]) { 38371 groupedByUrlKey[urlKey] = []; 38372 } 38373 groupedByUrlKey[urlKey].push({ 38374 qp: qp, 38375 value: value 38376 }); 38377 delete queryParams[key]; 38378 }); 38379 38380 for (var key in groupedByUrlKey) { 38381 var qps = groupedByUrlKey[key]; 38382 _emberMetalDebug.assert('You\'re not allowed to have more than one controller property map to the same query param key, but both `' + qps[0].qp.scopedPropertyName + '` and `' + (qps[1] ? qps[1].qp.scopedPropertyName : '') + '` map to `' + qps[0].qp.urlKey + '`. You can fix this by mapping one of the controller properties to a different query param key via the `as` config option, e.g. `' + qps[0].qp.prop + ': { as: \'other-' + qps[0].qp.prop + '\' }`', qps.length <= 1); 38383 var qp = qps[0].qp; 38384 queryParams[qp.urlKey] = qp.route.serializeQueryParam(qps[0].value, qp.urlKey, qp.type); 38385 } 38386 }, 38387 38388 _deserializeQueryParams: function (targetRouteName, queryParams) { 38389 forEachQueryParam(this, targetRouteName, queryParams, function (key, value, qp) { 38390 delete queryParams[key]; 38391 queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); 38392 }); 38393 }, 38394 38395 _pruneDefaultQueryParamValues: function (targetRouteName, queryParams) { 38396 var qps = this._queryParamsFor(targetRouteName); 38397 for (var key in queryParams) { 38398 var qp = qps.map[key]; 38399 if (qp && qp.serializedDefaultValue === queryParams[key]) { 38400 delete queryParams[key]; 38401 } 38402 } 38403 }, 38404 38405 _doTransition: function (_targetRouteName, models, _queryParams) { 38406 var targetRouteName = _targetRouteName || _emberRoutingUtils.getActiveTargetName(this.router); 38407 _emberMetalDebug.assert('The route ' + targetRouteName + ' was not found', targetRouteName && this.router.hasRoute(targetRouteName)); 38408 38409 var queryParams = {}; 38410 // merge in any queryParams from the active transition which could include 38411 // queryparams from the url on initial load. 38412 if (this.router.activeTransition) { 38413 _emberMetalAssign.default(queryParams, this.router.activeTransition.queryParams); 38414 } 38415 38416 _emberMetalAssign.default(queryParams, _queryParams); 38417 this._prepareQueryParams(targetRouteName, models, queryParams); 38418 38419 var transitionArgs = _emberRoutingUtils.routeArgs(targetRouteName, models, queryParams); 38420 var transition = this.router.transitionTo.apply(this.router, transitionArgs); 38421 38422 didBeginTransition(transition, this); 38423 38424 return transition; 38425 }, 38426 38427 _prepareQueryParams: function (targetRouteName, models, queryParams) { 38428 this._hydrateUnsuppliedQueryParams(targetRouteName, models, queryParams); 38429 this._serializeQueryParams(targetRouteName, queryParams); 38430 this._pruneDefaultQueryParamValues(targetRouteName, queryParams); 38431 }, 38432 38433 /** 38434 Returns a merged query params meta object for a given route. 38435 Useful for asking a route what its known query params are. 38436 @private 38437 */ 38438 _queryParamsFor: function (leafRouteName) { 38439 if (this._qpCache[leafRouteName]) { 38440 return this._qpCache[leafRouteName]; 38441 } 38442 38443 var map = {}; 38444 var qps = []; 38445 this._qpCache[leafRouteName] = { 38446 map: map, 38447 qps: qps 38448 }; 38449 38450 var routerjs = this.router; 38451 var recogHandlerInfos = routerjs.recognizer.handlersFor(leafRouteName); 38452 38453 for (var i = 0, len = recogHandlerInfos.length; i < len; ++i) { 38454 var recogHandler = recogHandlerInfos[i]; 38455 var route = routerjs.getHandler(recogHandler.handler); 38456 var qpMeta = _emberMetalProperty_get.get(route, '_qp'); 38457 38458 if (!qpMeta) { 38459 continue; 38460 } 38461 38462 _emberMetalAssign.default(map, qpMeta.map); 38463 qps.push.apply(qps, qpMeta.qps); 38464 } 38465 38466 return { 38467 qps: qps, 38468 map: map 38469 }; 38470 }, 38471 38472 _hydrateUnsuppliedQueryParams: function (leafRouteName, contexts, queryParams) { 38473 var state = calculatePostTransitionState(this, leafRouteName, contexts); 38474 var handlerInfos = state.handlerInfos; 38475 var appCache = this._bucketCache; 38476 _emberRoutingUtils.stashParamNames(this, handlerInfos); 38477 38478 for (var i = 0, len = handlerInfos.length; i < len; ++i) { 38479 var route = handlerInfos[i].handler; 38480 var qpMeta = _emberMetalProperty_get.get(route, '_qp'); 38481 38482 for (var j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { 38483 var qp = qpMeta.qps[j]; 38484 38485 var presentProp = qp.prop in queryParams && qp.prop || qp.scopedPropertyName in queryParams && qp.scopedPropertyName; 38486 38487 if (presentProp) { 38488 if (presentProp !== qp.scopedPropertyName) { 38489 queryParams[qp.scopedPropertyName] = queryParams[presentProp]; 38490 delete queryParams[presentProp]; 38491 } 38492 } else { 38493 var cacheKey = _emberRoutingUtils.calculateCacheKey(qp.ctrl, qp.parts, state.params); 38494 queryParams[qp.scopedPropertyName] = appCache.lookup(cacheKey, qp.prop, qp.defaultValue); 38495 } 38496 } 38497 } 38498 }, 38499
38500 _scheduleLoadingEvent: function (transition, originRoute) { 38501 this._cancelSlowTransitionTimer(); 38502 this._slowTransitionTimer = _emberMetalRun_loop.default.scheduleOnce('routerTransitions', this, '_handleSlowTransition', transition, originRoute); 38503 }, 38504 38505 currentState: null, 38506 targetState: null, 38507 38508 _handleSlowTransition: function (transition, originRoute) { 38509 if (!this.router.activeTransition) { 38510 // Don't fire an event if we've since moved on from 38511 // the transition that put us in a loading state. 38512 return; 38513 } 38514 38515 this.set('targetState', _emberRoutingSystemRouter_state.default.create({ 38516 emberRouter: this, 38517 routerJs: this.router, 38518 routerJsState: this.router.activeTransition.state 38519 })); 38520 38521 transition.trigger(true, 'loading', transition, originRoute); 38522 }, 38523 38524 _cancelSlowTransitionTimer: function () { 38525 if (this._slowTransitionTimer) { 38526 _emberMetalRun_loop.default.cancel(this._slowTransitionTimer); 38527 } 38528 this._slowTransitionTimer = null; 38529 }, 38530 38531 // These three helper functions are used to ensure errors aren't 38532 // re-raised if they're handled in a route's error action. 38533 _markErrorAsHandled: function (errorGuid) { 38534 this._handledErrors[errorGuid] = true; 38535 }, 38536 38537 _isErrorHandled: function (errorGuid) { 38538 return this._handledErrors[errorGuid]; 38539 }, 38540 38541 _clearHandledError: function (errorGuid) { 38542 delete this._handledErrors[errorGuid]; 38543 } 38544 }); 38545 38546 /* 38547 Helper function for iterating root-ward, starting 38548 from (but not including) the provided `originRoute`. 38549 38550 Returns true if the last callback fired requested 38551 to bubble upward. 38552 38553 @private 38554 */ 38555 function forEachRouteAbove(originRoute, transition, callback) { 38556 var handlerInfos = transition.state.handlerInfos; 38557 var originRouteFound = false; 38558 var handlerInfo, route; 38559 38560 for (var i = handlerInfos.length - 1; i >= 0; --i) { 38561 handlerInfo = handlerInfos[i]; 38562 route = handlerInfo.handler; 38563 38564 if (!originRouteFound) { 38565 if (originRoute === route) { 38566 originRouteFound = true; 38567 } 38568 continue; 38569 } 38570 38571 if (callback(route, handlerInfos[i + 1].handler) !== true) { 38572 return false; 38573 } 38574 } 38575 return true; 38576 } 38577 38578 // These get invoked when an action bubbles above ApplicationRoute 38579 // and are not meant to be overridable. 38580 var defaultActionHandlers = { 38581 38582 willResolveModel: function (transition, originRoute) { 38583 originRoute.router._scheduleLoadingEvent(transition, originRoute); 38584 }, 38585 38586 error: function (error, transition, originRoute) { 38587 // Attempt to find an appropriate error substate to enter. 38588 var router = originRoute.router; 38589 38590 var tryTopLevel = forEachRouteAbove(originRoute, transition, function (route, childRoute) { 38591 var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); 38592 if (childErrorRouteName) { 38593 router.intermediateTransitionTo(childErrorRouteName, error); 38594 return; 38595 } 38596 return true; 38597 }); 38598 38599 if (tryTopLevel) { 38600 // Check for top-level error state to enter. 38601 if (routeHasBeenDefined(originRoute.router, 'application_error')) { 38602 router.intermediateTransitionTo('application_error', error); 38603 return; 38604 } 38605 } 38606 38607 logError(error, 'Error while processing route: ' + transition.targetName); 38608 }, 38609 38610 loading: function (transition, originRoute) { 38611 // Attempt to find an appropriate loading substate to enter. 38612 var router = originRoute.router; 38613 38614 var tryTopLevel = forEachRouteAbove(originRoute, transition, function (route, childRoute) { 38615 var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); 38616 38617 if (childLoadingRouteName) { 38618 router.intermediateTransitionTo(childLoadingRouteName); 38619 return; 38620 } 38621 38622 // Don't bubble above pivot route. 38623 if (transition.pivotHandler !== route) { 38624 return true; 38625 } 38626 }); 38627 38628 if (tryTopLevel) { 38629 // Check for top-level loading state to enter. 38630 if (routeHasBeenDefined(originRoute.router, 'application_loading')) { 38631 router.intermediateTransitionTo('application_loading'); 38632 return; 38633 } 38634 } 38635 } 38636 }; 38637 38638 function logError(_error, initialMessage) { 38639 var errorArgs = []; 38640 var error; 38641 if (_error && typeof _error === 'object' && typeof _error.errorThrown === 'object') { 38642 error = _error.errorThrown; 38643 } else { 38644 error = _error; 38645 } 38646 38647 if (initialMessage) { 38648 errorArgs.push(initialMessage); 38649 } 38650 38651 if (error) { 38652 if (error.message) { 38653 errorArgs.push(error.message); 38654 } 38655 if (error.stack) { 38656 errorArgs.push(error.stack); 38657 } 38658 38659 if (typeof error === 'string') { 38660 errorArgs.push(error); 38661 } 38662 } 38663 38664 _emberMetalLogger.default.error.apply(this, errorArgs); 38665 } 38666 38667 function findChildRouteName(parentRoute, originatingChildRoute, name) { 38668 var router = parentRoute.router; 38669 var childName; 38670 var targetChildRouteName = originatingChildRoute.routeName.split('.').pop(); 38671 var namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; 38672 38673 // First, try a named loading state, e.g. 'foo_loading' 38674 childName = namespace + targetChildRouteName + '_' + name; 38675 if (routeHasBeenDefined(router, childName)) { 38676 return childName; 38677 } 38678
38679 // Second, try general loading state, e.g. 'loading' 38680 childName = namespace + name; 38681 if (routeHasBeenDefined(router, childName)) { 38682 return childName; 38683 } 38684 } 38685 38686 function routeHasBeenDefined(router, name) { 38687 var owner = _containerOwner.getOwner(router); 38688 return router.hasRoute(name) && (owner.hasRegistration('template:' + name) || owner.hasRegistration('route:' + name)); 38689 } 38690 38691 function triggerEvent(handlerInfos, ignoreFailure, args) { 38692 var name = args.shift(); 38693 38694 if (!handlerInfos) { 38695 if (ignoreFailure) { 38696 return; 38697 } 38698 throw new _emberMetalError.default('Can\'t trigger action \'' + name + '\' because your app hasn\'t finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks.'); 38699 } 38700 38701 var eventWasHandled = false; 38702 var handlerInfo, handler; 38703 38704 for (var i = handlerInfos.length - 1; i >= 0; i--) { 38705 handlerInfo = handlerInfos[i]; 38706 handler = handlerInfo.handler; 38707 38708 if (handler.actions && handler.actions[name]) { 38709 if (handler.actions[name].apply(handler, args) === true) { 38710 eventWasHandled = true; 38711 } else { 38712 // Should only hit here if a non-bubbling error action is triggered on a route. 38713 if (name === 'error') { 38714 var errorId = _emberMetalUtils.guidFor(args[0]); 38715 handler.router._markErrorAsHandled(errorId); 38716 } 38717 return; 38718 } 38719 } 38720 } 38721 38722 if (defaultActionHandlers[name]) { 38723 defaultActionHandlers[name].apply(null, args); 38724 return; 38725 } 38726 38727 if (!eventWasHandled && !ignoreFailure) { 38728 throw new _emberMetalError.default('Nothing handled the action \'' + name + '\'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.'); 38729 } 38730 } 38731 38732 function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { 38733 var routerjs = emberRouter.router; 38734 var state = routerjs.applyIntent(leafRouteName, contexts); 38735 var handlerInfos = state.handlerInfos; 38736 var params = state.params; 38737 38738 for (var i = 0, len = handlerInfos.length; i < len; ++i) { 38739 var handlerInfo = handlerInfos[i]; 38740 if (!handlerInfo.isResolved) { 38741 handlerInfo = handlerInfo.becomeResolved(null, handlerInfo.context); 38742 } 38743 params[handlerInfo.name] = handlerInfo.params; 38744 } 38745 return state; 38746 } 38747 38748 function updatePaths(router) { 38749 var infos = router.router.currentHandlerInfos; 38750 var path = EmberRouter._routePath(infos); 38751 var currentRouteName = infos[infos.length - 1].name; 38752 38753 _emberMetalProperty_set.set(router, 'currentPath', path); 38754 _emberMetalProperty_set.set(router, 'currentRouteName', currentRouteName); 38755 38756 var appController = _containerOwner.getOwner(router).lookup('controller:application'); 38757 38758 if (!appController) { 38759 // appController might not exist when top-level loading/error 38760 // substates have been entered since ApplicationRoute hasn't 38761 // actually been entered at that point. 38762 return; 38763 } 38764 38765 if (!('currentPath' in appController)) { 38766 _emberMetalProperties.defineProperty(appController, 'currentPath'); 38767 } 38768 38769 _emberMetalProperty_set.set(appController, 'currentPath', path); 38770 38771 if (!('currentRouteName' in appController)) { 38772 _emberMetalProperties.defineProperty(appController, 'currentRouteName'); 38773 } 38774 38775 _emberMetalProperty_set.set(appController, 'currentRouteName', currentRouteName); 38776 } 38777 38778 EmberRouter.reopenClass({ 38779 router: null, 38780 38781 /** 38782 The `Router.map` function allows you to define mappings from URLs to routes 38783 in your application. These mappings are defined within the 38784 supplied callback function using `this.route`. 38785 The first parameter is the name of the route which is used by default as the 38786 path name as well. 38787 The second parameter is the optional options hash. Available options are: 38788 * `path`: allows you to provide your own path as well as mark dynamic 38789 segments. 38790 * `resetNamespace`: false by default; when nesting routes, ember will 38791 combine the route names to form the fully-qualified route name, which is 38792 used with `{{link-to}}` or manually transitioning to routes. Setting 38793 `resetNamespace: true` will cause the route not to inherit from its 38794 parent route's names. This is handy for resources which can be accessed 38795 in multiple places as well as preventing extremely long route names. 38796 Keep in mind that the actual URL path behavior is still retained. 38797 The third parameter is a function, which can be used to nest routes. 38798 Nested routes, by default, will have the parent route tree's route name and
38799 path prepended to it's own. 38800 ```javascript 38801 App.Router.map(function(){ 38802 this.route('post', { path: '/post/:post_id' }, function() { 38803 this.route('edit'); 38804 this.route('comments', { resetNamespace: true }, function() { 38805 this.route('new'); 38806 }); 38807 }); 38808 }); 38809 ``` 38810 For more detailed documentation and examples please see 38811 [the guides](http://emberjs.com/guides/routing/defining-your-routes/). 38812 @method map 38813 @param callback 38814 @public 38815 */ 38816 map: function (callback) { 38817 if (!this.dslCallbacks) { 38818 this.dslCallbacks = []; 38819 this.reopenClass({ dslCallbacks: this.dslCallbacks }); 38820 } 38821 38822 this.dslCallbacks.push(callback); 38823 38824 return this; 38825 }, 38826 38827 _routePath: function (handlerInfos) { 38828 var path = []; 38829 38830 // We have to handle coalescing resource names that 38831 // are prefixed with their parent's names, e.g. 38832 // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz' 38833 38834 function intersectionMatches(a1, a2) { 38835 for (var i = 0, len = a1.length; i < len; ++i) { 38836 if (a1[i] !== a2[i]) { 38837 return false; 38838 } 38839 } 38840 return true; 38841 } 38842 38843 var name, nameParts, oldNameParts; 38844 for (var i = 1, l = handlerInfos.length; i < l; i++) { 38845 name = handlerInfos[i].name; 38846 nameParts = name.split('.'); 38847 oldNameParts = slice.call(path); 38848 38849 while (oldNameParts.length) { 38850 if (intersectionMatches(oldNameParts, nameParts)) { 38851 break; 38852 } 38853 oldNameParts.shift(); 38854 } 38855 38856 path.push.apply(path, nameParts.slice(oldNameParts.length)); 38857 } 38858 38859 return path.join('.'); 38860 } 38861 }); 38862 38863 function didBeginTransition(transition, router) { 38864 var routerState = _emberRoutingSystemRouter_state.default.create({ 38865 emberRouter: router, 38866 routerJs: router.router, 38867 routerJsState: transition.state 38868 }); 38869 38870 if (!router.currentState) { 38871 router.set('currentState', routerState); 38872 } 38873 router.set('targetState', routerState); 38874 38875 transition.promise = transition.catch(function (error) { 38876 var errorId = _emberMetalUtils.guidFor(error); 38877 38878 if (router._isErrorHandled(errorId)) { 38879 router._clearHandledError(errorId); 38880 } else { 38881 throw error; 38882 } 38883 }); 38884 } 38885 38886 function resemblesURL(str) { 38887 return typeof str === 'string' && (str === '' || str.charAt(0) === '/'); 38888 } 38889 38890 function forEachQueryParam(router, targetRouteName, queryParams, callback) { 38891 var qpCache = router._queryParamsFor(targetRouteName); 38892 38893 for (var key in queryParams) { 38894 if (!queryParams.hasOwnProperty(key)) { 38895 continue; 38896 } 38897 var value = queryParams[key]; 38898 var qp = qpCache.map[key]; 38899 38900 if (qp) { 38901 callback(key, value, qp); 38902 } 38903 } 38904 } 38905 38906 function findLiveRoute(liveRoutes, name) { 38907 if (!liveRoutes) { 38908 return; 38909 } 38910 var stack = [liveRoutes]; 38911 while (stack.length > 0) { 38912 var test = stack.shift(); 38913 if (test.render.name === name) { 38914 return test; 38915 } 38916 var outlets = test.outlets; 38917 for (var outletName in outlets) { 38918 stack.push(outlets[outletName]); 38919 } 38920 } 38921 } 38922 38923 function appendLiveRoute(liveRoutes, defaultParentState, renderOptions) { 38924 var target; 38925 var myState = { 38926 render: renderOptions, 38927 outlets: new _emberMetalEmpty_object.default() 38928 }; 38929 if (renderOptions.into) { 38930 target = findLiveRoute(liveRoutes, renderOptions.into); 38931 } else { 38932 target = defaultParentState; 38933 } 38934 if (target) { 38935 _emberMetalProperty_set.set(target.outlets, renderOptions.outlet, myState); 38936 } else { 38937 if (renderOptions.into) { 38938 // Megahax time. Post-2.0-breaking-changes, we will just assert 38939 // right here that the user tried to target a nonexistent 38940 // thing. But for now we still need to support the `render` 38941 // helper, and people are allowed to target templates rendered 38942 // by the render helper. So instead we defer doing anyting with 38943 // these orphan renders until afterRender. 38944 appendOrphan(liveRoutes, renderOptions.into, myState); 38945 } else { 38946 liveRoutes = myState; 38947 } 38948 } 38949 return { 38950 liveRoutes: liveRoutes, 38951 ownState: myState 38952 }; 38953 } 38954 38955 function appendOrphan(liveRoutes, into, myState) { 38956 if (!liveRoutes.outlets.__ember_orphans__) { 38957 liveRoutes.outlets.__ember_orphans__ = { 38958 render: { 38959 name: '__ember_orphans__' 38960 }, 38961 outlets: new _emberMetalEmpty_object.default() 38962 }; 38963 } 38964 liveRoutes.outlets.__ember_orphans__.outlets[into] = myState; 38965 _emberMetalRun_loop.default.schedule('afterRender', function () { 38966 // `wasUsed` gets set by the render helper. See the function 38967 // `impersonateAnOutlet`. 38968 _emberMetalDebug.assert('You attempted to render into \'' + into + '\' but it was not found', liveRoutes.outlets.__ember_orphans__.outlets[into].wasUsed); 38969 }); 38970 } 38971 38972 function representEmptyRoute(liveRoutes, defaultParentState, route) { 38973 // the route didn't render anything 38974 var alreadyAppended = findLiveRoute(liveRoutes, route.routeName); 38975 if (alreadyAppended) { 38976 // But some other route has already rendered our default 38977 // template, so that becomes the default target for any 38978 // children we may have. 38979 return alreadyAppended; 38980 } else { 38981 // Create an entry to represent our default template name, 38982 // just so other routes can target it and inherit its place 38983 // in the outlet hierarchy. 38984 defaultParentState.outlets.main = { 38985 render: { 38986 name: route.routeName, 38987 outlet: 'main' 38988 }, 38989 outlets: {} 38990 }; 38991 return defaultParentState; 38992 } 38993 } 38994 38995 exports.default = EmberRouter; 38996}); 38997 38998/** 38999@module ember 39000@submodule ember-routing 39001*/ 39002enifed('ember-routing/system/router_state', ['exports', 'ember-metal/is_empty', 'ember-runtime/system/object', 'ember-metal/assign'], function (exports, _emberMetalIs_empty, _emberRuntimeSystemObject, _emberMetalAssign) { 39003 'use strict'; 39004 39005 var keys = Object.keys; 39006 39007 var RouterState = _emberRuntimeSystemObject.default.extend({ 39008 emberRouter: null, 39009 routerJs: null, 39010 routerJsState: null, 39011 39012 isActiveIntent: function (routeName, models, queryParams, queryParamsMustMatch) { 39013 var state = this.routerJsState; 39014 if (!this.routerJs.isActiveIntent(routeName, models, null, state)) { 39015 return false;
39016 } 39017 39018 var emptyQueryParams = _emberMetalIs_empty.default(keys(queryParams)); 39019 39020 if (queryParamsMustMatch && !emptyQueryParams) { 39021 var visibleQueryParams = {}; 39022 _emberMetalAssign.default(visibleQueryParams, queryParams); 39023 39024 this.emberRouter._prepareQueryParams(routeName, models, visibleQueryParams); 39025 return shallowEqual(visibleQueryParams, state.queryParams); 39026 } 39027 39028 return true; 39029 } 39030 }); 39031 39032 function shallowEqual(a, b) { 39033 var k; 39034 for (k in a) { 39035 if (a.hasOwnProperty(k) && a[k] !== b[k]) { 39036 return false; 39037 } 39038 } 39039 for (k in b) { 39040 if (b.hasOwnProperty(k) && a[k] !== b[k]) { 39041 return false; 39042 } 39043 } 39044 return true; 39045 } 39046 39047 exports.default = RouterState; 39048}); 39049enifed('ember-routing/utils', ['exports', 'ember-metal/assign', 'ember-metal/property_get'], function (exports, _emberMetalAssign, _emberMetalProperty_get) { 39050 'use strict'; 39051 39052 exports.routeArgs = routeArgs; 39053 exports.getActiveTargetName = getActiveTargetName; 39054 exports.stashParamNames = stashParamNames; 39055 exports.calculateCacheKey = calculateCacheKey; 39056 exports.normalizeControllerQueryParams = normalizeControllerQueryParams; 39057 39058 function routeArgs(targetRouteName, models, queryParams) { 39059 var args = []; 39060 if (typeof targetRouteName === 'string') { 39061 args.push('' + targetRouteName); 39062 } 39063 args.push.apply(args, models); 39064 args.push({ queryParams: queryParams }); 39065 return args; 39066 } 39067 39068 function getActiveTargetName(router) { 39069 var handlerInfos = router.activeTransition ? router.activeTransition.state.handlerInfos : router.state.handlerInfos; 39070 return handlerInfos[handlerInfos.length - 1].name; 39071 } 39072 39073 function stashParamNames(router, handlerInfos) { 39074 if (handlerInfos._namesStashed) { 39075 return; 39076 } 39077 39078 // This helper exists because router.js/route-recognizer.js awkwardly 39079 // keeps separate a handlerInfo's list of parameter names depending 39080 // on whether a URL transition or named transition is happening. 39081 // Hopefully we can remove this in the future. 39082 var targetRouteName = handlerInfos[handlerInfos.length - 1].name; 39083 var recogHandlers = router.router.recognizer.handlersFor(targetRouteName); 39084 var dynamicParent = null; 39085 39086 for (var i = 0, len = handlerInfos.length; i < len; ++i) { 39087 var handlerInfo = handlerInfos[i]; 39088 var names = recogHandlers[i].names; 39089 39090 if (names.length) { 39091 dynamicParent = handlerInfo; 39092 } 39093 39094 handlerInfo._names = names; 39095 39096 var route = handlerInfo.handler; 39097 route._stashNames(handlerInfo, dynamicParent); 39098 } 39099 39100 handlerInfos._namesStashed = true; 39101 } 39102 39103 function _calculateCacheValuePrefix(prefix, part) { 39104 // calculates the dot seperated sections from prefix that are also 39105 // at the start of part - which gives us the route name 39106 39107 // given : prefix = site.article.comments, part = site.article.id 39108 // - returns: site.article (use get(values[site.article], 'id') to get the dynamic part - used below) 39109 39110 // given : prefix = site.article, part = site.article.id 39111 // - returns: site.article. (use get(values[site.article], 'id') to get the dynamic part - used below) 39112 39113 var prefixParts = prefix.split('.'); 39114 var currPrefix = ''; 39115 39116 for (var i = 0, len = prefixParts.length; i < len; i++) { 39117 var currPart = prefixParts.slice(0, i + 1).join('.'); 39118 if (part.indexOf(currPart) !== 0) { 39119 break; 39120 } 39121 currPrefix = currPart; 39122 } 39123 39124 return currPrefix; 39125 } 39126 39127 /* 39128 Stolen from Controller 39129 */ 39130 39131 function calculateCacheKey(prefix, _parts, values) { 39132 var parts = _parts || []; 39133 var suffixes = ''; 39134 for (var i = 0, len = parts.length; i < len; ++i) { 39135 var part = parts[i]; 39136 var cacheValuePrefix = _calculateCacheValuePrefix(prefix, part); 39137 var value; 39138 if (values) { 39139 if (cacheValuePrefix && cacheValuePrefix in values) { 39140 var partRemovedPrefix = part.indexOf(cacheValuePrefix) === 0 ? part.substr(cacheValuePrefix.length + 1) : part; 39141 value = _emberMetalProperty_get.get(values[cacheValuePrefix], partRemovedPrefix); 39142 } else { 39143 value = _emberMetalProperty_get.get(values, part); 39144 } 39145 }
39146 suffixes += '::' + part + ':' + value; 39147 } 39148 return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); 39149 } 39150 39151 var ALL_PERIODS_REGEX = /\./g; 39152 39153 /* 39154 Controller-defined query parameters can come in three shapes: 39155 39156 Array 39157 queryParams: ['foo', 'bar'] 39158 Array of simple objects where value is an alias 39159 queryParams: [ 39160 { 39161 'foo': 'rename_foo_to_this' 39162 }, 39163 { 39164 'bar': 'call_bar_this_instead' 39165 } 39166 ] 39167 Array of fully defined objects 39168 queryParams: [ 39169 { 39170 'foo': { 39171 as: 'rename_foo_to_this' 39172 }, 39173 } 39174 { 39175 'bar': { 39176 as: 'call_bar_this_instead', 39177 scope: 'controller' 39178 } 39179 } 39180 ] 39181 39182 This helper normalizes all three possible styles into the 39183 'Array of fully defined objects' style. 39184 */ 39185 39186 function normalizeControllerQueryParams(queryParams) { 39187 if (queryParams._qpMap) { 39188 return queryParams._qpMap; 39189 } 39190 39191 var qpMap = queryParams._qpMap = {}; 39192 39193 for (var i = 0, len = queryParams.length; i < len; ++i) { 39194 accumulateQueryParamDescriptors(queryParams[i], qpMap); 39195 } 39196 39197 return qpMap; 39198 } 39199 39200 function accumulateQueryParamDescriptors(_desc, accum) { 39201 var desc = _desc; 39202 var tmp; 39203 if (typeof desc === 'string') { 39204 tmp = {}; 39205 tmp[desc] = { as: null }; 39206 desc = tmp; 39207 } 39208 39209 for (var key in desc) { 39210 if (!desc.hasOwnProperty(key)) { 39211 return; 39212 } 39213 39214 var singleDesc = desc[key]; 39215 if (typeof singleDesc === 'string') { 39216 singleDesc = { as: singleDesc }; 39217 } 39218 39219 tmp = accum[key] || { as: null, scope: 'model' }; 39220 _emberMetalAssign.default(tmp, singleDesc); 39221 39222 accum[key] = tmp; 39223 } 39224 } 39225}); 39226enifed('ember-routing-htmlbars/helpers/query-params', ['exports', 'ember-metal/debug', 'ember-routing/system/query_params'], function (exports, _emberMetalDebug, _emberRoutingSystemQuery_params) { 39227 /** 39228 @module ember 39229 @submodule ember-routing-htmlbars 39230 */ 39231 39232 'use strict'; 39233 39234 exports.queryParamsHelper = queryParamsHelper; 39235 39236 /** 39237 This is a helper to be used in conjunction with the link-to helper. 39238 It will supply url query parameters to the target route. 39239 39240 Example 39241 39242 ```handlebars 39243 {{#link-to 'posts' (query-params direction="asc")}}Sort{{/link-to}} 39244 ``` 39245 39246 @method query-params 39247 @for Ember.Templates.helpers 39248 @param {Object} hash takes a hash of query parameters 39249 @return {Object} A `QueryParams` object for `{{link-to}}` 39250 @public 39251 */ 39252 39253 function queryParamsHelper(params, hash) { 39254 _emberMetalDebug.assert('The `query-params` helper only accepts hash parameters, e.g. (query-params queryParamPropertyName=\'foo\') as opposed to just (query-params \'foo\')', params.length === 0); 39255 39256 return _emberRoutingSystemQuery_params.default.create({ 39257 values: hash 39258 }); 39259 } 39260}); 39261enifed('ember-routing-htmlbars/index', ['exports', 'ember-metal/core', 'ember-htmlbars/helpers', 'ember-htmlbars/keywords', 'ember-routing-htmlbars/helpers/query-params', 'ember-routing-htmlbars/keywords/action', 'ember-routing-htmlbars/keywords/element-action', 'ember-routing-htmlbars/keywords/render'], function (exports, _emberMetalCore, _emberHtmlbarsHelpers, _emberHtmlbarsKeywords, _emberRoutingHtmlbarsHelpersQueryParams, _emberRoutingHtmlbarsKeywordsAction, _emberRoutingHtmlbarsKeywordsElementAction, _emberRoutingHtmlbarsKeywordsRender) { 39262 /** 39263 @module ember 39264 @submodule ember-routing-htmlbars 39265 */ 39266 39267 'use strict'; 39268 39269 _emberHtmlbarsHelpers.registerHelper('query-params', _emberRoutingHtmlbarsHelpersQueryParams.queryParamsHelper); 39270 39271 _emberHtmlbarsKeywords.registerKeyword('action', _emberRoutingHtmlbarsKeywordsAction.default); 39272 _emberHtmlbarsKeywords.registerKeyword('@element_action', _emberRoutingHtmlbarsKeywordsElementAction.default); 39273 _emberHtmlbarsKeywords.registerKeyword('render', _emberRoutingHtmlbarsKeywordsRender.default); 39274 39275 exports.default = _emberMetalCore.default; 39276}); 39277enifed('ember-routing-htmlbars/keywords/action', ['exports', 'htmlbars-runtime/hooks', 'ember-routing-htmlbars/keywords/closure-action'], function (exports, _htmlbarsRuntimeHooks, _emberRoutingHtmlbarsKeywordsClosureAction) { 39278 /** 39279 @module ember 39280 @submodule ember-templates 39281 */ 39282 39283 'use strict'; 39284 39285 /** 39286 The `{{action}}` helper provides a way to pass triggers for behavior (usually 39287 just a function) between components, and into components from controllers. 39288 39289 ### Passing functions with the action helper 39290 39291 There are three contexts an action helper can be used in. The first two
39292 contexts to discuss are attribute context, and Handlebars value context. 39293 39294 ```handlebars 39295 {{! An example of attribute context }} 39296 <div onclick={{action "save"}}></div> 39297 {{! Examples of Handlebars value context }} 39298 {{input on-input=(action "save")}} 39299 {{yield (action "refreshData") andAnotherParam}} 39300 ``` 39301 39302 In these contexts, 39303 the helper is called a "closure action" helper. Its behavior is simple: 39304 If passed a function name, read that function off the `actions` property 39305 of the current context. Once that function is read (or if a function was 39306 passed), create a closure over that function and any arguments. 39307 39308 The resulting value of an action helper used this way is simply a function. 39309 For example, in the attribute context: 39310 39311 ```handlebars 39312 {{! An example of attribute context }} 39313 <div onclick={{action "save"}}></div> 39314 ``` 39315 39316 The resulting template render logic would be: 39317 39318 ```js 39319 var div = document.createElement('div'); 39320 var actionFunction = (function(context){ 39321 return function() { 39322 return context.actions.save.apply(context, arguments); 39323 }; 39324 })(context); 39325 div.onclick = actionFunction; 39326 ``` 39327 39328 Thus when the div is clicked, the action on that context is called. 39329 Because the `actionFunction` is just a function, closure actions can be 39330 passed between components and still execute in the correct context. 39331 39332 Here is an example action handler on a component: 39333 39334 ```js 39335 export default Ember.Component.extend({ 39336 actions: { 39337 save() { 39338 this.get('model').save(); 39339 } 39340 } 39341 }); 39342 ``` 39343 39344 Actions are always looked up on the `actions` property of the current context. 39345 This avoids collisions in the naming of common actions, such as `destroy`. 39346 39347 Two options can be passed to the `action` helper when it is used in this way. 39348 39349 * `target=someProperty` will look to `someProperty` instead of the current 39350 context for the `actions` hash. This can be useful when targetting a 39351 service for actions. 39352 * `value="target.value"` will read the path `target.value` off the first 39353 argument to the action when it is called and rewrite the first argument 39354 to be that value. This is useful when attaching actions to event listeners. 39355 39356 ### Invoking an action 39357 39358 Closure actions curry both their scope and any arguments. When invoked, any 39359 additional arguments are added to the already curried list. 39360 39361 Actions should be invoked using the [sendAction](/api/classes/Ember.Component.html#method_sendAction) 39362 method. The first argument to `sendAction` is the action to be called, and 39363 additional arguments are passed to the action function. This has interesting 39364 properties combined with currying of arguments. For example: 39365 39366 ```js 39367 export default Ember.Component.extend({ 39368 actions: { 39369 // Usage {{input on-input=(action (action 'setName' model) value="target.value")}} 39370 setName(model, name) { 39371 model.set('name', name); 39372 } 39373 } 39374 }); 39375 ``` 39376 39377 The first argument (`model`) was curried over, and the run-time argument (`event`) 39378 becomes a second argument. Action calls can be nested this way because each simply 39379 returns a function. Any function can be passed to the `{{action}}` helper, including 39380 other actions. 39381 39382 Actions invoked with `sendAction` have the same currying behavior as demonstrated 39383 with `on-input` above. For example: 39384 39385 ```js 39386 export default Ember.Component.extend({ 39387 actions: { 39388 setName(model, name) { 39389 model.set('name', name); 39390 } 39391 } 39392 }); 39393 ``` 39394 39395 ```handlebars 39396 {{my-input submit=(action 'setName' model)}} 39397 ``` 39398 39399 ```js 39400
39400// app/components/my-component.js 39401 export default Ember.Component.extend({ 39402 click() { 39403 // Note that model is not passed, it was curried in the template 39404 this.sendAction('submit', 'bob'); 39405 } 39406 }); 39407 ``` 39408 39409 ### Attaching actions to DOM elements 39410 39411 The third context of the `{{action}}` helper can be called "element space". 39412 For example: 39413 39414 ```handlebars 39415 {{! An example of element space }} 39416 <div {{action "save"}}></div> 39417 ``` 39418 39419 Used this way, the `{{action}}` helper provides a useful shortcut for 39420 registering an HTML element in a template for a single DOM event and 39421 forwarding that interaction to the template's context (controller or component). 39422 39423 If the context of a template is a controller, actions used this way will 39424 bubble to routes when the controller does not implement the specified action. 39425 Once an action hits a route, it will bubble through the route hierarchy. 39426 39427 ### Event Propagation 39428 39429 `{{action}}` helpers called in element space can control event bubbling. Note 39430 that the closure style actions cannot. 39431 39432 Events triggered through the action helper will automatically have 39433 `.preventDefault()` called on them. You do not need to do so in your event 39434 handlers. If you need to allow event propagation (to handle file inputs for 39435 example) you can supply the `preventDefault=false` option to the `{{action}}` helper: 39436 39437 ```handlebars 39438 <div {{action "sayHello" preventDefault=false}}> 39439 <input type="file" /> 39440 <input type="checkbox" /> 39441 </div> 39442 ``` 39443 39444 To disable bubbling, pass `bubbles=false` to the helper: 39445 39446 ```handlebars 39447 <button {{action 'edit' post bubbles=false}}>Edit</button> 39448 ``` 39449 39450 To disable bubbling with closure style actions you must create your own 39451 wrapper helper that makes use of `event.stopPropagation()`: 39452 39453 ```handlebars 39454 <div onclick={{disable-bubbling (action "sayHello")}}>Hello</div> 39455 ``` 39456 39457 ```js 39458
39458// app/helpers/disable-bubbling.js 39459 import Ember from 'ember'; 39460 39461 export function disableBubbling([action]) { 39462 return function(event) { 39463 event.stopPropagation(); 39464 39465 return action(event); 39466 }; 39467 } 39468 39469 export default Ember.Helper.helper(disableBubbling); 39470 ``` 39471 39472 If you need the default handler to trigger you should either register your 39473 own event handler, or use event methods on your view class. See 39474 ["Responding to Browser Events"](/api/classes/Ember.View.html#toc_responding-to-browser-events) 39475 in the documentation for Ember.View for more information. 39476 39477 ### Specifying DOM event type 39478 39479 `{{action}}` helpers called in element space can specify an event type. 39480 39481 By default the `{{action}}` helper registers for DOM `click` events. You can 39482 supply an `on` option to the helper to specify a different DOM event name: 39483 39484 ```handlebars 39485 <div {{action "anActionName" on="doubleClick"}}> 39486 click me 39487 </div> 39488 ``` 39489 39490 See ["Event Names"](/api/classes/Ember.View.html#toc_event-names) for a list of 39491 acceptable DOM event names. 39492 39493 ### Specifying whitelisted modifier keys 39494 39495 `{{action}}
39495` helpers called in element space can specify modifier keys. 39496 39497 By default the `{{action}}` helper will ignore click events with pressed modifier 39498 keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. 39499 39500 ```handlebars 39501 <div {{action "anActionName" allowedKeys="alt"}}> 39502 click me 39503 </div> 39504 ``` 39505 39506 This way the action will fire when clicking with the alt key pressed down. 39507 39508 Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. 39509 39510 ```handlebars 39511 <div {{action "anActionName" allowedKeys="any"}}> 39512 click me with any key pressed 39513 </div> 39514 ``` 39515 39516 ### Specifying a Target 39517 39518 A `target` option can be provided to the helper to change 39519 which object will receive the method call. This option must be a path 39520 to an object, accessible in the current context: 39521 39522 ```handlebars 39523 {{! app/templates/application.hbs }} 39524 <div {{action "anActionName" target=someService}}> 39525 click me 39526 </div> 39527 ``` 39528 39529 ```javascript 39530
39530// app/controllers/application.js 39531 export default Ember.Controller.extend({ 39532 someService: Ember.inject.service() 39533 }); 39534 ``` 39535 39536 @method action 39537 @for Ember.Templates.helpers 39538 @public 39539 */ 39540 39541 exports.default = function (morph, env, scope, params, hash, template, inverse, visitor) { 39542 if (morph) { 39543 _htmlbarsRuntimeHooks.keyword('@element_action', morph, env, scope, params, hash, template, inverse, visitor); 39544 return true; 39545 } 39546 39547 return _emberRoutingHtmlbarsKeywordsClosureAction.default(morph, env, scope, params, hash, template, inverse, visitor); 39548 }; 39549}); 39550enifed('ember-routing-htmlbars/keywords/closure-action', ['exports', 'ember-metal/streams/stream', 'ember-metal/streams/utils', 'ember-metal/symbol', 'ember-metal/property_get', 'ember-htmlbars/hooks/subexpr', 'ember-metal/error', 'ember-metal/run_loop'], function (exports, _emberMetalStreamsStream, _emberMetalStreamsUtils, _emberMetalSymbol, _emberMetalProperty_get, _emberHtmlbarsHooksSubexpr, _emberMetalError, _emberMetalRun_loop) { 39551 'use strict'; 39552 39553 exports.default = closureAction; 39554 var INVOKE = _emberMetalSymbol.default('INVOKE'); 39555 exports.INVOKE = INVOKE; 39556 var ACTION = _emberMetalSymbol.default('ACTION'); 39557 39558 exports.ACTION = ACTION; 39559 39560 function closureAction(morph, env, scope, params, hash, template, inverse, visitor) { 39561 var s = new _emberMetalStreamsStream.Stream(function () { 39562 var rawAction = params[0]; 39563 var actionArguments = _emberMetalStreamsUtils.readArray(params.slice(1, params.length)); 39564 39565 var target, action, valuePath; 39566 if (rawAction[INVOKE]) { 39567 // on-change={{action (mut name)}} 39568 target = rawAction; 39569 action = rawAction[INVOKE]; 39570 } else { 39571 // on-change={{action setName}} 39572 // element-space actions look to "controller" then target. Here we only 39573 // look to "target". 39574 target = _emberMetalStreamsUtils.read(scope.getSelf()); 39575 action = _emberMetalStreamsUtils.read(rawAction); 39576 var actionType = typeof action; 39577 39578 if (actionType === 'string') { 39579 var actionName = action; 39580 action = null; 39581 // on-change={{action 'setName'}} 39582 if (hash.target) { 39583 // on-change={{action 'setName' target=alternativeComponent}} 39584 target = _emberMetalStreamsUtils.read(hash.target); 39585 } 39586 if (target.actions) { 39587 action = target.actions[actionName]; 39588 } 39589 39590 if (!action) { 39591 throw new _emberMetalError.default('An action named \'' + actionName + '\' was not found in ' + target + '.'); 39592 } 39593 } else if (action && typeof action[INVOKE] === 'function') { 39594 target = action; 39595 action = action[INVOKE]; 39596 } else if (actionType !== 'function') { 39597 throw new _emberMetalError.default('An action could not be made for `' + rawAction.label + '` in ' + target + '. Please confirm that you are using either a quoted action name (i.e. `(action \'' + rawAction.label + '\')`) or a function available in ' + target + '.'); 39598 } 39599 } 39600 39601 if (hash.value) { 39602 // <button on-keypress={{action (mut name) value="which"}} 39603 // on-keypress is not even an Ember feature yet 39604 valuePath = _emberMetalStreamsUtils.read(hash.value); 39605 } 39606 39607 return createClosureAction(target, action, valuePath, actionArguments); 39608 }, function () { 39609 return _emberHtmlbarsHooksSubexpr.labelForSubexpr(params, hash, 'action'); 39610 }); 39611 39612 params.forEach(s.addDependency, s); 39613 Object.keys(hash).forEach(function (item) { 39614 return s.addDependency(item); 39615 }); 39616 39617 return s; 39618 } 39619 39620 function createClosureAction(target, action, valuePath, actionArguments) { 39621 var closureAction; 39622 39623 if (actionArguments.length > 0) { 39624 closureAction = function () { 39625 var args = actionArguments; 39626 39627 for (var _len = arguments.length, passedArguments = Array(_len), _key = 0; _key < _len; _key++) { 39628 passedArguments[_key] = arguments[_key]; 39629 } 39630 39631 if (passedArguments.length > 0) { 39632 args = actionArguments.concat(passedArguments); 39633 } 39634 if (valuePath && args.length > 0) { 39635 args[0] = _emberMetalProperty_get.get(args[0], valuePath); 39636 } 39637 39638 return _emberMetalRun_loop.default.join.apply(_emberMetalRun_loop.default, [target, action].concat(args)); 39639 }; 39640 } else { 39641 closureAction = function () { 39642 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 39643 args[_key2] = arguments[_key2]; 39644 } 39645 39646 if (valuePath && args.length > 0) { 39647 args[0] = _emberMetalProperty_get.get(args[0], valuePath); 39648 } 39649 39650 return _emberMetalRun_loop.default.join.apply(_emberMetalRun_loop.default, [target, action].concat(args)); 39651 }; 39652 } 39653 39654 closureAction[ACTION] = true; 39655 39656 return closureAction; 39657 } 39658}); 39659enifed('ember-routing-htmlbars/keywords/element-action', ['exports', 'ember-metal/debug', 'ember-metal/utils', 'ember-metal/stream
39659s/utils', 'ember-metal/run_loop', 'ember-views/streams/utils', 'ember-views/system/utils', 'ember-views/system/action_manager'], function (exports, _emberMetalDebug, _emberMetalUtils, _emberMetalStreamsUtils, _emberMetalRun_loop, _emberViewsStreamsUtils, _emberViewsSystemUtils, _emberViewsSystemAction_manager) { 39660 'use strict'; 39661 39662 exports.default = { 39663 setupState: function (state, env, scope, params, hash) { 39664 var getStream = env.hooks.get; 39665 var read = env.hooks.getValue; 39666 39667 var actionName = read(params[0]); 39668 39669 _emberMetalDebug.assert('You specified a quoteless path to the {{action}} helper ' + 'which did not resolve to an action name (a string). ' + 'Perhaps you meant to use a quoted actionName? (e.g. {{action \'save\'}}).', typeof actionName === 'string' || typeof actionName === 'function'); 39670 39671 var actionArgs = []; 39672 for (var i = 1, l = params.length; i < l; i++) { 39673 actionArgs.push(_emberViewsStreamsUtils.readUnwrappedModel(params[i])); 39674 } 39675 39676 var target; 39677 if (hash.target) { 39678 if (typeof hash.target === 'string') { 39679 target = read(getStream(env, scope, hash.target)); 39680 } else { 39681 target = read(hash.target); 39682 } 39683 } else { 39684 target = read(scope.getLocal('controller')) || read(scope.getSelf()); 39685 } 39686 39687 return { actionName: actionName, actionArgs: actionArgs, target: target }; 39688 }, 39689 39690 isStable: function (state, env, scope, params, hash) { 39691 return true; 39692 }, 39693 39694 render: function (node, env, scope, params, hash, template, inverse, visitor) { 39695 var actionId = env.dom.getAttribute(node.element, 'data-ember-action') || _emberMetalUtils.uuid(); 39696 39697 ActionHelper.registerAction({ 39698 actionId: actionId, 39699 node: node, 39700 eventName: hash.on || 'click', 39701 bubbles: hash.bubbles, 39702 preventDefault: hash.preventDefault, 39703 withKeyCode: hash.withKeyCode, 39704 allowedKeys: hash.allowedKeys 39705 }); 39706 39707 node.cleanup = function () { 39708 ActionHelper.unregisterAction(actionId); 39709 }; 39710 39711 env.dom.setAttribute(node.element, 'data-ember-action', actionId); 39712 } 39713 }; 39714 var ActionHelper = {}; 39715 39716 exports.ActionHelper = ActionHelper; 39717 // registeredActions is re-exported for compatibility with older plugins 39718 // that were using this undocumented API. 39719 ActionHelper.registeredActions = _emberViewsSystemAction_manager.default.registeredActions; 39720 39721 ActionHelper.registerAction = function (_ref) { 39722 var actionId = _ref.actionId; 39723 var node = _ref.node; 39724 var eventName = _ref.eventName; 39725 var preventDefault = _ref.preventDefault; 39726 var bubbles = _ref.bubbles; 39727 var allowedKeys = _ref.allowedKeys; 39728 39729 var actions = _emberViewsSystemAction_manager.default.registeredActions[actionId]; 39730 39731 if (!actions) { 39732 actions = _emberViewsSystemAction_manager.default.registeredActions[actionId] = []; 39733 } 39734 39735 actions.push({ 39736 eventName: eventName, 39737 handler: function (event) { 39738 if (!isAllowedEvent(event, _emberMetalStreamsUtils.read(allowedKeys))) { 39739 return true; 39740 } 39741 39742 if (_emberMetalStreamsUtils.read(preventDefault) !== false) { 39743 event.preventDefault(); 39744 } 39745 39746 if (_emberMetalStreamsUtils.read(bubbles) === false) { 39747 event.stopPropagation(); 39748 } 39749 39750 var _node$getState = node.getState(); 39751 39752 var target = _node$getState.target; 39753 var actionName = _node$getState.actionName; 39754 var actionArgs = _node$getState.actionArgs; 39755 39756 _emberMetalRun_loop.default(function runRegisteredAction() { 39757 if (typeof actionName === 'function') { 39758 actionName.apply(target, actionArgs); 39759 return; 39760 } 39761 if (target.send) { 39762 target.send.apply(target, [actionName].concat(actionArgs)); 39763 } else { 39764 _emberMetalDebug.assert('The action \'' + actionName + '\' did not exist on ' + target, typeof target[actionName] === 'function'); 39765 39766 target[actionName].apply(target, actionArgs); 39767 } 39768 }); 39769 } 39770 }); 39771 39772 return actionId; 39773 }; 39774 39775 ActionHelper.unregisterAction = function (actionId) { 39776 delete _emberViewsSystemAction_manager.default.registeredActions[actionId]; 39777 }; 39778 39779 var MODIFIERS = ['alt', 'shift', 'meta', 'ctrl']; 39780 var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; 39781 39782 function isAllowedEvent(event, allowedKeys) { 39783 if (typeof allowedKeys === 'undefined') { 39784 if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { 39785 return _emberViewsSystemUtils.isSimpleClick(event); 39786 } else { 39787 allowedKeys = ''; 39788 } 39789 } 39790 39791 if (allowedKeys.indexOf('any') >= 0) { 39792 return true; 39793 } 39794 39795 for (var i = 0, l = MODIFIERS.length; i < l; i++) { 39796 if (event[MODIFIERS[i] + 'Key'] && allowedKeys.indexOf(MODIFIERS[i]) === -1) { 39797 return false;
39798 } 39799 } 39800 39801 return true; 39802 } 39803}); 39804enifed('ember-routing-htmlbars/keywords/render', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/empty_object', 'ember-metal/error', 'ember-metal/streams/utils', 'ember-runtime/system/string', 'ember-routing/system/generate_controller', 'ember-htmlbars/node-managers/view-node-manager'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalEmpty_object, _emberMetalError, _emberMetalStreamsUtils, _emberRuntimeSystemString, _emberRoutingSystemGenerate_controller, _emberHtmlbarsNodeManagersViewNodeManager) { 39805 /** 39806 @module ember 39807 @submodule ember-templates 39808 */ 39809 39810 'use strict'; 39811 39812 /** 39813 Calling ``{{render}}`` from within a template will insert another 39814 template that matches the provided name. The inserted template will 39815 access its properties on its own controller (rather than the controller 39816 of the parent template). 39817 If a view class with the same name exists, the view class also will be used. 39818 Note: A given controller may only be used *once* in your app in this manner. 39819 A singleton instance of the controller will be created for you. 39820 Example: 39821 39822 ```javascript 39823 App.NavigationController = Ember.Controller.extend({ 39824 who: "world" 39825 }); 39826 ``` 39827 39828 ```handlebars 39829 <!-- navigation.hbs --> 39830 Hello, {{who}}. 39831 ``` 39832 39833 ```handlebars 39834 <!-- application.hbs --> 39835 <h1>My great app</h1> 39836 {{render "navigation"}} 39837 ``` 39838 39839 ```html 39840 <h1>My great app</h1> 39841 <div class='ember-view'> 39842 Hello, world. 39843 </div> 39844 ``` 39845 39846 Optionally you may provide a second argument: a property path 39847 that will be bound to the `model` property of the controller. 39848 If a `model` property path is specified, then a new instance of the 39849 controller will be created and `{{render}}` can be used multiple times 39850 with the same name. 39851 39852 For example if you had this `author` template. 39853 39854 ```handlebars 39855 <div class="author"> 39856 Written by {{firstName}} {{lastName}}. 39857 Total Posts: {{postCount}} 39858 </div> 39859 ``` 39860 39861 You could render it inside the `post` template using the `render` helper. 39862 39863 ```handlebars 39864 <div class="post"> 39865 <h1>{{title}}</h1> 39866 <div>{{body}}</div> 39867 {{render "author" author}} 39868 </div> 39869 ``` 39870 39871 @method render 39872 @for Ember.Templates.helpers 39873 @param {String} name 39874 @param {Object?} context 39875 @param {Hash} options 39876 @return {String} HTML string 39877 @public 39878 */ 39879 exports.default = { 39880 willRender: function (renderNode, env) { 39881 if (env.view.ownerView._outlets) { 39882 // We make sure we will get dirtied when outlet state changes. 39883 env.view.ownerView._outlets.push(renderNode); 39884 } 39885 }, 39886 39887 setupState: function (prevState, env, scope, params, hash) { 39888 var name = params[0]; 39889 39890 _emberMetalDebug.assert('The first argument of {{render}} must be quoted, e.g. {{render "sidebar"}}.', typeof name === 'string'); 39891 39892 return { 39893 parentView: env.view, 39894 manager: prevState.manager, 39895 controller: prevState.controller, 39896 childOutletState: childOutletState(name, env) 39897 }; 39898 }, 39899 39900 childEnv: function (state, env) { 39901 return env.childWithOutletState(state.childOutletState); 39902 }, 39903 39904 isStable: function (lastState, nextState) { 39905 return isStable(lastState.childOutletState, nextState.childOutletState); 39906 }, 39907 39908 isEmpty: function (state) { 39909 return false; 39910 }, 39911 39912 render: function (node, env, scope, params, hash, template, inverse, visitor) { 39913 var state = node.getState(); 39914 var name = params[0]; 39915 var context = params[1]; 39916 39917 var owner = env.owner; 39918 39919 // The render keyword presumes it can work without a router. This is really 39920 // only to satisfy the test: 39921 // 39922 // {{view}} should not override class bindings defined on a child view" 39923 // 39924 var router = owner.lookup('router:main'); 39925 39926 _emberMetalDebug.assert('The second argument of {{render}} must be a path, e.g. {{render "post" post}}.', params.length < 2 || _emberMetalStreamsUtils.isStream(params[1])); 39927 39928 if (params.length === 1) { 39929 // use the singleton controller 39930 _emberMetalDebug.assert('You can only use the {{render}} helper once without a model object as ' + 'its second argument, as in {{render "post" post}}.', !router || !router._lookupActiveComponentNode(name)); 39931 } else if (params.length !== 2) { 39932 throw new _emberMetalError.default('You must pass a templateName to render'); 39933 } 39934 39935 var templateName = 'template:' + name;
39936 _emberMetalDebug.assert('You used `{{render \'' + name + '\'}}`, but \'' + name + '\' can not be ' + 'found as either a template or a view.', owner.hasRegistration('view:' + name) || owner.hasRegistration(templateName) || !!template); 39937 39938 var view = owner.lookup('view:' + name); 39939 if (!view) { 39940 view = owner.lookup('view:default'); 39941 } 39942 var viewHasTemplateSpecified = view && !!_emberMetalProperty_get.get(view, 'template'); 39943 if (!template && !viewHasTemplateSpecified) { 39944 template = owner.lookup(templateName); 39945 } 39946 39947 if (view) { 39948 view.ownerView = env.view.ownerView; 39949 } 39950 39951 // provide controller override 39952 var controllerName; 39953 var controllerFullName; 39954 39955 if (hash.controller) { 39956 controllerName = hash.controller; 39957 controllerFullName = 'controller:' + controllerName; 39958 delete hash.controller; 39959 39960 _emberMetalDebug.assert('The controller name you supplied \'' + controllerName + '\' ' + 'did not resolve to a controller.', owner.hasRegistration(controllerFullName)); 39961 } else { 39962 controllerName = name; 39963 controllerFullName = 'controller:' + controllerName; 39964 } 39965 39966 var parentController = _emberMetalStreamsUtils.read(scope.getLocal('controller')); 39967 var target = parentController || router; 39968 var controller; 39969 39970 // choose name 39971 if (params.length > 1) { 39972 var factory = owner._lookupFactory(controllerFullName) || _emberRoutingSystemGenerate_controller.generateControllerFactory(owner, controllerName); 39973 39974 controller = factory.create({ 39975 model: _emberMetalStreamsUtils.read(context), 39976 parentController: parentController, 39977 target: target 39978 }); 39979 39980 node.addDestruction(controller); 39981 } else { 39982 controller = owner.lookup(controllerFullName) || _emberRoutingSystemGenerate_controller.default(owner, controllerName); 39983 39984 controller.setProperties({ 39985 target: target, 39986 parentController: parentController 39987 }); 39988 } 39989 39990 if (view) { 39991 view.set('controller', controller); 39992 } 39993 state.controller = controller; 39994 39995 hash.viewName = _emberRuntimeSystemString.camelize(name); 39996 39997 if (template && template.raw) { 39998 template = template.raw; 39999 } 40000 40001 var options = { 40002 layout: null, 40003 self: controller 40004 }; 40005 40006 if (view) { 40007 options.component = view; 40008 } 40009 40010 var nodeManager = _emberHtmlbarsNodeManagersViewNodeManager.default.create(node, env, hash, options, state.parentView, null, null, template); 40011 state.manager = nodeManager; 40012 40013 if (router && params.length === 1) { 40014 router._connectActiveComponentNode(name, nodeManager); 40015 } 40016 40017 nodeManager.render(env, hash, visitor); 40018 }, 40019 40020 rerender: function (node, env, scope, params, hash, template, inverse, visitor) { 40021 if (params.length > 1) { 40022 var model = _emberMetalStreamsUtils.read(params[1]); 40023 node.getState().controller.set('model', model); 40024 } 40025 } 40026 }; 40027 40028 function childOutletState(name, env) { 40029 var topLevel = env.view.ownerView; 40030 if (!topLevel || !topLevel.outletState) { 40031 return; 40032 } 40033 40034 var outletState = topLevel.outletState; 40035 if (!outletState.main) { 40036 return; 40037 } 40038 40039 var selectedOutletState = outletState.main.outlets['__ember_orphans__']; 40040 if (!selectedOutletState) { 40041 return; 40042 } 40043 var matched = selectedOutletState.outlets[name]; 40044 if (matched) { 40045 var childState = new _emberMetalEmpty_object.default(); 40046 childState[matched.render.outlet] = matched; 40047 matched.wasUsed = true; 40048 return childState; 40049 } 40050 } 40051 40052 function isStable(a, b) { 40053 if (!a && !b) { 40054 return true; 40055 } 40056 if (!a || !b) { 40057 return false; 40058 } 40059 for (var outletName in a) { 40060 if (!isStableOutlet(a[outletName], b[outletName])) { 40061 return false; 40062 } 40063 } 40064 return true; 40065 } 40066 40067 function isStableOutlet(a, b) { 40068 if (!a && !b) { 40069 return true; 40070 } 40071 if (!a || !b) { 40072 return false; 40073 } 40074 a = a.render; 40075 b = b.render; 40076 for (var key in a) { 40077 if (a.hasOwnProperty(key)) { 40078 // name is only here for logging & debugging. If two different 40079 // names result in otherwise identical states, they're still 40080 // identical. 40081 if (a[key] !== b[key] && key !== 'name') { 40082 return false;
40083 } 40084 } 40085 } 40086 return true; 40087 } 40088}); 40089enifed('ember-routing-views/components/link-to', ['exports', 'ember-metal/logger', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/computed', 'ember-metal/computed_macros', 'ember-views/system/utils', 'ember-views/components/component', 'ember-runtime/inject', 'ember-runtime/system/service', 'ember-runtime/mixins/controller', 'ember-htmlbars/node-managers/component-node-manager', 'ember-htmlbars/templates/link-to'], function (exports, _emberMetalLogger, _emberMetalDebug, _emberMetalProperty_get, _emberMetalComputed, _emberMetalComputed_macros, _emberViewsSystemUtils, _emberViewsComponentsComponent, _emberRuntimeInject, _emberRuntimeSystemService, _emberRuntimeMixinsController, _emberHtmlbarsNodeManagersComponentNodeManager, _emberHtmlbarsTemplatesLinkTo) { 40090 /** 40091 @module ember 40092 @submodule ember-templates 40093 */ 40094 40095 /** 40096 The `{{link-to}}` component renders a link to the supplied 40097 `routeName` passing an optionally supplied model to the 40098 route as its `model` context of the route. The block 40099 for `{{link-to}}` becomes the innerHTML of the rendered 40100 element: 40101 40102 ```handlebars 40103 {{#link-to 'photoGallery'}} 40104 Great Hamster Photos 40105 {{/link-to}} 40106 ``` 40107 40108 You can also use an inline form of `{{link-to}}` component by 40109 passing the link text as the first argument 40110 to the component: 40111 40112 ```handlebars 40113 {{link-to 'Great Hamster Photos' 'photoGallery'}} 40114 ``` 40115 40116 Both will result in: 40117 40118 ```html 40119 <a href="/hamster-photos"> 40120 Great Hamster Photos 40121 </a> 40122 ``` 40123 40124 ### Supplying a tagName 40125 By default `{{link-to}}` renders an `<a>` element. This can 40126 be overridden for a single use of `{{link-to}}` by supplying 40127 a `tagName` option: 40128 40129 ```handlebars 40130 {{#link-to 'photoGallery' tagName="li"}} 40131 Great Hamster Photos 40132 {{/link-to}} 40133 ``` 40134 40135 ```html 40136 <li> 40137 Great Hamster Photos 40138 </li> 40139 ``` 40140 40141 To override this option for your entire application, see 40142 "Overriding Application-wide Defaults". 40143 40144 ### Disabling the `link-to` component 40145 By default `{{link-to}}` is enabled. 40146 any passed value to the `disabled` component property will disable 40147 the `link-to` component. 40148 40149 static use: the `disabled` option: 40150 40151 ```handlebars 40152 {{#link-to 'photoGallery' disabled=true}} 40153 Great Hamster Photos 40154 {{/link-to}} 40155 ``` 40156 40157 dynamic use: the `disabledWhen` option: 40158 40159 ```handlebars 40160 {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} 40161 Great Hamster Photos 40162 {{/link-to}} 40163 ``` 40164 40165 any passed value to `disabled` will disable it except `undefined`. 40166 to ensure that only `true` disable the `link-to` component you can 40167 override the global behaviour of `Ember.LinkComponent`. 40168 40169 ```javascript 40170 Ember.LinkComponent.reopen({ 40171 disabled: Ember.computed(function(key, value) { 40172 if (value !== undefined) { 40173 this.set('_isDisabled', value === true); 40174 } 40175 return value === true ? get(this, 'disabledClass') : false; 40176 }) 40177 }); 40178 ``` 40179 40180 see "Overriding Application-wide Defaults" for more. 40181 40182 ### Handling `href` 40183 `{{link-to}}` will use your application's Router to 40184 fill the element's `href` property with a url that 40185 matches the path to the supplied `routeName` for your 40186 router's configured `Location` scheme, which defaults 40187 to Ember.HashLocation. 40188 40189 ### Handling current route 40190 `{{link-to}}` will apply a CSS class name of 'active' 40191 when the application's current route matches 40192 the supplied routeName. For example, if the application's 40193 current route is 'photoGallery.recent' the following 40194 use of `{{link-to}}`: 40195 40196 ```handlebars 40197 {{#link-to 'photoGallery.recent'}} 40198 Great Hamster Photos 40199 {{/link-to}} 40200 ``` 40201 40202 will result in 40203 40204 ```html 40205 <a href="/hamster-photos/this-week" class="active"> 40206 Great Hamster Photos 40207 </a> 40208 ``` 40209 40210 The CSS class name used for active classes can be customized 40211 for a single use of `{{link-to}}` by passing an `activeClass` 40212 option: 40213 40214 ```handlebars 40215 {{#link-to 'photoGallery.recent' activeClass="current-url"}} 40216 Great Hamster Photos 40217 {{/link-to}} 40218 ``` 40219 40220 ```html 40221 <a href="/hamster-photos/this-week" class="current-url"> 40222 Great Hamster Photos 40223 </a> 40224 ``` 40225 40226 To override this option for your entire application, see 40227 "Overriding Application-wide Defaults". 40228 40229 ### Keeping a link active for other routes 40230 40231 If you need a link to be 'active' even when it doesn't match 40232 the current route, you can use the `current-when` argument. 40233 40234 ```handlebars 40235 {{#link-to 'photoGallery' current-when='photos'}} 40236 Photo Gallery 40237 {{/link-to}} 40238 ``` 40239 40240 This may be helpful for keeping links active for: 40241 40242 * non-nested routes that are logically related 40243 * some secondary menu approaches 40244 * 'top navigation' with 'sub navigation' scenarios 40245 40246 A link will be active if `current-when` is `true` or the current 40247 route is the route this link would transition to. 40248 40249 To match multiple routes 'space-separate' the routes: 40250 40251 ```handlebars 40252 {{#link-to 'gallery' current-when='photos drawings paintings'}} 40253 Art Gallery 40254 {{/link-to}} 40255 ``` 40256 40257 ### Supplying a model 40258 An optional model argument can be used for routes whose 40259 paths contain dynamic segments. This argument will become 40260 the model context of the linked route: 40261 40262 ```javascript 40263 Router.map(function() { 40264 this.route("photoGallery", {path: "hamster-photos/:photo_id"}); 40265 }); 40266 ``` 40267 40268 ```handlebars 40269 {{#link-to 'photoGallery' aPhoto}} 40270 {{aPhoto.title}} 40271 {{/link-to}} 40272 ``` 40273 40274 ```html 40275 <a href="/hamster-photos/42"> 40276 Tomster 40277 </a> 40278 ``` 40279 40280 ### Supplying multiple models 40281 For deep-linking to route paths that contain multiple 40282 dynamic segments, multiple model arguments can be used. 40283 As the router transitions through the route path, each 40284 supplied model argument will become the context for the 40285 route with the dynamic segments: 40286 40287 ```javascript 40288 Router.map(function() { 40289 this.route("photoGallery", { path: "hamster-photos/:photo_id" }, function() { 40290 this.route("comment", {path: "comments/:comment_id"}); 40291 }); 40292 }); 40293 ``` 40294 This argument will become the model context of the linked route: 40295 40296 ```handlebars 40297 {{#link-to 'photoGallery.comment' aPhoto comment}} 40298 {{comment.body}} 40299 {{/link-to}} 40300 ``` 40301 40302 ```html 40303 <a href="/hamster-photos/42/comments/718"> 40304 A+++ would snuggle again. 40305 </a> 40306 ``` 40307 40308 ### Supplying an explicit dynamic segment value 40309 If you don't have a model object available to pass to `{{link-to}}`, 40310 an optional string or integer argument can be passed for routes whose 40311 paths contain dynamic segments. This argument will become the value 40312 of the dynamic segment: 40313 40314 ```javascript 40315 Router.map(function() { 40316 this.route("photoGallery", { path: "hamster-photos/:photo_id" }); 40317 }); 40318 ``` 40319 40320 ```handlebars 40321 {{#link-to 'photoGallery' aPhotoId}} 40322 {{aPhoto.title}} 40323 {{/link-to}} 40324 ``` 40325 40326 ```html 40327 <a href="/hamster-photos/42"> 40328 Tomster 40329 </a> 40330 ``` 40331 40332 When transitioning into the linked route, the `model` hook will
40333 be triggered with parameters including this passed identifier. 40334 40335 ### Allowing Default Action 40336 40337 By default the `{{link-to}}` component prevents the default browser action 40338 by calling `preventDefault()` as this sort of action bubbling is normally 40339 handled internally and we do not want to take the browser to a new URL (for 40340 example). 40341 40342 If you need to override this behavior specify `preventDefault=false` in 40343 your template: 40344 40345 ```handlebars 40346 {{#link-to 'photoGallery' aPhotoId preventDefault=false}} 40347 {{aPhotoId.title}} 40348 {{/link-to}} 40349 ``` 40350 40351 ### Overriding attributes 40352 You can override any given property of the `Ember.LinkComponent` 40353 that is generated by the `{{link-to}}` component by passing 40354 key/value pairs, like so: 40355 40356 ```handlebars 40357 {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}} 40358 Uh-mazing! 40359 {{/link-to}} 40360 ``` 40361 40362 See [Ember.LinkComponent](/api/classes/Ember.LinkComponent.html) for a 40363 complete list of overrideable properties. Be sure to also 40364 check out inherited properties of `LinkComponent`. 40365 40366 ### Overriding Application-wide Defaults 40367 ``{{link-to}}`` creates an instance of `Ember.LinkComponent` 40368 for rendering. To override options for your entire 40369 application, reopen `Ember.LinkComponent` and supply the 40370 desired values: 40371 40372 ``` javascript 40373 Ember.LinkComponent.reopen({ 40374 activeClass: "is-active", 40375 tagName: 'li' 40376 }) 40377 ``` 40378 40379 It is also possible to override the default event in 40380 this manner: 40381 40382 ``` javascript 40383 Ember.LinkComponent.reopen({ 40384 eventName: 'customEventName' 40385 }); 40386 ``` 40387 40388 @method link-to 40389 @for Ember.Templates.helpers 40390 @param {String} routeName 40391 @param {Object} [context]* 40392 @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkComponent 40393 @return {String} HTML string 40394 @see {Ember.LinkComponent} 40395 @public 40396 */ 40397 40398 /** 40399 @module ember 40400 @submodule ember-routing-views 40401 */ 40402 40403 'use strict'; 40404 40405 _emberHtmlbarsTemplatesLinkTo.default.meta.revision = '[email protected]'; 40406 40407 /** 40408 `Ember.LinkComponent` renders an element whose `click` event triggers a 40409 transition of the application's instance of `Ember.Router` to 40410 a supplied route by name. 40411 40412 `Ember.LinkComponent` components are invoked with {{#link-to}}. Properties 40413 of this class can be overridden with `reopen` to customize application-wide 40414 behavior. 40415 40416 @class LinkComponent 40417 @namespace Ember 40418 @extends Ember.Component 40419 @see {Ember.Templates.helpers.link-to} 40420 @private 40421 **/ 40422 var LinkComponent = _emberViewsComponentsComponent.default.extend({ 40423 layout: _emberHtmlbarsTemplatesLinkTo.default, 40424 40425 tagName: 'a', 40426 40427 /** 40428 @deprecated Use current-when instead. 40429 @property currentWhen 40430 @private 40431 */ 40432 currentWhen: _emberMetalComputed_macros.deprecatingAlias('current-when', { id: 'ember-routing-view.deprecated-current-when', until: '3.0.0' }), 40433 40434 /** 40435 Used to determine when this `LinkComponent` is active. 40436 @property currentWhen 40437 @public 40438 */ 40439 'current-when': null, 40440 40441 /** 40442 Sets the `title` attribute of the `LinkComponent`'s HTML element. 40443 @property title 40444 @default null 40445 @public 40446 **/ 40447 title: null, 40448 40449 /** 40450 Sets the `rel` attribute of the `LinkComponent`'s HTML element. 40451 @property rel 40452 @default null 40453 @public 40454 **/ 40455 rel: null, 40456 40457 /** 40458 Sets the `tabindex` attribute of the `LinkComponent`'s HTML element. 40459 @property tabindex 40460 @default null 40461 @public 40462 **/ 40463 tabindex: null, 40464 40465 /** 40466 Sets the `target` attribute of the `LinkComponent`'s HTML element. 40467 @since 1.8.0 40468 @property target 40469 @default null 40470 @public 40471 **/ 40472 target: null, 40473 40474 /** 40475 The CSS class to apply to `LinkComponent`'s element when its `active` 40476 property is `true`. 40477 @property activeClass 40478 @type String 40479 @default active 40480 @private 40481 **/ 40482 activeClass: 'active', 40483 40484 /** 40485 The CSS class to apply to `LinkComponent`'s element when its `loading` 40486 property is `true`. 40487 @property loadingClass
40488 @type String 40489 @default loading 40490 @private 40491 **/ 40492 loadingClass: 'loading', 40493 40494 /** 40495 The CSS class to apply to a `LinkComponent`'s element when its `disabled` 40496 property is `true`. 40497 @property disabledClass 40498 @type String 40499 @default disabled 40500 @private 40501 **/ 40502 disabledClass: 'disabled', 40503 _isDisabled: false, 40504 40505 /** 40506 Determines whether the `LinkComponent` will trigger routing via 40507 the `replaceWith` routing strategy. 40508 @property replace 40509 @type Boolean 40510 @default false 40511 @public 40512 **/ 40513 replace: false, 40514 40515 /** 40516 By default the `{{link-to}}` component will bind to the `href` and 40517 `title` attributes. It's discouraged that you override these defaults, 40518 however you can push onto the array if needed. 40519 @property attributeBindings 40520 @type Array | String 40521 @default ['title', 'rel', 'tabindex', 'target'] 40522 @public 40523 */ 40524 attributeBindings: ['href', 'title', 'rel', 'tabindex', 'target'], 40525 40526 /** 40527 By default the `{{link-to}}` component will bind to the `active`, `loading`, 40528 and `disabled` classes. It is discouraged to override these directly. 40529 @property classNameBindings 40530 @type Array 40531 @default ['active', 'loading', 'disabled', 'ember-transitioning-in', 'ember-transitioning-out'] 40532 @public 40533 */ 40534 classNameBindings: ['active', 'loading', 'disabled', 'transitioningIn', 'transitioningOut'], 40535 40536 /** 40537 By default the `{{link-to}}` component responds to the `click` event. You 40538 can override this globally by setting this property to your custom 40539 event name. 40540 This is particularly useful on mobile when one wants to avoid the 300ms 40541 click delay using some sort of custom `tap` event. 40542 @property eventName 40543 @type String 40544 @default click 40545 @private 40546 */ 40547 eventName: 'click', 40548 40549 // this is doc'ed here so it shows up in the events 40550 // section of the API documentation, which is where 40551 // people will likely go looking for it. 40552 /** 40553 Triggers the `LinkComponent`'s routing behavior. If 40554 `eventName` is changed to a value other than `click` 40555 the routing behavior will trigger on that custom event 40556 instead. 40557 @event click 40558 @private 40559 */ 40560 40561 /** 40562 An overridable method called when `LinkComponent` objects are instantiated. 40563 Example: 40564 ```javascript 40565 App.MyLinkComponent = Ember.LinkComponent.extend({ 40566 init: function() { 40567 this._super(...arguments); 40568 Ember.Logger.log('Event is ' + this.get('eventName')); 40569 } 40570 }); 40571 ``` 40572 NOTE: If you do override `init` for a framework class like `Ember.View`, 40573 be sure to call `this._super(...arguments)` in your 40574 `init` declaration! If you don't, Ember may not have an opportunity to 40575 do important setup work, and you'll see strange behavior in your 40576 application. 40577 @method init 40578 @private 40579 */ 40580 init: function () { 40581 this._super.apply(this, arguments); 40582 40583 // Map desired event name to invoke function 40584 var eventName = _emberMetalProperty_get.get(this, 'eventName'); 40585 this.on(eventName, this, this._invoke); 40586 }, 40587 40588 _routing: _emberRuntimeInject.default.service('-routing'), 40589 40590 /** 40591 Accessed as a classname binding to apply the `LinkComponent`'s `disabledClass` 40592 CSS `class` to the element when the link is disabled. 40593 When `true` interactions with the element will not trigger route changes. 40594 @property disabled 40595 @private 40596 */ 40597 disabled: _emberMetalComputed.computed({ 40598 get: function (key, value) { 40599 return false; 40600 }, 40601 set: function (key, value) { 40602 if (value !== undefined) { 40603 this.set('_isDisabled', value); 40604 } 40605 40606 return value ? _emberMetalProperty_get.get(this, 'disabledClass') : false; 40607 } 40608 }), 40609 40610 _computeActive: function (routerState) { 40611 if (_emberMetalProperty_get.get(this, 'loading')) { 40612 return false; 40613 } 40614 40615 var routing = _emberMetalProperty_get.get(this, '_routing'); 40616 var models = _emberMetalProperty_get.get(this, 'models'); 40617 var resolvedQueryParams = _emberMetalProperty_get.get(this, 'resolvedQueryParams'); 40618 40619 var currentWhen = _emberMetalProperty_get.get(this, 'current-when'); 40620 var isCurrentWhenSpecified = !!currentWhen; 40621 currentWhen = currentWhen || _emberMetalProperty_get.get(this, 'qualifiedRouteName'); 40622 currentWhen = currentWhen.split(' '); 40623 40624 for (var i = 0, len = currentWhen.length; i < len; i++) { 40625 if (routing.isActiveForRoute(models, resolvedQueryParams, currentWhen[i], routerState, isCurrentWhenSpecified)) { 40626 return _emberMetalProperty_get.get(this, 'activeClass'); 40627 } 40628 } 40629 40630 return false;
40631 }, 40632 40633 /** 40634 Accessed as a classname binding to apply the `LinkComponent`'s `activeClass` 40635 CSS `class` to the element when the link is active. 40636 A `LinkComponent` is considered active when its `currentWhen` property is `true` 40637 or the application's current route is the route the `LinkComponent` would trigger 40638 transitions into. 40639 The `currentWhen` property can match against multiple routes by separating 40640 route names using the ` ` (space) character. 40641 @property active 40642 @private 40643 */ 40644 active: _emberMetalComputed.computed('attrs.params', '_routing.currentState', function computeLinkToComponentActive() { 40645 var currentState = _emberMetalProperty_get.get(this, '_routing.currentState'); 40646 if (!currentState) { 40647 return false; 40648 } 40649 40650 return this._computeActive(currentState); 40651 }), 40652 40653 willBeActive: _emberMetalComputed.computed('_routing.targetState', function computeLinkToComponentWillBeActive() { 40654 var routing = _emberMetalProperty_get.get(this, '_routing'); 40655 var targetState = _emberMetalProperty_get.get(routing, 'targetState'); 40656 if (_emberMetalProperty_get.get(routing, 'currentState') === targetState) { 40657 return; 40658 } 40659 40660 return !!this._computeActive(targetState); 40661 }), 40662 40663 transitioningIn: _emberMetalComputed.computed('active', 'willBeActive', function computeLinkToComponentTransitioningIn() { 40664 var willBeActive = _emberMetalProperty_get.get(this, 'willBeActive'); 40665 if (typeof willBeActive === 'undefined') { 40666 return false; 40667 } 40668 40669 return !_emberMetalProperty_get.get(this, 'active') && willBeActive && 'ember-transitioning-in'; 40670 }), 40671 40672 transitioningOut: _emberMetalComputed.computed('active', 'willBeActive', function computeLinkToComponentTransitioningOut() { 40673 var willBeActive = _emberMetalProperty_get.get(this, 'willBeActive'); 40674 if (typeof willBeActive === 'undefined') { 40675 return false; 40676 } 40677 40678 return _emberMetalProperty_get.get(this, 'active') && !willBeActive && 'ember-transitioning-out'; 40679 }), 40680 40681 /** 40682 Event handler that invokes the link, activating the associated route. 40683 @private 40684 @method _invoke 40685 @param {Event} event 40686 @private 40687 */ 40688 _invoke: function (event) { 40689 if (!_emberViewsSystemUtils.isSimpleClick(event)) { 40690 return true; 40691 } 40692 40693 var preventDefault = _emberMetalProperty_get.get(this, 'preventDefault'); 40694 var targetAttribute = _emberMetalProperty_get.get(this, 'target'); 40695 40696 if (preventDefault !== false) { 40697 if (!targetAttribute || targetAttribute === '_self') { 40698 event.preventDefault(); 40699 } 40700 } 40701 40702 if (_emberMetalProperty_get.get(this, 'bubbles') === false) { 40703 event.stopPropagation(); 40704 } 40705 40706 if (_emberMetalProperty_get.get(this, '_isDisabled')) { 40707 return false; 40708 } 40709 40710 if (_emberMetalProperty_get.get(this, 'loading')) { 40711 _emberMetalLogger.default.warn('This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.'); 40712 return false; 40713 } 40714 40715 if (targetAttribute && targetAttribute !== '_self') { 40716 return false; 40717 } 40718 40719 var routing = _emberMetalProperty_get.get(this, '_routing'); 40720 var qualifiedRouteName = _emberMetalProperty_get.get(this, 'qualifiedRouteName'); 40721 var models = _emberMetalProperty_get.get(this, 'models'); 40722 var queryParamValues = _emberMetalProperty_get.get(this, 'queryParams.values'); 40723 var shouldReplace = _emberMetalProperty_get.get(this, 'replace'); 40724 40725 routing.transitionTo(qualifiedRouteName, models, queryParamValues, shouldReplace); 40726 }, 40727 40728 queryParams: null, 40729 40730 qualifiedRouteName: _emberMetalComputed.computed('targetRouteName', '_routing.currentState', function computeLinkToComponentQualifiedRouteName() { 40731 var params = _emberMetalProperty_get.get(this, 'params').slice(); 40732 var lastParam = params[params.length - 1]; 40733 if (lastParam && lastParam.isQueryParams) { 40734 params.pop(); 40735 } 40736 var onlyQueryParamsSupplied = this[_emberHtmlbarsNodeManagersComponentNodeManager.HAS_BLOCK] ? params.length === 0 : params.length === 1; 40737 if (onlyQueryParamsSupplied) { 40738 return _emberMetalProperty_get.get(this, '_routing.currentRouteName'); 40739 } 40740 return _emberMetalProperty_get.get(this, 'targetRouteName'); 40741 }), 40742 40743 resolvedQueryParams: _emberMetalComputed.computed('queryParams', function computeLinkToComponentResolvedQueryParams() { 40744 var resolvedQueryParams = {}; 40745 var queryParams = _emberMetalProperty_get.get(this, 'queryParams'); 40746 40747 if (!queryParams) { 40748 return resolvedQueryParams; 40749 } 40750 40751 var values = queryParams.values; 40752 for (var key in values) { 40753 if (!values.hasOwnProperty(key)) { 40754 continue; 40755 } 40756 resolvedQueryParams[key] = values[key]; 40757 } 40758 40759 return resolvedQueryParams; 40760 }), 40761 40762 /** 40763 Sets the element's `href` attribute to the url for 40764 the `LinkComponent`'s targeted route. 40765 If the `LinkComponent`'s `tagName` is changed to a value other 40766 than `a`, this property will be ignored. 40767 @property href 40768 @private 40769 */ 40770 href: _emberMetalComputed.computed('models', 'qualifiedRouteName', function computeLinkToComponentHref() { 40771 if (_emberMetalProperty_get.get(this, 'tagName') !== 'a') { 40772 return; 40773 } 40774 40775 var qualifiedRouteName = _emberMetalProperty_get.get(this, 'qualifiedRouteName'); 40776 var models = _emberMetalProperty_get.get(this, 'models'); 40777 40778 if (_emberMetalProperty_get.get(this, 'loading')) { 40779 return _emberMetalProperty_get.get(this, 'loadingHref'); 40780 } 40781 40782 var routing = _emberMetalProperty_get.get(this, '_routing'); 40783 var queryParams = _emberMetalProperty_get.get(this, 'queryParams.values'); 40784 return routing.generateURL(qualifiedRouteName, models, queryParams); 40785 }), 40786 40787 loading: _emberMetalComputed.computed('_modelsAreLoaded', 'qualifiedRouteName', function computeLinkToComponentLoading() { 40788 var qualifiedRouteName = _emberMetalProperty_get.get(this, 'qualifiedRouteName'); 40789 var modelsAreLoaded = _emberMetalProperty_get.get(this, '_modelsAreLoaded'); 40790 40791 if (!modelsAreLoaded || qualifiedRouteName == null) { 40792 return _emberMetalProperty_get.get(this, 'loadingClass'); 40793 } 40794 }), 40795 40796 _modelsAreLoaded: _emberMetalComputed.computed('models', function computeLinkToComponentModelsAreLoaded() { 40797 var models = _emberMetalProperty_get.get(this, 'models'); 40798 for (var i = 0, l = models.length; i < l; i++) { 40799 if (models[i] == null) { 40800 return false;
40801 } 40802 } 40803 40804 return true; 40805 }), 40806 40807 _getModels: function (params) { 40808 var modelCount = params.length - 1; 40809 var models = new Array(modelCount); 40810 40811 for (var i = 0; i < modelCount; i++) { 40812 var value = params[i + 1]; 40813 40814 while (_emberRuntimeMixinsController.default.detect(value)) { 40815 _emberMetalDebug.deprecate('Providing `{{link-to}}` with a param that is wrapped in a controller is deprecated. ' + (this.parentView ? 'Please update `' + this.parentView + '` to use `{{link-to "post" someController.model}}` instead.' : ''), false, { id: 'ember-routing-views.controller-wrapped-param', until: '3.0.0' }); 40816 value = value.get('model'); 40817 } 40818 40819 models[i] = value; 40820 } 40821 40822 return models; 40823 }, 40824 40825 /** 40826 The default href value to use while a link-to is loading. 40827 Only applies when tagName is 'a' 40828 @property loadingHref 40829 @type String 40830 @default # 40831 @private 40832 */ 40833 loadingHref: '#', 40834 40835 willRender: function () { 40836 var queryParams = undefined; 40837 40838 // Do not mutate params in place 40839 var params = _emberMetalProperty_get.get(this, 'params').slice(); 40840 40841 _emberMetalDebug.assert('You must provide one or more parameters to the link-to component.', params.length); 40842 40843 var disabledWhen = _emberMetalProperty_get.get(this, 'disabledWhen'); 40844 if (disabledWhen !== undefined) { 40845 this.set('disabled', disabledWhen); 40846 } 40847 40848 // Process the positional arguments, in order. 40849 // 1. Inline link title comes first, if present. 40850 if (!this[_emberHtmlbarsNodeManagersComponentNodeManager.HAS_BLOCK]) { 40851 this.set('linkTitle', params.shift()); 40852 } 40853 40854 // 2. `targetRouteName` is now always at index 0. 40855 this.set('targetRouteName', params[0]); 40856 40857 // 3. The last argument (if still remaining) is the `queryParams` object. 40858 var lastParam = params[params.length - 1]; 40859 40860 if (lastParam && lastParam.isQueryParams) { 40861 queryParams = params.pop(); 40862 } else { 40863 queryParams = {}; 40864 } 40865 this.set('queryParams', queryParams); 40866 40867 // 4. Any remaining indices (excepting `targetRouteName` at 0) are `models`. 40868 if (params.length > 1) { 40869 this.set('models', this._getModels(params)); 40870 } else { 40871 this.set('models', []); 40872 } 40873 } 40874 }); 40875 40876 LinkComponent.toString = function () { 40877 return 'LinkComponent'; 40878 }; 40879 40880 LinkComponent.reopenClass({ 40881 positionalParams: 'params' 40882 }); 40883 40884 exports.default = LinkComponent; 40885}); 40886// creates inject.service 40887enifed('ember-routing-views/index', ['exports', 'ember-metal/core', 'ember-routing-views/components/link-to', 'ember-routing-views/views/outlet'], function (exports, _emberMetalCore, _emberRoutingViewsComponentsLinkTo, _emberRoutingViewsViewsOutlet) { 40888 /** 40889 @module ember 40890 @submodule ember-routing-views 40891 */ 40892 40893 'use strict'; 40894 40895 _emberMetalCore.default.LinkComponent = _emberRoutingViewsComponentsLinkTo.default; 40896 _emberMetalCore.default.OutletView = _emberRoutingViewsViewsOutlet.OutletView; 40897 40898 exports.default = _emberMetalCore.default; 40899}); 40900enifed('ember-routing-views/views/outlet', ['exports', 'ember-views/views/view', 'ember-htmlbars/templates/top-level-view'], function (exports, _emberViewsViewsView, _emberHtmlbarsTemplatesTopLevelView) { 40901 /** 40902 @module ember 40903 @submodule ember-routing-views 40904 */ 40905 40906 'use strict'; 40907 40908 _emberHtmlbarsTemplatesTopLevelView.default.meta.revision = '[email protected]'; 40909 40910 var CoreOutletView = _emberViewsViewsView.default.extend({ 40911 defaultTemplate: _emberHtmlbarsTemplatesTopLevelView.default, 40912 40913 init: function () { 40914 this._super(); 40915 this._outlets = []; 40916 }, 40917 40918 setOutletState: function (state) { 40919 this.outletState = { main: state }; 40920 40921 if (this.env) { 40922 this.env.outletState = this.outletState; 40923 } 40924 40925 if (this.lastResult) { 40926 this.dirtyOutlets(); 40927 this._outlets = []; 40928 40929 this.scheduleRevalidate(null, null); 40930 } 40931 }, 40932 40933 dirtyOutlets: function () { 40934 // Dirty any render nodes that correspond to outlets 40935 for (var i = 0; i < this._outlets.length; i++) { 40936 this._outlets[i].isDirty = true; 40937 } 40938 } 40939 }); 40940 40941 exports.CoreOutletView = CoreOutletView; 40942 var OutletView = CoreOutletView.extend({ tagName: '' }); 40943 exports.OutletView = OutletView; 40944}); 40945enifed('ember-runtime/compare', ['exports', 'ember-runtime/utils', 'ember-runtime/mixins/comparable'], function (exports, _emberRuntimeUtils, _emberRuntimeMixinsComparable) { 40946 'use strict'; 40947 40948 exports.default = compare; 40949 40950 var TYPE_ORDER = { 40951 'undefined': 0, 40952 'null': 1, 40953 'boolean': 2, 40954 'number': 3, 40955 'string': 4, 40956 'array': 5, 40957 'object': 6, 40958 'instance': 7, 40959 'function': 8, 40960 'class': 9, 40961 'date': 10 40962 }; 40963 40964 // 40965 // the spaceship operator
40966 // 40967 // `. ___ 40968 // __,' __`. _..----....____ 40969 // __...--.'``;. ,. ;``--..__ .' ,-._ _.-' 40970 // _..-''-------' `' `' `' O ``-''._ (,;') _,' 40971 // ,'________________ \`-._`-',' 40972 // `._ ```````````------...___ '-.._'-: 40973 // ```--.._ ,. ````--...__\-. 40974 // `.--. `-` "INFINTIY IS LESS ____ | |` 40975 // `. `. THAN BEYOND" ,'`````. ; ;` 40976 // `._`. __________ `. \'__/` 40977 // `-:._____/______/___/____`. \ ` 40978 // | `._ `. \ 40979 // `._________`-. `. `.___ 40980 // SSt `------'` 40981 function spaceship(a, b) { 40982 var diff = a - b; 40983 return (diff > 0) - (diff < 0); 40984 } 40985 40986 /** 40987 Compares two javascript values and returns: 40988 40989 - -1 if the first is smaller than the second, 40990 - 0 if both are equal, 40991 - 1 if the first is greater than the second. 40992 40993 ```javascript 40994 Ember.compare('hello', 'hello'); // 0 40995 Ember.compare('abc', 'dfg'); // -1 40996 Ember.compare(2, 1); // 1 40997 ``` 40998 40999 If the types of the two objects are different precedence occurs in the 41000 following order, with types earlier in the list considered `<` types 41001 later in the list: 41002 41003 - undefined 41004 - null 41005 - boolean 41006 - number 41007 - string 41008 - array 41009 - object 41010 - instance 41011 - function 41012 - class 41013 - date 41014 41015 ```javascript 41016 Ember.compare('hello', 50); // 1 41017 Ember.compare(50, 'hello'); // -1 41018 ``` 41019 41020 @method compare 41021 @for Ember 41022 @param {Object} v First value to compare 41023 @param {Object} w Second value to compare 41024 @return {Number} -1 if v < w, 0 if v = w and 1 if v > w. 41025 @public 41026 */ 41027 41028 function compare(v, w) { 41029 if (v === w) { 41030 return 0; 41031 } 41032 41033 var type1 = _emberRuntimeUtils.typeOf(v); 41034 var type2 = _emberRuntimeUtils.typeOf(w); 41035 41036 if (_emberRuntimeMixinsComparable.default) { 41037 if (type1 === 'instance' && _emberRuntimeMixinsComparable.default.detect(v) && v.constructor.compare) { 41038 return v.constructor.compare(v, w); 41039 } 41040 41041 if (type2 === 'instance' && _emberRuntimeMixinsComparable.default.detect(w) && w.constructor.compare) { 41042 return w.constructor.compare(w, v) * -1; 41043 } 41044 } 41045 41046 var res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]); 41047 41048 if (res !== 0) { 41049 return res; 41050 } 41051
41052 // types are equal - so we have to check values now 41053 switch (type1) { 41054 case 'boolean': 41055 case 'number': 41056 return spaceship(v, w); 41057 41058 case 'string': 41059 return spaceship(v.localeCompare(w), 0); 41060 41061 case 'array': 41062 var vLen = v.length; 41063 var wLen = w.length; 41064 var len = Math.min(vLen, wLen); 41065 41066 for (var i = 0; i < len; i++) { 41067 var r = compare(v[i], w[i]); 41068 if (r !== 0) { 41069 return r; 41070 } 41071 } 41072 41073 // all elements are equal now 41074 // shorter array should be ordered first 41075 return spaceship(vLen, wLen); 41076 41077 case 'instance': 41078 if (_emberRuntimeMixinsComparable.default && _emberRuntimeMixinsComparable.default.detect(v)) { 41079 return v.compare(v, w); 41080 } 41081 return 0; 41082 41083 case 'date': 41084 return spaceship(v.getTime(), w.getTime()); 41085 41086 default: 41087 return 0; 41088 } 41089 } 41090}); 41091enifed('ember-runtime/computed/reduce_computed_macros', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/error', 'ember-metal/computed', 'ember-metal/observer', 'ember-runtime/compare', 'ember-runtime/utils', 'ember-runtime/system/native_array', 'ember-metal/is_none', 'ember-metal/get_properties', 'ember-metal/weak_map'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalError, _emberMetalComputed, _emberMetalObserver, _emberRuntimeCompare, _emberRuntimeUtils, _emberRuntimeSystemNative_array, _emberMetalIs_none, _emberMetalGet_properties, _emberMetalWeak_map) { 41092 /** 41093 @module ember 41094 @submodule ember-runtime 41095 */ 41096 41097 'use strict'; 41098 41099 exports.sum = sum; 41100 exports.max = max; 41101 exports.min = min; 41102 exports.map = map; 41103 exports.mapBy = mapBy; 41104 exports.filter = filter; 41105 exports.filterBy = filterBy; 41106 exports.uniq = uniq; 41107 exports.intersect = intersect; 41108 exports.setDiff = setDiff; 41109 exports.collect = collect; 41110 exports.sort = sort; 41111 41112 function reduceMacro(dependentKey, callback, initialValue) { 41113 return _emberMetalComputed.computed(dependentKey + '.[]', function () { 41114 var _this = this; 41115 41116 var arr = _emberMetalProperty_get.get(this, dependentKey); 41117 41118 if (arr === null || typeof arr !== 'object') { 41119 return initialValue; 41120 } 41121 41122 return arr.reduce(function (previousValue, currentValue, index, array) { 41123 return callback.call(_this, previousValue, currentValue, index, array); 41124 }, initialValue); 41125 }).readOnly(); 41126 } 41127 41128 function arrayMacro(dependentKey, callback) { 41129 // This is a bit ugly 41130 var propertyName; 41131 if (/@each/.test(dependentKey)) { 41132 propertyName = dependentKey.replace(/\.@each.*$/, ''); 41133 } else { 41134 propertyName = dependentKey; 41135 dependentKey += '.[]'; 41136 } 41137 41138 return _emberMetalComputed.computed(dependentKey, function () { 41139 var value = _emberMetalProperty_get.get(this, propertyName); 41140 if (_emberRuntimeUtils.isArray(value)) { 41141 return _emberRuntimeSystemNative_array.A(callback.call(this, value)); 41142 } else { 41143 return _emberRuntimeSystemNative_array.A(); 41144 } 41145 }).readOnly(); 41146 } 41147 41148 function multiArrayMacro(dependentKeys, callback) { 41149 var args = dependentKeys.map(function (key) { 41150 return key + '.[]'; 41151 }); 41152 41153 args.push(function () { 41154 return _emberRuntimeSystemNative_array.A(callback.call(this, dependentKeys)); 41155 }); 41156 41157 return _emberMetalComputed.computed.apply(this, args).readOnly(); 41158 } 41159 41160 /** 41161 A computed property that returns the sum of the values 41162 in the dependent array. 41163 41164 @method sum 41165 @for Ember.computed 41166 @param {String} dependentKey 41167 @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array 41168 @since 1.4.0 41169 @public 41170 */ 41171 41172 function sum(dependentKey) { 41173 return reduceMacro(dependentKey, function (sum, item) { 41174 return sum + item; 41175 }, 0); 41176 } 41177 41178 /** 41179 A computed property that calculates the maximum value in the 41180 dependent array. This will return `-Infinity` when the dependent 41181 array is empty. 41182 41183 ```javascript 41184 var Person = Ember.Object.extend({ 41185 childAges: Ember.computed.mapBy('children', 'age'), 41186 maxChildAge: Ember.computed.max('childAges') 41187 }); 41188 41189 var lordByron = Person.create({ children: [] }); 41190 41191 lordByron.get('maxChildAge'); // -Infinity 41192 lordByron.get('children').pushObject({ 41193 name: 'Augusta Ada Byron', age: 7 41194 }); 41195 lordByron.get('maxChildAge'); // 7 41196 lordByron.get('children').pushObjects([{ 41197 name: 'Allegra Byron', 41198 age: 5 41199 }, {
41200 name: 'Elizabeth Medora Leigh', 41201 age: 8 41202 }]); 41203 lordByron.get('maxChildAge'); // 8 41204 ``` 41205 41206 @method max 41207 @for Ember.computed 41208 @param {String} dependentKey 41209 @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array 41210 @public 41211 */ 41212 41213 function max(dependentKey) { 41214 return reduceMacro(dependentKey, function (max, item) { 41215 return Math.max(max, item); 41216 }, -Infinity); 41217 } 41218 41219 /** 41220 A computed property that calculates the minimum value in the 41221 dependent array. This will return `Infinity` when the dependent 41222 array is empty. 41223 41224 ```javascript 41225 var Person = Ember.Object.extend({ 41226 childAges: Ember.computed.mapBy('children', 'age'), 41227 minChildAge: Ember.computed.min('childAges') 41228 }); 41229 41230 var lordByron = Person.create({ children: [] }); 41231 41232 lordByron.get('minChildAge'); // Infinity 41233 lordByron.get('children').pushObject({ 41234 name: 'Augusta Ada Byron', age: 7 41235 }); 41236 lordByron.get('minChildAge'); // 7 41237 lordByron.get('children').pushObjects([{ 41238 name: 'Allegra Byron', 41239 age: 5 41240 }, { 41241 name: 'Elizabeth Medora Leigh', 41242 age: 8 41243 }]); 41244 lordByron.get('minChildAge'); // 5 41245 ``` 41246 41247 @method min 41248 @for Ember.computed 41249 @param {String} dependentKey 41250 @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array 41251 @public 41252 */ 41253 41254 function min(dependentKey) { 41255 return reduceMacro(dependentKey, function (min, item) { 41256 return Math.min(min, item); 41257 }, Infinity); 41258 } 41259 41260 /** 41261 Returns an array mapped via the callback 41262 41263 The callback method you provide should have the following signature. 41264 `item` is the current item in the iteration. 41265 `index` is the integer index of the current item in the iteration. 41266 41267 ```javascript 41268 function(item, index); 41269 ``` 41270 41271 Example 41272 41273 ```javascript 41274 var Hamster = Ember.Object.extend({ 41275 excitingChores: Ember.computed.map('chores', function(chore, index) { 41276 return chore.toUpperCase() + '!'; 41277 }) 41278 }); 41279 41280 var hamster = Hamster.create({ 41281 chores: ['clean', 'write more unit tests'] 41282 }); 41283 41284 hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] 41285 ``` 41286 41287 @method map 41288 @for Ember.computed 41289 @param {String} dependentKey 41290 @param {Function} callback 41291 @return {Ember.ComputedProperty} an array mapped via the callback 41292 @public 41293 */ 41294 41295 function map(dependentKey, callback) { 41296 return arrayMacro(dependentKey, function (value) { 41297 return value.map(callback, this); 41298 }); 41299 } 41300 41301 /** 41302 Returns an array mapped to the specified key. 41303 41304 ```javascript 41305 var Person = Ember.Object.extend({ 41306 childAges: Ember.computed.mapBy('children', 'age') 41307 }); 41308 41309 var lordByron = Person.create({ children: [] }); 41310 41311 lordByron.get('childAges'); // [] 41312 lordByron.get('children').pushObject({ name: 'Augusta Ada Byron', age: 7 }); 41313 lordByron.get('childAges'); // [7] 41314 lordByron.get('children').pushObjects([{ 41315 name: 'Allegra Byron', 41316 age: 5 41317 }, { 41318 name: 'Elizabeth Medora Leigh', 41319 age: 8 41320 }]); 41321 lordByron.get('childAges'); // [7, 5, 8] 41322 ``` 41323 41324 @method mapBy 41325 @for Ember.computed 41326 @param {String} dependentKey 41327 @param {String} propertyKey 41328 @return {Ember.ComputedProperty} an array mapped to the specified key 41329 @public 41330 */ 41331 41332 function mapBy(dependentKey, propertyKey) { 41333 _emberMetalDebug.assert('Ember.computed.mapBy expects a property string for its second argument, ' + 'perhaps you meant to use "map"', typeof propertyKey === 'string'); 41334 41335 return map(dependentKey + '.@each.' + propertyKey, function (item) { 41336 return _emberMetalProperty_get.get(item, propertyKey); 41337 }); 41338 } 41339 41340 /** 41341 Filters the array by the callback. 41342 41343 The callback method you provide should have the following signature. 41344 `item` is the current item in the iteration. 41345 `index` is the integer index of the current item in the iteration. 41346 `array` is the dependant array itself. 41347 41348 ```javascript 41349 function(item, index, array); 41350 ``` 41351 41352 ```javascript 41353 var Hamster = Ember.Object.extend({ 41354 remainingChores: Ember.computed.filter('chores', function(chore, index, array) { 41355 return !chore.done; 41356 }) 41357 }); 41358 41359 var hamster = Hamster.create({ 41360 chores: [ 41361 { name: 'cook', done: true }, 41362 { name: 'clean', done: true }, 41363 { name: 'write more unit tests', done: false } 41364 ] 41365 }); 41366 41367 hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] 41368 ``` 41369 41370 @method filter 41371 @for Ember.computed 41372 @param {String} dependentKey 41373 @param {Function} callback 41374 @return {Ember.ComputedProperty} the filtered array 41375 @public 41376 */ 41377 41378 function filter(dependentKey, callback) { 41379 return arrayMacro(dependentKey, function (value) { 41380 return value.filter(callback, this); 41381 }); 41382 } 41383 41384 /** 41385 Filters the array by the property and value 41386 41387 ```javascript 41388 var Hamster = Ember.Object.extend({ 41389 remainingChores: Ember.computed.filterBy('chores', 'done', false) 41390 }); 41391 41392 var hamster = Hamster.create({ 41393 chores: [ 41394 { name: 'cook', done: true }, 41395 { name: 'clean', done: true }, 41396 { name: 'write more unit tests', done: false } 41397 ] 41398 }); 41399 41400 hamster.get('remainingChores'); // [{ name: 'write more unit tests', done: false }] 41401 ``` 41402 41403 @method filterBy 41404 @for Ember.computed 41405 @param {String} dependentKey 41406 @param {String} propertyKey 41407 @param {*} value 41408 @return {Ember.ComputedProperty} the filtered array 41409 @public 41410 */ 41411 41412 function filterBy(dependentKey, propertyKey, value) { 41413 var callback; 41414 41415 if (arguments.length === 2) { 41416 callback = function (item) { 41417 return _emberMetalProperty_get.get(item, propertyKey); 41418 }; 41419 } else { 41420 callback = function (item) { 41421 return _emberMetalProperty_get.get(item, propertyKey) === value; 41422 }; 41423 } 41424 41425 return filter(dependentKey + '.@each.' + propertyKey, callback); 41426 } 41427 41428 /** 41429 A computed property which returns a new array with all the unique 41430 elements from one or more dependent arrays. 41431 41432 Example 41433 41434 ```javascript 41435 var Hamster = Ember.Object.extend({ 41436 uniqueFruits: Ember.computed.uniq('fruits') 41437 }); 41438 41439 var hamster = Hamster.create({ 41440 fruits: [ 41441 'banana', 41442 'grape', 41443 'kale', 41444 'banana' 41445 ] 41446 }); 41447 41448 hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] 41449 ``` 41450 41451 @method uniq 41452 @for Ember.computed 41453 @param {String} propertyKey* 41454 @return {Ember.ComputedProperty} computes a new array with all the 41455 unique elements from the dependent array 41456 @public 41457 */ 41458 41459 function uniq() { 41460 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 41461 args[_key] = arguments[_key]; 41462 } 41463 41464 return multiArrayMacro(args, function (dependentKeys) { 41465 var _this2 = this; 41466 41467 var uniq = _emberRuntimeSystemNative_array.A(); 41468 41469 dependentKeys.forEach(function (dependentKey) { 41470 var value = _emberMetalProperty_get.get(_this2, dependentKey); 41471 if (_emberRuntimeUtils.isArray(value)) { 41472 value.forEach(function (item) { 41473 if (uniq.indexOf(item) === -1) { 41474 uniq.push(item); 41475 } 41476 }); 41477 } 41478 }); 41479 41480 return uniq; 41481 }); 41482 } 41483 41484 /** 41485 Alias for [Ember.computed.uniq](/api/#method_computed_uniq). 41486 41487 @method union 41488 @for Ember.computed 41489 @param {String} propertyKey* 41490 @return {Ember.ComputedProperty} computes a new array with all the 41491 unique elements from the dependent array 41492 @public 41493 */ 41494 var union = uniq; 41495 41496 exports.union = union; 41497 /** 41498 A computed property which returns a new array with all the duplicated 41499 elements from two or more dependent arrays. 41500 41501 Example 41502 41503 ```javascript 41504 var obj = Ember.Object.extend({ 41505 friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends') 41506 }).create({ 41507 adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], 41508 charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'] 41509 }); 41510 41511 obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] 41512 ``` 41513 41514 @method intersect 41515 @for Ember.computed 41516 @param {String} propertyKey* 41517 @return {Ember.ComputedProperty} computes a new array with all the 41518 duplicated elements from the dependent arrays 41519 @public 41520 */ 41521 41522 function intersect() { 41523 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 41524 args[_key2] = arguments[_key2]; 41525 } 41526 41527 return multiArrayMacro(args, function (dependentKeys) { 41528 var _this3 = this; 41529
41530 var arrays = dependentKeys.map(function (dependentKey) { 41531 var array = _emberMetalProperty_get.get(_this3, dependentKey); 41532 41533 return _emberRuntimeUtils.isArray(array) ? array : []; 41534 }); 41535 41536 var results = arrays.pop().filter(function (candidate) { 41537 for (var i = 0; i < arrays.length; i++) { 41538 var found = false; 41539 var array = arrays[i]; 41540 for (var j = 0; j < array.length; j++) { 41541 if (array[j] === candidate) { 41542 found = true; 41543 break; 41544 } 41545 } 41546 41547 if (found === false) { 41548 return false; 41549 } 41550 } 41551 41552 return true; 41553 }); 41554 41555 return _emberRuntimeSystemNative_array.A(results); 41556 }); 41557 } 41558 41559 /** 41560 A computed property which returns a new array with all the 41561 properties from the first dependent array that are not in the second 41562 dependent array. 41563 41564 Example 41565 41566 ```javascript 41567 var Hamster = Ember.Object.extend({ 41568 likes: ['banana', 'grape', 'kale'], 41569 wants: Ember.computed.setDiff('likes', 'fruits') 41570 }); 41571 41572 var hamster = Hamster.create({ 41573 fruits: [ 41574 'grape', 41575 'kale', 41576 ] 41577 }); 41578 41579 hamster.get('wants'); // ['banana'] 41580 ``` 41581 41582 @method setDiff 41583 @for Ember.computed 41584 @param {String} setAProperty 41585 @param {String} setBProperty 41586 @return {Ember.ComputedProperty} computes a new array with all the 41587 items from the first dependent array that are not in the second 41588 dependent array 41589 @public 41590 */ 41591 41592 function setDiff(setAProperty, setBProperty) { 41593 if (arguments.length !== 2) { 41594 throw new _emberMetalError.default('setDiff requires exactly two dependent arrays.'); 41595 } 41596 41597 return _emberMetalComputed.computed(setAProperty + '.[]', setBProperty + '.[]', function () { 41598 var setA = this.get(setAProperty); 41599 var setB = this.get(setBProperty); 41600 41601 if (!_emberRuntimeUtils.isArray(setA)) { 41602 return _emberRuntimeSystemNative_array.A(); 41603 } 41604 if (!_emberRuntimeUtils.isArray(setB)) { 41605 return _emberRuntimeSystemNative_array.A(setA); 41606 } 41607 41608 return setA.filter(function (x) { 41609 return setB.indexOf(x) === -1; 41610 }); 41611 }).readOnly(); 41612 } 41613 41614 /** 41615 A computed property that returns the array of values 41616 for the provided dependent properties. 41617 41618 Example 41619 41620 ```javascript 41621 var Hamster = Ember.Object.extend({ 41622 clothes: Ember.computed.collect('hat', 'shirt') 41623 }); 41624 41625 var hamster = Hamster.create(); 41626 41627 hamster.get('clothes'); // [null, null] 41628 hamster.set('hat', 'Camp Hat'); 41629 hamster.set('shirt', 'Camp Shirt'); 41630 hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] 41631 ``` 41632 41633 @method collect 41634 @for Ember.computed 41635 @param {String} dependentKey* 41636 @return {Ember.ComputedProperty} computed property which maps 41637 values of all passed in properties to an array. 41638 @public 41639 */ 41640 41641 function collect() { 41642 for (var _len3 = arguments.length, dependentKeys = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { 41643 dependentKeys[_key3] = arguments[_key3]; 41644 } 41645 41646 return multiArrayMacro(dependentKeys, function () { 41647 var properties = _emberMetalGet_properties.default(this, dependentKeys); 41648 var res = _emberRuntimeSystemNative_array.A(); 41649 for (var key in properties) { 41650 if (properties.hasOwnProperty(key)) { 41651 if (_emberMetalIs_none.default(properties[key])) { 41652 res.push(null); 41653 } else { 41654 res.push(properties[key]); 41655 } 41656 } 41657 } 41658 return res; 41659 }); 41660 } 41661 41662 /** 41663 A computed property which returns a new array with all the 41664 properties from the first dependent array sorted based on a property 41665 or sort function. 41666 41667 The callback method you provide should have the following signature: 41668 41669 ```javascript 41670 function(itemA, itemB); 41671 ``` 41672 41673 - `itemA` the first item to compare. 41674 - `itemB` the second item to compare. 41675 41676 This function should return negative number (e.g. `-1`) when `itemA` should come before 41677 `itemB`. It should return positive number (e.g. `1`) when `itemA` should come after 41678 `itemB`. If the `itemA` and `itemB` are equal this function should return `0`. 41679 41680 Therefore, if this function is comparing some numeric values, simple `itemA - itemB` or 41681 `itemA.get( 'foo' ) - itemB.get( 'foo' )` can be used instead of series of `if`. 41682 41683 Example 41684 41685 ```javascript 41686 var ToDoList = Ember.Object.extend({ 41687 // using standard ascending sort 41688 todosSorting: ['name'], 41689 sortedTodos: Ember.computed.sort('todos', 'todosSorting'), 41690 41691 // using descending sort 41692 todosSortingDesc: ['name:desc'], 41693 sortedTodosDesc: Ember.computed.sort('todos', 'todosSortingDesc'), 41694 41695 // using a custom sort function 41696 priorityTodos: Ember.computed.sort('todos', function(a, b){ 41697 if (a.priority > b.priority) { 41698 return 1; 41699 } else if (a.priority < b.priority) { 41700 return -1; 41701 } 41702 41703 return 0; 41704 }) 41705 }); 41706 41707 var todoList = ToDoList.create({todos: [ 41708 { name: 'Unit Test', priority: 2 }, 41709 { name: 'Documentation', priority: 3 }, 41710 { name: 'Release', priority: 1 } 41711 ]}); 41712 41713 todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] 41714 todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] 41715 todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] 41716 ``` 41717 41718 @method sort 41719 @for Ember.computed 41720 @param {String} itemsKey 41721 @param {String or Function} sortDefinition a dependent key to an 41722 array of sort properties (add `:desc` to the arrays sort properties to sort descending) or a function to use when sorting 41723 @return {Ember.ComputedProperty} computes a new sorted array based 41724 on the sort property array or callback function 41725 @public 41726 */ 41727 41728 function sort(itemsKey, sortDefinition) { 41729 _emberMetalDebug.assert('Ember.computed.sort requires two arguments: an array key to sort and ' + 'either a sort properties key or sort function', arguments.length === 2); 41730 41731 if (typeof sortDefinition === 'function') { 41732 return customSort(itemsKey, sortDefinition); 41733 } else { 41734 return propertySort(itemsKey, sortDefinition); 41735 } 41736 } 41737 41738 function customSort(itemsKey, comparator) { 41739 return arrayMacro(itemsKey, function (value) { 41740 var _this4 = this; 41741 41742 return value.slice().sort(function (x, y) { 41743 return comparator.call(_this4, x, y); 41744 }); 41745 }); 41746 } 41747 41748 // This one needs to dynamically set up and tear down observers on the itemsKey 41749 // depending on the sortProperties 41750 function propertySort(itemsKey, sortPropertiesKey) { 41751 var cp = new _emberMetalComputed.ComputedProperty(function (key) { 41752 var _this5 = this; 41753 41754 var itemsKeyIsAtThis = itemsKey === '@this'; 41755 var sortProperties = _emberMetalProperty_get.get(this, sortPropertiesKey); 41756 41757 _emberMetalDebug.assert('The sort definition for \'' + key + '\' on ' + this + ' must be a function or an array of str
41757ings', _emberRuntimeUtils.isArray(sortProperties) && sortProperties.every(function (s) { 41758 return typeof s === 'string'; 41759 })); 41760 41761 var normalizedSortProperties = normalizeSortProperties(sortProperties); 41762 41763 // Add/remove property observers as required. 41764 var activeObserversMap = cp._activeObserverMap || (cp._activeObserverMap = new _emberMetalWeak_map.default()); 41765 var activeObservers = activeObserversMap.get(this); 41766 41767 if (activeObservers) { 41768 activeObservers.forEach(function (args) { 41769 _emberMetalObserver.removeObserver.apply(null, args); 41770 }); 41771 } 41772 41773 function sortPropertyDidChange() { 41774 this.notifyPropertyChange(key); 41775 } 41776 41777 activeObservers = normalizedSortProperties.map(function (_ref) { 41778 var prop = _ref[0]; 41779 41780 var path = itemsKeyIsAtThis ? '@each.' + prop : itemsKey + '.@each.' + prop; 41781 var args = [_this5, path, sortPropertyDidChange]; 41782 _emberMetalObserver.addObserver.apply(null, args); 41783 return args; 41784 }); 41785 41786 activeObserversMap.set(this, activeObservers); 41787 41788 // Sort and return the array. 41789 var items = itemsKeyIsAtThis ? this : _emberMetalProperty_get.get(this, itemsKey); 41790 41791 if (_emberRuntimeUtils.isArray(items)) { 41792 return sortByNormalizedSortProperties(items, normalizedSortProperties); 41793 } else { 41794 return _emberRuntimeSystemNative_array.A(); 41795 } 41796 }); 41797 41798 cp._activeObserverMap = undefined; 41799 41800 return cp.property(sortPropertiesKey + '.[]').readOnly(); 41801 } 41802 41803 function normalizeSortProperties(sortProperties) { 41804 return sortProperties.map(function (p) { 41805 var _p$split = p.split(':'); 41806 41807 var prop = _p$split[0]; 41808 var direction = _p$split[1]; 41809 41810 direction = direction || 'asc'; 41811 41812 return [prop, direction]; 41813 }); 41814 } 41815 41816 function sortByNormalizedSortProperties(items, normalizedSortProperties) { 41817 return _emberRuntimeSystemNative_array.A(items.slice().sort(function (itemA, itemB) { 41818 for (var i = 0; i < normalizedSortProperties.length; i++) { 41819 var _normalizedSortProperties$i = normalizedSortProperties[i]; 41820 var prop = _normalizedSortProperties$i[0]; 41821 var direction = _normalizedSortProperties$i[1]; 41822 41823 var result = _emberRuntimeCompare.default(_emberMetalProperty_get.get(itemA, prop), _emberMetalProperty_get.get(itemB, prop)); 41824 if (result !== 0) { 41825 return direction === 'desc' ? -1 * result : result; 41826 } 41827 } 41828 41829 return 0; 41830 })); 41831 } 41832}); 41833enifed('ember-runtime/controllers/controller', ['exports', 'ember-metal/debug', 'ember-runtime/system/object', 'ember-runtime/mixins/controller', 'ember-runtime/inject', 'ember-runtime/mixins/action_handler'], function (exports, _emberMetalDebug, _emberRuntimeSystemObject, _emberRuntimeMixinsController, _emberRuntimeInject, _emberRuntimeMixinsAction_handler) { 41834 'use strict'; 41835 41836 /** 41837 @module ember 41838 @submodule ember-runtime 41839 */ 41840 41841 /** 41842 @class Controller 41843 @namespace Ember 41844 @extends Ember.Object 41845 @uses Ember.ControllerMixin 41846 @public 41847 */ 41848 var Controller = _emberRuntimeSystemObject.default.extend(_emberRuntimeMixinsController.default); 41849 41850 _emberRuntimeMixinsAction_handler.deprecateUnderscoreActions(Controller); 41851 41852 function controllerInjectionHelper(factory) { 41853 _emberMetalDebug.assert('Defining an injected controller property on a ' + 'non-controller is not allowed.', _emberRuntimeMixinsController.default.detect(factory.PrototypeMixin)); 41854 } 41855 41856 /** 41857 Creates a property that lazily looks up another controller in the container. 41858 Can only be used when defining another controller. 41859 41860 Example: 41861 41862 ```javascript 41863 App.PostController = Ember.Controller.extend({ 41864 posts: Ember.inject.controller() 41865 }); 41866 ``` 41867 41868 This example will create a `posts` property on the `post` controller that 41869 looks up the `posts` controller in the container, making it easy to 41870 reference other controllers. This is functionally equivalent to: 41871 41872 ```javascript 41873 App.PostController = Ember.Controller.extend({ 41874 needs: 'posts', 41875 posts: Ember.computed.alias('controllers.posts') 41876 }); 41877 ``` 41878 41879 @method controller
41880 @since 1.10.0 41881 @for Ember.inject 41882 @param {String} name (optional) name of the controller to inject, defaults 41883 to the property's name 41884 @return {Ember.InjectedProperty} injection descriptor instance 41885 @public 41886 */ 41887 _emberRuntimeInject.createInjectionHelper('controller', controllerInjectionHelper); 41888 41889 exports.default = Controller; 41890}); 41891enifed('ember-runtime/copy', ['exports', 'ember-metal/debug', 'ember-runtime/system/object', 'ember-runtime/mixins/copyable'], function (exports, _emberMetalDebug, _emberRuntimeSystemObject, _emberRuntimeMixinsCopyable) { 41892 'use strict'; 41893 41894 exports.default = copy; 41895 41896 function _copy(obj, deep, seen, copies) { 41897 var ret, loc, key; 41898 41899 // primitive data types are immutable, just return them. 41900 if (typeof obj !== 'object' || obj === null) { 41901 return obj; 41902 } 41903 41904 // avoid cyclical loops 41905 if (deep && (loc = seen.indexOf(obj)) >= 0) { 41906 return copies[loc]; 41907 } 41908 41909 _emberMetalDebug.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', !(obj instanceof _emberRuntimeSystemObject.default) || _emberRuntimeMixinsCopyable.default && _emberRuntimeMixinsCopyable.default.detect(obj)); 41910 41911 // IMPORTANT: this specific test will detect a native array only. Any other 41912 // object will need to implement Copyable. 41913 if (Array.isArray(obj)) { 41914 ret = obj.slice(); 41915 41916 if (deep) { 41917 loc = ret.length; 41918 41919 while (--loc >= 0) {
41920 ret[loc] = _copy(ret[loc], deep, seen, copies); 41921 } 41922 } 41923 } else if (_emberRuntimeMixinsCopyable.default && _emberRuntimeMixinsCopyable.default.detect(obj)) { 41924 ret = obj.copy(deep, seen, copies); 41925 } else if (obj instanceof Date) { 41926 ret = new Date(obj.getTime()); 41927 } else { 41928 ret = {}; 41929 41930 for (key in obj) { 41931 // support Null prototype 41932 if (!Object.prototype.hasOwnProperty.call(obj, key)) { 41933 continue; 41934 } 41935 41936 // Prevents browsers that don't respect non-enumerability from 41937 // copying internal Ember properties 41938 if (key.substring(0, 2) === '__') { 41939 continue; 41940 } 41941 41942 ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; 41943 } 41944 } 41945 41946 if (deep) { 41947 seen.push(obj); 41948 copies.push(ret); 41949 } 41950 41951 return ret; 41952 } 41953 41954 /** 41955 Creates a shallow copy of the passed object. A deep copy of the object is 41956 returned if the optional `deep` argument is `true`. 41957 41958 If the passed object implements the `Ember.Copyable` interface, then this 41959 function will delegate to the object's `copy()` method and return the 41960 result. See `Ember.Copyable` for further details. 41961 41962 For primitive values (which are immutable in JavaScript), the passed object 41963 is simply returned. 41964 41965 @method copy 41966 @for Ember 41967 @param {Object} obj The object to clone 41968 @param {Boolean} [deep=false] If true, a deep copy of the object is made. 41969 @return {Object} The copied object 41970 @public 41971 */ 41972 41973 function copy(obj, deep) { 41974 // fast paths 41975 if ('object' !== typeof obj || obj === null) { 41976 return obj; // can't copy primitives 41977 } 41978 41979 if (_emberRuntimeMixinsCopyable.default && _emberRuntimeMixinsCopyable.default.detect(obj)) { 41980 return obj.copy(deep); 41981 } 41982 41983 return _copy(obj, deep, deep ? [] : null, deep ? [] : null); 41984 } 41985}); 41986enifed("ember-runtime/core", ["exports"], function (exports) { 41987 "use strict"; 41988}); 41989/** 41990@module ember 41991@submodule ember-runtime 41992*/ 41993enifed('ember-runtime/ext/function', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-metal/computed', 'ember-metal/mixin'], function (exports, _emberMetalCore, _emberMetalDebug, _emberMetalComputed, _emberMetalMixin) { 41994 /** 41995 @module ember 41996 @submodule ember-runtime 41997 */ 41998 41999 'use strict'; 42000 42001 var a_slice = Array.prototype.slice; 42002 var FunctionPrototype = Function.prototype; 42003 42004 if (_emberMetalCore.default.EXTEND_PROTOTYPES === true || _emberMetalCore.default.EXTEND_PROTOTYPES.Function) { 42005 /** 42006 The `property` extension of Javascript's Function prototype is available 42007 when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is 42008 `true`, which is the default. 42009 Computed properties allow you to treat a function like a property: 42010 ```javascript 42011 MyApp.President = Ember.Object.extend({ 42012 firstName: '', 42013 lastName: '', 42014 fullName: function() { 42015 return this.get('firstName') + ' ' + this.get('lastName'); 42016 }.property() // Call this flag to mark the function as a property 42017 }); 42018 var president = MyApp.President.create({ 42019 firstName: 'Barack', 42020 lastName: 'Obama' 42021 }); 42022 president.get('fullName'); // 'Barack Obama' 42023 ``` 42024 Treating a function like a property is useful because they can work with 42025 bindings, just like any other property. 42026 Many computed properties have dependencies on other properties. For 42027 example, in the above example, the `fullName` property depends on 42028 `firstName` and `lastName` to determine its value. You can tell Ember 42029 about these dependencies like this: 42030 ```javascript 42031 MyApp.President = Ember.Object.extend({ 42032 firstName: '', 42033 lastName: '', 42034 fullName: function() { 42035 return this.get('firstName') + ' ' + this.get('lastName'); 42036 // Tell Ember.js that this computed property depends on firstName 42037 // and lastName 42038 }.property('firstName', 'lastName') 42039 }); 42040 ``` 42041 Make sure you list these dependencies so Ember knows when to update 42042 bindings that connect to a computed property. Changing a dependency 42043 will not immediately trigger an update of the computed property, but 42044 will instead clear the cache so that it is updated when the next `get` 42045 is called on the property. 42046 See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed). 42047 @method property 42048 @for Function 42049 @public 42050 */ 42051 FunctionPrototype.property = function () { 42052 var ret = _emberMetalComputed.computed(this); 42053 // ComputedProperty.prototype.property expands properties; no need for us to
42054 // do so here. 42055 return ret.property.apply(ret, arguments); 42056 }; 42057 42058 /** 42059 The `observes` extension of Javascript's Function prototype is available 42060 when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is 42061 true, which is the default. 42062 You can observe property changes simply by adding the `observes` 42063 call to the end of your method declarations in classes that you write. 42064 For example: 42065 ```javascript 42066 Ember.Object.extend({ 42067 valueObserver: function() { 42068 // Executes whenever the "value" property changes 42069 }.observes('value') 42070 }); 42071 ``` 42072 In the future this method may become asynchronous. 42073 See `Ember.observer`. 42074 @method observes 42075 @for Function 42076 @public 42077 */ 42078 FunctionPrototype.observes = function () { 42079 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 42080 args[_key] = arguments[_key]; 42081 } 42082 42083 args.push(this); 42084 return _emberMetalMixin.observer.apply(this, args); 42085 }; 42086 42087 FunctionPrototype._observesImmediately = function () { 42088 _emberMetalDebug.assert('Immediate observers must observe internal properties only, ' + 'not properties on other objects.', function checkIsInternalProperty() { 42089 for (var i = 0, l = arguments.length; i < l; i++) { 42090 if (arguments[i].indexOf('.') !== -1) { 42091 return false; 42092 } 42093 } 42094 return true; 42095 }); 42096 42097 // observes handles property expansion 42098 return this.observes.apply(this, arguments); 42099 }; 42100 /** 42101 The `observesImmediately` extension of Javascript's Function prototype is 42102 available when `Ember.EXTEND_PROTOTYPES` or 42103 `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. 42104 You can observe property changes simply by adding the `observesImmediately` 42105 call to the end of your method declarations in classes that you write. 42106 For example: 42107 ```javascript 42108 Ember.Object.extend({ 42109 valueObserver: function() { 42110 // Executes immediately after the "value" property changes 42111 }.observesImmediately('value') 42112 }); 42113 ``` 42114 In the future, `observes` may become asynchronous. In this event, 42115 `observesImmediately` will maintain the synchronous behavior. 42116 See `Ember.immediateObserver`. 42117 @method observesImmediately 42118 @for Function 42119 @deprecated 42120 @private 42121 */ 42122 FunctionPrototype.observesImmediately = _emberMetalDebug.deprecateFunc('Function#observesImmediately is deprecated. Use Function#observes instead', { id: 'ember-runtime.ext-function', until: '3.0.0' }, FunctionPrototype._observesImmediately); 42123 42124 /** 42125 The `on` extension of Javascript's Function prototype is available 42126 when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is 42127 true, which is the default. 42128 You can listen for events simply by adding the `on` call to the end of 42129 your method declarations in classes or mixins that you write. For example: 42130 ```javascript 42131 Ember.Mixin.create({ 42132 doSomethingWithElement: function() { 42133 // Executes whenever the "didInsertElement" event fires 42134 }.on('didInsertElement') 42135 }); 42136 ``` 42137 See `Ember.on`. 42138 @method on 42139 @for Function 42140 @public 42141 */ 42142 FunctionPrototype.on = function () { 42143 var events = a_slice.call(arguments); 42144 this.__ember_listens__ = events; 42145 42146 return this; 42147 }; 42148 } 42149}); 42150// Ember.EXTEND_PROTOTYPES 42151enifed('ember-runtime/ext/rsvp', ['exports', 'ember-metal/core', 'require', 'ember-metal/debug', 'ember-metal/logger', 'ember-metal/run_loop', 'rsvp'], function (exports, _emberMetalCore, _require, _emberMetalDebug, _emberMetalLogger, _emberMetalRun_loop, _rsvp) { 42152 'use strict'; 42153 42154 exports.onerrorDefault = onerrorDefault; 42155 exports.after = after; 42156 42157 var testModuleName = 'ember-testing/test'; 42158 var Test; 42159 42160 var asyncStart = function () { 42161 if (_emberMetalCore.default.Test && _emberMetalCore.default.Test.adapter) { 42162 _emberMetalCore.default.Test.adapter.asyncStart(); 42163 } 42164 }; 42165 42166 var asyncEnd = function () { 42167 if (_emberMetalCore.default.Test && _emberMetalCore.default.Test.adapter) { 42168 _emberMetalCore.default.Test.adapter.asyncEnd(); 42169 } 42170 }; 42171 42172 _rsvp.configure('async', function (callback, promise) { 42173 var async = !_emberMetalRun_loop.default.currentRunLoop; 42174 42175 if (_emberMetalCore.default.testing && async) { 42176 asyncStart(); 42177 } 42178 42179 _emberMetalRun_loop.default.backburner.schedule('actions', function () { 42180 if (_emberMetalCore.default.testing && async) { 42181 asyncEnd(); 42182 } 42183 callback(promise); 42184 }); 42185 }); 42186 42187 function onerrorDefault(reason) { 42188 var error; 42189 42190 if (reason && reason.errorThrown) { 42191 // jqXHR provides this 42192 error = reason.errorThrown; 42193 if (typeof error === 'string') { 42194 error = new Error(error); 42195 } 42196 Object.defineProperty(error, '__reason_with_error_thrown__', { 42197 value: reason, 42198 enumerable: false 42199 }); 42200 } else { 42201 error = reason; 42202 } 42203
42204 if (error && error.name === "UnrecognizedURLError") { 42205 _emberMetalDebug.assert("The URL '" + error.message + "' did not match any routes in your application", false); 42206 return; 42207 } 42208 42209 if (error && error.name !== 'TransitionAborted') { 42210 if (_emberMetalCore.default.testing) { 42211 // ES6TODO: remove when possible 42212 if (!Test && _require.has(testModuleName)) { 42213 Test = _require.default(testModuleName)['default']; 42214 } 42215 42216 if (Test && Test.adapter) { 42217 Test.adapter.exception(error); 42218 _emberMetalLogger.default.error(error.stack); 42219 } else { 42220 throw error; 42221 } 42222 } else if (_emberMetalCore.default.onerror) { 42223 _emberMetalCore.default.onerror(error); 42224 } else { 42225 _emberMetalLogger.default.error(error.stack); 42226 } 42227 } 42228 } 42229 42230 function after(cb) { 42231 _emberMetalRun_loop.default.schedule(_emberMetalRun_loop.default.queues[_emberMetalRun_loop.default.queues.length - 1], cb); 42232 } 42233 42234 _rsvp.on('error', onerrorDefault); 42235 _rsvp.configure('after', after); 42236 42237 exports.default = _rsvp; 42238}); 42239enifed('ember-runtime/ext/string', ['exports', 'ember-metal/core', 'ember-runtime/system/string'], function (exports, _emberMetalCore, _emberRuntimeSystemString) { 42240 /** 42241 @module ember 42242 @submodule ember-runtime 42243 */ 42244 42245 'use strict'; 42246 42247 var StringPrototype = String.prototype; 42248 42249 if (_emberMetalCore.default.EXTEND_PROTOTYPES === true || _emberMetalCore.default.EXTEND_PROTOTYPES.String) { 42250 /** 42251 See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt). 42252 @method fmt 42253 @for String 42254 @private 42255 @deprecated 42256 */ 42257 StringPrototype.fmt = function () { 42258 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 42259 args[_key] = arguments[_key]; 42260 } 42261 42262 return _emberRuntimeSystemString.fmt(this, args); 42263 }; 42264 42265 /** 42266 See [Ember.String.w](/api/classes/Ember.String.html#method_w). 42267 @method w 42268 @for String 42269 @private 42270 */ 42271 StringPrototype.w = function () { 42272 return _emberRuntimeSystemString.w(this); 42273 }; 42274 42275 /** 42276 See [Ember.String.loc](/api/classes/Ember.String.html#method_loc). 42277 @method loc 42278 @for String 42279 @private 42280 */ 42281 StringPrototype.loc = function () { 42282 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 42283 args[_key2] = arguments[_key2]; 42284 } 42285 42286 return _emberRuntimeSystemString.loc(this, args); 42287 }; 42288 42289 /** 42290 See [Ember.String.camelize](/api/classes/Ember.String.html#method_camelize). 42291 @method camelize 42292 @for String 42293 @private 42294 */ 42295 StringPrototype.camelize = function () { 42296 return _emberRuntimeSystemString.camelize(this); 42297 }; 42298 42299 /** 42300 See [Ember.String.decamelize](/api/classes/Ember.String.html#method_decamelize). 42301 @method decamelize 42302 @for String 42303 @private 42304 */ 42305 StringPrototype.decamelize = function () { 42306 return _emberRuntimeSystemString.decamelize(this); 42307 }; 42308 42309 /** 42310 See [Ember.String.dasherize](/api/classes/Ember.String.html#method_dasherize). 42311 @method dasherize 42312 @for String 42313 @private 42314 */ 42315 StringPrototype.dasherize = function () { 42316 return _emberRuntimeSystemString.dasherize(this); 42317 }; 42318 42319 /** 42320 See [Ember.String.underscore](/api/classes/Ember.String.html#method_underscore). 42321 @method underscore 42322 @for String 42323 @private 42324 */ 42325 StringPrototype.underscore = function () { 42326 return _emberRuntimeSystemString.underscore(this); 42327 }; 42328 42329 /** 42330 See [Ember.String.classify](/api/classes/Ember.String.html#method_classify). 42331 @method classify 42332 @for String 42333 @private 42334 */ 42335 StringPrototype.classify = function () { 42336 return _emberRuntimeSystemString.classify(this); 42337 }; 42338 42339 /** 42340 See [Ember.String.capitalize](/api/classes/Ember.String.html#method_capitalize). 42341 @method capitalize 42342 @for String 42343 @private 42344 */ 42345 StringPrototype.capitalize = function () { 42346 return _emberRuntimeSystemString.capitalize(this); 42347 }; 42348 } 42349}); 42350// Ember.EXTEND_PROTOTYPES 42351enifed('ember-runtime/index', ['exports', 'ember-metal', 'ember-runtime/is-equal', 'ember-runtime/compare', 'ember-runtime/copy', 'ember-runtime/inject', 'ember-runtime/system/namespace', 'ember-runtime/system/object', 'ember-runtime/system/container', 'ember-runtime/system/array_proxy', 'ember-runtime/system/object_proxy', 'ember-runtime/system/core_object', 'ember-runtime/system/native_array', 'ember-runtime/system/string', 'ember-runtime/system/lazy_load', 'ember-runtime/mixins/array', 'ember-runtime/mixins/comparable', 'ember-runtime/mixins/copyable', 'ember-runtime/mixins/enumerable', 'ember-runtime/mixins/freezable', 'ember-runtime/mixins/-proxy', 'ember-runtime/mixins/observable', 'ember-runtime/mixins/action_handler', 'ember-runtime/mixins/mutable_enumerable', 'ember-runtime/mixins/mutable_array', 'ember-runtime/mixins/target_action_support', 'ember-runtime/mixins/evented', 'ember-runtime/mixins/promise_proxy', 'ember-runtime/computed/reduce_computed_macros', 'ember-runtime/controllers/controller', 'ember-runtime/mixins/controller', 'ember-runtime/system/service', 'ember-runtime/ext/rsvp', 'ember-runtime/ext/string', 'ember-runtime/ext/function', 'ember-runtime/utils', 'ember-metal/features', 'ember-runtime/mixins/registry_proxy', 'ember-runtime/mixins/container_proxy', 'ember-runtime/string_registry'], function (exports, _emberMetal, _emberRuntimeIsEqual, _emberRuntimeCompare, _emberRuntimeCopy, _emberRuntimeInject, _emberRuntimeSystemNamespace, _emberRuntimeSystemObject, _emberRuntimeSystemContainer, _emberRuntimeSystemArray_proxy, _emberRuntimeSystemObject_proxy, _emberRuntimeSystemCore_object, _emberRuntimeSystemNative_array, _emberRuntimeSystemString, _emberRuntimeSystemLazy_load, _emberRuntimeMixinsArray, _emberRuntimeMixinsComparable, _emberRuntimeMixinsCopyable, _emberRuntimeMixinsEnumerable, _emberRuntimeMixinsFreezable, _emberRuntimeMixinsProxy, _emberRuntimeMixinsObservable, _emberRuntimeMixinsAction_handler, _emberRuntimeMixinsMutable_enumerable, _emberRuntimeMixinsMutable_array, _emberRuntimeMixinsTarget_action_support, _emberRuntimeMixinsEvented, _emberRuntimeMixinsPromise_proxy, _emberRuntimeComputedReduce_computed_macros, _emberRuntimeControllersController, _emberRuntimeMixinsController, _emberRuntimeSystemService, _emberRuntimeExtRsvp, _emberRuntimeExtString, _emberRuntimeExtFunction, _emberRuntimeUtils, _emberMetalFeatures, _emberRuntimeMixinsReg
42351istry_proxy, _emberRuntimeMixinsContainer_proxy, _emberRuntimeString_registry) { 42352 /** 42353 @module ember 42354 @submodule ember-runtime 42355 */ 42356 42357 // BEGIN IMPORTS 42358 'use strict'; 42359 42360 // END IMPORTS 42361 42362 // BEGIN EXPORTS 42363 _emberMetal.default.compare = _emberRuntimeCompare.default; 42364 _emberMetal.default.copy = _emberRuntimeCopy.default; 42365 _emberMetal.default.isEqual = _emberRuntimeIsEqual.default; 42366 42367 _emberMetal.default.inject = _emberRuntimeInject.default; 42368 42369 _emberMetal.default.Array = _emberRuntimeMixinsArray.default; 42370 42371 _emberMetal.default.Comparable = _emberRuntimeMixinsComparable.default; 42372 _emberMetal.default.Copyable = _emberRuntimeMixinsCopyable.default; 42373 42374 _emberMetal.default.Freezable = _emberRuntimeMixinsFreezable.Freezable; 42375 _emberMetal.default.FROZEN_ERROR = _emberRuntimeMixinsFreezable.FROZEN_ERROR; 42376 42377 _emberMetal.default.MutableEnumerable = _emberRuntimeMixinsMutable_enumerable.default; 42378 _emberMetal.default.MutableArray = _emberRuntimeMixinsMutable_array.default; 42379 42380 _emberMetal.default.TargetActionSupport = _emberRuntimeMixinsTarget_action_support.default; 42381 _emberMetal.default.Evented = _emberRuntimeMixinsEvented.default; 42382 42383 _emberMetal.default.PromiseProxyMixin = _emberRuntimeMixinsPromise_proxy.default; 42384 42385 _emberMetal.default.Observable = _emberRuntimeMixinsObservable.default; 42386 42387 _emberMetal.default.typeOf = _emberRuntimeUtils.typeOf; 42388 _emberMetal.default.isArray = _emberRuntimeUtils.isArray; 42389 42390 // ES6TODO: this seems a less than ideal way/place to add properties to Ember.computed 42391 var EmComputed = _emberMetal.default.computed; 42392 42393 EmComputed.sum = _emberRuntimeComputedReduce_computed_macros.sum; 42394 EmComputed.min = _emberRuntimeComputedReduce_computed_macros.min; 42395 EmComputed.max = _emberRuntimeComputedReduce_computed_macros.max; 42396 EmComputed.map = _emberRuntimeComputedReduce_computed_macros.map; 42397 EmComputed.sort = _emberRuntimeComputedReduce_computed_macros.sort; 42398 EmComputed.setDiff = _emberRuntimeComputedReduce_computed_macros.setDiff; 42399 EmComputed.mapBy = _emberRuntimeComputedReduce_computed_macros.mapBy; 42400 EmComputed.filter = _emberRuntimeComputedReduce_computed_macros.filter; 42401 EmComputed.filterBy = _emberRuntimeComputedReduce_computed_macros.filterBy; 42402 EmComputed.uniq = _emberRuntimeComputedReduce_computed_macros.uniq; 42403 EmComputed.union = _emberRuntimeComputedReduce_computed_macros.union; 42404 EmComputed.intersect = _emberRuntimeComputedReduce_computed_macros.intersect; 42405 EmComputed.collect = _emberRuntimeComputedReduce_computed_macros.collect; 42406 42407 _emberMetal.default.String = _emberRuntimeSystemString.default; 42408 _emberMetal.default.Object = _emberRuntimeSystemObject.default; 42409 _emberMetal.default.Container = _emberRuntimeSystemContainer.Container; 42410 _emberMetal.default.Registry = _emberRuntimeSystemContainer.Registry; 42411 42412 _emberMetal.default.getOwner = _emberRuntimeSystemContainer.getOwner; 42413 _emberMetal.default.setOwner = _emberRuntimeSystemContainer.setOwner; 42414 42415 _emberMetal.default._RegistryProxyMixin = _emberRuntimeMixinsRegistry_proxy.default; 42416 _emberMetal.default._ContainerProxyMixin = _emberRuntimeMixinsContainer_proxy.default; 42417 42418 _emberMetal.default.Namespace = _emberRuntimeSystemNamespace.default; 42419 _emberMetal.default.Enumerable = _emberRuntimeMixinsEnumerable.default; 42420 _emberMetal.default.ArrayProxy = _emberRuntimeSystemArray_proxy.default; 42421 _emberMetal.default.ObjectProxy = _emberRuntimeSystemObject_proxy.default; 42422 _emberMetal.default.ActionHandler = _emberRuntimeMixinsAction_handler.default; 42423 _emberMetal.default.CoreObject = _emberRuntimeSystemCore_object.default; 42424 _emberMetal.default.NativeArray = _emberRuntimeSystemNative_array.default; 42425 // ES6TODO: Currently we must rely on the global from ember-metal/core to avoid circular deps 42426 // Ember.A = A; 42427 _emberMetal.default.onLoad = _emberRuntimeSystemLazy_load.onLoad;
42428 _emberMetal.default.runLoadHooks = _emberRuntimeSystemLazy_load.runLoadHooks; 42429 42430 _emberMetal.default.Controller = _emberRuntimeControllersController.default; 42431 _emberMetal.default.ControllerMixin = _emberRuntimeMixinsController.default; 42432 42433 _emberMetal.default.Service = _emberRuntimeSystemService.default; 42434 42435 _emberMetal.default._ProxyMixin = _emberRuntimeMixinsProxy.default; 42436 42437 _emberMetal.default.RSVP = _emberRuntimeExtRsvp.default; 42438 // END EXPORTS 42439 42440 /** 42441 Defines the hash of localized strings for the current language. Used by 42442 the `Ember.String.loc()` helper. To localize, add string values to this 42443 hash. 42444 42445 @property STRINGS 42446 @for Ember 42447 @type Object 42448 @private 42449 */ 42450 Object.defineProperty(_emberMetal.default, 'STRINGS', { 42451 configurable: false, 42452 get: _emberRuntimeString_registry.getStrings, 42453 set: _emberRuntimeString_registry.setStrings 42454 }); 42455 42456 exports.default = _emberMetal.default; 42457}); 42458// just for side effect of extending Ember.RSVP 42459// just for side effect of extending String.prototype 42460// just for side effect of extending Function.prototype 42461enifed('ember-runtime/inject', ['exports', 'ember-metal/debug', 'ember-metal/injected_property'], function (exports, _emberMetalDebug, _emberMetalInjected_property) { 42462 'use strict'; 42463 42464 exports.default = inject; 42465 exports.createInjectionHelper = createInjectionHelper; 42466 exports.validatePropertyInjections = validatePropertyInjections; 42467 42468 /** 42469 Namespace for injection helper methods. 42470 42471 @class inject 42472 @namespace Ember 42473 @static 42474 @public 42475 */ 42476 42477 function inject() { 42478 _emberMetalDebug.assert('Injected properties must be created through helpers, see \'' + Object.keys(inject).join('"', '"') + '\''); 42479 } 42480 42481 // Dictionary of injection validations by type, added to by `createInjectionHelper` 42482 var typeValidators = {}; 42483 42484 /** 42485 This method allows other Ember modules to register injection helpers for a 42486 given container type. Helpers are exported to the `inject` namespace as the 42487 container type itself. 42488 42489 @private 42490 @method createInjectionHelper 42491 @since 1.10.0 42492 @for Ember 42493 @param {String} type The container type the helper will inject 42494 @param {Function} validator A validation callback that is executed at mixin-time 42495 */ 42496 42497 function createInjectionHelper(type, validator) { 42498 typeValidators[type] = validator; 42499 42500 inject[type] = function (name) { 42501 return new _emberMetalInjected_property.default(type, name); 42502 }; 42503 } 42504 42505 /** 42506 Validation function that runs per-type validation functions once for each 42507 injected type encountered. 42508 42509 @private 42510 @method validatePropertyInjections 42511 @since 1.10.0 42512 @for Ember 42513 @param {Object} factory The factory object 42514 */ 42515 42516 function validatePropertyInjections(factory) { 42517 var proto = factory.proto(); 42518 var types = []; 42519 var key, desc, validator, i, l; 42520 42521 for (key in proto) { 42522 desc = proto[key]; 42523 if (desc instanceof _emberMetalInjected_property.default && types.indexOf(desc.type) === -1) { 42524 types.push(desc.type); 42525 } 42526 } 42527 42528 if (types.length) { 42529 for (i = 0, l = types.length; i < l; i++) { 42530 validator = typeValidators[types[i]]; 42531 42532 if (typeof validator === 'function') { 42533 validator(factory); 42534 } 42535 } 42536 } 42537 42538 return true; 42539 } 42540}); 42541enifed('ember-runtime/is-equal', ['exports'], function (exports) { 42542 /** 42543 Compares two objects, returning true if they are equal. 42544 42545 ```javascript 42546 Ember.isEqual('hello', 'hello'); // true 42547 Ember.isEqual(1, 2); // false 42548 ``` 42549 42550 `isEqual` is a more specific comparison than a triple equal comparison. 42551 It will call the `isEqual` instance method on the objects being 42552 compared, allowing finer control over when objects should be considered 42553 equal to each other. 42554 42555 ```javascript 42556 let Person = Ember.Object.extend({ 42557 isEqual(other) { return this.ssn == other.ssn; } 42558 }); 42559 42560 let personA = Person.create({name: 'Muhammad Ali', ssn: '123-45-6789'}); 42561 let personB = Person.create({name: 'Cassius Clay', ssn: '123-45-6789'}); 42562 42563 Ember.isEqual(personA, personB); // true 42564 ``` 42565 42566 Due to the expense of array comparisons, collections will never be equal to 42567 each other even if each of their items are equal to each other. 42568 42569 ```javascript 42570 Ember.isEqual([4, 2], [4, 2]); // false 42571 ``` 42572 42573 @method isEqual 42574 @for Ember 42575 @param {Object} a first object to compare 42576 @param {Object} b second object to compare 42577 @return {Boolean} 42578 @public 42579 */ 42580 'use strict'; 42581 42582 exports.default = isEqual; 42583 42584 function isEqual(a, b) { 42585 if (a && typeof a.isEqual === 'function') { 42586 return a.isEqual(b); 42587 } 42588 42589 if (a instanceof Date && b instanceof Date) { 42590 return a.getTime() === b.getTime(); 42591 } 42592 42593 return a === b; 42594 } 42595}); 42596enifed('ember-runtime/mixins/-proxy', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/meta', 'ember-metal/observer', 'ember-metal/property_events', 'ember-metal/computed', 'ember-metal/properties', 'ember-metal/mixin'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalMeta, _emberMetalObserver, _emberMetalProperty_events, _emberMetalComputed, _emberMetalProperties, _emberMetalMixin) { 42597 /** 42598 @module ember 42599 @submodule ember-runtime 42600 */ 42601 42602 'use strict'; 42603 42604 function contentPropertyWillChange(content, contentKey) { 42605 var key = contentKey.slice(8); // remove "content." 42606 if (key in this) { 42607 return; 42608 } // if shadowed in proxy 42609 _emberMetalProperty_events.propertyWillChange(this, key); 42610 } 42611 42612 function contentPropertyDidChange(content, contentKey) { 42613 var key = contentKey.slice(8); // remove "content." 42614 if (key in this) { 42615 return; 42616 } // if shadowed in proxy 42617 _emberMetalProperty_events.propertyDidChange(this, key); 42618 } 42619 42620 /** 42621 `Ember.ProxyMixin` forwards all properties not defined by the proxy itself 42622 to a proxied `content` object. See Ember.ObjectProxy for more details. 42623 42624 @class ProxyMixin 42625 @namespace Ember 42626 @private 42627 */ 42628 exports.default = _emberMetalMixin.Mixin.create({ 42629 /** 42630 The object whose properties will be forwarded. 42631 @property content 42632 @type Ember.Object 42633 @default null 42634 @private 42635 */ 42636 content: null, 42637 _contentDidChange: _emberMetalMixin.observer('content', function () { 42638 _emberMetalDebug.assert('Can\'t set Proxy\'s content to itself', _emberMetalProperty_get.get(this, 'content') !== this); 42639 }), 42640 42641 isTruthy: _emberMetalComputed.computed.bool('content'), 42642 42643 _debugContainerKey: null, 42644 42645 willWatchProperty: function (key) { 42646 var contentKey = 'content.' + key; 42647 _emberMetalObserver._addBeforeObserver(this, contentKey, null, contentPropertyWillChange); 42648 _emberMetalObserver.addObserver(this, contentKey, null, contentPropertyDidChange); 42649 }, 42650 42651 didUnwatchProperty: function (key) { 42652 var contentKey = 'content.' + key; 42653 _emberMetalObserver._removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); 42654 _emberMetalObserver.removeObserver(this, contentKey, null, contentPropertyDidChange); 42655 }, 42656 42657 unknownProperty: function (key) { 42658 var content = _emberMetalProperty_get.get(this, 'content'); 42659 if (content) { 42660 _emberMetalDebug.deprecate('You attempted to access `' + key + '` from `' + this + '`, but object proxying is deprecated. Please use `model.' + key + '` instead.', !this.isController, { id: 'ember-runtime.controller-proxy', until: '3.0.0' }); 42661 return _emberMetalProperty_get.get(content, key); 42662 } 42663 }, 42664 42665 setUnknownProperty: function (key, value) { 42666 var m = _emberMetalMeta.meta(this); 42667 if (m.proto === this) { 42668 // if marked as prototype then just defineProperty 42669 // rather than delegate 42670 _emberMetalProperties.defineProperty(this, key, null, value); 42671 return value; 42672 } 42673 42674 var content = _emberMetalProperty_get.get(this, 'content'); 42675 _emberMetalDebug.assert('Cannot delegate set(\'' + key + '\', ' + value + ') to the \'content\' property of object proxy ' + this + ': its \'content\' is undefined.', content); 42676 42677 _emberMetalDebug.deprecate('You attempted to set `' + key + '` from `' + this + '`, but object proxying is deprecated. Please use `model.' + key + '` instead.', !this.isController, { id: 'ember-runtime.controller-proxy', until: '3.0.0' }); 42678 return _emberMetalProperty_set.set(content, key, value); 42679 } 42680 42681 }); 42682}); 42683enifed('ember-runtime/mixins/action_handler', ['exports', 'ember-metal/debug', 'ember-metal/mixin', 'ember-metal/property_get'], function (exports, _emberMetalDebug, _emberMetalMixin, _emberMetalProperty_get) { 42684 /** 42685 @module ember 42686 @submodule ember-runtime 42687 */ 42688 42689 'use strict'; 42690 42691 exports.deprecateUnderscoreActions = deprecateUnderscoreActions; 42692 42693 /** 42694 `Ember.ActionHandler` is available on some familiar classes including 42695 `Ember.Route`, `Ember.View`, `Ember.Component`, and `Ember.Controller`. 42696 (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`, 42697 and `Ember.Route` and available to the above classes through 42698 inheritance.) 42699 42700 @class ActionHandler 42701 @namespace Ember 42702 @private 42703 */ 42704 var ActionHandler = _emberMetalMixin.Mixin.create({ 42705 mergedProperties: ['actions'], 42706 42707 /** 42708 The collection of functions, keyed by name, available on this 42709 `ActionHandler` as action targets. 42710 These functions will be invoked when a matching `{{action}}` is triggered 42711 from within a template and the application's current route is this route. 42712 Actions can also be invoked from other parts of your application 42713 via `ActionHandler#send`. 42714 The `actions` hash will inherit action handlers from 42715 the `actions` hash defined on extended parent classes 42716 or mixins rather than just replace the entire hash, e.g.: 42717 ```js 42718 App.CanDisplayBanner = Ember.Mixin.create({ 42719 actions: { 42720 displayBanner: function(msg) { 42721 // ... 42722 } 42723 } 42724 }); 42725 App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, { 42726 actions: { 42727 playMusic: function() { 42728 // ... 42729 } 42730 } 42731 }); 42732 // `WelcomeRoute`, when active, will be able to respond 42733 // to both actions, since the actions hash is merged rather 42734 // then replaced when extending mixins / parent classes. 42735 this.send('displayBanner'); 42736 this.send('playMusic'); 42737 ``` 42738 Within a Controller, Route, View or Component's action handler, 42739 the value of the `this` context is the Controller, Route, View or 42740 Component object: 42741 ```js 42742 App.SongRoute = Ember.Route.extend({ 42743 actions: { 42744 myAction: function() { 42745 this.controllerFor("song"); 42746 this.transitionTo("other.route"); 42747 ... 42748 } 42749 } 42750 }); 42751 ``` 42752 It is also possible to call `this._super(...arguments)` from within an 42753 action handler if it overrides a handler defined on a parent 42754 class or mixin: 42755 Take for example the following routes: 42756 ```js 42757 App.DebugRoute = Ember.Mixin.create({ 42758 actions: { 42759 debugRouteInformation: function() { 42760 console.debug("trololo"); 42761 } 42762 } 42763 }); 42764 App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, { 42765 actions: { 42766 debugRouteInformation: function() { 42767 // also call the debugRouteInformation of mixed in App.DebugRoute 42768 this._super(...arguments); 42769 // show additional annoyance 42770 window.alert(...); 42771 } 42772 } 42773 }); 42774 ``` 42775 ## Bubbling 42776 By default, an action will stop bubbling once a handler defined 42777 on the `actions` hash handles it. To continue bubbling the action, 42778 you must return `true` from the handler: 42779 ```js 42780 App.Router.map(function() { 42781 this.route("album", function() { 42782 this.route("song"); 42783 }); 42784 }); 42785 App.AlbumRoute = Ember.Route.extend({ 42786 actions: { 42787 startPlaying: function() { 42788 } 42789 } 42790 }); 42791 App.AlbumSongRoute = Ember.Route.extend({ 42792 actions: { 42793 startPlaying: function() { 42794 // ... 42795 if (actionShouldAlsoBeTriggeredOnParentRoute) { 42796 return true; 42797 } 42798 } 42799 } 42800 }); 42801 ``` 42802 @property actions 42803 @type Object 42804 @default null 42805 @public 42806 */ 42807 42808 /** 42809 Triggers a named action on the `ActionHandler`. Any parameters 42810 supplied after the `actionName` string will be passed as arguments 42811 to the action target function. 42812 If the `ActionHandler` has its `target` property set, actions may 42813 bubble to the `target`. Bubbling happens when an `actionName` can 42814 not be found in the `ActionHandler`'s `actions` hash or if the 42815 action target function returns `true`. 42816 Example 42817 ```js 42818 App.WelcomeRoute = Ember.Route.extend({ 42819 actions: { 42820 playTheme: function() { 42821 this.send('playMusic', 'theme.mp3'); 42822 }, 42823 playMusic: function(track) { 42824 // ... 42825 } 42826 } 42827 }); 42828 ``` 42829 @method send 42830 @param {String} actionName The action to trigger 42831 @param {*} context a context to send with the action 42832 @public 42833 */ 42834 send: function (actionName) { 42835 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 42836 args[_key - 1] = arguments[_key]; 42837 } 42838 42839 var target; 42840 42841 if (this.actions && this.actions[actionName]) { 42842 var shouldBubble = this.actions[actionName].apply(this, args) === true; 42843 if (!shouldBubble) { 42844 return; 42845 } 42846 } 42847 42848 if (target = _emberMetalProperty_get.get(this, 'target')) { 42849 var _target; 42850 42851 _emberMetalDebug.assert('The `target` for ' + this + ' (' + target + ') does not have a `send` method', typeof target.send === 'function'); 42852 (_target = target).send.apply(_target, arguments); 42853 } 42854 }, 42855 42856 willMergeMixin: function (props) { 42857 _emberMetalDebug.assert('Specifying `_actions` and `actions` in the same mixin is not supported.', !props.actions || !props._actions); 42858 42859 if (props._actions) { 42860 _emberMetalDebug.deprecate('Specifying actions in `_actions` is deprecated, please use `actions` instead.', false, { id: 'ember-runtime.action-handler-_actions', until: '3.0.0' }); 42861 42862 props.actions = props._actions; 42863 delete props._actions; 42864 } 42865 } 42866 }); 42867 42868 exports.default = ActionHandler; 42869 42870 function deprecateUnderscoreActions(factory) { 42871 Object.defineProperty(factory.prototype, '_actions', { 42872 configurable: true, 42873 enumerable: false, 42874 set: function (value) { 42875 _emberMetalDebug.assert('You cannot set `_actions` on ' + this + ', please use `actions` instead.'); 42876 }, 42877 get: function () { 42878 _emberMetalDebug.deprecate('Usage of `_actions` is deprecated, use `actions` instead.', false, { id: 'ember-runtime.action-handler-_actions', until: '3.0.0' }); 42879 return _emberMetalProperty_get.get(this, 'actions'); 42880 } 42881 }); 42882 } 42883}); 42884enifed('ember-runtime/mixins/array', ['exports', 'ember-metal/core', 'ember-metal/property_get', 'ember-metal/computed', 'ember-metal/is_none', 'ember-runtime/mixins/enumerable', 'ember-metal/mixin', 'ember-metal/property_events', 'ember-metal/events', 'ember-runtime/system/each_proxy'], function (exports, _emberMetalCore, _emberMetalProperty_get, _emberMetalComputed, _emberMetalIs_none, _emberRuntimeMixinsEnumerable, _emberMetalMixin, _emberMetalProperty_events, _emberMetalEvents, _emberRuntimeSystemEach_proxy) { 42885 /** 42886 @module ember 42887 @submodule ember-runtime 42888 */ 42889 42890 // .......................................................... 42891 // HELPERS 42892 // 42893 'use strict'; 42894 42895 exports.addArrayObserver = addArrayObserver; 42896 exports.removeArrayObserver = removeArrayObserver; 42897 exports.objectAt = objectAt; 42898 42899 function arrayObserversHelper(obj, target, opts, operation, notify) { 42900 var willChange = opts && opts.willChange || 'arrayWillChange'; 42901 var didChange = opts && opts.didChange || 'arrayDidChange'; 42902 var hasObservers = _em
42902berMetalProperty_get.get(obj, 'hasArrayObservers'); 42903 42904 if (hasObservers === notify) { 42905 _emberMetalProperty_events.propertyWillChange(obj, 'hasArrayObservers'); 42906 } 42907 42908 operation(obj, '@array:before', target, willChange); 42909 operation(obj, '@array:change', target, didChange); 42910 42911 if (hasObservers === notify) { 42912 _emberMetalProperty_events.propertyDidChange(obj, 'hasArrayObservers'); 42913 } 42914 42915 return obj; 42916 } 42917 42918 function addArrayObserver(array, target, opts) { 42919 return arrayObserversHelper(array, target, opts, _emberMetalEvents.addListener, false); 42920 } 42921 42922 function removeArrayObserver(array, target, opts) { 42923 return arrayObserversHelper(array, target, opts, _emberMetalEvents.removeListener, true); 42924 } 42925 42926 function objectAt(content, idx) { 42927 if (content.objectAt) { 42928 return content.objectAt(idx); 42929 } 42930 42931 return content[idx]; 42932 } 42933 42934 // .......................................................... 42935 // ARRAY 42936 // 42937 /** 42938 This mixin implements Observer-friendly Array-like behavior. It is not a 42939 concrete implementation, but it can be used up by other classes that want 42940 to appear like arrays. 42941 42942 For example, ArrayProxy is a concrete classes that can 42943 be instantiated to implement array-like behavior. Both of these classes use 42944 the Array Mixin by way of the MutableArray mixin, which allows observable 42945 changes to be made to the underlying array. 42946 42947 Unlike `Ember.Enumerable,` this mixin defines methods specifically for 42948 collections that provide index-ordered access to their contents. When you 42949 are designing code that needs to accept any kind of Array-like object, you 42950 should use these methods instead of Array primitives because these will 42951 properly notify observers of changes to the array. 42952 42953 Although these methods are efficient, they do add a layer of indirection to 42954 your application so it is a good idea to use them only when you need the 42955 flexibility of using both true JavaScript arrays and "virtual" arrays such 42956 as controllers and collections. 42957 42958 You can use the methods defined in this module to access and modify array 42959 contents in a KVO-friendly way. You can also be notified whenever the 42960 membership of an array changes by using `.observes('myArray.[]')`. 42961 42962 To support `Ember.Array` in your own class, you must override two 42963 primitives to use it: `length()` and `objectAt()`. 42964 42965 Note that the Ember.Array mixin also incorporates the `Ember.Enumerable` 42966 mixin. All `Ember.Array`-like objects are also enumerable. 42967 42968 @class Array 42969 @namespace Ember 42970 @uses Ember.Enumerable 42971 @since Ember 0.9.0 42972 @public 42973 */ 42974 exports.default = _emberMetalMixin.Mixin.create(_emberRuntimeMixinsEnumerable.default, { 42975 42976 /** 42977 __Required.__ You must implement this method to apply this mixin. 42978 Your array must support the `length` property. Your replace methods should 42979 set this property whenever it changes. 42980 @property {Number} length 42981 @public 42982 */ 42983 length: null, 42984 42985 /** 42986 Returns the object at the given `index`. If the given `index` is negative 42987 or is greater or equal than the array length, returns `undefined`. 42988 This is one of the primitives you must implement to support `Ember.Array`. 42989 If your object supports retrieving the value of an array item using `get()` 42990 (i.e. `myArray.get(0)`), then you do not need to implement this method 42991 yourself. 42992 ```javascript 42993 var arr = ['a', 'b', 'c', 'd']; 42994 arr.objectAt(0); // 'a' 42995 arr.objectAt(3); // 'd' 42996 arr.objectAt(-1); // undefined 42997 arr.objectAt(4); // undefined 42998 arr.objectAt(5); // undefined 42999 ``` 43000 @method objectAt 43001 @param {Number} idx The index of the item to return. 43002 @return {*} item at index or undefined 43003 @public 43004 */ 43005 objectAt: function (idx) { 43006 if (idx < 0 || idx >= _emberMetalProperty_get.get(this, 'length')) { 43007 return undefined; 43008 } 43009 43010 return _emberMetalProperty_get.get(this, idx); 43011 }, 43012 43013 /** 43014 This returns the objects at the specified indexes, using `objectAt`. 43015 ```javascript 43016 var arr =Â ['a', 'b', 'c', 'd']; 43017 arr.objectsAt([0, 1, 2]); // ['a', 'b', 'c'] 43018 arr.objectsAt([2, 3, 4]); // ['c', 'd', undefined] 43019 ``` 43020 @method objectsAt 43021 @param {Array} indexes An array of indexes of items to return. 43022 @return {Array} 43023 @public 43024 */ 43025 objectsAt: function (indexes) { 43026 var _this = this; 43027 43028 return indexes.map(function (idx) { 43029 return objectAt(_this, idx); 43030 }); 43031 }, 43032 43033 // overrides Ember.Enumerable version 43034 nextObject: function (idx) { 43035 return objectAt(this, idx); 43036 }, 43037 43038 /** 43039 This is the handler for the special array content property. If you get 43040 this property, it will return this. If you set this property to a new 43041 array, it will replace the current content. 43042 This property overrides the default property defined in `Ember.Enumerable`. 43043 @property [] 43044 @return this 43045 @public 43046 */ 43047 '[]': _emberMetalComputed.computed({ 43048 get: function (key) { 43049 return this; 43050 }, 43051 set: function (key, value) { 43052 this.replace(0, _emberMetalProperty_get.get(this, 'length'), value); 43053 return this; 43054 } 43055 }), 43056 43057 firstObject: _emberMetalComputed.computed(function () { 43058 return objectAt(this, 0); 43059 }), 43060 43061 lastObject: _emberMetalComputed.computed(function () { 43062 return objectAt(this, _emberMetalProperty_get.get(this, 'length') - 1); 43063 }), 43064 43065 // optimized version from Enumerable 43066 contains: function (obj) { 43067 return this.indexOf(obj) >= 0; 43068 }, 43069 43070 // Add any extra methods to Ember.Array that are native to the built-in Array. 43071 /** 43072 Returns a new array that is a slice of the receiver. This implementation 43073 uses the observable array methods to retrieve the objects for the new 43074 slice. 43075 ```javascript 43076 var arr = ['red', 'green', 'blue']; 43077 arr.slice(0); // ['red', 'green', 'blue'] 43078 arr.slice(0, 2); // ['red', 'green'] 43079 arr.slice(1, 100); // ['green', 'blue'] 43080 ``` 43081 @method slice 43082 @param {Number} beginIndex (Optional) index to begin slicing from. 43083 @param {Number} endIndex (Optional) index to end the slice at (but not included). 43084 @return {Array} New array with specified slice 43085 @public 43086 */ 43087 slice: function (beginIndex, endIndex) { 43088 var ret = _emberMetalCore.default.A(); 43089 var length = _emberMetalProperty_get.get(this, 'length'); 43090 43091 if (_emberMetalIs_none.default(beginIndex)) { 43092 beginIndex = 0; 43093 } 43094 43095 if (_emberMetalIs_none.default(endIndex) || endIndex > length) { 43096 endIndex = length; 43097 } 43098 43099 if (beginIndex < 0) { 43100 beginIndex = length + beginIndex; 43101 } 43102 43103 if (endIndex < 0) { 43104 endIndex = length + endIndex; 43105 } 43106 43107 while (beginIndex < endIndex) { 43108 ret[ret.length] = objectAt(this, beginIndex++); 43109 } 43110 43111 return ret; 43112 }, 43113 43114 /** 43115 Returns the index of the given object's first occurrence. 43116 If no `startAt` argument is given, the starting location to
43117 search is 0. If it's negative, will count backward from 43118 the end of the array. Returns -1 if no match is found. 43119 ```javascript 43120 var arr = ['a', 'b', 'c', 'd', 'a']; 43121 arr.indexOf('a'); // 0 43122 arr.indexOf('z'); // -1 43123 arr.indexOf('a', 2); // 4 43124 arr.indexOf('a', -1); // 4 43125 arr.indexOf('b', 3); // -1 43126 arr.indexOf('a', 100); // -1 43127 ``` 43128 @method indexOf 43129 @param {Object} object the item to search for 43130 @param {Number} startAt optional starting location to search, default 0 43131 @return {Number} index or -1 if not found 43132 @public 43133 */ 43134 indexOf: function (object, startAt) { 43135 var len = _emberMetalProperty_get.get(this, 'length'); 43136 var idx; 43137 43138 if (startAt === undefined) { 43139 startAt = 0; 43140 } 43141 43142 if (startAt < 0) { 43143 startAt += len; 43144 } 43145 43146 for (idx = startAt; idx < len; idx++) { 43147 if (objectAt(this, idx) === object) { 43148 return idx; 43149 } 43150 } 43151 43152 return -1; 43153 }, 43154 43155 /** 43156 Returns the index of the given object's last occurrence. 43157 If no `startAt` argument is given, the search starts from 43158 the last position. If it's negative, will count backward 43159 from the end of the array. Returns -1 if no match is found. 43160 ```javascript 43161 var arr = ['a', 'b', 'c', 'd', 'a']; 43162 arr.lastIndexOf('a'); // 4 43163 arr.lastIndexOf('z'); // -1 43164 arr.lastIndexOf('a', 2); // 0 43165 arr.lastIndexOf('a', -1); // 4 43166 arr.lastIndexOf('b', 3); // 1 43167 arr.lastIndexOf('a', 100); // 4 43168 ``` 43169 @method lastIndexOf 43170 @param {Object} object the item to search for 43171 @param {Number} startAt optional starting location to search, default 0 43172 @return {Number} index or -1 if not found 43173 @public 43174 */ 43175 lastIndexOf: function (object, startAt) { 43176 var len = _emberMetalProperty_get.get(this, 'length'); 43177 var idx; 43178 43179 if (startAt === undefined || startAt >= len) { 43180 startAt = len - 1; 43181 } 43182 43183 if (startAt < 0) { 43184 startAt += len; 43185 } 43186 43187 for (idx = startAt; idx >= 0; idx--) { 43188 if (objectAt(this, idx) === object) { 43189 return idx; 43190 } 43191 } 43192 43193 return -1; 43194 }, 43195 43196 // .......................................................... 43197 // ARRAY OBSERVERS 43198 // 43199 43200 /** 43201 Adds an array observer to the receiving array. The array observer object 43202 normally must implement two methods: 43203 * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be 43204 called just before the array is modified. 43205 * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be 43206 called just after the array is modified. 43207 Both callbacks will be passed the observed object, starting index of the 43208 change as well as a count of the items to be removed and added. You can use 43209 these callbacks to optionally inspect the array during the change, clear 43210 caches, or do any other bookkeeping necessary. 43211 In addition to passing a target, you can also include an options hash 43212 which you can use to override the method names that will be invoked on the 43213 target. 43214 @method addArrayObserver 43215 @param {Object} target The observer object. 43216 @param {Object} opts Optional hash of configuration options including 43217 `willChange` and `didChange` option. 43218 @return {Ember.Array} receiver 43219 @public 43220 */ 43221 43222 addArrayObserver: function (target, opts) { 43223 return addArrayObserver(this, target, opts); 43224 }, 43225 43226 /** 43227 Removes an array observer from the object if the observer is current 43228 registered. Calling this method multiple times with the same object will 43229 have no effect. 43230 @method removeArrayObserver 43231 @param {Object} target The object observing the array. 43232 @param {Object} opts Optional hash of configuration options including 43233 `willChange` and `didChange` option. 43234 @return {Ember.Array} receiver 43235 @public 43236 */ 43237 removeArrayObserver: function (target, opts) { 43238 return removeArrayObserver(this, target, opts); 43239 }, 43240 43241 /** 43242 Becomes true whenever the array currently has observers watching changes 43243 on the array. 43244 @property {Boolean} hasArrayObservers 43245 @public 43246 */ 43247 hasArrayObservers: _emberMetalComputed.computed(function () { 43248 return _emberMetalEvents.hasListeners(this, '@array:change') || _emberMetalEvents.hasListeners(this, '@array:before'); 43249 }), 43250 43251 /** 43252 If you are implementing an object that supports `Ember.Array`, call this 43253 method just before the array content changes to notify any observers and 43254 invalidate any related properties. Pass the starting index of the change 43255 as well as a delta of the amounts to change. 43256 @method arrayContentWillChange 43257 @param {Number} startIdx The starting index in the array that will change. 43258 @param {Number} removeAmt The number of items that will be removed. If you 43259 pass `null` assumes 0 43260 @param {Number} addAmt The number of items that will be added. If you 43261 pass `null` assumes 0. 43262 @return {Ember.Array} receiver 43263 @public 43264 */ 43265 arrayContentWillChange: function (startIdx, removeAmt, addAmt) { 43266 var removing, lim; 43267 43268 // if no args are passed assume everything changes 43269 if (startIdx === undefined) { 43270 startIdx = 0; 43271 removeAmt = addAmt = -1; 43272 } else { 43273 if (removeAmt === undefined) { 43274 removeAmt = -1; 43275 } 43276 43277 if (addAmt === undefined) { 43278 addAmt = -1; 43279 } 43280 } 43281 43282 if (this.__each) { 43283 this.__each.arrayWillChange(this, startIdx, removeAmt, addAmt); 43284 } 43285 43286 _emberMetalEvents.sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); 43287 43288 if (startIdx >= 0 && removeAmt >= 0 && _emberMetalProperty_get.get(this, 'hasEnumerableObservers')) { 43289 removing = []; 43290 lim = startIdx + removeAmt; 43291 43292 for (var idx = startIdx; idx < lim; idx++) { 43293 removing.push(objectAt(this, idx)); 43294 } 43295 } else { 43296 removing = removeAmt; 43297 } 43298 43299 this.enumerableContentWillChange(removing, addAmt); 43300 43301 return this; 43302 }, 43303 43304 /** 43305 If you are implementing an object that supports `Ember.Array`, call this 43306 method just after the array content changes to notify any observers and 43307 invalidate any related properties. Pass the starting index of the change 43308 as well as a delta of the amounts to change. 43309 @method arrayContentDidChange 43310 @param {Number} startIdx The starting index in the array that did change. 43311 @param {Number} removeAmt The number of items that were removed. If you 43312 pass `null` assumes 0 43313 @param {Number} addAmt The number of items that were added. If you 43314 pass `null` assumes 0. 43315 @return {Ember.Array} receiver 43316 @public 43317 */ 43318 arrayContentDidChange: function (startIdx, removeAmt, addAmt) { 43319 var adding, lim; 43320 43321 // if no args are passed assume everything changes 43322 if (startIdx === undefined) { 43323 startIdx = 0; 43324 removeAmt = addAmt = -1; 43325 } else { 43326 if (removeAmt === undefined) { 43327 removeAmt = -1; 43328 } 43329 43330 if (addAmt === undefined) { 43331 addAmt = -1; 43332 } 43333 } 43334 43335 if (startIdx >= 0 && addAmt >= 0 && _emberMetalProperty_get.get(this, 'hasEnumerableObservers')) { 43336 adding = []; 43337 lim = startIdx + addAmt; 43338 43339 for (var idx = startIdx; idx < lim; idx++) { 43340 adding.push(objectAt(this, idx)); 43341 } 43342 } else { 43343 adding = addAmt; 43344 } 43345 43346 this.enumerableContentDidChange(removeAmt, adding); 43347 43348 if (this.__each) { 43349 this.__each.arrayDidChange(this, startIdx, removeAmt, addAmt); 43350 } 43351 43352 _emberMetalEvents.sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); 43353 43354 var length = _emberMetalProperty_get.get(this, 'length'); 43355 var cachedFirst = _emberMetalComputed.cacheFor(this, 'firstObject'); 43356 var cachedLast = _emberMetalComputed.cacheFor(this, 'lastObject'); 43357 43358 if (objectAt(this, 0) !== cachedFirst) { 43359 _emberMetalProperty_events.propertyWillChange(this, 'firstObject'); 43360 _emberMetalProperty_events.propertyDidChange(this, 'firstObject'); 43361 } 43362 43363 if (objectAt(this, length - 1) !== cachedLast) { 43364 _emberMetalProperty_events.propertyWillChange(this, 'lastObject'); 43365 _emberMetalProperty_events.propertyDidChange(this, 'lastObject'); 43366 } 43367 43368 return this; 43369 }, 43370 43371 /** 43372 Returns a special object that can be used to observe individual properties 43373 on the array. Just get an equivalent property on this object and it will 43374 return an enumerable that maps automatically to the named key on the 43375 member objects. 43376 `@each` should only be used in a non-terminal context. Example: 43377 ```javascript 43378 myMethod: computed('[email protected]', function(){ 43379 ... 43380 }); 43381 ``` 43382 If you merely want to watch for the array being changed, like an object being 43383 replaced, added or removed, use `[]` instead of `@each`. 43384 ```javascript 43385 myMethod: computed('posts.[]', function(){ 43386 ... 43387 }); 43388 ``` 43389 @property @each 43390 @public 43391 */ 43392 '@each': _emberMetalComputed.computed(function () { 43393 // TODO use Symbol or add to meta 43394 if (!this.__each) { 43395 this.__each = new _emberRuntimeSystemEach_proxy.default(this); 43396 } 43397 43398 return this.__each; 43399 }).volatile() 43400 }); 43401}); 43402// ES6TODO: Ember.A 43403enifed('ember-runtime/mixins/comparable', ['exports', 'ember-metal/mixin'], function (exports, _emberMetalMixin) { 43404 'use strict'; 43405 43406 /** 43407 @module ember 43408 @submodule ember-runtime 43409 */ 43410 43411 /** 43412 Implements some standard methods for comparing objects. Add this mixin to 43413 any class you create that can compare its instances. 43414 43415 You should implement the `compare()` method. 43416 43417 @class Comparable 43418 @namespace Ember 43419 @since Ember 0.9 43420 @private 43421 */ 43422 exports.default = _emberMetalMixin.Mixin.create({ 43423 43424 /** 43425 __Required.__ You must implement this method to apply this mixin. 43426 Override to return the result of the comparison of the two parameters. The 43427 compare method should return: 43428 - `-1` if `a < b` 43429 - `0` if `a == b` 43430 - `1` if `a > b`
43431 Default implementation raises an exception. 43432 @method compare 43433 @param a {Object} the first object to compare 43434 @param b {Object} the second object to compare 43435 @return {Number} the result of the comparison 43436 @private 43437 */ 43438 compare: null 43439 }); 43440}); 43441enifed('ember-runtime/mixins/container_proxy', ['exports', 'ember-metal/run_loop', 'ember-metal/debug', 'ember-metal/mixin'], function (exports, _emberMetalRun_loop, _emberMetalDebug, _emberMetalMixin) { 43442 /** 43443 @module ember 43444 @submodule ember-runtime 43445 */ 43446 'use strict'; 43447 43448 exports.buildFakeContainerWithDeprecations = buildFakeContainerWithDeprecations; 43449 43450 /** 43451 ContainerProxyMixin is used to provide public access to specific 43452 container functionality. 43453 43454 @class ContainerProxyMixin 43455 @private 43456 */ 43457 exports.default = _emberMetalMixin.Mixin.create({ 43458 /** 43459 The container stores state. 43460 @private 43461 @property {Ember.Container} __container__ 43462 */ 43463 __container__: null, 43464 43465 /** 43466 Returns an object that can be used to provide an owner to a 43467 manually created instance. 43468 Example: 43469 ``` 43470 let owner = Ember.getOwner(this); 43471 User.create( 43472 owner.ownerInjection(), 43473 { username: 'rwjblue' } 43474 ) 43475 ``` 43476 @public 43477 @method ownerInjection 43478 @return {Object} 43479 */ 43480 ownerInjection: containerAlias('ownerInjection'), 43481 43482 /** 43483 Given a fullName return a corresponding instance. 43484 The default behaviour is for lookup to return a singleton instance. 43485 The singleton is scoped to the container, allowing multiple containers 43486 to all have their own locally scoped singletons. 43487 ```javascript 43488 var registry = new Registry(); 43489 var container = registry.container(); 43490 registry.register('api:twitter', Twitter); 43491 var twitter = container.lookup('api:twitter'); 43492 twitter instanceof Twitter; // => true 43493 // by default the container will return singletons 43494 var twitter2 = container.lookup('api:twitter'); 43495 twitter2 instanceof Twitter; // => true 43496 twitter === twitter2; //=> true 43497 ``` 43498 If singletons are not wanted an optional flag can be provided at lookup. 43499 ```javascript 43500 var registry = new Registry(); 43501 var container = registry.container(); 43502 registry.register('api:twitter', Twitter); 43503 var twitter = container.lookup('api:twitter', { singleton: false }); 43504 var twitter2 = container.lookup('api:twitter', { singleton: false }); 43505 twitter === twitter2; //=> false 43506 ``` 43507 @public 43508 @method lookup 43509 @param {String} fullName 43510 @param {Object} options 43511 @return {any} 43512 */ 43513 lookup: containerAlias('lookup'), 43514 43515 /** 43516 Given a fullName return the corresponding factory. 43517 @private 43518 @method _lookupFactory 43519 @param {String} fullName 43520 @return {any} 43521 */ 43522 _lookupFactory: containerAlias('lookupFactory'), 43523 43524 /** 43525 @private 43526 */ 43527 willDestroy: function () { 43528 this._super.apply(this, arguments); 43529 43530 if (this.__container__) { 43531 _emberMetalRun_loop.default(this.__container__, 'destroy'); 43532 } 43533 } 43534 }); 43535 43536 function containerAlias(name) { 43537 return function () { 43538 var _container__; 43539 43540 return (_container__ = this.__container__)[name].apply(_container__, arguments); 43541 }; 43542 } 43543 43544 function buildFakeContainerWithDeprecations(container) { 43545 var fakeContainer = {}; 43546 var propertyMappings = { 43547 lookup: 'lookup', 43548 lookupFactory: '_lookupFactory' 43549 }; 43550 43551 for (var containerProperty in propertyMappings) { 43552 fakeContainer[containerProperty] = buildFakeContainerFunction(container, containerProperty, propertyMappings[containerProperty]); 43553 } 43554 43555 return fakeContainer; 43556 } 43557 43558 function buildFakeContainerFunction(container, containerProperty, ownerProperty) { 43559 return function () { 43560 _emberMetalDebug.deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper to access the owner of this object and then call `' + ownerProperty + '` instead.', false, { 43561 id: 'ember-application.injected-container', 43562 until: '3.0.0',
43563 url: 'http://emberjs.com/deprecations/v2.x#toc_injected-container-access' 43564 }); 43565 return container[containerProperty].apply(container, arguments); 43566 }; 43567 } 43568}); 43569enifed('ember-runtime/mixins/controller', ['exports', 'ember-metal/mixin', 'ember-metal/alias', 'ember-runtime/mixins/action_handler', 'ember-runtime/mixins/controller_content_model_alias_deprecation'], function (exports, _emberMetalMixin, _emberMetalAlias, _emberRuntimeMixinsAction_handler, _emberRuntimeMixinsController_content_model_alias_deprecation) { 43570 'use strict'; 43571 43572 /** 43573 @class ControllerMixin 43574 @namespace Ember 43575 @uses Ember.ActionHandler 43576 @private 43577 */ 43578 exports.default = _emberMetalMixin.Mixin.create(_emberRuntimeMixinsAction_handler.default, _emberRuntimeMixinsController_content_model_alias_deprecation.default, { 43579 /* ducktype as a controller */ 43580 isController: true, 43581 43582 /** 43583 The object to which actions from the view should be sent. 43584 For example, when a Handlebars template uses the `{{action}}` helper, 43585 it will attempt to send the action to the view's controller's `target`. 43586 By default, the value of the target property is set to the router, and 43587 is injected when a controller is instantiated. This injection is applied 43588 as part of the application's initialization process. In most cases the 43589 `target` property will automatically be set to the logical consumer of 43590 actions for the controller. 43591 @property target 43592 @default null 43593 @public 43594 */ 43595 target: null, 43596 43597 parentController: null, 43598 43599 store: null, 43600 43601 /** 43602 The controller's current model. When retrieving or modifying a controller's 43603 model, this property should be used instead of the `content` property. 43604 @property model 43605 @public 43606 */ 43607 model: null, 43608 43609 /** 43610 @private 43611 */ 43612 content: _emberMetalAlias.default('model') 43613 43614 }); 43615}); 43616enifed('ember-runtime/mixins/controller_content_model_alias_deprecation', ['exports', 'ember-metal/debug', 'ember-metal/mixin'], function (exports, _emberMetalDebug, _emberMetalMixin) { 43617 'use strict'; 43618 43619 /* 43620 The ControllerContentModelAliasDeprecation mixin is used to provide a useful 43621 deprecation warning when specifying `content` directly on a `Ember.Controller` 43622 (without also specifying `model`). 43623 43624 Ember versions prior to 1.7 used `model` as an alias of `content`, but due to 43625 much confusion this alias was reversed (so `content` is now an alias of `model). 43626 43627 This change reduces many caveats with model/content, and also sets a 43628 simple ground rule: Never set a controllers content, rather always set 43629 its model and ember will do the right thing. 43630 43631 Used internally by Ember in `Ember.Controller`. 43632 */ 43633 exports.default = _emberMetalMixin.Mixin.create({ 43634 /** 43635 @private 43636 Moves `content` to `model` at extend time if a `model` is not also specified. 43637 Note that this currently modifies the mixin themselves, which is technically 43638 dubious but is practically of little consequence. This may change in the 43639 future. 43640 @method willMergeMixin 43641 @since 1.4.0 43642 */ 43643 willMergeMixin: function (props) { 43644 // Calling super is only OK here since we KNOW that 43645 // there is another Mixin loaded first. 43646 this._super.apply(this, arguments); 43647 43648 var modelSpecified = !!props.model; 43649 43650 if (props.content && !modelSpecified) { 43651 props.model = props.content; 43652 delete props['content']; 43653 43654 _emberMetalDebug.deprecate('Do not specify `content` on a Controller, use `model` instead.', false, { id: 'ember-runtime.will-merge-mixin', until: '3.0.0' }); 43655 } 43656 } 43657 }); 43658}); 43659enifed('ember-runtime/mixins/copyable', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/mixin', 'ember-runtime/mixins/freezable', 'ember-metal/error'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalMixin, _emberRuntimeMixinsFreezable, _emberMetalError) { 43660 /** 43661 @module ember 43662 @submodule ember-runtime 43663 */ 43664 43665 'use strict'; 43666 43667 /** 43668 Implements some standard methods for copying an object. Add this mixin to 43669 any object you create that can create a copy of itself. This mixin is 43670 added automatically to the built-in array.
43671 43672 You should generally implement the `copy()` method to return a copy of the 43673 receiver. 43674 43675 Note that `frozenCopy()` will only work if you also implement 43676 `Ember.Freezable`. 43677 43678 @class Copyable 43679 @namespace Ember 43680 @since Ember 0.9 43681 @private 43682 */ 43683 exports.default = _emberMetalMixin.Mixin.create({ 43684 /** 43685 __Required.__ You must implement this method to apply this mixin. 43686 Override to return a copy of the receiver. Default implementation raises 43687 an exception. 43688 @method copy 43689 @param {Boolean} deep if `true`, a deep copy of the object should be made 43690 @return {Object} copy of receiver 43691 @private 43692 */ 43693 copy: null, 43694 43695 /** 43696 If the object implements `Ember.Freezable`, then this will return a new 43697 copy if the object is not frozen and the receiver if the object is frozen. 43698 Raises an exception if you try to call this method on a object that does 43699 not support freezing. 43700 You should use this method whenever you want a copy of a freezable object 43701 since a freezable object can simply return itself without actually 43702 consuming more memory. 43703 @method frozenCopy 43704 @return {Object} copy of receiver or receiver 43705 @deprecated Use `Object.freeze` instead. 43706 @private 43707 */ 43708 frozenCopy: function () { 43709 _emberMetalDebug.deprecate('`frozenCopy` is deprecated, use `Object.freeze` instead.', false, { id: 'ember-runtime.frozen-copy', until: '3.0.0' }); 43710 if (_emberRuntimeMixinsFreezable.Freezable && _emberRuntimeMixinsFreezable.Freezable.detect(this)) { 43711 return _emberMetalProperty_get.get(this, 'isFrozen') ? this : this.copy().freeze(); 43712 } else { 43713 throw new _emberMetalError.default(this + ' does not support freezing'); 43714 } 43715 } 43716 }); 43717}); 43718enifed('ember-runtime/mixins/enumerable', ['exports', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/mixin', 'ember-metal/computed', 'ember-metal/property_events', 'ember-metal/events', 'ember-runtime/compare', 'require'], function (exports, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalMixin, _emberMetalComputed, _emberMetalProperty_events, _emberMetalEvents, _emberRuntimeCompare, _require) { 43719 /** 43720 @module ember 43721 @submodule ember-runtime 43722 */ 43723 43724 // .......................................................... 43725 // HELPERS 43726 // 43727 43728 'use strict'; 43729 43730 var _emberA = undefined; 43731 43732 function emberA() { 43733 return (_emberA || (_emberA = _require.default('ember-runtime/system/native_array').A))(); 43734 } 43735 43736 var contexts = []; 43737 43738 function popCtx() { 43739 return contexts.length === 0 ? {} : contexts.pop(); 43740 } 43741 43742 function pushCtx(ctx) { 43743 contexts.push(ctx); 43744 return null; 43745 } 43746 43747 function iter(key, value) { 43748 var valueProvided = arguments.length === 2; 43749 43750 function i(item) { 43751 var cur = _emberMetalProperty_get.get(item, key); 43752 return valueProvided ? value === cur : !!cur; 43753 } 43754 43755 return i; 43756 } 43757 43758 /** 43759 This mixin defines the common interface implemented by enumerable objects 43760 in Ember. Most of these methods follow the standard Array iteration 43761 API defined up to JavaScript 1.8 (excluding language-specific features that 43762 cannot be emulated in older versions of JavaScript). 43763 43764 This mixin is applied automatically to the Array class on page load, so you 43765 can use any of these methods on simple arrays. If Array already implements 43766 one of these methods, the mixin will not override them. 43767 43768 ## Writing Your Own Enumerable 43769 43770 To make your own custom class enumerable, you need two items: 43771 43772 1. You must have a length property. This property should change whenever 43773 the number of items in your enumerable object changes. If you use this 43774 with an `Ember.Object` subclass, you should be sure to change the length 43775 property using `set().` 43776 43777 2. You must implement `nextObject().` See documentation. 43778 43779 Once you have these two methods implemented, apply the `Ember.Enumerable` mixin 43780 to your class and you will be able to enumerate the contents of your object 43781 like any other collection. 43782 43783 ## Using Ember Enumeration with Other Libraries 43784 43785 Many other libraries provide some kind of iterator or enumeration like 43786 facility. This is often where the most common API conflicts occur. 43787 Ember's API is designed to be as friendly as possible with other 43788 libraries by implementing only methods that mostly correspond to the 43789 JavaScript 1.8 API. 43790 43791 @class Enumerable 43792 @namespace Ember 43793 @since Ember 0.9 43794 @private 43795 */ 43796 exports.default = _emberMetalMixin.Mixin.create({ 43797 43798 /** 43799 __Required.__ You must implement this method to apply this mixin. 43800 Implement this method to make your class enumerable. 43801 This method will be called repeatedly during enumeration. The index value 43802 will always begin with 0 and increment monotonically. You don't have to 43803 rely on the index value to determine what object to return, but you should 43804 always check the value and start from the beginning when you see the 43805 requested index is 0. 43806 The `previousObject` is the object that was returned from the last call 43807 to `nextObject` for the current iteration. This is a useful way to 43808 manage iteration if you are tracing a linked list, for example. 43809 Finally the context parameter will always contain a hash you can use as 43810 a "scratchpad" to maintain any other state you need in order to iterate 43811 properly. The context object is reused and is not reset between 43812 iterations so make sure you setup the context with a fresh state whenever 43813 the index parameter is 0. 43814 Generally iterators will continue to call `nextObject` until the index 43815 reaches the current length-1. If you run out of data before this 43816 time for some reason, you should simply return undefined. 43817 The default implementation of this method simply looks up the index. 43818 This works great on any Array-like objects. 43819 @method nextObject 43820 @param {Number} index the current index of the iteration 43821 @param {Object} previousObject the value returned by the last call to 43822 `nextObject`. 43823 @param {Object} context a context object you can use to maintain state. 43824 @return {Object} the next object in the iteration or undefined 43825 @private 43826 */ 43827 nextObject: null, 43828 43829 /** 43830 Helper method returns the first object from a collection. This is usually 43831 used by bindings and other parts of the framework to extract a single 43832 object if the enumerable contains only one item. 43833 If you override this method, you should implement it so that it will 43834 always return the same value each time it is called. If your enumerable 43835 contains only one object, this method should always return that object. 43836 If your enumerable is empty, this method should return `undefined`. 43837 ```javascript 43838 var arr = ['a', 'b', 'c']; 43839 arr.get('firstObject'); // 'a' 43840 var arr = []; 43841 arr.get('firstObject'); // undefined 43842 ``` 43843 @property firstObject 43844 @return {Object} the object or undefined 43845 @readOnly 43846 @public 43847 */ 43848 firstObject: _emberMetalComputed.computed('[]', function () { 43849 if (_emberMetalProperty_get.get(this, 'length') === 0) { 43850 return undefined; 43851 } 43852 43853 // handle generic enumerables 43854 var context = popCtx(); 43855 var ret = this.nextObject(0, null, context); 43856 43857 pushCtx(context); 43858 43859 return ret; 43860 }), 43861 43862 /** 43863 Helper method returns the last object from a collection. If your enumerable 43864 contains only one object, this method should always return that object. 43865 If your enumerable is empty, this method should return `undefined`. 43866 ```javascript 43867 var arr = ['a', 'b', 'c']; 43868 arr.get('lastObject'); // 'c' 43869 var arr = []; 43870 arr.get('lastObject'); // undefined 43871 ``` 43872 @property lastObject 43873 @return {Object} the last object or undefined 43874 @readOnly 43875 @public 43876 */ 43877 lastObject: _emberMetalComputed.computed('[]', function () { 43878 var len = _emberMetalProperty_get.get(this, 'length'); 43879 43880 if (len === 0) { 43881 return undefined; 43882 } 43883 43884 var context = popCtx(); 43885 var idx = 0; 43886 var last = null; 43887 var cur; 43888 43889 do { 43890 last = cur; 43891 cur = this.nextObject(idx++, last, context); 43892 } while (cur !== undefined); 43893 43894 pushCtx(context); 43895 43896 return last; 43897 }), 43898 43899 /** 43900 Returns `true` if the passed object can be found in the receiver. The 43901 default version will iterate through the enumerable until the object 43902 is found. You may want to override this with a more efficient version. 43903 ```javascript 43904 var arr = ['a', 'b', 'c']; 43905 arr.contains('a'); // true 43906 arr.contains('z'); // false 43907 ``` 43908 @method contains 43909 @param {Object} obj The object to search for. 43910 @return {Boolean} `true` if object is found in enumerable. 43911 @public 43912 */ 43913 contains: function (obj) { 43914 var found = this.find(function (item) { 43915 return item === obj; 43916 }); 43917 43918 return found !== undefined; 43919 }, 43920 43921 /** 43922 Iterates through the enumerable, calling the passed function on each
43923 item. This method corresponds to the `forEach()` method defined in 43924 JavaScript 1.6. 43925 The callback method you provide should have the following signature (all 43926 parameters are optional): 43927 ```javascript 43928 function(item, index, enumerable); 43929 ``` 43930 - `item` is the current item in the iteration. 43931 - `index` is the current index in the iteration. 43932 - `enumerable` is the enumerable object itself. 43933 Note that in addition to a callback, you can also pass an optional target 43934 object that will be set as `this` on the context. This is a good way 43935 to give your iterator function access to the current object. 43936 @method forEach 43937 @param {Function} callback The callback to execute 43938 @param {Object} [target] The target object to use 43939 @return {Object} receiver 43940 @public 43941 */ 43942 forEach: function (callback, target) { 43943 if (typeof callback !== 'function') { 43944 throw new TypeError(); 43945 } 43946 43947 var context = popCtx(); 43948 var len = _emberMetalProperty_get.get(this, 'length'); 43949 var last = null; 43950 43951 if (target === undefined) { 43952 target = null; 43953 } 43954 43955 for (var idx = 0; idx < len; idx++) { 43956 var next = this.nextObject(idx, last, context); 43957 callback.call(target, next, idx, this); 43958 last = next; 43959 } 43960 43961 last = null; 43962 context = pushCtx(context); 43963 43964 return this; 43965 }, 43966 43967 /** 43968 Alias for `mapBy` 43969 @method getEach 43970 @param {String} key name of the property 43971 @return {Array} The mapped array. 43972 @public 43973 */ 43974 getEach: _emberMetalMixin.aliasMethod('mapBy'), 43975 43976 /** 43977 Sets the value on the named property for each member. This is more 43978 efficient than using other methods defined on this helper. If the object 43979 implements Ember.Observable, the value will be changed to `set(),` otherwise 43980 it will be set directly. `null` objects are skipped. 43981 @method setEach 43982 @param {String} key The key to set 43983 @param {Object} value The object to set 43984 @return {Object} receiver 43985 @public 43986 */ 43987 setEach: function (key, value) { 43988 return this.forEach(function (item) { 43989 _emberMetalProperty_set.set(item, key, value); 43990 }); 43991 }, 43992 43993 /** 43994 Maps all of the items in the enumeration to another value, returning 43995 a new array. This method corresponds to `map()` defined in JavaScript 1.6. 43996 The callback method you provide should have the following signature (all 43997 parameters are optional): 43998 ```javascript 43999 function(item, index, enumerable); 44000 ``` 44001 - `item` is the current item in the iteration. 44002 - `index` is the current index in the iteration. 44003 - `enumerable` is the enumerable object itself. 44004 It should return the mapped value. 44005 Note that in addition to a callback, you can also pass an optional target 44006 object that will be set as `this` on the context. This is a good way 44007 to give your iterator function access to the current object. 44008 @method map 44009 @param {Function} callback The callback to execute 44010 @param {Object} [target] The target object to use 44011 @return {Array} The mapped array. 44012 @public 44013 */ 44014 map: function (callback, target) { 44015 var ret = emberA(); 44016 44017 this.forEach(function (x, idx, i) { 44018 ret[idx] = callback.call(target, x, idx, i); 44019 }); 44020 44021 return ret; 44022 }, 44023 44024 /** 44025 Similar to map, this specialized function returns the value of the named 44026 property on all items in the enumeration. 44027 @method mapBy 44028 @param {String} key name of the property 44029 @return {Array} The mapped array. 44030 @public 44031 */ 44032 mapBy: function (key) { 44033 return this.map(function (next) { 44034 return _emberMetalProperty_get.get(next, key); 44035 }); 44036 }, 44037 44038 /** 44039 Returns an array with all of the items in the enumeration that the passed 44040 function returns true for. This method corresponds to `filter()` defined in 44041 JavaScript 1.6. 44042 The callback method you provide should have the following signature (all 44043 parameters are optional): 44044 ```javascript 44045 function(item, index, enumerable); 44046 ``` 44047 - `item` is the current item in the iteration. 44048 - `index` is the current index in the iteration. 44049 - `enumerable` is the enumerable object itself. 44050 It should return `true` to include the item in the results, `false` 44051 otherwise. 44052 Note that in addition to a callback, you can also pass an optional target 44053 object that will be set as `this` on the context. This is a good way 44054 to give your iterator function access to the current object. 44055 @method filter 44056 @param {Function} callback The callback to execute 44057 @param {Object} [target] The target object to use 44058 @return {Array} A filtered array.
44059 @public 44060 */ 44061 filter: function (callback, target) { 44062 var ret = emberA(); 44063 44064 this.forEach(function (x, idx, i) { 44065 if (callback.call(target, x, idx, i)) { 44066 ret.push(x); 44067 } 44068 }); 44069 44070 return ret; 44071 }, 44072 44073 /** 44074 Returns an array with all of the items in the enumeration where the passed 44075 function returns false. This method is the inverse of filter(). 44076 The callback method you provide should have the following signature (all 44077 parameters are optional): 44078 ```javascript 44079 function(item, index, enumerable); 44080 ``` 44081 - *item* is the current item in the iteration. 44082 - *index* is the current index in the iteration 44083 - *enumerable* is the enumerable object itself. 44084 It should return a falsey value to include the item in the results. 44085 Note that in addition to a callback, you can also pass an optional target 44086 object that will be set as "this" on the context. This is a good way 44087 to give your iterator function access to the current object. 44088 @method reject 44089 @param {Function} callback The callback to execute 44090 @param {Object} [target] The target object to use 44091 @return {Array} A rejected array. 44092 @public 44093 */ 44094 reject: function (callback, target) { 44095 return this.filter(function () { 44096 return !callback.apply(target, arguments); 44097 }); 44098 }, 44099 44100 /** 44101 Returns an array with just the items with the matched property. You 44102 can pass an optional second argument with the target value. Otherwise 44103 this will match any property that evaluates to `true`. 44104 @method filterBy 44105 @param {String} key the property to test 44106 @param {*} [value] optional value to test against. 44107 @return {Array} filtered array 44108 @public 44109 */ 44110 filterBy: function (key, value) { 44111 return this.filter(iter.apply(this, arguments)); 44112 }, 44113 44114 /** 44115 Returns an array with the items that do not have truthy values for 44116 key. You can pass an optional second argument with the target value. Otherwise 44117 this will match any property that evaluates to false. 44118 @method rejectBy 44119 @param {String} key the property to test 44120 @param {String} [value] optional value to test against. 44121 @return {Array} rejected array 44122 @public 44123 */ 44124 rejectBy: function (key, value) { 44125 var exactValue = function (item) { 44126 return _emberMetalProperty_get.get(item, key) === value; 44127 }; 44128 44129 var hasValue = function (item) { 44130 return !!_emberMetalProperty_get.get(item, key); 44131 }; 44132 44133 var use = arguments.length === 2 ? exactValue : hasValue; 44134 44135 return this.reject(use); 44136 }, 44137 44138 /** 44139 Returns the first item in the array for which the callback returns true. 44140 This method works similar to the `filter()` method defined in JavaScript 1.6 44141 except that it will stop working on the array once a match is found. 44142 The callback method you provide should have the following signature (all 44143 parameters are optional): 44144 ```javascript 44145 function(item, index, enumerable); 44146 ``` 44147 - `item` is the current item in the iteration. 44148 - `index` is the current index in the iteration. 44149 - `enumerable` is the enumerable object itself. 44150 It should return the `true` to include the item in the results, `false` 44151 otherwise. 44152 Note that in addition to a callback, you can also pass an optional target 44153 object that will be set as `this` on the context. This is a good way 44154 to give your iterator function access to the current object. 44155 @method find 44156 @param {Function} callback The callback to execute 44157 @param {Object} [target] The target object to use 44158 @return {Object} Found item or `undefined`. 44159 @public 44160 */ 44161 find: function (callback, target) { 44162 var len = _emberMetalProperty_get.get(this, 'length'); 44163 44164 if (target === undefined) { 44165 target = null; 44166 } 44167 44168 var context = popCtx(); 44169 var found = false; 44170 var last = null; 44171 var next, ret; 44172 44173 for (var idx = 0; idx < len && !found; idx++) { 44174 next = this.nextObject(idx, last, context); 44175 44176 if (found = callback.call(target, next, idx, this)) { 44177 ret = next; 44178 } 44179 44180 last = next; 44181 } 44182 44183 next = last = null; 44184 context = pushCtx(context); 44185 44186 return ret; 44187 }, 44188 44189 /** 44190 Returns the first item with a property matching the passed value. You 44191 can pass an optional second argument with the target value. Otherwise 44192 this will match any property that evaluates to `true`. 44193 This method works much like the more generic `find()` method. 44194 @method findBy 44195 @param {String} key the property to test 44196 @param {String} [value] optional value to test against. 44197 @return {Object} found item or `undefined` 44198 @public 44199 */ 44200 findBy: function (key, value) { 44201 return this.find(iter.apply(this, arguments)); 44202 }, 44203 44204 /** 44205 Returns `true` if the passed function returns true for every item in the 44206 enumeration. This corresponds with the `every()` method in JavaScript 1.6. 44207 The callback method you provide should have the following signature (all 44208 parameters are optional): 44209 ```javascript 44210 function(item, index, enumerable); 44211 ``` 44212 - `item` is the current item in the iteration. 44213 - `index` is the current index in the iteration. 44214 - `enumerable` is the enumerable object itself. 44215 It should return the `true` or `false`. 44216 Note that in addition to a callback, you can also pass an optional target 44217 object that will be set as `this` on the context. This is a good way 44218 to give your iterator function access to the current object. 44219 Example Usage: 44220 ```javascript 44221 if (people.every(isEngineer)) { 44222 Paychecks.addBigBonus(); 44223 } 44224 ``` 44225 @method every 44226 @param {Function} callback The callback to execute 44227 @param {Object} [target] The target object to use 44228 @return {Boolean} 44229 @public 44230 */ 44231 every: function (callback, target) { 44232 return !this.find(function (x, idx, i) { 44233 return !callback.call(target, x, idx, i); 44234 }); 44235 }, 44236 44237 /** 44238 Returns `true` if the passed property resolves to the value of the second 44239 argument for all items in the enumerable. This method is often simpler/faster 44240 than using a callback. 44241 @method isEvery 44242 @param {String} key the property to test 44243 @param {String} [value] optional value to test against. Defaults to `true` 44244 @return {Boolean} 44245 @since 1.3.0 44246 @public 44247 */ 44248 isEvery: function (key, value) { 44249 return this.every(iter.apply(this, arguments)); 44250 }, 44251 44252 /** 44253 Returns `true` if the passed function returns true for any item in the 44254 enumeration. This corresponds with the `some()` method in JavaScript 1.6. 44255 The callback method you provide should have the following signature (all 44256 parameters are optional): 44257 ```javascript 44258 function(item, index, enumerable); 44259 ``` 44260 - `item` is the current item in the iteration. 44261 - `index` is the current index in the iteration. 44262 - `enumerable` is the enumerable object itself. 44263 It should return the `true` to include the item in the results, `false` 44264 otherwise. 44265 Note that in addition to a callback, you can also pass an optional target 44266 object that will be set as `this` on the context. This is a good way 44267 to give your iterator function access to the current object. 44268 Usage Example: 44269 ```javascript 44270 if (people.any(isManager)) { 44271 Paychecks.addBiggerBonus(); 44272 } 44273 ``` 44274 @method any 44275 @param {Function} callback The callback to execute 44276 @param {Object} [target] The target object to use 44277 @return {Boolean} `true` if the passed function returns `true` for any item 44278 @public 44279 */ 44280 any: function (callback, target) { 44281 var len = _emberMetalProperty_get.get(this, 'length'); 44282 var context = popCtx(); 44283 var found = false;
44284 var last = null; 44285 var next, idx; 44286 44287 if (target === undefined) { 44288 target = null; 44289 } 44290 44291 for (idx = 0; idx < len && !found; idx++) { 44292 next = this.nextObject(idx, last, context); 44293 found = callback.call(target, next, idx, this); 44294 last = next; 44295 } 44296 44297 next = last = null; 44298 context = pushCtx(context); 44299 return found; 44300 }, 44301 44302 /** 44303 Returns `true` if the passed property resolves to the value of the second 44304 argument for any item in the enumerable. This method is often simpler/faster 44305 than using a callback. 44306 @method isAny 44307 @param {String} key the property to test 44308 @param {String} [value] optional value to test against. Defaults to `true` 44309 @return {Boolean} 44310 @since 1.3.0 44311 @public 44312 */ 44313 isAny: function (key, value) { 44314 return this.any(iter.apply(this, arguments)); 44315 }, 44316 44317 /** 44318 This will combine the values of the enumerator into a single value. It 44319 is a useful way to collect a summary value from an enumeration. This 44320 corresponds to the `reduce()` method defined in JavaScript 1.8. 44321 The callback method you provide should have the following signature (all 44322 parameters are optional): 44323 ```javascript 44324 function(previousValue, item, index, enumerable); 44325 ``` 44326 - `previousValue` is the value returned by the last call to the iterator. 44327 - `item` is the current item in the iteration. 44328 - `index` is the current index in the iteration. 44329 - `enumerable` is the enumerable object itself. 44330 Return the new cumulative value. 44331 In addition to the callback you can also pass an `initialValue`. An error 44332 will be raised if you do not pass an initial value and the enumerator is 44333 empty. 44334 Note that unlike the other methods, this method does not allow you to 44335 pass a target object to set as this for the callback. It's part of the 44336 spec. Sorry. 44337 @method reduce 44338 @param {Function} callback The callback to execute 44339 @param {Object} initialValue Initial value for the reduce 44340 @param {String} reducerProperty internal use only. 44341 @return {Object} The reduced value. 44342 @public 44343 */ 44344 reduce: function (callback, initialValue, reducerProperty) { 44345 if (typeof callback !== 'function') { 44346 throw new TypeError(); 44347 } 44348 44349 var ret = initialValue; 44350 44351 this.forEach(function (item, i) { 44352 ret = callback(ret, item, i, this, reducerProperty); 44353 }, this); 44354 44355 return ret; 44356 }, 44357 44358 /** 44359 Invokes the named method on every object in the receiver that 44360 implements it. This method corresponds to the implementation in 44361 Prototype 1.6. 44362 @method invoke 44363 @param {String} methodName the name of the method 44364 @param {Object...} args optional arguments to pass as well. 44365 @return {Array} return values from calling invoke. 44366 @public 44367 */ 44368 invoke: function (methodName) { 44369 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 44370 args[_key - 1] = arguments[_key]; 44371 } 44372 44373 var ret = emberA(); 44374 44375 this.forEach(function (x, idx) { 44376 var method = x && x[methodName]; 44377 44378 if ('function' === typeof method) { 44379 ret[idx] = args ? method.apply(x, args) : x[methodName](); 44380 } 44381 }, this); 44382 44383 return ret; 44384 }, 44385 44386 /** 44387 Simply converts the enumerable into a genuine array. The order is not 44388 guaranteed. Corresponds to the method implemented by Prototype. 44389 @method toArray 44390 @return {Array} the enumerable as an array. 44391 @public 44392 */ 44393 toArray: function () { 44394 var ret = emberA(); 44395 44396 this.forEach(function (o, idx) { 44397 ret[idx] = o; 44398 }); 44399 44400 return ret; 44401 }, 44402 44403 /** 44404 Returns a copy of the array with all `null` and `undefined` elements removed. 44405 ```javascript 44406 var arr = ['a', null, 'c', undefined]; 44407 arr.compact(); // ['a', 'c'] 44408 ``` 44409 @method compact 44410 @return {Array} the array without null and undefined elements. 44411 @public 44412 */ 44413 compact: function () { 44414 return this.filter(function (value) { 44415 return value != null; 44416 }); 44417 }, 44418 44419 /** 44420 Returns a new enumerable that excludes the passed value. The default 44421 implementation returns an array regardless of the receiver type unless 44422 the receiver does not contain the value. 44423 ```javascript 44424 var arr = ['a', 'b', 'a', 'c']; 44425 arr.without('a'); // ['b', 'c'] 44426 ``` 44427 @method without 44428 @param {Object} value 44429 @return {Ember.Enumerable} 44430 @public 44431 */ 44432 without: function (value) { 44433 if (!this.contains(value)) { 44434 return this; // nothing to do 44435 } 44436 44437 var ret = emberA(); 44438 44439 this.forEach(function (k) { 44440 if (k !== value) { 44441 ret[ret.length] = k; 44442 } 44443 }); 44444 44445 return ret; 44446 }, 44447 44448 /** 44449 Returns a new enumerable that contains only unique values. The default 44450 implementation returns an array regardless of the receiver type. 44451 ```javascript 44452 var arr = ['a', 'a', 'b', 'b']; 44453 arr.uniq(); // ['a', 'b'] 44454 ``` 44455 This only works on primitive data types, e.g. Strings, Numbers, etc. 44456 @method uniq 44457 @return {Ember.Enumerable} 44458 @public 44459 */ 44460 uniq: function () { 44461 var ret = emberA(); 44462 44463 this.forEach(function (k) { 44464 if (ret.indexOf(k) < 0) {
44465 ret.push(k); 44466 } 44467 }); 44468 44469 return ret; 44470 }, 44471 44472 /** 44473 This property will trigger anytime the enumerable's content changes. 44474 You can observe this property to be notified of changes to the enumerable's 44475 content. 44476 For plain enumerables, this property is read only. `Array` overrides 44477 this method. 44478 @property [] 44479 @type Array 44480 @return this 44481 @private 44482 */ 44483 '[]': _emberMetalComputed.computed({ 44484 get: function (key) { 44485 return this; 44486 } 44487 }), 44488 44489 // .......................................................... 44490 // ENUMERABLE OBSERVERS 44491 // 44492 44493 /** 44494 Registers an enumerable observer. Must implement `Ember.EnumerableObserver` 44495 mixin. 44496 @method addEnumerableObserver 44497 @param {Object} target 44498 @param {Object} [opts] 44499 @return this 44500 @private 44501 */ 44502 addEnumerableObserver: function (target, opts) { 44503 var willChange = opts && opts.willChange || 'enumerableWillChange'; 44504 var didChange = opts && opts.didChange || 'enumerableDidChange'; 44505 var hasObservers = _emberMetalProperty_get.get(this, 'hasEnumerableObservers'); 44506 44507 if (!hasObservers) { 44508 _emberMetalProperty_events.propertyWillChange(this, 'hasEnumerableObservers'); 44509 } 44510 44511 _emberMetalEvents.addListener(this, '@enumerable:before', target, willChange); 44512 _emberMetalEvents.addListener(this, '@enumerable:change', target, didChange); 44513 44514 if (!hasObservers) { 44515 _emberMetalProperty_events.propertyDidChange(this, 'hasEnumerableObservers'); 44516 } 44517 44518 return this; 44519 }, 44520 44521 /** 44522 Removes a registered enumerable observer. 44523 @method removeEnumerableObserver 44524 @param {Object} target 44525 @param {Object} [opts] 44526 @return this 44527 @private 44528 */ 44529 removeEnumerableObserver: function (target, opts) { 44530 var willChange = opts && opts.willChange || 'enumerableWillChange'; 44531 var didChange = opts && opts.didChange || 'enumerableDidChange'; 44532 var hasObservers = _emberMetalProperty_get.get(this, 'hasEnumerableObservers'); 44533 44534 if (hasObservers) { 44535 _emberMetalProperty_events.propertyWillChange(this, 'hasEnumerableObservers'); 44536 } 44537 44538 _emberMetalEvents.removeListener(this, '@enumerable:before', target, willChange); 44539 _emberMetalEvents.removeListener(this, '@enumerable:change', target, didChange); 44540 44541 if (hasObservers) { 44542 _emberMetalProperty_events.propertyDidChange(this, 'hasEnumerableObservers'); 44543 } 44544 44545 return this; 44546 }, 44547 44548 /** 44549 Becomes true whenever the array currently has observers watching changes 44550 on the array. 44551 @property hasEnumerableObservers 44552 @type Boolean 44553 @private 44554 */ 44555 hasEnumerableObservers: _emberMetalComputed.computed(function () { 44556 return _emberMetalEvents.hasListeners(this, '@enumerable:change') || _emberMetalEvents.hasListeners(this, '@enumerable:before'); 44557 }), 44558 44559 /** 44560 Invoke this method just before the contents of your enumerable will 44561 change. You can either omit the parameters completely or pass the objects 44562 to be removed or added if available or just a count. 44563 @method enumerableContentWillChange 44564 @param {Ember.Enumerable|Number} removing An enumerable of the objects to 44565 be removed or the number of items to be removed. 44566 @param {Ember.Enumerable|Number} adding An enumerable of the objects to be 44567 added or the number of items to be added. 44568 @chainable 44569 @private 44570 */ 44571 enumerableContentWillChange: function (removing, adding) { 44572 var removeCnt, addCnt, hasDelta; 44573 44574 if ('number' === typeof removing) { 44575 removeCnt = removing; 44576 } else if (removing) { 44577 removeCnt = _emberMetalProperty_get.get(removing, 'length'); 44578 } else { 44579 removeCnt = removing = -1; 44580 } 44581 44582 if ('number' === typeof adding) { 44583 addCnt = adding; 44584 } else if (adding) { 44585 addCnt = _emberMetalProperty_get.get(adding, 'length'); 44586 } else { 44587 addCnt = adding = -1; 44588 } 44589 44590 hasDelta = addCnt < 0 || removeCnt < 0 || addCnt - removeCnt !== 0; 44591 44592 if (removing === -1) { 44593 removing = null; 44594 } 44595 44596 if (adding === -1) { 44597 adding = null; 44598 } 44599 44600 _emberMetalProperty_events.propertyWillChange(this, '[]'); 44601 44602 if (hasDelta) { 44603 _emberMetalProperty_events.propertyWillChange(this, 'length'); 44604 } 44605 44606 _emberMetalEvents.sendEvent(this, '@enumerable:before', [this, removing, adding]); 44607 44608 return this; 44609 }, 44610 44611 /** 44612 Invoke this method when the contents of your enumerable has changed. 44613 This will notify any observers watching for content changes. If you are 44614 implementing an ordered enumerable (such as an array), also pass the 44615 start and end values where the content changed so that it can be used to 44616 notify range observers. 44617 @method enumerableContentDidChange 44618 @param {Ember.Enumerable|Number} removing An enumerable of the objects to 44619 be removed or the number of items to be removed. 44620 @param {Ember.Enumerable|Number} adding An enumerable of the objects to 44621 be added or the number of items to be added. 44622 @chainable 44623 @private 44624 */ 44625 enumerableContentDidChange: function (removing, adding) { 44626 var removeCnt, addCnt, hasDelta; 44627 44628 if ('number' === typeof removing) { 44629 removeCnt = removing; 44630 } else if (removing) { 44631 removeCnt = _emberMetalProperty_get.get(removing, 'length'); 44632 } else { 44633 removeCnt = removing = -1; 44634 } 44635 44636 if ('number' === typeof adding) { 44637 addCnt = adding; 44638 } else if (adding) { 44639 addCnt = _emberMetalProperty_get.get(adding, 'length'); 44640 } else { 44641 addCnt = adding = -1; 44642 } 44643 44644 hasDelta = addCnt < 0 || removeCnt < 0 || addCnt - removeCnt !== 0; 44645 44646 if (removing === -1) { 44647 removing = null; 44648 } 44649 44650 if (adding === -1) { 44651 adding = null; 44652 } 44653 44654 _emberMetalEvents.sendEvent(this, '@enumerable:change', [this, removing, adding]); 44655 44656 if (hasDelta) { 44657 _emberMetalProperty_events.propertyDidChange(this, 'length'); 44658 } 44659 44660 _emberMetalProperty_events.propertyDidChange(this, '[]'); 44661 44662 return this; 44663 }, 44664 44665 /** 44666 Converts the enumerable into an array and sorts by the keys 44667 specified in the argument. 44668 You may provide multiple arguments to sort by multiple properties. 44669 @method sortBy 44670 @param {String} property name(s) to sort on 44671 @return {Array} The sorted array.
44672 @since 1.2.0 44673 @public 44674 */ 44675 sortBy: function () { 44676 var sortKeys = arguments; 44677 44678 return this.toArray().sort(function (a, b) { 44679 for (var i = 0; i < sortKeys.length; i++) { 44680 var key = sortKeys[i]; 44681 var propA = _emberMetalProperty_get.get(a, key); 44682 var propB = _emberMetalProperty_get.get(b, key); 44683 // return 1 or -1 else continue to the next sortKey 44684 var compareValue = _emberRuntimeCompare.default(propA, propB); 44685 44686 if (compareValue) { 44687 return compareValue; 44688 } 44689 } 44690 return 0; 44691 }); 44692 } 44693 }); 44694}); 44695enifed('ember-runtime/mixins/evented', ['exports', 'ember-metal/mixin', 'ember-metal/events'], function (exports, _emberMetalMixin, _emberMetalEvents) { 44696 'use strict'; 44697 44698 /** 44699 @module ember 44700 @submodule ember-runtime 44701 */ 44702 44703 /** 44704 This mixin allows for Ember objects to subscribe to and emit events. 44705 44706 ```javascript 44707 App.Person = Ember.Object.extend(Ember.Evented, { 44708 greet: function() { 44709 // ... 44710 this.trigger('greet'); 44711 } 44712 }); 44713 44714 var person = App.Person.create(); 44715 44716 person.on('greet', function() { 44717 console.log('Our person has greeted'); 44718 }); 44719 44720 person.greet(); 44721 44722 // outputs: 'Our person has greeted' 44723 ``` 44724 44725 You can also chain multiple event subscriptions: 44726 44727 ```javascript 44728 person.on('greet', function() { 44729 console.log('Our person has greeted'); 44730 }).one('greet', function() { 44731 console.log('Offer one-time special'); 44732 }).off('event', this, forgetThis); 44733 ``` 44734 44735 @class Evented 44736 @namespace Ember 44737 @public 44738 */ 44739 exports.default = _emberMetalMixin.Mixin.create({ 44740 44741 /** 44742 Subscribes to a named event with given function. 44743 ```javascript 44744 person.on('didLoad', function() { 44745 // fired once the person has loaded 44746 }); 44747 ``` 44748 An optional target can be passed in as the 2nd argument that will 44749 be set as the "this" for the callback. This is a good way to give your 44750 function access to the object triggering the event. When the target 44751 parameter is used the callback becomes the third argument. 44752 @method on 44753 @param {String} name The name of the event 44754 @param {Object} [target] The "this" binding for the callback 44755 @param {Function} method The callback to execute 44756 @return this 44757 @public 44758 */ 44759 on: function (name, target, method) { 44760 _emberMetalEvents.addListener(this, name, target, method); 44761 return this; 44762 }, 44763 44764 /** 44765 Subscribes a function to a named event and then cancels the subscription 44766 after the first time the event is triggered. It is good to use ``one`` when 44767 you only care about the first time an event has taken place. 44768 This function takes an optional 2nd argument that will become the "this" 44769 value for the callback. If this argument is passed then the 3rd argument 44770 becomes the function. 44771 @method one 44772 @param {String} name The name of the event 44773 @param {Object} [target] The "this" binding for the callback 44774 @param {Function} method The callback to execute 44775 @return this 44776 @public 44777 */ 44778 one: function (name, target, method) { 44779 if (!method) { 44780 method = target; 44781 target = null; 44782 } 44783 44784 _emberMetalEvents.addListener(this, name, target, method, true); 44785 return this; 44786 }, 44787 44788 /** 44789 Triggers a named event for the object. Any additional arguments 44790 will be passed as parameters to the functions that are subscribed to the 44791 event. 44792 ```javascript 44793 person.on('didEat', function(food) { 44794 console.log('person ate some ' + food); 44795 }); 44796 person.trigger('didEat', 'broccoli'); 44797 // outputs: person ate some broccoli 44798 ``` 44799 @method trigger 44800 @param {String} name The name of the event 44801 @param {Object...} args Optional arguments to pass on 44802 @public 44803 */ 44804 trigger: function (name) { 44805 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 44806 args[_key - 1] = arguments[_key]; 44807 } 44808 44809 _emberMetalEvents.sendEvent(this, name, args); 44810 }, 44811 44812 /** 44813 Cancels subscription for given name, target, and method. 44814 @method off 44815 @param {String} name The name of the event 44816 @param {Object} target The target of the subscription 44817 @param {Function} method The function of the subscription 44818 @return this 44819 @public 44820 */ 44821 off: function (name, target, method) { 44822 _emberMetalEvents.removeListener(this, name, target, method); 44823 return this; 44824 }, 44825 44826 /** 44827 Checks to see if object has any subscriptions for named event. 44828 @method has 44829 @param {String} name The name of the event 44830 @return {Boolean} does the object have a subscription for event 44831 @public 44832 */ 44833 has: function (name) { 44834 return _emberMetalEvents.hasListeners(this, name); 44835 } 44836 }); 44837}); 44838enifed('ember-runtime/mixins/freezable', ['exports', 'ember-metal/debug', 'ember-metal/mixin', 'ember-metal/property_get', 'ember-metal/property_set'], function (exports, _emberMetalDebug, _emberMetalMixin, _emberMetalProperty_get, _emberMetalProperty_set) { 44839 /** 44840 @module ember 44841 @submodule ember-runtime 44842 */ 44843 44844 'use strict'; 44845 44846 /** 44847 The `Ember.Freezable` mixin implements some basic methods for marking an 44848 object as frozen. Once an object is frozen it should be read only. No changes 44849 may be made the internal state of the object. 44850 44851 ## Enforcement 44852
44853 To fully support freezing in your subclass, you must include this mixin and 44854 override any method that might alter any property on the object to instead 44855 raise an exception. You can check the state of an object by checking the 44856 `isFrozen` property. 44857 44858 Although future versions of JavaScript may support language-level freezing 44859 object objects, that is not the case today. Even if an object is freezable, 44860 it is still technically possible to modify the object, even though it could 44861 break other parts of your application that do not expect a frozen object to 44862 change. It is, therefore, very important that you always respect the 44863 `isFrozen` property on all freezable objects. 44864 44865 ## Example Usage 44866 44867 The example below shows a simple object that implement the `Ember.Freezable` 44868 protocol. 44869 44870 ```javascript 44871 Contact = Ember.Object.extend(Ember.Freezable, { 44872 firstName: null, 44873 lastName: null, 44874 44875 // swaps the names 44876 swapNames: function() { 44877 if (this.get('isFrozen')) throw Ember.FROZEN_ERROR; 44878 var tmp = this.get('firstName'); 44879 this.set('firstName', this.get('lastName')); 44880 this.set('lastName', tmp); 44881 return this; 44882 } 44883 44884 }); 44885 44886 c = Contact.create({ firstName: "John", lastName: "Doe" }); 44887 c.swapNames(); // returns c 44888 c.freeze(); 44889 c.swapNames(); // EXCEPTION 44890 ``` 44891 44892 ## Copying 44893 44894 Usually the `Ember.Freezable` protocol is implemented in cooperation with the 44895 `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will 44896 return a frozen object, if the object implements this method as well. 44897 44898 @class Freezable 44899 @namespace Ember 44900 @since Ember 0.9 44901 @deprecated Use `Object.freeze` instead. 44902 @private 44903 */ 44904 var Freezable = _emberMetalMixin.Mixin.create({ 44905 44906 init: function () { 44907 _emberMetalDebug.deprecate('`Ember.Freezable` is deprecated, use `Object.freeze` instead.', false, { id: 'ember-runtime.freezable-init', until: '3.0.0' }); 44908 this._super.apply(this, arguments); 44909 }, 44910 44911 /** 44912 Set to `true` when the object is frozen. Use this property to detect 44913 whether your object is frozen or not. 44914 @property isFrozen 44915 @type Boolean 44916 @private 44917 */ 44918 isFrozen: false, 44919 44920 /** 44921 Freezes the object. Once this method has been called the object should 44922 no longer allow any properties to be edited. 44923 @method freeze 44924 @return {Object} receiver 44925 @private 44926 */ 44927 freeze: function () { 44928 if (_emberMetalProperty_get.get(this, 'isFrozen')) { 44929 return this; 44930 } 44931 44932 _emberMetalProperty_set.set(this, 'isFrozen', true); 44933 return this; 44934 } 44935 44936 }); 44937 44938 exports.Freezable = Freezable; 44939 var FROZEN_ERROR = 'Frozen object cannot be modified.'; 44940 exports.FROZEN_ERROR = FROZEN_ERROR; 44941}); 44942enifed('ember-runtime/mixins/mutable_array', ['exports', 'ember-metal/property_get', 'ember-metal/error', 'ember-metal/mixin', 'ember-runtime/mixins/array', 'ember-runtime/mixins/mutable_enumerable', 'ember-runtime/mixins/enumerable'], function (exports, _emberMetalProperty_get, _emberMetalError, _emberMetalMixin, _emberRuntimeMixinsArray, _emberRuntimeMixinsMutable_enumerable, _emberRuntimeMixinsEnumerable) { 44943 /** 44944 @module ember 44945 @submodule ember-runtime 44946 */ 44947 44948 // require('ember-runtime/mixins/array'); 44949 // require('ember-runtime/mixins/mutable_enumerable'); 44950 44951 // .......................................................... 44952 // CONSTANTS 44953 // 44954 44955 'use strict'; 44956 44957 var OUT_OF_RANGE_EXCEPTION = 'Index out of range'; 44958 var EMPTY = []; 44959 44960 // .......................................................... 44961 // HELPERS 44962 // 44963 44964 /** 44965 This mixin defines the API for modifying array-like objects. These methods 44966 can be applied only to a collection that keeps its items in an ordered set. 44967 It builds upon the Array mixin and adds methods to modify the array. 44968 One concrete implementations of this class include ArrayProxy. 44969 44970 It is important to use the methods in this class to modify arrays so that 44971 changes are observable. This allows the binding system in Ember to function 44972 correctly. 44973 44974 44975 Note that an Array can change even if it does not implement this mixin. 44976 For example, one might implement a SparseArray that cannot be directly 44977 modified, but if its underlying enumerable changes, it will change also. 44978 44979 @class MutableArray 44980 @namespace Ember 44981 @uses Ember.Array 44982 @uses Ember.MutableEnumerable 44983 @public 44984 */ 44985 exports.default = _emberMetalMixin.Mixin.create(_emberRuntimeMixinsArray.default, _emberRuntimeMixinsMutable_enumerable.default, { 44986 44987 /** 44988 __Required.__ You must implement this method to apply this mixin.
44989 This is one of the primitives you must implement to support `Ember.Array`. 44990 You should replace amt objects started at idx with the objects in the 44991 passed array. You should also call `this.enumerableContentDidChange()` 44992 @method replace 44993 @param {Number} idx Starting index in the array to replace. If 44994 idx >= length, then append to the end of the array. 44995 @param {Number} amt Number of elements that should be removed from 44996 the array, starting at *idx*. 44997 @param {Array} objects An array of zero or more objects that should be 44998 inserted into the array at *idx* 44999 @public 45000 */ 45001 replace: null, 45002 45003 /** 45004 Remove all elements from the array. This is useful if you 45005 want to reuse an existing array without having to recreate it. 45006 ```javascript 45007 var colors = ['red', 'green', 'blue']; 45008 color.length(); // 3 45009 colors.clear(); // [] 45010 colors.length(); // 0 45011 ``` 45012 @method clear 45013 @return {Ember.Array} An empty Array. 45014 @public 45015 */ 45016 clear: function () { 45017 var len = _emberMetalProperty_get.get(this, 'length'); 45018 if (len === 0) { 45019 return this; 45020 } 45021 45022 this.replace(0, len, EMPTY); 45023 return this; 45024 }, 45025 45026 /** 45027 This will use the primitive `replace()` method to insert an object at the 45028 specified index. 45029 ```javascript 45030 var colors = ['red', 'green', 'blue']; 45031 colors.insertAt(2, 'yellow'); // ['red', 'green', 'yellow', 'blue'] 45032 colors.insertAt(5, 'orange'); // Error: Index out of range 45033 ``` 45034 @method insertAt 45035 @param {Number} idx index of insert the object at. 45036 @param {Object} object object to insert 45037 @return {Ember.Array} receiver 45038 @public 45039 */ 45040 insertAt: function (idx, object) { 45041 if (idx > _emberMetalProperty_get.get(this, 'length')) { 45042 throw new _emberMetalError.default(OUT_OF_RANGE_EXCEPTION); 45043 } 45044 45045 this.replace(idx, 0, [object]); 45046 return this; 45047 }, 45048 45049 /** 45050 Remove an object at the specified index using the `replace()` primitive 45051 method. You can pass either a single index, or a start and a length. 45052 If you pass a start and length that is beyond the 45053 length this method will throw an `OUT_OF_RANGE_EXCEPTION`. 45054 ```javascript 45055 var colors = ['red', 'green', 'blue', 'yellow', 'orange']; 45056 colors.removeAt(0); // ['green', 'blue', 'yellow', 'orange'] 45057 colors.removeAt(2, 2); // ['green', 'blue'] 45058 colors.removeAt(4, 2); // Error: Index out of range 45059 ``` 45060 @method removeAt 45061 @param {Number} start index, start of range 45062 @param {Number} len length of passing range 45063 @return {Ember.Array} receiver 45064 @public 45065 */ 45066 removeAt: function (start, len) { 45067 if ('number' === typeof start) { 45068 if (start < 0 || start >= _emberMetalProperty_get.get(this, 'length')) { 45069 throw new _emberMetalError.default(OUT_OF_RANGE_EXCEPTION); 45070 } 45071 45072 // fast case 45073 if (len === undefined) { 45074 len = 1; 45075 } 45076 45077 this.replace(start, len, EMPTY); 45078 } 45079 45080 return this; 45081 }, 45082 45083 /** 45084 Push the object onto the end of the array. Works just like `push()` but it 45085 is KVO-compliant. 45086 ```javascript 45087 var colors = ['red', 'green']; 45088 colors.pushObject('black'); // ['red', 'green', 'black'] 45089 colors.pushObject(['yellow']); // ['red', 'green', ['yellow']] 45090 ``` 45091 @method pushObject 45092 @param {*} obj object to push 45093 @return object same object passed as a param 45094 @public 45095 */ 45096 pushObject: function (obj) { 45097 this.insertAt(_emberMetalProperty_get.get(this, 'length'), obj); 45098 return obj; 45099 }, 45100 45101 /** 45102 Add the objects in the passed numerable to the end of the array. Defers 45103 notifying observers of the change until all objects are added. 45104 ```javascript 45105 var colors = ['red']; 45106 colors.pushObjects(['yellow', 'orange']); // ['red', 'yellow', 'orange'] 45107 ``` 45108 @method pushObjects 45109 @param {Ember.Enumerable} objects the objects to add 45110 @return {Ember.Array} receiver 45111 @public 45112 */ 45113 pushObjects: function (objects) { 45114 if (!(_emberRuntimeMixinsEnumerable.default.detect(objects) || Array.isArray(objects))) { 45115 throw new TypeError('Must pass Ember.Enumerable to Ember.MutableArray#pushObjects'); 45116 } 45117 this.replace(_emberMetalProperty_get.get(this, 'length'), 0, objects); 45118 return this; 45119 }, 45120 45121 /** 45122 Pop object from array or nil if none are left. Works just like `pop()` but 45123 it is KVO-compliant. 45124 ```javascript 45125 var colors = ['red', 'green', 'blue']; 45126 colors.popObject(); // 'blue' 45127 console.log(colors); // ['red', 'green'] 45128 ``` 45129 @method popObject 45130 @return object 45131 @public 45132 */ 45133 popObject: function () { 45134 var len = _emberMetalProperty_get.get(this, 'length'); 45135 if (len === 0) { 45136 return null; 45137 } 45138 45139 var ret = _emberRuntimeMixinsArray.objectAt(this, len - 1); 45140 this.removeAt(len - 1, 1); 45141 return ret; 45142 }, 45143 45144 /** 45145 Shift an object from start of array or nil if none are left. Works just 45146 like `shift()` but it is KVO-compliant. 45147 ```javascript 45148 var colors = ['red', 'green', 'blue']; 45149 colors.shiftObject(); // 'red' 45150 console.log(colors); // ['green', 'blue'] 45151 ``` 45152 @method shiftObject 45153 @return object 45154 @public 45155 */ 45156 shiftObject: function () { 45157 if (_emberMetalProperty_get.get(this, 'length') === 0) { 45158 return null; 45159 } 45160 45161 var ret = _emberRuntimeMixinsArray.objectAt(this, 0); 45162 this.removeAt(0); 45163 return ret; 45164 }, 45165 45166 /** 45167 Unshift an object to start of array. Works just like `unshift()` but it is 45168 KVO-compliant. 45169 ```javascript 45170 var colors = ['red']; 45171 colors.unshiftObject('yellow'); // ['yellow', 'red'] 45172 colors.unshiftObject(['black']); // [['black'], 'yellow', 'red'] 45173 ``` 45174 @method unshiftObject 45175 @param {*} obj object to unshift 45176 @return object same object passed as a param 45177 @public 45178 */ 45179 unshiftObject: function (obj) { 45180 this.insertAt(0, obj); 45181 return obj; 45182 }, 45183 45184 /** 45185 Adds the named objects to the beginning of the array. Defers notifying 45186 observers until all objects have been added.
45187 ```javascript 45188 var colors = ['red']; 45189 colors.unshiftObjects(['black', 'white']); // ['black', 'white', 'red'] 45190 colors.unshiftObjects('yellow'); // Type Error: 'undefined' is not a function 45191 ``` 45192 @method unshiftObjects 45193 @param {Ember.Enumerable} objects the objects to add 45194 @return {Ember.Array} receiver 45195 @public 45196 */ 45197 unshiftObjects: function (objects) { 45198 this.replace(0, 0, objects); 45199 return this; 45200 }, 45201 45202 /** 45203 Reverse objects in the array. Works just like `reverse()` but it is 45204 KVO-compliant. 45205 @method reverseObjects 45206 @return {Ember.Array} receiver 45207 @public 45208 */ 45209 reverseObjects: function () { 45210 var len = _emberMetalProperty_get.get(this, 'length'); 45211 if (len === 0) { 45212 return this; 45213 } 45214 45215 var objects = this.toArray().reverse(); 45216 this.replace(0, len, objects); 45217 return this; 45218 }, 45219 45220 /** 45221 Replace all the receiver's content with content of the argument. 45222 If argument is an empty array receiver will be cleared. 45223 ```javascript 45224 var colors = ['red', 'green', 'blue']; 45225 colors.setObjects(['black', 'white']); // ['black', 'white'] 45226 colors.setObjects([]); // [] 45227 ``` 45228 @method setObjects 45229 @param {Ember.Array} objects array whose content will be used for replacing 45230 the content of the receiver 45231 @return {Ember.Array} receiver with the new content 45232 @public 45233 */ 45234 setObjects: function (objects) { 45235 if (objects.length === 0) { 45236 return this.clear(); 45237 } 45238 45239 var len = _emberMetalProperty_get.get(this, 'length'); 45240 this.replace(0, len, objects); 45241 return this; 45242 }, 45243 45244 // .......................................................... 45245 // IMPLEMENT Ember.MutableEnumerable 45246 // 45247 45248 /** 45249 Remove all occurrences of an object in the array. 45250 ```javascript 45251 var cities = ['Chicago', 'Berlin', 'Lima', 'Chicago']; 45252 cities.removeObject('Chicago'); // ['Berlin', 'Lima'] 45253 cities.removeObject('Lima'); // ['Berlin'] 45254 cities.removeObject('Tokyo') // ['Berlin'] 45255 ``` 45256 @method removeObject 45257 @param {*} obj object to remove 45258 @return {Ember.Array} receiver 45259 @public 45260 */ 45261 removeObject: function (obj) { 45262 var loc = _emberMetalProperty_get.get(this, 'length') || 0; 45263 while (--loc >= 0) { 45264 var curObject = _emberRuntimeMixinsArray.objectAt(this, loc); 45265 45266 if (curObject === obj) { 45267 this.removeAt(loc); 45268 } 45269 } 45270 return this; 45271 }, 45272 45273 /** 45274 Push the object onto the end of the array if it is not already 45275 present in the array. 45276 ```javascript 45277 var cities = ['Chicago', 'Berlin']; 45278 cities.addObject('Lima'); // ['Chicago', 'Berlin', 'Lima'] 45279 cities.addObject('Berlin'); // ['Chicago', 'Berlin', 'Lima'] 45280 ``` 45281 @method addObject 45282 @param {*} obj object to add, if not already present 45283 @return {Ember.Array} receiver 45284 @public 45285 */ 45286 addObject: function (obj) { 45287 if (!this.contains(obj)) { 45288 this.pushObject(obj); 45289 } 45290 45291 return this; 45292 } 45293 }); 45294}); 45295enifed('ember-runtime/mixins/mutable_enumerable', ['exports', 'ember-runtime/mixins/enumerable', 'ember-metal/mixin', 'ember-metal/property_events'], function (exports, _emberRuntimeMixinsEnumerable, _emberMetalMixin, _emberMetalProperty_events) { 45296 'use strict'; 45297 45298 /** 45299 @module ember 45300 @submodule ember-runtime 45301 */ 45302 45303 /** 45304 This mixin defines the API for modifying generic enumerables. These methods 45305 can be applied to an object regardless of whether it is ordered or 45306 unordered. 45307 45308 Note that an Enumerable can change even if it does not implement this mixin. 45309 For example, a MappedEnumerable cannot be directly modified but if its 45310 underlying enumerable changes, it will change also. 45311 45312 ## Adding Objects 45313 45314 To add an object to an enumerable, use the `addObject()` method. This 45315 method will only add the object to the enumerable if the object is not 45316 already present and is of a type supported by the enumerable. 45317 45318 ```javascript 45319 set.addObject(contact); 45320 ``` 45321 45322 ## Removing Objects 45323 45324 To remove an object from an enumerable, use the `removeObject()` method. This 45325 will only remove the object if it is present in the enumerable, otherwise 45326 this method has no effect. 45327 45328 ```javascript 45329 set.removeObject(contact); 45330 ``` 45331 45332 ## Implementing In Your Own Code 45333
45334 If you are implementing an object and want to support this API, just include 45335 this mixin in your class and implement the required methods. In your unit 45336 tests, be sure to apply the Ember.MutableEnumerableTests to your object. 45337 45338 @class MutableEnumerable 45339 @namespace Ember 45340 @uses Ember.Enumerable 45341 @public 45342 */ 45343 exports.default = _emberMetalMixin.Mixin.create(_emberRuntimeMixinsEnumerable.default, { 45344 45345 /** 45346 __Required.__ You must implement this method to apply this mixin. 45347 Attempts to add the passed object to the receiver if the object is not 45348 already present in the collection. If the object is present, this method 45349 has no effect. 45350 If the passed object is of a type not supported by the receiver, 45351 then this method should raise an exception. 45352 @method addObject 45353 @param {Object} object The object to add to the enumerable. 45354 @return {Object} the passed object 45355 @public 45356 */ 45357 addObject: null, 45358 45359 /** 45360 Adds each object in the passed enumerable to the receiver. 45361 @method addObjects 45362 @param {Ember.Enumerable} objects the objects to add. 45363 @return {Object} receiver 45364 @public 45365 */ 45366 addObjects: function (objects) { 45367 var _this = this; 45368 45369 _emberMetalProperty_events.beginPropertyChanges(this); 45370 objects.forEach(function (obj) { 45371 return _this.addObject(obj); 45372 }); 45373 _emberMetalProperty_events.endPropertyChanges(this); 45374 return this; 45375 }, 45376 45377 /** 45378 __Required.__ You must implement this method to apply this mixin. 45379 Attempts to remove the passed object from the receiver collection if the 45380 object is present in the collection. If the object is not present, 45381 this method has no effect. 45382 If the passed object is of a type not supported by the receiver, 45383 then this method should raise an exception. 45384 @method removeObject 45385 @param {Object} object The object to remove from the enumerable. 45386 @return {Object} the passed object 45387 @public 45388 */ 45389 removeObject: null, 45390 45391 /** 45392 Removes each object in the passed enumerable from the receiver. 45393 @method removeObjects 45394 @param {Ember.Enumerable} objects the objects to remove 45395 @return {Object} receiver 45396 @public 45397 */ 45398 removeObjects: function (objects) { 45399 _emberMetalProperty_events.beginPropertyChanges(this); 45400 for (var i = objects.length - 1; i >= 0; i--) { 45401 this.removeObject(objects[i]); 45402 } 45403 _emberMetalProperty_events.endPropertyChanges(this); 45404 return this; 45405 } 45406 }); 45407}); 45408enifed('ember-runtime/mixins/observable', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/get_properties', 'ember-metal/set_properties', 'ember-metal/mixin', 'ember-metal/events', 'ember-metal/property_events', 'ember-metal/observer', 'ember-metal/computed', 'ember-metal/is_none'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalGet_properties, _emberMetalSet_properties, _emberMetalMixin, _emberMetalEvents, _emberMetalProperty_events, _emberMetalObserver, _emberMetalComputed, _emberMetalIs_none) { 45409 /** 45410 @module ember 45411 @submodule ember-runtime 45412 */ 45413 45414 'use strict'; 45415 45416 /** 45417 ## Overview 45418 45419 This mixin provides properties and property observing functionality, core 45420 features of the Ember object model. 45421 45422 Properties and observers allow one object to observe changes to a 45423 property on another object. This is one of the fundamental ways that 45424 models, controllers and views communicate with each other in an Ember 45425 application. 45426 45427 Any object that has this mixin applied can be used in observer 45428 operations. That includes `Ember.Object` and most objects you will 45429 interact with as you write your Ember application. 45430 45431 Note that you will not generally apply this mixin to classes yourself, 45432 but you will use the features provided by this module frequently, so it 45433 is important to understand how to use it. 45434 45435 ## Using `get()` and `set()` 45436 45437 Because of Ember's support for bindings and observers, you will always 45438 access properties using the get method, and set properties using the 45439 set method. This allows the observing objects to be notified and 45440 computed properties to be handled properly. 45441 45442 More documentation about `get` and `set` are below.
45443 45444 ## Observing Property Changes 45445 45446 You typically observe property changes simply by using the `Ember.observer` 45447 function in classes that you write. 45448 45449 For example: 45450 45451 ```javascript 45452 Ember.Object.extend({ 45453 valueObserver: Ember.observer('value', function(sender, key, value, rev) { 45454 // Executes whenever the "value" property changes 45455 // See the addObserver method for more information about the callback arguments 45456 }) 45457 }); 45458 ``` 45459 45460 Although this is the most common way to add an observer, this capability 45461 is actually built into the `Ember.Object` class on top of two methods 45462 defined in this mixin: `addObserver` and `removeObserver`. You can use 45463 these two methods to add and remove observers yourself if you need to 45464 do so at runtime. 45465 45466 To add an observer for a property, call: 45467 45468 ```javascript 45469 object.addObserver('propertyKey', targetObject, targetAction) 45470 ``` 45471 45472 This will call the `targetAction` method on the `targetObject` whenever 45473 the value of the `propertyKey` changes. 45474 45475 Note that if `propertyKey` is a computed property, the observer will be 45476 called when any of the property dependencies are changed, even if the 45477 resulting value of the computed property is unchanged. This is necessary 45478 because computed properties are not computed until `get` is called. 45479 45480 @class Observable 45481 @namespace Ember 45482 @public 45483 */ 45484 exports.default = _emberMetalMixin.Mixin.create({ 45485 45486 /** 45487 Retrieves the value of a property from the object. 45488 This method is usually similar to using `object[keyName]` or `object.keyName`, 45489 however it supports both computed properties and the unknownProperty 45490 handler. 45491 Because `get` unifies the syntax for accessing all these kinds 45492 of properties, it can make many refactorings easier, such as replacing a 45493 simple property with a computed property, or vice versa. 45494 ### Computed Properties 45495 Computed properties are methods defined with the `property` modifier 45496 declared at the end, such as: 45497 ```javascript 45498 fullName: function() { 45499 return this.get('firstName') + ' ' + this.get('lastName'); 45500 }.property('firstName', 'lastName') 45501 ``` 45502 When you call `get` on a computed property, the function will be 45503 called and the return value will be returned instead of the function 45504 itself. 45505 ### Unknown Properties 45506 Likewise, if you try to call `get` on a property whose value is 45507 `undefined`, the `unknownProperty()` method will be called on the object. 45508 If this method returns any value other than `undefined`, it will be returned 45509 instead. This allows you to implement "virtual" properties that are 45510 not defined upfront. 45511 @method get 45512 @param {String} keyName The property to retrieve 45513 @return {Object} The property value or undefined. 45514 @public 45515 */ 45516 get: function (keyName) { 45517 return _emberMetalProperty_get.get(this, keyName); 45518 }, 45519 45520 /** 45521 To get the values of multiple properties at once, call `getProperties` 45522 with a list of strings or an array: 45523 ```javascript 45524 record.getProperties('firstName', 'lastName', 'zipCode'); 45525 // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } 45526 ``` 45527 is equivalent to: 45528 ```javascript 45529 record.getProperties(['firstName', 'lastName', 'zipCode']); 45530 // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } 45531 ``` 45532 @method getProperties 45533 @param {String...|Array} list of keys to get 45534 @return {Object} 45535 @public 45536 */ 45537 getProperties: function () { 45538 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 45539 args[_key] = arguments[_key]; 45540 } 45541 45542 return _emberMetalGet_properties.default.apply(null, [this].concat(args)); 45543 }, 45544 45545 /** 45546 Sets the provided key or path to the value. 45547 This method is generally very similar to calling `object[key] = value` or 45548 `object.key = value`, except that it provides support for computed 45549 properties, the `setUnknownProperty()` method and property observers. 45550 ### Computed Properties 45551 If you try to set a value on a key that has a computed property handler 45552 defined (see the `get()` method for an example), then `set()` will call 45553 that method, passing both the value and key instead of simply changing 45554 the value itself. This is useful for those times when you need to 45555 implement a property that is composed of one or more member 45556 properties. 45557 ### Unknown Properties 45558 If you try to set a value on a key that is undefined in the target 45559 object, then the `setUnknownProperty()` handler will be called instead. This 45560 gives you an opportunity to implement complex "virtual" properties that 45561 are not predefined on the object. If `setUnknownProperty()` returns 45562 undefined, then `set()` will simply set the value on the object. 45563 ### Property Observers 45564 In addition to changing the property, `set()` will also register a property 45565 change with the object. Unless you have placed this call inside of a 45566 `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers 45567 (i.e. observer methods declared on the same object), will be called 45568 immediately. Any "remote" observers (i.e. observer methods declared on 45569 another object) will be placed in a queue and called at a later time in a 45570 coalesced manner. 45571 @method set 45572 @param {String} keyName The property to set 45573 @param {Object} value The value to set or `null`. 45574 @return {Object} The passed value 45575 @public 45576 */ 45577 set: function (keyName, value) { 45578 return _emberMetalProperty_set.set(this, keyName, value); 45579 }, 45580 45581 /** 45582 Sets a list of properties at once. These properties are set inside 45583 a single `beginPropertyChanges` and `endPropertyChanges` batch, so 45584 observers will be buffered. 45585 ```javascript 45586 record.setProperties({ firstName: 'Charles', lastName: 'Jolley' }); 45587 ``` 45588 @method setProperties 45589 @param {Object} hash the hash of keys and values to set 45590 @return {Object} The passed in hash 45591 @public 45592 */
45593 setProperties: function (hash) { 45594 return _emberMetalSet_properties.default(this, hash); 45595 }, 45596 45597 /** 45598 Begins a grouping of property changes. 45599 You can use this method to group property changes so that notifications 45600 will not be sent until the changes are finished. If you plan to make a 45601 large number of changes to an object at one time, you should call this 45602 method at the beginning of the changes to begin deferring change 45603 notifications. When you are done making changes, call 45604 `endPropertyChanges()` to deliver the deferred change notifications and end 45605 deferring. 45606 @method beginPropertyChanges 45607 @return {Ember.Observable} 45608 @private 45609 */ 45610 beginPropertyChanges: function () { 45611 _emberMetalProperty_events.beginPropertyChanges(); 45612 return this; 45613 }, 45614 45615 /** 45616 Ends a grouping of property changes. 45617 You can use this method to group property changes so that notifications 45618 will not be sent until the changes are finished. If you plan to make a 45619 large number of changes to an object at one time, you should call 45620 `beginPropertyChanges()` at the beginning of the changes to defer change 45621 notifications. When you are done making changes, call this method to 45622 deliver the deferred change notifications and end deferring. 45623 @method endPropertyChanges 45624 @return {Ember.Observable} 45625 @private 45626 */ 45627 endPropertyChanges: function () { 45628 _emberMetalProperty_events.endPropertyChanges(); 45629 return this; 45630 }, 45631 45632 /** 45633 Notify the observer system that a property is about to change. 45634 Sometimes you need to change a value directly or indirectly without 45635 actually calling `get()` or `set()` on it. In this case, you can use this 45636 method and `propertyDidChange()` instead. Calling these two methods 45637 together will notify all observers that the property has potentially 45638 changed value. 45639 Note that you must always call `propertyWillChange` and `propertyDidChange` 45640 as a pair. If you do not, it may get the property change groups out of 45641 order and cause notifications to be delivered more often than you would 45642 like. 45643 @method propertyWillChange 45644 @param {String} keyName The property key that is about to change. 45645 @return {Ember.Observable} 45646 @private 45647 */ 45648 propertyWillChange: function (keyName) { 45649 _emberMetalProperty_events.propertyWillChange(this, keyName); 45650 return this; 45651 }, 45652 45653 /** 45654 Notify the observer system that a property has just changed. 45655 Sometimes you need to change a value directly or indirectly without 45656 actually calling `get()` or `set()` on it. In this case, you can use this 45657 method and `propertyWillChange()` instead. Calling these two methods 45658 together will notify all observers that the property has potentially 45659 changed value. 45660 Note that you must always call `propertyWillChange` and `propertyDidChange` 45661 as a pair. If you do not, it may get the property change groups out of 45662 order and cause notifications to be delivered more often than you would 45663 like. 45664 @method propertyDidChange 45665 @param {String} keyName The property key that has just changed. 45666 @return {Ember.Observable} 45667 @private 45668 */ 45669 propertyDidChange: function (keyName) { 45670 _emberMetalProperty_events.propertyDidChange(this, keyName); 45671 return this; 45672 }, 45673 45674 /** 45675 Convenience method to call `propertyWillChange` and `propertyDidChange` in 45676 succession. 45677 @method notifyPropertyChange 45678 @param {String} keyName The property key to be notified about. 45679 @return {Ember.Observable} 45680 @public 45681 */ 45682 notifyPropertyChange: function (keyName) { 45683 this.propertyWillChange(keyName); 45684 this.propertyDidChange(keyName); 45685 return this; 45686 }, 45687 45688 /** 45689 Adds an observer on a property. 45690 This is the core method used to register an observer for a property. 45691 Once you call this method, any time the key's value is set, your observer 45692 will be notified. Note that the observers are triggered any time the 45693 value is set, regardless of whether it has actually changed. Your 45694 observer should be prepared to handle that. 45695 You can also pass an optional context parameter to this method. The 45696 context will be passed to your observer method whenever it is triggered. 45697 Note that if you add the same target/method pair on a key multiple times
45698 with different context parameters, your observer will only be called once 45699 with the last context you passed. 45700 ### Observer Methods 45701 Observer methods you pass should generally have the following signature if 45702 you do not pass a `context` parameter: 45703 ```javascript 45704 fooDidChange: function(sender, key, value, rev) { }; 45705 ``` 45706 The sender is the object that changed. The key is the property that 45707 changes. The value property is currently reserved and unused. The rev 45708 is the last property revision of the object when it changed, which you can 45709 use to detect if the key value has really changed or not. 45710 If you pass a `context` parameter, the context will be passed before the 45711 revision like so: 45712 ```javascript 45713 fooDidChange: function(sender, key, value, context, rev) { }; 45714 ``` 45715 Usually you will not need the value, context or revision parameters at 45716 the end. In this case, it is common to write observer methods that take 45717 only a sender and key value as parameters or, if you aren't interested in 45718 any of these values, to write an observer that has no parameters at all. 45719 @method addObserver 45720 @param {String} key The key to observer 45721 @param {Object} target The target object to invoke 45722 @param {String|Function} method The method to invoke. 45723 @public 45724 */ 45725 addObserver: function (key, target, method) { 45726 _emberMetalObserver.addObserver(this, key, target, method); 45727 }, 45728 45729 /** 45730 Remove an observer you have previously registered on this object. Pass 45731 the same key, target, and method you passed to `addObserver()` and your 45732 target will no longer receive notifications. 45733 @method removeObserver 45734 @param {String} key The key to observer 45735 @param {Object} target The target object to invoke 45736 @param {String|Function} method The method to invoke. 45737 @public 45738 */ 45739 removeObserver: function (key, target, method) { 45740 _emberMetalObserver.removeObserver(this, key, target, method); 45741 }, 45742 45743 /** 45744 Returns `true` if the object currently has observers registered for a 45745 particular key. You can use this method to potentially defer performing 45746 an expensive action until someone begins observing a particular property 45747 on the object. 45748 @method hasObserverFor 45749 @param {String} key Key to check 45750 @return {Boolean} 45751 @private 45752 */ 45753 hasObserverFor: function (key) { 45754 return _emberMetalEvents.hasListeners(this, key + ':change'); 45755 }, 45756 45757 /** 45758 Retrieves the value of a property, or a default value in the case that the 45759 property returns `undefined`. 45760 ```javascript 45761 person.getWithDefault('lastName', 'Doe'); 45762 ``` 45763 @method getWithDefault 45764 @param {String} keyName The name of the property to retrieve 45765 @param {Object} defaultValue The value to return if the property value is undefined 45766 @return {Object} The property value or the defaultValue. 45767 @public 45768 */ 45769 getWithDefault: function (keyName, defaultValue) { 45770 return _emberMetalProperty_get.getWithDefault(this, keyName, defaultValue); 45771 }, 45772 45773 /** 45774 Set the value of a property to the current value plus some amount. 45775 ```javascript 45776 person.incrementProperty('age'); 45777 team.incrementProperty('score', 2); 45778 ``` 45779 @method incrementProperty 45780 @param {String} keyName The name of the property to increment 45781 @param {Number} increment The amount to increment by. Defaults to 1 45782 @return {Number} The new property value 45783 @public 45784 */ 45785 incrementProperty: function (keyName, increment) { 45786 if (_emberMetalIs_none.default(increment)) { 45787 increment = 1; 45788 } 45789 _emberMetalDebug.assert('Must pass a numeric value to incrementProperty', !isNaN(parseFloat(increment)) && isFinite(increment)); 45790 return _emberMetalProperty_set.set(this, keyName, (parseFloat(_emberMetalProperty_get.get(this, keyName)) || 0) + increment); 45791 }, 45792 45793 /** 45794 Set the value of a property to the current value minus some amount. 45795 ```javascript 45796 player.decrementProperty('lives'); 45797 orc.decrementProperty('health', 5); 45798 ``` 45799 @method decrementProperty 45800 @param {String} keyName The name of the property to decrement 45801 @param {Number} decrement The amount to decrement by. Defaults to 1 45802 @return {Number} The new property value 45803 @public 45804 */ 45805 decrementProperty: function (keyName, decrement) { 45806 if (_emberMetalIs_none.default(decrement)) { 45807 decrement = 1; 45808 } 45809 _emberMetalDebug.assert('Must pass a numeric value to decrementProperty', !isNaN(parseFloat(decrement)) && isFinite(decrement)); 45810 return _emberMetalProperty_set.set(this, keyName, (_emberMetalProperty_get.get(this, keyName) || 0) - decrement); 45811 }, 45812 45813 /** 45814 Set the value of a boolean property to the opposite of its 45815 current value. 45816 ```javascript 45817 starship.toggleProperty('warpDriveEngaged'); 45818 ``` 45819 @method toggleProperty 45820 @param {String} keyName The name of the property to toggle 45821 @return {Boolean} The new property value 45822 @public 45823 */ 45824 toggleProperty: function (keyName) { 45825 return _emberMetalProperty_set.set(this, keyName, !_emberMetalProperty_get.get(this, keyName)); 45826 }, 45827 45828 /** 45829 Returns the cached value of a computed property, if it exists. 45830 This allows you to inspect the value of a computed property 45831 without accidentally invoking it if it is intended to be 45832 generated lazily. 45833 @method cacheFor 45834 @param {String} keyName 45835 @return {Object} The cached value of the computed property, if any 45836 @public 45837 */ 45838 cacheFor: function (keyName) { 45839 return _emberMetalComputed.cacheFor(this, keyName); 45840 }, 45841 45842 // intended for debugging purposes 45843 observersForKey: function (keyName) { 45844 return _emberMetalObserver.observersFor(this, keyName); 45845 } 45846 }); 45847}); 45848enifed('ember-runtime/mixins/promise_proxy', ['exports', 'ember-metal/property_get', 'ember-metal/set_properties', 'ember-metal/computed', 'ember-metal/mixin', 'ember-metal/error'], function (exports, _emberMetalProperty_get, _emberMetalSet_properties, _emberMetalComputed, _emberMetalMixin, _emberMetalError) { 45849 'use strict'; 45850 45851 var not = _emberMetalComputed.computed.not; 45852 var or = _emberMetalComputed.computed.or; 45853 45854 /** 45855 @module ember 45856 @submodule ember-runtime 45857 */ 45858 45859 function tap(proxy, promise) { 45860 _emberMetalSet_properties.default(proxy, { 45861 isFulfilled: false, 45862 isRejected: false 45863 }); 45864 45865 return promise.then(function (value) { 45866 _emberMetalSet_properties.default(proxy, { 45867 content: value, 45868 isFulfilled: true 45869 }); 45870 return value; 45871 }, function (reason) { 45872 _emberMetalSet_properties.default(proxy, { 45873 reason: reason, 45874 isRejected: true 45875 }); 45876 throw reason; 45877 }, 'Ember: PromiseProxy'); 45878 } 45879 45880 /** 45881 A low level mixin making ObjectProxy promise-aware. 45882 45883 ```javascript 45884 var ObjectPromiseProxy = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); 45885 45886 var proxy = ObjectPromiseProxy.create({ 45887 promise: $.getJSON('/some/remote/data.json') 45888 }); 45889 45890 proxy.then(function(json){ 45891 // the json 45892 }, function(reason) { 45893 // the reason why you have no json 45894 }); 45895 ``` 45896 45897 the proxy has bindable attributes which 45898 track the promises life cycle 45899
45900 ```javascript 45901 proxy.get('isPending') //=> true 45902 proxy.get('isSettled') //=> false 45903 proxy.get('isRejected') //=> false 45904 proxy.get('isFulfilled') //=> false 45905 ``` 45906 45907 When the $.getJSON completes, and the promise is fulfilled 45908 with json, the life cycle attributes will update accordingly. 45909 45910 ```javascript 45911 proxy.get('isPending') //=> false 45912 proxy.get('isSettled') //=> true 45913 proxy.get('isRejected') //=> false 45914 proxy.get('isFulfilled') //=> true 45915 ``` 45916 45917 As the proxy is an ObjectProxy, and the json now its content, 45918 all the json properties will be available directly from the proxy. 45919 45920 ```javascript 45921 // Assuming the following json: 45922 { 45923 firstName: 'Stefan', 45924 lastName: 'Penner' 45925 } 45926 45927 // both properties will accessible on the proxy 45928 proxy.get('firstName') //=> 'Stefan' 45929 proxy.get('lastName') //=> 'Penner' 45930 ``` 45931 45932 @class Ember.PromiseProxyMixin 45933 @public 45934 */ 45935 exports.default = _emberMetalMixin.Mixin.create({ 45936 /** 45937 If the proxied promise is rejected this will contain the reason 45938 provided. 45939 @property reason 45940 @default null 45941 @public 45942 */ 45943 reason: null, 45944 45945 /** 45946 Once the proxied promise has settled this will become `false`. 45947 @property isPending 45948 @default true 45949 @public 45950 */ 45951 isPending: not('isSettled').readOnly(), 45952 45953 /** 45954 Once the proxied promise has settled this will become `true`. 45955 @property isSettled 45956 @default false 45957 @public 45958 */ 45959 isSettled: or('isRejected', 'isFulfilled').readOnly(), 45960 45961 /** 45962 Will become `true` if the proxied promise is rejected. 45963 @property isRejected 45964 @default false 45965 @public 45966 */ 45967 isRejected: false, 45968 45969 /** 45970 Will become `true` if the proxied promise is fulfilled. 45971 @property isFulfilled 45972 @default false 45973 @public 45974 */ 45975 isFulfilled: false, 45976 45977 /** 45978 The promise whose fulfillment value is being proxied by this object. 45979 This property must be specified upon creation, and should not be 45980 changed once created. 45981 Example: 45982 ```javascript 45983 Ember.ObjectProxy.extend(Ember.PromiseProxyMixin).create({ 45984 promise: <thenable> 45985 }); 45986 ``` 45987 @property promise 45988 @public 45989 */ 45990 promise: _emberMetalComputed.computed({ 45991 get: function () { 45992 throw new _emberMetalError.default('PromiseProxy\'s promise must be set'); 45993 }, 45994 set: function (key, promise) { 45995 return tap(this, promise); 45996 } 45997 }), 45998 45999 /** 46000 An alias to the proxied promise's `then`. 46001 See RSVP.Promise.then. 46002 @method then 46003 @param {Function} callback 46004 @return {RSVP.Promise} 46005 @public 46006 */ 46007 then: promiseAlias('then'), 46008 46009 /** 46010 An alias to the proxied promise's `catch`. 46011 See RSVP.Promise.catch. 46012 @method catch 46013 @param {Function} callback 46014 @return {RSVP.Promise} 46015 @since 1.3.0 46016 @public 46017 */ 46018 'catch': promiseAlias('catch'), 46019 46020 /** 46021 An alias to the proxied promise's `finally`. 46022 See RSVP.Promise.finally. 46023 @method finally 46024 @param {Function} callback 46025 @return {RSVP.Promise} 46026 @since 1.3.0 46027 @public 46028 */ 46029 'finally': promiseAlias('finally') 46030 46031 }); 46032 46033 function promiseAlias(name) { 46034 return function () { 46035 var promise = _emberMetalProperty_get.get(this, 'promise'); 46036 return promise[name].apply(promise, arguments); 46037 }; 46038 } 46039}); 46040enifed('ember-runtime/mixins/registry_proxy', ['exports', 'ember-metal/debug', 'ember-metal/mixin'], function (exports, _emberMetalDebug, _emberMetalMixin) { 46041 /** 46042 @module ember 46043 @submodule ember-runtime 46044 */ 46045 46046 'use strict'; 46047 46048 exports.buildFakeRegistryWithDeprecations = buildFakeRegistryWithDeprecations; 46049 46050 /** 46051 RegistryProxyMixin is used to provide public access to specific 46052 registry functionality. 46053 46054 @class RegistryProxyMixin 46055 @private 46056 */ 46057 exports.default = _emberMetalMixin.Mixin.create({ 46058 __registry__: null, 46059 46060 /** 46061 Given a fullName return the corresponding factory. 46062 @public 46063 @method resolveRegistration 46064 @param {String} fullName 46065 @return {Function} fullName's factory 46066 */ 46067 resolveRegistration: registryAlias('resolve'), 46068 46069 /** 46070 Registers a factory that can be used for dependency injection (with 46071 `inject`) or for service lookup. Each factory is registered with 46072 a full name including two parts: `type:name`. 46073 A simple example: 46074 ```javascript 46075 var App = Ember.Application.create(); 46076 App.Orange = Ember.Object.extend(); 46077 App.register('fruit:favorite', App.Orange); 46078 ``` 46079 Ember will resolve factories from the `App` namespace automatically. 46080 For example `App.CarsController` will be discovered and returned if 46081 an application requests `controller:cars`. 46082 An example of registering a controller with a non-standard name: 46083 ```javascript 46084 var App = Ember.Application.create(); 46085 var Session = Ember.Controller.extend(); 46086 App.register('controller:session', Session); 46087 // The Session controller can now be treated like a normal controller, 46088 // despite its non-standard name. 46089 App.ApplicationController = Ember.Controller.extend({ 46090 needs: ['session'] 46091 }); 46092 ``` 46093 Registered factories are **instantiated** by having `create` 46094 called on them. Additionally they are **singletons**, each time 46095 they are looked up they return the same instance. 46096 Some examples modifying that default behavior: 46097 ```javascript 46098 var App = Ember.Application.create(); 46099 App.Person = Ember.Object.extend(); 46100 App.Orange = Ember.Object.extend(); 46101 App.Email = Ember.Object.extend(); 46102 App.session = Ember.Object.create();
46103 App.register('model:user', App.Person, { singleton: false }); 46104 App.register('fruit:favorite', App.Orange); 46105 App.register('communication:main', App.Email, { singleton: false }); 46106 App.register('session', App.session, { instantiate: false }); 46107 ``` 46108 @method register 46109 @param fullName {String} type:name (e.g., 'model:user') 46110 @param factory {Function} (e.g., App.Person) 46111 @param options {Object} (optional) disable instantiation or singleton usage 46112 @public 46113 */ 46114 register: registryAlias('register'), 46115 46116 /** 46117 Unregister a factory. 46118 ```javascript 46119 var App = Ember.Application.create(); 46120 var User = Ember.Object.extend(); 46121 App.register('model:user', User); 46122 App.resolveRegistration('model:user').create() instanceof User //=> true 46123 App.unregister('model:user') 46124 App.resolveRegistration('model:user') === undefined //=> true 46125 ``` 46126 @public 46127 @method unregister 46128 @param {String} fullName 46129 */ 46130 unregister: registryAlias('unregister'), 46131 46132 /** 46133 Check if a factory is registered. 46134 @public 46135 @method hasRegistration 46136 @param {String} fullName 46137 @return {Boolean} 46138 */ 46139 hasRegistration: registryAlias('has'), 46140 46141 /** 46142 Register an option for a particular factory. 46143 @public 46144 @method registerOption 46145 @param {String} fullName 46146 @param {String} optionName 46147 @param {Object} options 46148 */ 46149 registerOption: registryAlias('option'), 46150 46151 /** 46152 Return a specific registered option for a particular factory. 46153 @public 46154 @method registeredOption 46155 @param {String} fullName 46156 @param {String} optionName 46157 @return {Object} options 46158 */ 46159 registeredOption: registryAlias('getOption'), 46160 46161 /** 46162 Register options for a particular factory. 46163 @public 46164 @method registerOptions 46165 @param {String} fullName 46166 @param {Object} options 46167 */ 46168 registerOptions: registryAlias('options'), 46169 46170 /** 46171 Return registered options for a particular factory. 46172 @public 46173 @method registeredOptions 46174 @param {String} fullName 46175 @return {Object} options 46176 */ 46177 registeredOptions: registryAlias('getOptions'), 46178 46179 /** 46180 Allow registering options for all factories of a type. 46181 ```javascript 46182 var App = Ember.Application.create(); 46183 var appInstance = App.buildInstance(); 46184 // if all of type `connection` must not be singletons 46185 appInstance.optionsForType('connection', { singleton: false }); 46186 appInstance.register('connection:twitter', TwitterConnection); 46187 appInstance.register('connection:facebook', FacebookConnection); 46188 var twitter = appInstance.lookup('connection:twitter'); 46189 var twitter2 = appInstance.lookup('connection:twitter'); 46190 twitter === twitter2; // => false 46191 var facebook = appInstance.lookup('connection:facebook'); 46192 var facebook2 = appInstance.lookup('connection:facebook'); 46193 facebook === facebook2; // => false 46194 ``` 46195 @public 46196 @method registerOptionsForType 46197 @param {String} type 46198 @param {Object} options 46199 */ 46200 registerOptionsForType: registryAlias('optionsForType'), 46201 46202 /** 46203 Return the registered options for all factories of a type. 46204 @public 46205 @method registeredOptionsForType 46206 @param {String} type 46207 @return {Object} options 46208 */ 46209 registeredOptionsForType: registryAlias('getOptionsForType'), 46210 46211 /** 46212 Define a dependency injection onto a specific factory or all factories 46213 of a type. 46214 When Ember instantiates a controller, view, or other framework component 46215 it can attach a dependency to that component. This is often used to 46216 provide services to a set of framework components. 46217 An example of providing a session object to all controllers: 46218 ```javascript 46219 var App = Ember.Application.create(); 46220 var Session = Ember.Object.extend({ isAuthenticated: false }); 46221 // A factory must be registered before it can be injected 46222 App.register('session:main', Session); 46223 // Inject 'session:main' onto all factories of the type 'controller' 46224 // with the name 'session' 46225 App.inject('controller', 'session', 'session:main'); 46226 App.IndexController = Ember.Controller.extend({ 46227 isLoggedIn: Ember.computed.alias('session.isAuthenticated') 46228 }); 46229 ``` 46230 Injections can also be performed on specific factories. 46231 ```javascript 46232 App.inject(<full_name or type>, <property name>, <full_name>) 46233 App.inject('route', 'source', 'source:main') 46234 App.inject('route:application', 'email', 'model:email') 46235 ``` 46236 It is important to note that injections can only be performed on 46237 classes that are instantiated by Ember itself. Instantiating a class
46238 directly (via `create` or `new`) bypasses the dependency injection 46239 system. 46240 **Note:** Ember-Data instantiates its models in a unique manner, and consequently 46241 injections onto models (or all models) will not work as expected. Injections 46242 on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` 46243 to `true`. 46244 @public 46245 @method inject 46246 @param factoryNameOrType {String} 46247 @param property {String} 46248 @param injectionName {String} 46249 **/ 46250 inject: registryAlias('injection') 46251 }); 46252 46253 function registryAlias(name) { 46254 return function () { 46255 var _registry__; 46256 46257 return (_registry__ = this.__registry__)[name].apply(_registry__, arguments); 46258 }; 46259 } 46260 46261 function buildFakeRegistryWithDeprecations(instance, typeForMessage) { 46262 var fakeRegistry = {}; 46263 var registryProps = { 46264 resolve: 'resolveRegistration', 46265 register: 'register', 46266 unregister: 'unregister', 46267 has: 'hasRegistration', 46268 option: 'registerOption', 46269 options: 'registerOptions', 46270 getOptions: 'registeredOptions', 46271 optionsForType: 'registerOptionsForType', 46272 getOptionsForType: 'registeredOptionsForType', 46273 injection: 'inject' 46274 }; 46275 46276 for (var deprecatedProperty in registryProps) { 46277 fakeRegistry[deprecatedProperty] = buildFakeRegistryFunction(instance, typeForMessage, deprecatedProperty, registryProps[deprecatedProperty]); 46278 } 46279 46280 return fakeRegistry; 46281 } 46282 46283 function buildFakeRegistryFunction(instance, typeForMessage, deprecatedProperty, nonDeprecatedProperty) { 46284 return function () { 46285 _emberMetalDebug.deprecate('Using `' + typeForMessage + '.registry.' + deprecatedProperty + '` is deprecated. Please use `' + typeForMessage + '.' + nonDeprecatedProperty + '` instead.', false, { 46286 id: 'ember-application.app-instance-registry', 46287 until: '3.0.0', 46288 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-application-registry-ember-applicationinstance-registry' 46289 }); 46290 return instance[nonDeprecatedProperty].apply(instance, arguments); 46291 }; 46292 } 46293}); 46294enifed('ember-runtime/mixins/target_action_support', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/mixin', 'ember-metal/computed'], function (exports, _emberMetalCore, _emberMetalDebug, _emberMetalProperty_get, _emberMetalMixin, _emberMetalComputed) { 46295 /** 46296 @module ember 46297 @submodule ember-runtime 46298 */ 46299 46300 'use strict'; 46301 46302 /** 46303 `Ember.TargetActionSupport` is a mixin that can be included in a class 46304 to add a `triggerAction` method with semantics similar to the Handlebars 46305 `{{action}}` helper. In normal Ember usage, the `{{action}}` helper is 46306 usually the best choice. This mixin is most often useful when you are 46307 doing more complex event handling in View objects. 46308 46309 See also `Ember.ViewTargetActionSupport`, which has 46310 view-aware defaults for target and actionContext. 46311 46312 @class TargetActionSupport 46313 @namespace Ember 46314 @extends Ember.Mixin 46315 @private 46316 */ 46317 var TargetActionSupport = _emberMetalMixin.Mixin.create({ 46318 target: null, 46319 action: null, 46320 actionContext: null, 46321 46322 targetObject: _emberMetalComputed.computed('target', function () { 46323 if (this._targetObject) { 46324 return this._targetObject; 46325 } 46326 46327 var target = _emberMetalProperty_get.get(this, 'target'); 46328 46329 if (typeof target === 'string') { 46330 var value = _emberMetalProperty_get.get(this, target); 46331 if (value === undefined) { 46332 value = _emberMetalProperty_get.get(_emberMetalCore.default.lookup, target); 46333 } 46334 46335 return value; 46336 } else { 46337 return target; 46338 } 46339 }), 46340 46341 actionContextObject: _emberMetalComputed.computed(function () { 46342 var actionContext = _emberMetalProperty_get.get(this, 'actionContext'); 46343 46344 if (typeof actionContext === 'string') { 46345 var value = _emberMetalProperty_get.get(this, actionContext); 46346 if (value === undefined) { 46347 value = _emberMetalProperty_get.get(_emberMetalCore.default.lookup, actionContext); 46348 } 46349 return value; 46350 } else { 46351 return actionContext; 46352 } 46353 }).property('actionContext'), 46354 46355 /** 46356 Send an `action` with an `actionContext` to a `target`. The action, actionContext 46357 and target will be retrieved from properties of the object. For example: 46358 ```javascript 46359 App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { 46360 target: Ember.computed.alias('controller'), 46361 action: 'save', 46362 actionContext: Ember.computed.alias('context'), 46363 click: function() { 46364 this.triggerAction(); // Sends the `save` action, along with the current context 46365 // to the current controller 46366 } 46367 }); 46368 ```
46369 The `target`, `action`, and `actionContext` can be provided as properties of 46370 an optional object argument to `triggerAction` as well. 46371 ```javascript 46372 App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { 46373 click: function() { 46374 this.triggerAction({ 46375 action: 'save', 46376 target: this.get('controller'), 46377 actionContext: this.get('context') 46378 }); // Sends the `save` action, along with the current context 46379 // to the current controller 46380 } 46381 }); 46382 ``` 46383 The `actionContext` defaults to the object you are mixing `TargetActionSupport` into. 46384 But `target` and `action` must be specified either as properties or with the argument 46385 to `triggerAction`, or a combination: 46386 ```javascript 46387 App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { 46388 target: Ember.computed.alias('controller'), 46389 click: function() { 46390 this.triggerAction({ 46391 action: 'save' 46392 }); // Sends the `save` action, along with a reference to `this`, 46393 // to the current controller 46394 } 46395 }); 46396 ``` 46397 @method triggerAction 46398 @param opts {Object} (optional, with the optional keys action, target and/or actionContext) 46399 @return {Boolean} true if the action was sent successfully and did not return false 46400 @private 46401 */ 46402 triggerAction: function () { 46403 var opts = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 46404 46405 var action = opts.action || _emberMetalProperty_get.get(this, 'action'); 46406 var target = opts.target || _emberMetalProperty_get.get(this, 'targetObject'); 46407 var actionContext = opts.actionContext; 46408 46409 function args(options, actionName) { 46410 var ret = []; 46411 if (actionName) { 46412 ret.push(actionName); 46413 } 46414 46415 return ret.concat(options); 46416 } 46417 46418 if (typeof actionContext === 'undefined') { 46419 actionContext = _emberMetalProperty_get.get(this, 'actionContextObject') || this; 46420 } 46421 46422 if (target && action) { 46423 var ret; 46424 46425 if (target.send) { 46426 ret = target.send.apply(target, args(actionContext, action)); 46427 } else { 46428 _emberMetalDebug.assert('The action \'' + action + '\' did not exist on ' + target, typeof target[action] === 'function'); 46429 ret = target[action].apply(target, args(actionContext)); 46430 } 46431 46432 if (ret !== false) { 46433 ret = true; 46434 } 46435 46436 return ret; 46437 } else { 46438 return false; 46439 } 46440 } 46441 }); 46442 46443 exports.default = TargetActionSupport; 46444}); 46445// Ember.lookup 46446enifed("ember-runtime/string_registry", ["exports"], function (exports) { 46447 // STATE within a module is frowned apon, this exists 46448 // to support Ember.STRINGS but shield ember internals from this legacy global 46449 // API. 46450 "use strict"; 46451 46452 exports.setStrings = setStrings; 46453 exports.getStrings = getStrings; 46454 exports.get = get; 46455 var STRINGS = {}; 46456 46457 function setStrings(strings) { 46458 STRINGS = strings; 46459 } 46460 46461 function getStrings() { 46462 return STRINGS; 46463 } 46464 46465 function get(name) { 46466 return STRINGS[name]; 46467 } 46468}); 46469enifed('ember-runtime/system/application', ['exports', 'ember-runtime/system/namespace'], function (exports, _emberRuntimeSystemNamespace) { 46470 'use strict'; 46471 46472 exports.default = _emberRuntimeSystemNamespace.default.extend(); 46473}); 46474enifed('ember-runtime/system/array_proxy', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-runtime/utils', 'ember-metal/computed', 'ember-metal/mixin', 'ember-metal/property_events', 'ember-metal/error', 'ember-runtime/system/object', 'ember-runtime/mixins/mutable_array', 'ember-runtime/mixins/enumerable', 'ember-metal/alias', 'ember-runtime/mixins/array'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberRuntimeUtils, _emberMetalComputed, _emberMetalMixin, _emberMetalProperty_events, _emberMetalError, _emberRuntimeSystemObject, _emberRuntimeMixinsMutable_array, _emberRuntimeMixinsEnumerable, _emberMetalAlias, _emberRuntimeMixinsArray) { 46475 'use strict'; 46476 46477 /** 46478 @module ember 46479 @submodule ember-runtime 46480 */ 46481 46482 var OUT_OF_RANGE_EXCEPTION = 'Index out of range'; 46483 var EMPTY = []; 46484 46485 function K() { 46486 return this; 46487 } 46488 46489 /** 46490 An ArrayProxy wraps any other object that implements `Ember.Array` and/or 46491 `Ember.MutableArray,` forwarding all requests. This makes it very useful for 46492 a number of binding use cases or other cases where being able to swap 46493 out the underlying array is useful. 46494 46495 A simple example of usage: 46496 46497 ```javascript 46498 var pets = ['dog', 'cat', 'fish']; 46499 var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) }); 46500 46501 ap.get('firstObject'); // 'dog' 46502 ap.set('content', ['amoeba', 'paramecium']); 46503 ap.get('firstObject'); // 'amoeba' 46504 ``` 46505 46506 This class can also be useful as a layer to transform the contents of 46507 an array, as they are accessed. This can be done by overriding 46508 `objectAtContent`: 46509 46510 ```javascript 46511 var pets = ['dog', 'cat', 'fish']; 46512 var ap = Ember.ArrayProxy.create({ 46513 content: Ember.A(pets), 46514 objectAtContent: function(idx) { 46515 return this.get('content').objectAt(idx).toUpperCase(); 46516 } 46517 }); 46518 46519 ap.get('firstObject'); // . 'DOG' 46520 ``` 46521 46522 @class ArrayProxy 46523 @namespace Ember
46524 @extends Ember.Object 46525 @uses Ember.MutableArray 46526 @public 46527 */ 46528 var ArrayProxy = _emberRuntimeSystemObject.default.extend(_emberRuntimeMixinsMutable_array.default, { 46529 46530 /** 46531 The content array. Must be an object that implements `Ember.Array` and/or 46532 `Ember.MutableArray.` 46533 @property content 46534 @type Ember.Array 46535 @private 46536 */ 46537 content: null, 46538 46539 /** 46540 The array that the proxy pretends to be. In the default `ArrayProxy` 46541 implementation, this and `content` are the same. Subclasses of `ArrayProxy` 46542 can override this property to provide things like sorting and filtering. 46543 @property arrangedContent 46544 @private 46545 */ 46546 arrangedContent: _emberMetalAlias.default('content'), 46547 46548 /** 46549 Should actually retrieve the object at the specified index from the 46550 content. You can override this method in subclasses to transform the 46551 content item to something new. 46552 This method will only be called if content is non-`null`. 46553 @method objectAtContent 46554 @param {Number} idx The index to retrieve. 46555 @return {Object} the value or undefined if none found 46556 @private 46557 */ 46558 objectAtContent: function (idx) { 46559 return _emberRuntimeMixinsArray.objectAt(_emberMetalProperty_get.get(this, 'arrangedContent'), idx); 46560 }, 46561 46562 /** 46563 Should actually replace the specified objects on the content array. 46564 You can override this method in subclasses to transform the content item 46565 into something new. 46566 This method will only be called if content is non-`null`. 46567 @method replaceContent 46568 @param {Number} idx The starting index 46569 @param {Number} amt The number of items to remove from the content. 46570 @param {Array} objects Optional array of objects to insert or null if no 46571 objects. 46572 @return {void} 46573 @private 46574 */ 46575 replaceContent: function (idx, amt, objects) { 46576 _emberMetalProperty_get.get(this, 'content').replace(idx, amt, objects); 46577 }, 46578 46579 /** 46580 Invoked when the content property is about to change. Notifies observers that the 46581 entire array content will change. 46582 @private 46583 @method _contentWillChange 46584 */ 46585 _contentWillChange: _emberMetalMixin._beforeObserver('content', function () { 46586 this._teardownContent(); 46587 }), 46588 46589 _teardownContent: function () { 46590 var content = _emberMetalProperty_get.get(this, 'content'); 46591 46592 if (content) { 46593 _emberRuntimeMixinsArray.removeArrayObserver(content, this, { 46594 willChange: 'contentArrayWillChange', 46595 didChange: 'contentArrayDidChange' 46596 }); 46597 } 46598 }, 46599 46600 /** 46601 Override to implement content array `willChange` observer. 46602 @method contentArrayWillChange 46603 @param {Ember.Array} contentArray the content array 46604 @param {Number} start starting index of the change 46605 @param {Number} removeCount count of items removed 46606 @param {Number} addCount count of items added 46607 @private 46608 */ 46609 contentArrayWillChange: K, 46610 /** 46611 Override to implement content array `didChange` observer. 46612 @method contentArrayDidChange 46613 @param {Ember.Array} contentArray the content array 46614 @param {Number} start starting index of the change 46615 @param {Number} removeCount count of items removed 46616 @param {Number} addCount count of items added 46617 @private 46618 */ 46619 contentArrayDidChange: K, 46620 46621 /** 46622 Invoked when the content property changes. Notifies observers that the 46623 entire array content has changed. 46624 @private 46625 @method _contentDidChange 46626 */ 46627 _contentDidChange: _emberMetalMixin.observer('content', function () { 46628 var content = _emberMetalProperty_get.get(this, 'content'); 46629 46630 _emberMetalDebug.assert('Can\'t set ArrayProxy\'s content to itself', content !== this); 46631 46632 this._setupContent(); 46633 }), 46634 46635 _setupContent: function () { 46636 var content = _emberMetalProperty_get.get(this, 'content'); 46637 46638 if (content) { 46639 _emberMetalDebug.assert('ArrayProxy expects an Array or Ember.ArrayProxy, but you passed ' + typeof content, _emberRuntimeUtils.isArray(content) || content.isDestroyed); 46640 46641 _emberRuntimeMixinsArray.addArrayObserver(content, this, { 46642 willChange: 'contentArrayWillChange', 46643 didChange: 'contentArrayDidChange' 46644 }); 46645 } 46646 }, 46647 46648 _arrangedContentWillChange: _emberMetalMixin._beforeObserver('arrangedContent', function () { 46649 var arrangedContent = _emberMetalProperty_get.get(this, 'arrangedContent'); 46650 var len = arrangedContent ? _emberMetalProperty_get.get(arrangedContent, 'length') : 0; 46651 46652 this.arrangedContentArrayWillChange(this, 0, len, undefined); 46653 this.arrangedContentWillChange(this); 46654 46655 this._teardownArrangedContent(arrangedContent); 46656 }), 46657 46658 _arrangedContentDidChange: _emberMetalMixin.observer('arrangedContent', function () { 46659 var arrangedContent = _emberMetalProperty_get.get(this, 'arrangedContent'); 46660 var len = arrangedContent ? _emberMetalProperty_get.get(arrangedContent, 'length') : 0; 46661 46662 _emberMetalDebug.assert('Can\'t set ArrayProxy\'s content to itself', arrangedContent !== this); 46663 46664 this._setupArrangedContent(); 46665 46666 this.arrangedContentDidChange(this); 46667 this.arrangedContentArrayDidChange(this, 0, undefined, len); 46668 }), 46669 46670 _setupArrangedContent: function () { 46671 var arrangedContent = _emberMetalProperty_get.get(this, 'arrangedContent'); 46672 46673 if (arrangedContent) { 46674 _emberMetalDebug.assert('ArrayProxy expects an Array or Ember.ArrayProxy, but you passed ' + typeof arrangedContent, _emberRuntimeUtils.isArray(arrangedContent) || arrangedContent.isDestroyed); 46675 46676 _emberRuntimeMixinsArray.addArrayObserver(arrangedContent, this, { 46677 willChange: 'arrangedContentArrayWillChange', 46678 didChange: 'arrangedContentArrayDidChange' 46679 }); 46680 } 46681 }, 46682 46683 _teardownArrangedContent: function () { 46684 var arrangedContent = _emberMetalProperty_get.get(this, 'arrangedContent'); 46685 46686 if (arrangedContent) { 46687 _emberRuntimeMixinsArray.removeArrayObserver(arrangedContent, this, { 46688 willChange: 'arrangedContentArrayWillChange', 46689 didChange: 'arrangedContentArrayDidChange' 46690 }); 46691 } 46692 }, 46693 46694 arrangedContentWillChange: K, 46695 arrangedContentDidChange: K, 46696 46697 objectAt: function (idx) { 46698 return _emberMetalProperty_get.get(this, 'content') && this.objectAtContent(idx); 46699 }, 46700 46701 length: _emberMetalComputed.computed(function () { 46702 var arrangedContent = _emberMetalProperty_get.get(this, 'arrangedContent'); 46703 return arrangedContent ? _emberMetalProperty_get.get(arrangedContent, 'length') : 0;
46704 // No dependencies since Enumerable notifies length of change 46705 }), 46706 46707 _replace: function (idx, amt, objects) { 46708 var content = _emberMetalProperty_get.get(this, 'content'); 46709 _emberMetalDebug.assert('The content property of ' + this.constructor + ' should be set before modifying it', content); 46710 if (content) { 46711 this.replaceContent(idx, amt, objects); 46712 } 46713 46714 return this; 46715 }, 46716 46717 replace: function () { 46718 if (_emberMetalProperty_get.get(this, 'arrangedContent') === _emberMetalProperty_get.get(this, 'content')) { 46719 this._replace.apply(this, arguments); 46720 } else { 46721 throw new _emberMetalError.default('Using replace on an arranged ArrayProxy is not allowed.'); 46722 } 46723 }, 46724 46725 _insertAt: function (idx, object) { 46726 if (idx > _emberMetalProperty_get.get(this, 'content.length')) { 46727 throw new _emberMetalError.default(OUT_OF_RANGE_EXCEPTION); 46728 } 46729 46730 this._replace(idx, 0, [object]); 46731 return this; 46732 }, 46733 46734 insertAt: function (idx, object) { 46735 if (_emberMetalProperty_get.get(this, 'arrangedContent') === _emberMetalProperty_get.get(this, 'content')) { 46736 return this._insertAt(idx, object); 46737 } else { 46738 throw new _emberMetalError.default('Using insertAt on an arranged ArrayProxy is not allowed.'); 46739 } 46740 }, 46741 46742 removeAt: function (start, len) { 46743 if ('number' === typeof start) { 46744 var content = _emberMetalProperty_get.get(this, 'content'); 46745 var arrangedContent = _emberMetalProperty_get.get(this, 'arrangedContent'); 46746 var indices = []; 46747 var i; 46748 46749 if (start < 0 || start >= _emberMetalProperty_get.get(this, 'length')) { 46750 throw new _emberMetalError.default(OUT_OF_RANGE_EXCEPTION); 46751 } 46752 46753 if (len === undefined) { 46754 len = 1; 46755 } 46756 46757 // Get a list of indices in original content to remove 46758 for (i = start; i < start + len; i++) { 46759 // Use arrangedContent here so we avoid confusion with objects transformed by objectAtContent 46760 indices.push(content.indexOf(_emberRuntimeMixinsArray.objectAt(arrangedContent, i))); 46761 } 46762 46763 // Replace in reverse order since indices will change 46764 indices.sort(function (a, b) { 46765 return b - a; 46766 }); 46767 46768 _emberMetalProperty_events.beginPropertyChanges(); 46769 for (i = 0; i < indices.length; i++) { 46770 this._replace(indices[i], 1, EMPTY); 46771 } 46772 _emberMetalProperty_events.endPropertyChanges(); 46773 } 46774 46775 return this; 46776 }, 46777 46778 pushObject: function (obj) { 46779 this._insertAt(_emberMetalProperty_get.get(this, 'content.length'), obj); 46780 return obj; 46781 }, 46782 46783 pushObjects: function (objects) { 46784 if (!(_emberRuntimeMixinsEnumerable.default.detect(objects) || _emberRuntimeUtils.isArray(objects))) { 46785 throw new TypeError('Must pass Ember.Enumerable to Ember.MutableArray#pushObjects'); 46786 } 46787 this._replace(_emberMetalProperty_get.get(this, 'length'), 0, objects); 46788 return this; 46789 }, 46790 46791 setObjects: function (objects) { 46792 if (objects.length === 0) { 46793 return this.clear(); 46794 } 46795 46796 var len = _emberMetalProperty_get.get(this, 'length'); 46797 this._replace(0, len, objects); 46798 return this; 46799 }, 46800 46801 unshiftObject: function (obj) { 46802 this._insertAt(0, obj); 46803 return obj; 46804 }, 46805 46806 unshiftObjects: function (objects) { 46807 this._replace(0, 0, objects); 46808 return this; 46809 }, 46810 46811 slice: function () { 46812 var arr = this.toArray(); 46813 return arr.slice.apply(arr, arguments); 46814 }, 46815 46816 arrangedContentArrayWillChange: function (item, idx, removedCnt, addedCnt) { 46817 this.arrayContentWillChange(idx, removedCnt, addedCnt); 46818 }, 46819 46820 arrangedContentArrayDidChange: function (item, idx, removedCnt, addedCnt) { 46821 this.arrayContentDidChange(idx, removedCnt, addedCnt); 46822 }, 46823 46824 init: function () { 46825 this._super.apply(this, arguments); 46826 this._setupContent(); 46827 this._setupArrangedContent(); 46828 }, 46829 46830 willDestroy: function () { 46831 this._teardownArrangedContent(); 46832 this._teardownContent(); 46833 } 46834 }); 46835 46836 exports.default = ArrayProxy; 46837}); 46838enifed('ember-runtime/system/container', ['exports', 'ember-metal/property_set', 'container/registry', 'container/container', 'container/owner'], function (exports, _emberMetalProperty_set, _containerRegistry, _containerContainer, _containerOwner) { 46839 'use strict'; 46840 46841 _containerRegistry.default.set = _emberMetalProperty_set.set; 46842 _containerContainer.default.set = _emberMetalProperty_set.set; 46843 46844 exports.Registry = _containerRegistry.default; 46845 exports.Container = _containerContainer.default; 46846 exports.getOwner = _containerOwner.getOwner; 46847 exports.setOwner = _containerOwner.setOwner;
46848}); 46849enifed('ember-runtime/system/core_object', ['exports', 'ember-metal/debug', 'ember-metal/features', 'ember-metal/assign', 'ember-metal/property_get', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/chains', 'ember-metal/events', 'ember-metal/mixin', 'ember-metal/error', 'ember-runtime/mixins/action_handler', 'ember-metal/properties', 'ember-metal/binding', 'ember-metal/computed', 'ember-metal/injected_property', 'ember-metal/run_loop', 'ember-metal/watching', 'ember-metal/core', 'ember-runtime/inject', 'ember-metal/symbol'], function (exports, _emberMetalDebug, _emberMetalFeatures, _emberMetalAssign, _emberMetalProperty_get, _emberMetalUtils, _emberMetalMeta, _emberMetalChains, _emberMetalEvents, _emberMetalMixin, _emberMetalError, _emberRuntimeMixinsAction_handler, _emberMetalProperties, _emberMetalBinding, _emberMetalComputed, _emberMetalInjected_property, _emberMetalRun_loop, _emberMetalWatching, _emberMetalCore, _emberRuntimeInject, _emberMetalSymbol) { 46850 'no use strict'; 46851 // Remove "use strict"; from transpiled module until 46852 // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed 46853 46854 /** 46855 @module ember 46856 @submodule ember-runtime 46857 */ 46858 46859 // using ember-metal/lib/main here to ensure that ember-debug is setup 46860 // if present 46861 46862 var _Mixin$create; 46863 46864 var POST_INIT = _emberMetalSymbol.default('POST_INIT'); 46865 exports.POST_INIT = POST_INIT; 46866 var schedule = _emberMetalRun_loop.default.schedule; 46867 var applyMixin = _emberMetalMixin.Mixin._apply; 46868 var finishPartial = _emberMetalMixin.Mixin.finishPartial; 46869 var reopen = _emberMetalMixin.Mixin.prototype.reopen; 46870 var hasCachedComputedProperties = false; 46871 46872 function makeCtor() { 46873 // Note: avoid accessing any properties on the object since it makes the 46874 // method a lot faster. This is glue code so we want it to be as fast as 46875 // possible. 46876 46877 var wasApplied = false; 46878 var initProperties; 46879 46880 var Class = function () { 46881 if (!wasApplied) { 46882 Class.proto(); // prepare prototype... 46883 } 46884 46885 if (arguments.length > 0) { 46886 initProperties = [arguments[0]]; 46887 } 46888 46889 this.__defineNonEnumerable(_emberMetalUtils.GUID_KEY_PROPERTY); 46890 var m = _emberMetalMeta.meta(this); 46891 var proto = m.proto; 46892 m.proto = this; 46893 if (initProperties) { 46894 // capture locally so we can clear the closed over variable 46895 var props = initProperties; 46896 initProperties = null; 46897 46898 var concatenatedProperties = this.concatenatedProperties; 46899 var mergedProperties = this.mergedProperties; 46900 46901 for (var i = 0, l = props.length; i < l; i++) { 46902 var properties = props[i]; 46903 46904 _emberMetalDebug.assert('Ember.Object.create no longer supports mixing in other ' + 'definitions, use .extend & .create seperately instead.', !(properties instanceof _emberMetalMixin.Mixin)); 46905 46906 if (typeof properties !== 'object' && properties !== undefined) { 46907 throw new _emberMetalError.default('Ember.Object.create only accepts objects.'); 46908 } 46909 46910 if (!properties) { 46911 continue; 46912 } 46913 46914 var keyNames = Object.keys(properties); 46915 46916 for (var j = 0, ll = keyNames.length; j < ll; j++) { 46917 var keyName = keyNames[j]; 46918 var value = properties[keyName]; 46919 46920 if (_emberMetalMixin.IS_BINDING.test(keyName)) { 46921 m.writeBindings(keyName, value); 46922 } 46923 46924 var possibleDesc = this[keyName]; 46925 var desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 46926 46927 _emberMetalDebug.assert('Ember.Object.create no longer supports defining computed ' + 'properties. Define computed properties using extend() or reopen() ' + 'before calling create().', !(value instanceof _emberMetalComputed.ComputedProperty)); 46928 _emberMetalDebug.assert('Ember.Object.create no longer supports defining methods that call _super.', !(typeof value === 'function' && value.toString().indexOf('._super') !== -1)); 46929 _emberMetalDebug.assert('`actions` must be provided at extend time, not at create time, ' + 'when Ember.ActionHandler is used (i.e. views, controllers & routes).', !(keyName === 'actions' && _emberRuntimeMixinsAction_handler.default.detect(this))); 46930 46931 if (concatenatedProperties && concatenatedProperties.length > 0 && concatenatedProperties.indexOf(keyName) >= 0) { 46932 var baseValue = this[keyName]; 46933 46934 if (baseValue) { 46935 if ('function' === typeof baseValue.concat) { 46936 value = baseValue.concat(value); 46937 } else { 46938 value = _emberMetalUtils.makeArray(baseValue).concat(value); 46939 } 46940 } else { 46941 value = _emberMetalUtils.makeArray(value); 46942 } 46943 } 46944 46945 if (mergedProperties && mergedProperties.length && mergedProperties.indexOf(keyName) >= 0) { 46946 var originalValue = this[keyName]; 46947 46948 value = _emberMetalAssign.default({}, originalValue, value); 46949 } 46950 46951 if (desc) { 46952 desc.set(this, keyName, value); 46953 } else { 46954 if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { 46955 this.setUnknownProperty(keyName, value); 46956 } else { 46957 _emberMetalProperties.defineProperty(this, keyName, null, value); // setup mandatory setter 46958 } 46959 } 46960 } 46961 } 46962 } 46963 46964 finishPartial(this, m); 46965 46966 var length = arguments.length; 46967 46968 if (length === 0) { 46969 this.init(); 46970 } else if (length === 1) {
46971 this.init(arguments[0]); 46972 } else { 46973 // v8 bug potentially incorrectly deopts this function: https://code.google.com/p/v8/issues/detail?id=3709 46974 // we may want to keep this around till this ages out on mobile 46975 var args = new Array(length); 46976 for (var x = 0; x < length; x++) { 46977 args[x] = arguments[x]; 46978 } 46979 this.init.apply(this, args); 46980 } 46981 46982 this[POST_INIT](); 46983 46984 m.proto = proto; 46985 _emberMetalChains.finishChains(this); 46986 _emberMetalEvents.sendEvent(this, 'init'); 46987 }; 46988 46989 Class.toString = _emberMetalMixin.Mixin.prototype.toString; 46990 Class.willReopen = function () { 46991 if (wasApplied) { 46992 Class.PrototypeMixin = _emberMetalMixin.Mixin.create(Class.PrototypeMixin); 46993 } 46994 46995 wasApplied = false; 46996 }; 46997 46998 Class._initProperties = function (args) { 46999 initProperties = args; 47000 }; 47001 47002 Class.proto = function () { 47003 var superclass = Class.superclass; 47004 if (superclass) { 47005 superclass.proto(); 47006 } 47007 47008 if (!wasApplied) { 47009 wasApplied = true; 47010 Class.PrototypeMixin.applyPartial(Class.prototype); 47011 } 47012 47013 return this.prototype; 47014 }; 47015 47016 return Class; 47017 } 47018 47019 /** 47020 @class CoreObject 47021 @namespace Ember 47022 @public 47023 */ 47024 var CoreObject = makeCtor(); 47025 CoreObject.toString = function () { 47026 return 'Ember.CoreObject'; 47027 }; 47028 CoreObject.PrototypeMixin = _emberMetalMixin.Mixin.create((_Mixin$create = { 47029 reopen: function () { 47030 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 47031 args[_key] = arguments[_key]; 47032 } 47033 47034 applyMixin(this, args, true); 47035 return this; 47036 }, 47037 47038 /** 47039 An overridable method called when objects are instantiated. By default, 47040 does nothing unless it is overridden during class definition. 47041 Example: 47042 ```javascript 47043 App.Person = Ember.Object.extend({ 47044 init: function() { 47045 alert('Name is ' + this.get('name')); 47046 } 47047 }); 47048 var steve = App.Person.create({ 47049 name: "Steve" 47050 }); 47051 // alerts 'Name is Steve'. 47052 ``` 47053 NOTE: If you do override `init` for a framework class like `Ember.View`, 47054 be sure to call `this._super(...arguments)` in your 47055 `init` declaration! If you don't, Ember may not have an opportunity to 47056 do important setup work, and you'll see strange behavior in your 47057 application. 47058 @method init 47059 @public 47060 */ 47061 init: function () {} 47062 47063 }, _Mixin$create[POST_INIT] = function () {}, _Mixin$create.__defineNonEnumerable = function (property) { 47064 Object.defineProperty(this, property.name, property.descriptor); 47065 //this[property.name] = property.descriptor.value; 47066 }, _Mixin$create.concatenatedProperties = null, _Mixin$create.mergedProperties = null, _Mixin$create.isDestroyed = false, _Mixin$create.isDestroying = false, _Mixin$create.destroy = function () { 47067 if (this.isDestroying) { 47068 return; 47069 } 47070 this.isDestroying = true; 47071 47072 schedule('actions', this, this.willDestroy); 47073 schedule('destroy', this, this._scheduledDestroy); 47074 return this; 47075 }, _Mixin$create.willDestroy = _emberMetalCore.K, _Mixin$create._scheduledDestroy = function () { 47076 if (this.isDestroyed) { 47077 return; 47078 } 47079 _emberMetalWatching.destroy(this); 47080 this.isDestroyed = true; 47081 }, _Mixin$create.bind = function (to, from) { 47082 if (!(from instanceof _emberMetalBinding.Binding)) { 47083 from = _emberMetalBinding.Binding.from(from); 47084 } 47085 from.to(to).connect(this); 47086 return from; 47087 }, _Mixin$create.toString = function () { 47088 var hasToStringExtension = typeof this.toStringExtension === 'function'; 47089 var extension = hasToStringExtension ? ':' + this.toStringExtension() : ''; 47090 var ret = '<' + this.constructor.toString() + ':' + _emberMetalUtils.guidFor(this) + extension + '>'; 47091 47092 return ret; 47093 }, _Mixin$create)); 47094 47095 CoreObject.PrototypeMixin.ownerConstructor = CoreObject; 47096 47097 CoreObject.__super__ = null; 47098 47099 var ClassMixinProps = { 47100 47101 ClassMixin: _emberMetalMixin.REQUIRED, 47102 47103 PrototypeMixin: _emberMetalMixin.REQUIRED, 47104 47105 isClass: true, 47106 47107 isMethod: false, 47108 47109 /** 47110 Creates a new subclass. 47111 ```javascript 47112 App.Person = Ember.Object.extend({ 47113 say: function(thing) { 47114 alert(thing); 47115 } 47116 }); 47117 ``` 47118 This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`. 47119 You can also create a subclass from any existing class by calling its `extend()` method. 47120 For example, you might want to create a subclass of Ember's built-in `Ember.View` class: 47121 ```javascript 47122 App.PersonView = Ember.View.extend({ 47123 tagName: 'li', 47124 classNameBindings: ['isAdministrator'] 47125 }); 47126 ``` 47127 When defining a subclass, you can override methods but still access the 47128 implementation of your parent class by calling the special `_super()` method: 47129 ```javascript 47130 App.Person = Ember.Object.extend({ 47131 say: function(thing) { 47132 var name = this.get('name'); 47133 alert(name + ' says: ' + thing); 47134 } 47135 }); 47136 App.Soldier = App.Person.extend({ 47137 say: function(thing) { 47138 this._super(thing + ", sir!"); 47139 }, 47140 march: function(numberOfHours) { 47141 alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.'); 47142 } 47143 }); 47144 var yehuda = App.Soldier.create({ 47145 name: "Yehuda Katz" 47146 }); 47147 yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!" 47148 ``` 47149 The `create()` on line #17 creates an *instance* of the `App.Soldier` class. 47150 The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance 47151 of the `App.Person` class will *not* have the `march()` method. 47152 You can also pass `Mixin` classes to add additional properties to the subclass. 47153 ```javascript 47154 App.Person = Ember.Object.extend({ 47155 say: function(thing) { 47156 alert(this.get('name') + ' says: ' + thing); 47157 } 47158 }); 47159 App.SingingMixin = Mixin.create({ 47160 sing: function(thing){ 47161 alert(this.get('name') + ' sings: la la la ' + thing); 47162 } 47163 }); 47164 App.BroadwayStar = App.Person.extend(App.SingingMixin, { 47165 dance: function() { 47166 alert(this.get('name') + ' dances: tap tap tap tap '); 47167 } 47168 }); 47169 ``` 47170 The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`. 47171 @method extend 47172 @static 47173 @param {Mixin} [mixins]* One or more Mixin classes 47174 @param {Object} [arguments]* Object containing values to use within the new class 47175 @public 47176 */ 47177 extend: function () { 47178 var Class = makeCtor(); 47179 var proto; 47180 Class.ClassMixin = _emberMetalMixin.Mixin.create(this.ClassMixin); 47181 Class.PrototypeMixin = _emberMetalMixin.Mixin.create(this.PrototypeMixin); 47182 47183 Class.ClassMixin.ownerConstructor = Class; 47184 Class.PrototypeMixin.ownerConstructor = Class; 47185 47186 reopen.apply(Class.PrototypeMixin, arguments); 47187 47188 Class.superclass = this; 47189 Class.__super__ = this.prototype; 47190 47191 proto = Class.prototype = Object.create(this.prototype); 47192 proto.constructor = Class; 47193 _emberMetalUtils.generateGuid(proto); 47194 _emberMetalMeta.meta(proto).proto = proto; // this will disable observers on prototype 47195 47196 Class.ClassMixin.apply(Class); 47197 return Class; 47198 }, 47199 47200 /** 47201 Creates an instance of a class. Accepts either no arguments, or an object 47202 containing values to initialize the newly instantiated object with. 47203 ```javascript 47204 App.Person = Ember.Object.extend({ 47205 helloWorld: function() { 47206 alert("Hi, my name is " + this.get('name')); 47207 } 47208 }); 47209 var tom = App.Person.create({ 47210 name: 'Tom Dale' 47211 }); 47212 tom.helloWorld(); // alerts "Hi, my name is Tom Dale". 47213 ``` 47214 `create` will call the `init` function if defined during 47215 `Ember.AnyObject.extend` 47216 If no arguments are passed to `create`, it will not set values to the new 47217 instance during initialization: 47218 ```javascript 47219 var noName = App.Person.create(); 47220 noName.helloWorld(); // alerts undefined 47221 ``` 47222 NOTE: For performance reasons, you cannot declare methods or computed 47223 properties during `create`. You should instead declare methods and computed 47224 properties when using `extend`. 47225 @method create 47226 @static 47227 @param [arguments]* 47228 @public 47229 */ 47230 create: function () { 47231 var C = this; 47232 47233 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 47234 args[_key2] = arguments[_key2]; 47235 } 47236 47237 if (args.length > 0) { 47238 this._initProperties(args); 47239 } 47240 return new C(); 47241 }, 47242 47243 /** 47244 Augments a constructor's prototype with additional 47245 properties and functions: 47246 ```javascript 47247 MyObject = Ember.Object.extend({ 47248 name: 'an object' 47249 }); 47250 o = MyObject.create(); 47251 o.get('name'); // 'an object' 47252 MyObject.reopen({ 47253 say: function(msg){ 47254 console.log(msg); 47255 } 47256 }) 47257 o2 = MyObject.create(); 47258 o2.say("hello"); // logs "hello" 47259 o.say("goodbye"); // logs "goodbye" 47260 ``` 47261 To add functions and properties to the constructor itself, 47262 see `reopenClass` 47263 @method reopen 47264 @public 47265 */ 47266 reopen: function () { 47267 this.willReopen(); 47268 reopen.apply(this.PrototypeMixin, arguments); 47269 return this; 47270 }, 47271 47272 /** 47273 Augments a constructor's own properties and functions: 47274 ```javascript 47275 MyObject = Ember.Object.extend({ 47276 name: 'an object' 47277 }); 47278 MyObject.reopenClass({ 47279 canBuild: false 47280 }); 47281 MyObject.canBuild; // false 47282 o = MyObject.create(); 47283 ``` 47284 In other words, this creates static properties and functions for the class. 47285 These are only available on the class and not on any instance of that class. 47286 ```javascript 47287 App.Person = Ember.Object.extend({ 47288 name : "", 47289 sayHello : function() { 47290 alert("Hello. My name is " + this.get('name')); 47291 } 47292 }); 47293 App.Person.reopenClass({ 47294 species : "Homo sapiens", 47295 createPerson: function(newPersonsName){ 47296 return App.Person.create({ 47297 name:newPersonsName
47298 }); 47299 } 47300 }); 47301 var tom = App.Person.create({ 47302 name : "Tom Dale" 47303 }); 47304 var yehuda = App.Person.createPerson("Yehuda Katz"); 47305 tom.sayHello(); // "Hello. My name is Tom Dale" 47306 yehuda.sayHello(); // "Hello. My name is Yehuda Katz" 47307 alert(App.Person.species); // "Homo sapiens" 47308 ``` 47309 Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda` 47310 variables. They are only valid on `App.Person`. 47311 To add functions and properties to instances of 47312 a constructor by extending the constructor's prototype 47313 see `reopen` 47314 @method reopenClass 47315 @public 47316 */ 47317 reopenClass: function () { 47318 reopen.apply(this.ClassMixin, arguments); 47319 applyMixin(this, arguments, false); 47320 return this; 47321 }, 47322 47323 detect: function (obj) { 47324 if ('function' !== typeof obj) { 47325 return false; 47326 } 47327 while (obj) { 47328 if (obj === this) { 47329 return true; 47330 } 47331 obj = obj.superclass; 47332 } 47333 return false; 47334 }, 47335 47336 detectInstance: function (obj) { 47337 return obj instanceof this; 47338 }, 47339 47340 /** 47341 In some cases, you may want to annotate computed properties with additional 47342 metadata about how they function or what values they operate on. For 47343 example, computed property functions may close over variables that are then 47344 no longer available for introspection. 47345 You can pass a hash of these values to a computed property like this: 47346 ```javascript 47347 person: function() { 47348 var personId = this.get('personId'); 47349 return App.Person.create({ id: personId }); 47350 }.property().meta({ type: App.Person }) 47351 ``` 47352 Once you've done this, you can retrieve the values saved to the computed 47353 property from your class like this: 47354 ```javascript 47355 MyClass.metaForProperty('person'); 47356 ``` 47357 This will return the original hash that was passed to `meta()`. 47358 @static 47359 @method metaForProperty 47360 @param key {String} property name 47361 @private 47362 */ 47363 metaForProperty: function (key) { 47364 var proto = this.proto(); 47365 var possibleDesc = proto[key]; 47366 var desc = possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor ? possibleDesc : undefined; 47367 47368 _emberMetalDebug.assert('metaForProperty() could not find a computed property ' + 'with key \'' + key + '\'.', !!desc && desc instanceof _emberMetalComputed.ComputedProperty); 47369 return desc._meta || {}; 47370 }, 47371 47372 _computedProperties: _emberMetalComputed.computed(function () { 47373 hasCachedComputedProperties = true; 47374 var proto = this.proto(); 47375 var property; 47376 var properties = []; 47377 47378 for (var name in proto) { 47379 property = proto[name]; 47380 47381 if (property && property.isDescriptor) { 47382 properties.push({ 47383 name: name, 47384 meta: property._meta 47385 }); 47386 } 47387 } 47388 return properties; 47389 }).readOnly(), 47390 47391 /** 47392 Iterate over each computed property for the class, passing its name 47393 and any associated metadata (see `metaForProperty`) to the callback. 47394 @static 47395 @method eachComputedProperty 47396 @param {Function} callback 47397 @param {Object} binding 47398 @private 47399 */ 47400 eachComputedProperty: function (callback, binding) { 47401 var property; 47402 var empty = {}; 47403 47404 var properties = _emberMetalProperty_get.get(this, '_computedProperties'); 47405 47406 for (var i = 0, length = properties.length; i < length; i++) { 47407 property = properties[i]; 47408 callback.call(binding || this, property.name, property.meta || empty); 47409 } 47410 } 47411 }; 47412 47413 function injectedPropertyAssertion() { 47414 _emberMetalDebug.assert('Injected properties are invalid', _emberRuntimeInject.validatePropertyInjections(this)); 47415 } 47416 47417 _emberMetalDebug.runInDebug(function () { 47418 /** 47419 Provides lookup-time type validation for injected properties. 47420 @private 47421 @method _onLookup 47422 */ 47423 ClassMixinProps._onLookup = injectedPropertyAssertion; 47424 }); 47425 47426 /** 47427 Returns a hash of property names and container names that injected 47428 properties will lookup on the container lazily. 47429 47430 @method _lazyInjections 47431 @return {Object} Hash of all lazy injected property keys to container names 47432 @private 47433 */ 47434 ClassMixinProps._lazyInjections = function () { 47435 var injections = {}; 47436 var proto = this.proto(); 47437 var key, desc; 47438 47439 for (key in proto) { 47440 desc = proto[key]; 47441 if (desc instanceof _emberMetalInjected_property.default) { 47442 injections[key] = desc.type + ':' + (desc.name || key); 47443 } 47444 } 47445 47446 return injections; 47447 }; 47448 47449 var ClassMixin = _emberMetalMixin.Mixin.create(ClassMixinProps); 47450 47451 ClassMixin.ownerConstructor = CoreObject; 47452 47453 CoreObject.ClassMixin = ClassMixin; 47454 47455 ClassMixin.apply(CoreObject); 47456 47457 CoreObject.reopen({ 47458 didDefineProperty: function (proto, key, value) { 47459 if (hasCachedComputedProperties === false) { 47460 return; 47461 } 47462 if (value instanceof _emberMetalComputed.ComputedProperty) { 47463 var cache = _emberMetalMeta.meta(this.constructor).readableCache(); 47464 47465 if (cache && cache._computedProperties !== undefined) { 47466 cache._computedProperties = undefined; 47467 } 47468 } 47469 } 47470 }); 47471 47472 exports.default = CoreObject; 47473}); 47474 47475// NOTE: this object should never be included directly. Instead use `Ember.Object`. 47476// We only define this separately so that `Ember.Set` can depend on it. 47477 47478/** 47479 Defines the properties that will be concatenated from the superclass 47480 (instead of overridden). 47481 By default, when you extend an Ember class a property defined in 47482 the subclass overrides a property with the same name that is defined 47483 in the superclass. However, there are some cases where it is preferable
47484 to build up a property's value by combining the superclass' property 47485 value with the subclass' value. An example of this in use within Ember 47486 is the `classNames` property of `Ember.View`. 47487 Here is some sample code showing the difference between a concatenated 47488 property and a normal one: 47489 ```javascript 47490 App.BarView = Ember.View.extend({ 47491 someNonConcatenatedProperty: ['bar'], 47492 classNames: ['bar'] 47493 }); 47494 App.FooBarView = App.BarView.extend({ 47495 someNonConcatenatedProperty: ['foo'], 47496 classNames: ['foo'] 47497 }); 47498 var fooBarView = App.FooBarView.create(); 47499 fooBarView.get('someNonConcatenatedProperty'); // ['foo'] 47500 fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo'] 47501 ``` 47502 This behavior extends to object creation as well. Continuing the 47503 above example: 47504 ```javascript 47505 var view = App.FooBarView.create({ 47506 someNonConcatenatedProperty: ['baz'], 47507 classNames: ['baz'] 47508 }) 47509 view.get('someNonConcatenatedProperty'); // ['baz'] 47510 view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] 47511 ``` 47512 Adding a single property that is not an array will just add it in the array: 47513 ```javascript 47514 var view = App.FooBarView.create({ 47515 classNames: 'baz' 47516 }) 47517 view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] 47518 ``` 47519 Using the `concatenatedProperties` property, we can tell Ember to mix the 47520 content of the properties. 47521 In `Ember.View` the `classNameBindings` and `attributeBindings` properties 47522 are also concatenated, in addition to `classNames`. 47523 This feature is available for you to use throughout the Ember object model, 47524 although typical app developers are likely to use it infrequently. Since 47525 it changes expectations about behavior of properties, you should properly 47526 document its usage in each individual concatenated property (to not 47527 mislead your users to think they can override the property in a subclass). 47528 @property concatenatedProperties 47529 @type Array 47530 @default null 47531 @public 47532*/ 47533 47534/** 47535 Defines the properties that will be merged from the superclass 47536 (instead of overridden). 47537 By default, when you extend an Ember class a property defined in 47538 the subclass overrides a property with the same name that is defined 47539 in the superclass. However, there are some cases where it is preferable 47540 to build up a property's value by merging the superclass property value 47541 with the subclass property's value. An example of this in use within Ember 47542 is the `queryParams` property of routes. 47543 Here is some sample code showing the difference between a merged 47544 property and a normal one: 47545 ```javascript 47546 App.BarRoute = Ember.Route.extend({ 47547 someNonMergedProperty: { 47548 nonMerged: 'superclass value of nonMerged' 47549 }, 47550 queryParams: { 47551 page: {replace: false}, 47552 limit: {replace: true} 47553 } 47554 }); 47555 App.FooBarRoute = App.BarRoute.extend({ 47556 someNonMergedProperty: { 47557 completelyNonMerged: 'subclass value of nonMerged' 47558 }, 47559 queryParams: { 47560 limit: {replace: false} 47561 } 47562 }); 47563 var fooBarRoute = App.FooBarRoute.create(); 47564 fooBarRoute.get('someNonMergedProperty'); 47565 // => { completelyNonMerged: 'subclass value of nonMerged' } 47566 // 47567 // Note the entire object, including the nonMerged property of 47568 // the superclass object, has been replaced 47569 fooBarRoute.get('queryParams'); 47570 // => { 47571 // page: {replace: false}, 47572 // limit: {replace: false} 47573 // } 47574 // 47575 // Note the page remains from the superclass, and the 47576 // `limit` property's value of `false` has been merged from 47577 // the subclass. 47578 ``` 47579 This behavior is not available during object `create` calls. It is only 47580 available at `extend` time. 47581 This feature is available for you to use throughout the Ember object model, 47582 although typical app developers are likely to use it infrequently. Since 47583 it changes expectations about behavior of properties, you should properly 47584 document its usage in each individual merged property (to not 47585 mislead your users to think they can override the property in a subclass). 47586 @property mergedProperties 47587 @type Array 47588 @default null 47589 @public 47590*/ 47591 47592/** 47593 Destroyed object property flag. 47594 if this property is `true` the observers and bindings were already 47595 removed by the effect of calling the `destroy()` method. 47596 @property isDestroyed 47597 @default false 47598 @public 47599*/ 47600 47601/** 47602 Destruction scheduled flag. The `destroy()` method has been called. 47603 The object stays intact until the end of the run loop at which point 47604 the `isDestroyed` flag is set. 47605 @property isDestroying 47606 @default false 47607 @public 47608*/ 47609 47610/** 47611 Destroys an object by setting the `isDestroyed` flag and removing its 47612 metadata, which effectively destroys observers and bindings. 47613 If you try to set a property on a destroyed object, an exception will be 47614 raised. 47615 Note that destruction is scheduled for the end of the run loop and does not 47616 happen immediately. It will set an isDestroying flag immediately. 47617 @method destroy 47618 @return {Ember.Object} receiver 47619 @public 47620*/ 47621 47622/** 47623 Override to implement teardown. 47624 @method willDestroy 47625 @public 47626*/ 47627 47628/** 47629 Invoked by the run loop to actually destroy the object. This is 47630 scheduled for execution by the `destroy` method. 47631 @private 47632 @method _scheduledDestroy 47633*/ 47634 47635/** 47636 Returns a string representation which attempts to provide more information 47637 than Javascript's `toString` typically does, in a generic way for all Ember 47638 objects. 47639 ```javascript 47640 App.Person = Em.Object.extend() 47641 person = App.Person.create() 47642 person.toString() //=> "<App.Person:ember1024>" 47643 ``` 47644 If the object's class is not defined on an Ember namespace, it will 47645 indicate it is a subclass of the registered superclass: 47646 ```javascript 47647 Student = App.Person.extend() 47648 student = Student.create() 47649 student.toString() //=> "<(subclass of App.Person):ember1025>" 47650 ``` 47651 If the method `toStringExtension` is defined, its return value will be 47652 included in the output. 47653 ```javascript 47654 App.Teacher = App.Person.extend({ 47655 toStringExtension: function() { 47656 return this.get('fullName'); 47657 } 47658 }); 47659 teacher = App.Teacher.create() 47660 teacher.toString(); //=> "<App.Teacher:ember1026:Tom Dale>" 47661 ``` 47662 @method toString 47663 @return {String} string representation 47664 @public 47665*/ 47666enifed('ember-runtime/system/each_proxy', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/observer', 'ember-metal/property_events', 'ember-metal/empty_object', 'ember-runtime/mixins/array'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalObserver, _emberMetalProperty_events, _emberMetalEmpty_object, _emberRuntimeMixinsArray) { 47667 'use strict'; 47668 47669 /** 47670 This is the object instance returned when you get the `@each` property on an 47671 array. It uses the unknownProperty handler to automatically create 47672 EachArray instances for property names. 47673 @class EachProxy 47674 @private 47675 */ 47676 function EachProxy(content) { 47677 this._content = content; 47678 this._keys = undefined; 47679 this.__ember_meta__ = null; 47680 } 47681 47682 EachProxy.prototype = { 47683 __defineNonEnumerable: function (property) { 47684 this[property.name] = property.descriptor.value; 47685 }, 47686 47687 // .......................................................... 47688 // ARRAY CHANGES 47689 // Invokes whenever the content array itself changes. 47690 47691 arrayWillChange: function (content, idx, removedCnt, addedCnt) { 47692 var keys = this._keys; 47693 var lim = removedCnt > 0 ? idx + removedCnt : -1; 47694 for (var key in keys) { 47695 if (lim > 0) { 47696 removeObserverForContentKey(content, key, this, idx, lim); 47697 } 47698 _emberMetalProperty_events.propertyWillChange(this, key); 47699 } 47700 }, 47701 47702 arrayDidChange: function (content, idx, removedCnt, addedCnt) { 47703 var keys = this._keys; 47704 var lim = addedCnt > 0 ? idx + addedCnt : -1; 47705 for (var key in keys) { 47706 if (lim > 0) { 47707 addObserverForContentKey(content, key, this, idx, lim); 47708 } 47709 _emberMetalProperty_events.propertyDidChange(this, key); 47710 } 47711 }, 47712 47713 // .......................................................... 47714 // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS 47715 // Start monitoring keys based on who is listening... 47716 47717 willWatchProperty: function (property) { 47718 this.beginObservingContentKey(property); 47719 }, 47720 47721 didUnwatchProperty: function (property) { 47722 this.stopObservingContentKey(property); 47723 }, 47724 47725 // .......................................................... 47726 // CONTENT KEY OBSERVING 47727 // Actual watch keys on the source content. 47728 47729 beginObservingContentKey: function (keyName) { 47730 var keys = this._keys; 47731 if (!keys) { 47732 keys = this._keys = new _emberMetalEmpty_object.default(); 47733 } 47734 47735 if (!keys[keyName]) { 47736 keys[keyName] = 1; 47737 var content = this._content; 47738 var len = _emberMetalProperty_get.get(content, 'length'); 47739 47740 addObserverForContentKey(content, keyName, this, 0, len); 47741 } else { 47742 keys[keyName]++; 47743 } 47744 }, 47745 47746 stopObservingContentKey: function (keyName) { 47747 var keys = this._keys; 47748 if (keys && keys[keyName] > 0 && --keys[keyName] <= 0) { 47749 var content = this._content; 47750 var len = _emberMetalProperty_get.get(content, 'length'); 47751 47752 removeObserverForContentKey(content, keyName, this, 0, len); 47753 } 47754 }, 47755 47756 contentKeyWillChange: function (obj, keyName) { 47757 _emberMetalProperty_events.propertyWillChange(this, keyName); 47758 }, 47759 47760 contentKeyDidChange: function (obj, keyName) { 47761 _emberMetalProperty_events.propertyDidChange(this, keyName); 47762 } 47763 }; 47764 47765 function addObserverForContentKey(content, keyName, proxy, idx, loc) { 47766 while (--loc >= idx) { 47767 var item = _emberRuntimeMixinsArray.objectAt(content, loc); 47768 if (item) { 47769 _emberMetalDebug.assert('When using @each to observe the array ' + content + ', the array must return an object', typeof item === 'object'); 47770 _emberMetalObserver._addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); 47771 _emberMetalObserver.addObserver(item, keyName, proxy, 'contentKeyDidChange'); 47772 } 47773 } 47774 } 47775 47776 function removeObserverForContentKey(content, keyName, proxy, idx, loc) { 47777 while (--loc >= idx) { 47778 var item = _emberRuntimeMixinsArray.objectAt(content, loc); 47779 if (item) { 47780 _emberMetalObserver._removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); 47781 _emberMetalObserver.removeObserver(item, keyName, proxy, 'contentKeyDidChange'); 47782 } 47783 } 47784 } 47785 47786 exports.default = EachProxy; 47787}); 47788enifed('ember-runtime/system/lazy_load', ['exports', 'ember-metal/core', 'ember-runtime/system/native_array'], function (exports, _emberMetalCore, _emberRuntimeSystemNative_array) { 47789 /*globals CustomEvent */ 47790 47791 'use strict'; 47792 47793 exports.onLoad = onLoad;
47794 exports.runLoadHooks = runLoadHooks; 47795 47796 /** 47797 @module ember 47798 @submodule ember-runtime 47799 */ 47800 47801 var loadHooks = _emberMetalCore.default.ENV.EMBER_LOAD_HOOKS || {}; 47802 var loaded = {}; 47803 var _loaded = loaded; 47804 47805 exports._loaded = _loaded; 47806 /** 47807 Detects when a specific package of Ember (e.g. 'Ember.Application') 47808 has fully loaded and is available for extension. 47809 47810 The provided `callback` will be called with the `name` passed 47811 resolved from a string into the object: 47812 47813 ``` javascript 47814 Ember.onLoad('Ember.Application' function(hbars) { 47815 hbars.registerHelper(...); 47816 }); 47817 ``` 47818 47819 @method onLoad 47820 @for Ember 47821 @param name {String} name of hook 47822 @param callback {Function} callback to be called 47823 @private 47824 */ 47825 47826 function onLoad(name, callback) { 47827 var object = loaded[name]; 47828 47829 loadHooks[name] = loadHooks[name] || _emberRuntimeSystemNative_array.A(); 47830 loadHooks[name].pushObject(callback); 47831 47832 if (object) { 47833 callback(object); 47834 } 47835 } 47836 47837 /** 47838 Called when an Ember.js package (e.g Ember.Application) has finished 47839 loading. Triggers any callbacks registered for this event. 47840
47841 @method runLoadHooks 47842 @for Ember 47843 @param name {String} name of hook 47844 @param object {Object} object to pass to callbacks 47845 @private 47846 */ 47847 47848 function runLoadHooks(name, object) { 47849 loaded[name] = object; 47850 47851 if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === 'function') { 47852 var event = new CustomEvent(name, { detail: object, name: name }); 47853 window.dispatchEvent(event); 47854 } 47855 47856 if (loadHooks[name]) { 47857 loadHooks[name].forEach(function (callback) { 47858 return callback(object); 47859 }); 47860 } 47861 } 47862}); 47863// Ember.ENV.EMBER_LOAD_HOOKS 47864enifed('ember-runtime/system/namespace', ['exports', 'ember-metal/core', 'ember-metal/property_get', 'ember-metal/utils', 'ember-metal/mixin', 'ember-runtime/system/object'], function (exports, _emberMetalCore, _emberMetalProperty_get, _emberMetalUtils, _emberMetalMixin, _emberRuntimeSystemObject) { 47865 /** 47866 @module ember 47867 @submodule ember-runtime 47868 */ 47869 47870 // Ember.lookup, Ember.BOOTED, Ember.NAME_KEY, Ember.anyUnprocessedMixins 47871 'use strict'; 47872 47873 /** 47874 A Namespace is an object usually used to contain other objects or methods 47875 such as an application or framework. Create a namespace anytime you want 47876 to define one of these new containers. 47877 47878 # Example Usage 47879 47880 ```javascript 47881 MyFramework = Ember.Namespace.create({ 47882 VERSION: '1.0.0' 47883 }); 47884 ``` 47885 47886 @class Namespace 47887 @namespace Ember 47888 @extends Ember.Object 47889 @public 47890 */ 47891 var Namespace = _emberRuntimeSystemObject.default.extend({ 47892 isNamespace: true, 47893 47894 init: function () { 47895 Namespace.NAMESPACES.push(this); 47896 Namespace.PROCESSED = false; 47897 }, 47898 47899 toString: function () { 47900 var name = _emberMetalProperty_get.get(this, 'name') || _emberMetalProperty_get.get(this, 'modulePrefix'); 47901 if (name) { 47902 return name; 47903 } 47904 47905 findNamespaces(); 47906 return this[NAME_KEY]; 47907 }, 47908 47909 nameClasses: function () { 47910 processNamespace([this.toString()], this, {}); 47911 }, 47912 47913 destroy: function () { 47914 var namespaces = Namespace.NAMESPACES; 47915 var toString = this.toString(); 47916 47917 if (toString) { 47918 _emberMetalCore.default.lookup[toString] = undefined; 47919 delete Namespace.NAMESPACES_BY_ID[toString]; 47920 } 47921 namespaces.splice(namespaces.indexOf(this), 1); 47922 this._super.apply(this, arguments); 47923 } 47924 }); 47925 47926 Namespace.reopenClass({ 47927 NAMESPACES: [_emberMetalCore.default], 47928 NAMESPACES_BY_ID: {}, 47929 PROCESSED: false, 47930 processAll: processAllNamespaces, 47931 byName: function (name) { 47932 if (!_emberMetalCore.default.BOOTED) { 47933 processAllNamespaces(); 47934 } 47935 47936 return NAMESPACES_BY_ID[name]; 47937 } 47938 }); 47939 47940 var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; 47941 47942 var hasOwnProp = ({}).hasOwnProperty; 47943 47944 function processNamespace(paths, root, seen) { 47945 var idx = paths.length; 47946 47947 NAMESPACES_BY_ID[paths.join('.')] = root; 47948 47949 // Loop over all of the keys in the namespace, looking for classes 47950 for (var key in root) { 47951 if (!hasOwnProp.call(root, key)) { 47952 continue; 47953 } 47954 var obj = root[key]; 47955 47956 // If we are processing the `Ember` namespace, for example, the 47957 // `paths` will start with `["Ember"]`. Every iteration through 47958 // the loop will update the **second** element of this list with 47959 // the key, so processing `Ember.View` will make the Array 47960 // `['Ember', 'View']`. 47961 paths[idx] = key; 47962 47963 // If we have found an unprocessed class 47964 if (obj && obj.toString === classToString && !obj[NAME_KEY]) { 47965 // Replace the class' `toString` with the dot-separated path 47966 // and set its `NAME_KEY` 47967 obj[NAME_KEY] = paths.join('.'); 47968 47969 // Support nested namespaces 47970 } else if (obj && obj.isNamespace) { 47971 // Skip aliased namespaces 47972 if (seen[_emberMetalUtils.guidFor(obj)]) { 47973 continue; 47974 } 47975 seen[_emberMetalUtils.guidFor(obj)] = true; 47976 47977 // Process the child namespace 47978 processNamespace(paths, obj, seen); 47979 } 47980 } 47981 47982 paths.length = idx; // cut out last item 47983 } 47984 47985 var STARTS_WITH_UPPERCASE = /^[A-Z]/; 47986
47987 function tryIsNamespace(lookup, prop) { 47988 try { 47989 var obj = lookup[prop]; 47990 return obj && obj.isNamespace && obj; 47991 } catch (e) { 47992 // continue 47993 } 47994 } 47995 47996 function findNamespaces() { 47997 var lookup = _emberMetalCore.default.lookup; 47998 var obj; 47999 48000 if (Namespace.PROCESSED) { 48001 return; 48002 } 48003 48004 for (var prop in lookup) { 48005 // Only process entities that start with uppercase A-Z 48006 if (!STARTS_WITH_UPPERCASE.test(prop)) { 48007 continue; 48008 } 48009 48010 // Unfortunately, some versions of IE don't support window.hasOwnProperty 48011 if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { 48012 continue; 48013 } 48014 48015 // At times we are not allowed to access certain properties for security reasons. 48016 // There are also times where even if we can access them, we are not allowed to access their properties. 48017 obj = tryIsNamespace(lookup, prop); 48018 if (obj) { 48019 obj[NAME_KEY] = prop; 48020 } 48021 } 48022 } 48023 48024 var NAME_KEY = _emberMetalCore.default.NAME_KEY = _emberMetalUtils.GUID_KEY + '_name'; 48025 48026 function superClassString(mixin) { 48027 var superclass = mixin.superclass; 48028 if (superclass) { 48029 if (superclass[NAME_KEY]) { 48030 return superclass[NAME_KEY]; 48031 } else { 48032 return superClassString(superclass); 48033 } 48034 } else { 48035 return; 48036 } 48037 } 48038 48039 function classToString() { 48040 if (!_emberMetalCore.default.BOOTED && !this[NAME_KEY]) { 48041 processAllNamespaces(); 48042 } 48043 48044 var ret; 48045 48046 if (this[NAME_KEY]) { 48047 ret = this[NAME_KEY]; 48048 } else if (this._toString) { 48049 ret = this._toString; 48050 } else { 48051 var str = superClassString(this); 48052 if (str) { 48053 ret = '(subclass of ' + str + ')'; 48054 } else { 48055 ret = '(unknown mixin)'; 48056 } 48057 this.toString = makeToString(ret); 48058 } 48059 48060 return ret; 48061 } 48062 48063 function processAllNamespaces() { 48064 var unprocessedNamespaces = !Namespace.PROCESSED; 48065 var unprocessedMixins = _emberMetalCore.default.anyUnprocessedMixins; 48066 48067 if (unprocessedNamespaces) { 48068 findNamespaces(); 48069 Namespace.PROCESSED = true; 48070 } 48071 48072 if (unprocessedNamespaces || unprocessedMixins) { 48073 var namespaces = Namespace.NAMESPACES; 48074 var namespace; 48075 48076 for (var i = 0, l = namespaces.length; i < l; i++) { 48077 namespace = namespaces[i]; 48078 processNamespace([namespace.toString()], namespace, {}); 48079 } 48080 48081 _emberMetalCore.default.anyUnprocessedMixins = false; 48082 } 48083 } 48084 48085 function makeToString(ret) { 48086 return function () { 48087 return ret; 48088 }; 48089 } 48090 48091 _emberMetalMixin.Mixin.prototype.toString = classToString; // ES6TODO: altering imported objects. SBB. 48092 48093 exports.default = Namespace; 48094}); 48095enifed('ember-runtime/system/native_array', ['exports', 'ember-metal/core', 'ember-metal/replace', 'ember-metal/property_get', 'ember-metal/mixin', 'ember-runtime/mixins/array', 'ember-runtime/mixins/mutable_array', 'ember-runtime/mixins/observable', 'ember-runtime/mixins/copyable', 'ember-runtime/mixins/freezable', 'ember-runtime/copy'], function (exports, _emberMetalCore, _emberMetalReplace, _emberMetalProperty_get, _emberMetalMixin, _emberRuntimeMixinsArray, _emberRuntimeMixinsMutable_array, _emberRuntimeMixinsObservable, _emberRuntimeMixinsCopyable, _emberRuntimeMixinsFreezable, _emberRuntimeCopy) { 48096 /** 48097 @module ember 48098 @submodule ember-runtime 48099 */ 48100 48101 'use strict'; 48102 48103 // Add Ember.Array to Array.prototype. Remove methods with native 48104 // implementations and supply some more optimized versions of generic methods 48105 // because they are so common. 48106 48107 /** 48108 The NativeArray mixin contains the properties needed to make the native 48109 Array support Ember.MutableArray and all of its dependent APIs. Unless you 48110 have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to 48111 false, this will be applied automatically. Otherwise you can apply the mixin 48112 at anytime by calling `Ember.NativeArray.activate`. 48113 48114 @class NativeArray 48115 @namespace Ember 48116 @uses Ember.MutableArray 48117 @uses Ember.Observable 48118 @uses Ember.Copyable 48119 @public 48120 */ 48121 var NativeArray = _emberMetalMixin.Mixin.create(_emberRuntimeMixinsMutable_array.default, _emberRuntimeMixinsObservable.default, _emberRuntimeMixinsCopyable.default, { 48122 48123 // because length is a built-in property we need to know to just get the 48124 // original property. 48125 get: function (key) { 48126 if (key === 'length') { 48127 return this.length; 48128 } else if ('number' === typeof key) { 48129 return this[key]; 48130 } else { 48131 return this._super(key); 48132 } 48133 }, 48134 48135 objectAt: function (idx) { 48136 return this[idx]; 48137 }, 48138
48139 // primitive for array support. 48140 replace: function (idx, amt, objects) { 48141 if (this.isFrozen) { 48142 throw _emberRuntimeMixinsFreezable.FROZEN_ERROR; 48143 } 48144 48145 // if we replaced exactly the same number of items, then pass only the 48146 // replaced range. Otherwise, pass the full remaining array length 48147 // since everything has shifted 48148 var len = objects ? _emberMetalProperty_get.get(objects, 'length') : 0; 48149 this.arrayContentWillChange(idx, amt, len); 48150 48151 if (len === 0) { 48152 this.splice(idx, amt); 48153 } else { 48154 _emberMetalReplace._replace(this, idx, amt, objects); 48155 } 48156 48157 this.arrayContentDidChange(idx, amt, len); 48158 return this; 48159 }, 48160 48161 // If you ask for an unknown property, then try to collect the value 48162 // from member items. 48163 unknownProperty: function (key, value) { 48164 var ret; // = this.reducedProperty(key, value); 48165 if (value !== undefined && ret === undefined) { 48166 ret = this[key] = value; 48167 } 48168 return ret; 48169 }, 48170 48171 indexOf: Array.prototype.indexOf, 48172 lastIndexOf: Array.prototype.lastIndexOf, 48173 48174 copy: function (deep) { 48175 if (deep) { 48176 return this.map(function (item) { 48177 return _emberRuntimeCopy.default(item, true); 48178 }); 48179 } 48180 48181 return this.slice(); 48182 } 48183 }); 48184 48185 // Remove any methods implemented natively so we don't override them 48186 var ignore = ['length']; 48187 NativeArray.keys().forEach(function (methodName) { 48188 if (Array.prototype[methodName]) { 48189 ignore.push(methodName); 48190 } 48191 }); 48192 48193 exports.NativeArray // TODO: only use default export 48194 = NativeArray = NativeArray.without.apply(NativeArray, ignore); 48195 48196 /** 48197 Creates an `Ember.NativeArray` from an Array like object. 48198 Does not modify the original object. Ember.A is not needed if 48199 `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However, 48200 it is recommended that you use Ember.A when creating addons for 48201 ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` 48202 will be `true`. 48203 48204 Example 48205 48206 ```js 48207 var Pagination = Ember.CollectionView.extend({ 48208 tagName: 'ul', 48209 classNames: ['pagination'], 48210 48211 init: function() { 48212 this._super(...arguments); 48213 if (!this.get('content')) { 48214 this.set('content', Ember.A()); 48215 } 48216 } 48217 }); 48218 ``` 48219 48220 @method A 48221 @for Ember 48222 @return {Ember.NativeArray} 48223 @public 48224 */ 48225 var A; 48226 48227 if (_emberMetalCore.default.EXTEND_PROTOTYPES === true || _emberMetalCore.default.EXTEND_PROTOTYPES.Array) { 48228 NativeArray.apply(Array.prototype); 48229 exports. // ES6TODO: Setting A onto the object returned by ember-metal/core to avoid circles 48230 A = A = function (arr) { 48231 return arr || []; 48232 }; 48233 } else { 48234 exports.A = A = function (arr) { 48235 if (!arr) { 48236 arr = []; 48237 } 48238 return _emberRuntimeMixinsArray.default.detect(arr) ? arr : NativeArray.apply(arr); 48239 }; 48240 } 48241 48242 _emberMetalCore.default.A = A;exports.A = A; 48243 exports.NativeArray = NativeArray; 48244 exports.default = NativeArray; 48245}); 48246// Ember.EXTEND_PROTOTYPES 48247enifed('ember-runtime/system/object', ['exports', 'ember-runtime/system/core_object', 'ember-runtime/mixins/observable'], function (exports, _emberRuntimeSystemCore_object, _emberRuntimeMixinsObservable) { 48248 /** 48249 @module ember 48250 @submodule ember-runtime 48251 */ 48252 48253 'use strict'; 48254 48255 /** 48256 `Ember.Object` is the main base class for all Ember objects. It is a subclass 48257 of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, 48258 see the documentation for each of these. 48259 48260 @class Object 48261 @namespace Ember 48262 @extends Ember.CoreObject 48263 @uses Ember.Observable 48264 @public 48265 */ 48266 var EmberObject = _emberRuntimeSystemCore_object.default.extend(_emberRuntimeMixinsObservable.default); 48267 EmberObject.toString = function () { 48268 return 'Ember.Object'; 48269 }; 48270 48271 exports.default = EmberObject; 48272}); 48273enifed('ember-runtime/system/object_proxy', ['exports', 'ember-runtime/system/object', 'ember-runtime/mixins/-proxy'], function (exports, _emberRuntimeSystemObject, _emberRuntimeMixinsProxy) { 48274 'use strict'; 48275 48276 /** 48277 `Ember.ObjectProxy` forwards all properties not defined by the proxy itself 48278 to a proxied `content` object. 48279 48280 ```javascript 48281 object = Ember.Object.create({ 48282 name: 'Foo' 48283 }); 48284 48285 proxy = Ember.ObjectProxy.create({ 48286 content: object 48287 }); 48288 48289 // Access and change existing properties 48290 proxy.get('name') // 'Foo' 48291 proxy.set('name', 'Bar'); 48292 object.get('name') // 'Bar' 48293 48294 // Create new 'description' property on `object` 48295 proxy.set('description', 'Foo is a whizboo baz'); 48296 object.get('description') // 'Foo is a whizboo baz' 48297 ``` 48298 48299 While `content` is unset, setting a property to be delegated
48299will throw an 48300 Error. 48301 48302 ```javascript 48303 proxy = Ember.ObjectProxy.create({ 48304 content: null, 48305 flag: null 48306 }); 48307 proxy.set('flag', true); 48308 proxy.get('flag'); // true 48309 proxy.get('foo'); // undefined 48310 proxy.set('foo', 'data'); // throws Error 48311 ``` 48312 48313 Delegated properties can be bound to and will change when content is updated. 48314 48315 Computed properties on the proxy itself can depend on delegated properties. 48316 48317 ```javascript 48318 ProxyWithComputedProperty = Ember.ObjectProxy.extend({ 48319 fullName: function() { 48320 var firstName = this.get('firstName'), 48321 lastName = this.get('lastName'); 48322 if (firstName && lastName) { 48323 return firstName + ' ' + lastName; 48324 } 48325 return firstName || lastName; 48326 }.property('firstName', 'lastName') 48327 }); 48328 48329 proxy = ProxyWithComputedProperty.create(); 48330 48331 proxy.get('fullName'); // undefined 48332 proxy.set('content', { 48333 firstName: 'Tom', lastName: 'Dale' 48334 }); // triggers property change for fullName on proxy 48335 48336 proxy.get('fullName'); // 'Tom Dale' 48337 ``` 48338 48339 @class ObjectProxy 48340 @namespace Ember 48341 @extends Ember.Object 48342 @extends Ember._ProxyMixin 48343 @public 48344 */ 48345 48346 exports.default = _emberRuntimeSystemObject.default.extend(_emberRuntimeMixinsProxy.default); 48347}); 48348enifed('ember-runtime/system/service', ['exports', 'ember-runtime/system/object', 'ember-runtime/inject'], function (exports, _emberRuntimeSystemObject, _emberRuntimeInject) { 48349 'use strict'; 48350 48351 /** 48352 Creates a property that lazily looks up a service in the container. There 48353 are no restrictions as to what objects a service can be injected into. 48354 48355 Example: 48356 48357 ```javascript 48358 App.ApplicationRoute = Ember.Route.extend({ 48359 authManager: Ember.inject.service('auth'), 48360 48361 model: function() { 48362 return this.get('authManager').findCurrentUser(); 48363 } 48364 }); 48365 ``` 48366 48367 This example will create an `authManager` property on the application route 48368 that looks up the `auth` service in the container, making it easily 48369 accessible in the `model` hook. 48370 48371 @method service 48372 @since 1.10.0 48373 @for Ember.inject 48374 @param {String} name (optional) name of the service to inject, defaults to 48375 the property's name 48376 @return {Ember.InjectedProperty} injection descriptor instance 48377 @public 48378 */ 48379 _emberRuntimeInject.createInjectionHelper('service'); 48380 48381 /** 48382 @class Service 48383 @namespace Ember 48384 @extends Ember.Object 48385 @since 1.10.0 48386 @public 48387 */ 48388 var Service = _emberRuntimeSystemObject.default.extend(); 48389 48390 Service.reopenClass({ 48391 isServiceFactory: true 48392 }); 48393 48394 exports.default = Service; 48395}); 48396enifed('ember-runtime/system/string', ['exports', 'ember-metal/debug', 'ember-metal/utils', 'ember-runtime/utils', 'ember-runtime/string_registry', 'ember-metal/cache'], function (exports, _emberMetalDebug, _emberMetalUtils, _emberRuntimeUtils, _emberRuntimeString_registry, _emberMetalCache) { 48397 /** 48398 @module ember 48399 @submodule ember-runtime 48400 */ 48401 'use strict'; 48402 48403 var STRING_DASHERIZE_REGEXP = /[ _]/g; 48404 48405 var STRING_DASHERIZE_CACHE = new _emberMetalCache.default(1000, function (key) { 48406 return decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'); 48407 }); 48408 48409 var STRING_CAMELIZE_REGEXP_1 = /(\-|\_|\.|\s)+(.)?/g; 48410 var STRING_CAMELIZE_REGEXP_2 = /(^|\/)([A-Z])/g; 48411 48412 var CAMELIZE_CACHE = new _emberMetalCache.default(1000, function (key) { 48413 return key.replace(STRING_CAMELIZE_REGEXP_1, function (match, separator, chr) { 48414 return chr ? chr.toUpperCase() : ''; 48415 }).replace(STRING_CAMELIZE_REGEXP_2, function (match, separator, chr) { 48416 return match.toLowerCase(); 48417 }); 48418 }); 48419 48420 var STRING_CLASSIFY_REGEXP_1 = /^(\-|_)+(.)?/; 48421 var STRING_CLASSIFY_REGEXP_2 = /(.)(\-|\_|\.|\s)+(.)?/g; 48422 var STRING_CLASSIFY_REGEXP_3 = /(^|\/|\.)([a-z])/g; 48423 48424 var CLASSIFY_CACHE = new _emberMetalCache.default(1000, function (str) { 48425 var replace1 = function (match, separator, chr) { 48426 return chr ? '_' + chr.toUpperCase() : ''; 48427 }; 48428 var replace2 = function (match, initialChar, separator, chr) { 48429 return initialChar + (chr ? chr.toUpperCase() : ''); 48430 }; 48431 var parts = str.split('/'); 48432 for (var i = 0, len = parts.length; i < len; i++) { 48433 parts[i] = parts[i].replace(STRING_CLASSIFY_REGEXP_1, replace1).replace(STRING_CLASSIFY_REGEXP_2, replace2); 48434 } 48435 return parts.join('/').replace(STRING_CLASSIFY_REGEXP_3, function (match, separator, chr) { 48436 return match.toUpperCase(); 48437 }); 48438 }); 48439 48440 var STRING_UNDERSCORE_REGEXP_1 = /([a-z\d])([A-Z]+)/g; 48441 var STRING_UNDERSCORE_REGEXP_2 = /\-|\s+/g; 48442 48443 var UNDERSCORE_CACHE = new _emberMetalCache.default(1000, function (str) { 48444 return str.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2').replace(STRING_UNDERSCORE_REGEXP_2, '_').toLowerCase(); 48445 }); 48446 48447 var STRING_CAPITALIZE_REGEXP = /(^|\/)([a-z])/g; 48448 48449 var CAPITALIZE_CACHE = new _emberMetalCache.default(1000, function (str) { 48450 return str.replace(STRING_CAPITALIZE_REGEXP, function (match, separator, chr) { 48451 return match.toUpperCase(); 48452 }); 48453 }); 48454 48455 var STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g; 48456 48457 var DECAMELIZE_CACHE = new _emberMetalCache.default(1000, function (str) { 48458 return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); 48459 }); 48460 48461 function _fmt(str, formats) { 48462 var cachedFormats = formats; 48463 48464 if (!_emberRuntimeUtils.isArray(cachedFormats) || arguments.length > 2) { 48465 cachedFormats = new Array(arguments.length - 1); 48466 48467 for (var i = 1, l = arguments.length; i < l; i++) { 48468 cachedFormats[i - 1] = arguments[i]; 48469 } 48470 } 48471 48472 // first, replace any ORDERED replacements. 48473 var idx = 0; // the current index for non-numerical replacements 48474 return str.replace(/%@([0-9]+)?/g, function (s, argIndex) { 48475 argIndex = argIndex ? parseInt(argIndex, 10) - 1 : idx++; 48476 s = cachedFormats[argIndex]; 48477 return s === null ? '(null)' : s === undefined ? '' : _emberMetalUtils.inspect(s); 48478 }); 48479 } 48480 48481 function fmt(str, formats) { 48482 _emberMetalDebug.deprecate('Ember.String.fmt is deprecated, use ES6 template strings instead.', false, { id: 'ember-string-utils.fmt', until: '3.0.0', url: 'http://babeljs.io/docs/learn-es2015/#template-strings' }); 48483 return _fmt.apply(undefined, arguments); 48484 } 48485 48486 function loc(str, formats) { 48487 if (!_emberRuntimeUtils.isArray(formats) || arguments.length > 2) { 48488 formats = Array.prototype.slice.call(arguments, 1); 48489 } 48490 48491 str = _emberRuntimeString_registry.get(str) || str; 48492 return _fmt(str, formats); 48493 } 48494 48495 function w(str) { 48496 return str.split(/\s+/); 48497 } 48498 48499 function decamelize(str) { 48500 return DECAMELIZE_CACHE.get(str); 48501 } 48502 48503 function dasherize(str) { 48504 return STRING_DASHERIZE_CACHE.get(str); 48505 } 48506 48507 function camelize(str) { 48508 return CAMELIZE_CACHE.get(str); 48509 } 48510 48511 function classify(str) { 48512 return CLASSIFY_CACHE.get(str); 48513 } 48514 48515 function underscore(str) { 48516 return UNDERSCORE_CACHE.get(str); 48517 } 48518 48519 function capitalize(str) { 48520 return CAPITALIZE_CACHE.get(str); 48521 } 48522 48523 /**
48524 Defines string helper methods including string formatting and localization. 48525 Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be 48526 added to the `String.prototype` as well. 48527 48528 @class String 48529 @namespace Ember 48530 @static 48531 @public 48532 */ 48533 exports.default = { 48534 /** 48535 Apply formatting options to the string. This will look for occurrences 48536 of "%@" in your string and substitute them with the arguments you pass into 48537 this method. If you want to control the specific order of replacement, 48538 you can add a number after the key as well to indicate which argument 48539 you want to insert. 48540 Ordered insertions are most useful when building loc strings where values 48541 you need to insert may appear in different orders. 48542 ```javascript 48543 "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe" 48544 "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John" 48545 ``` 48546 @method fmt 48547 @param {String} str The string to format 48548 @param {Array} formats An array of parameters to interpolate into string. 48549 @return {String} formatted string 48550 @public 48551 @deprecated Use ES6 template strings instead: http://babeljs.io/docs/learn-es2015/#template-strings 48552 */ 48553 fmt: fmt, 48554 48555 /** 48556 Formats the passed string, but first looks up the string in the localized
48557 strings hash. This is a convenient way to localize text. See 48558 `Ember.String.fmt()` for more information on formatting. 48559 Note that it is traditional but not required to prefix localized string 48560 keys with an underscore or other character so you can easily identify 48561 localized strings. 48562 ```javascript 48563 Ember.STRINGS = { 48564 '_Hello World': 'Bonjour le monde', 48565 '_Hello %@ %@': 'Bonjour %@ %@' 48566 }; 48567 Ember.String.loc("_Hello World"); // 'Bonjour le monde'; 48568 Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith"; 48569 ``` 48570 @method loc 48571 @param {String} str The string to format 48572 @param {Array} formats Optional array of parameters to interpolate into string. 48573 @return {String} formatted string 48574 @public 48575 */ 48576 loc: loc, 48577 48578 /** 48579 Splits a string into separate units separated by spaces, eliminating any 48580 empty strings in the process. This is a convenience method for split that 48581 is mostly useful when applied to the `String.prototype`. 48582 ```javascript 48583 Ember.String.w("alpha beta gamma").forEach(function(key) { 48584 console.log(key); 48585 }); 48586 // > alpha 48587 // > beta 48588 // > gamma 48589 ``` 48590 @method w 48591 @param {String} str The string to split 48592 @return {Array} array containing the split strings 48593 @public 48594 */ 48595 w: w, 48596 48597 /** 48598 Converts a camelized string into all lower case separated by underscores. 48599 ```javascript 48600 'innerHTML'.decamelize(); // 'inner_html' 48601 'action_name'.decamelize(); // 'action_name' 48602 'css-class-name'.decamelize(); // 'css-class-name' 48603 'my favorite items'.decamelize(); // 'my favorite items' 48604 ``` 48605 @method decamelize 48606 @param {String} str The string to decamelize. 48607 @return {String} the decamelized string. 48608 @public 48609 */ 48610 decamelize: decamelize, 48611 48612 /** 48613 Replaces underscores, spaces, or camelCase with dashes. 48614 ```javascript 48615 'innerHTML'.dasherize(); // 'inner-html' 48616 'action_name'.dasherize(); // 'action-name' 48617 'css-class-name'.dasherize(); // 'css-class-name' 48618 'my favorite items'.dasherize(); // 'my-favorite-items' 48619 'privateDocs/ownerInvoice'.dasherize(); // 'private-docs/owner-invoice' 48620 ``` 48621 @method dasherize 48622 @param {String} str The string to dasherize. 48623 @return {String} the dasherized string. 48624 @public 48625 */ 48626 dasherize: dasherize, 48627 48628 /** 48629 Returns the lowerCamelCase form of a string. 48630 ```javascript 48631 'innerHTML'.camelize(); // 'innerHTML' 48632 'action_name'.camelize(); // 'actionName' 48633 'css-class-name'.camelize(); // 'cssClassName' 48634 'my favorite items'.camelize(); // 'myFavoriteItems' 48635 'My Favorite Items'.camelize(); // 'myFavoriteItems' 48636 'private-docs/owner-invoice'.camelize(); // 'privateDocs/ownerInvoice' 48637 ``` 48638 @method camelize 48639 @param {String} str The string to camelize. 48640 @return {String} the camelized string. 48641 @public 48642 */ 48643 camelize: camelize, 48644 48645 /** 48646 Returns the UpperCamelCase form of a string. 48647 ```javascript 48648 'innerHTML'.classify(); // 'InnerHTML' 48649 'action_name'.classify(); // 'ActionName' 48650 'css-class-name'.classify(); // 'CssClassName' 48651 'my favorite items'.classify(); // 'MyFavoriteItems' 48652 'private-docs/owner-invoice'.classify(); // 'PrivateDocs/OwnerInvoice' 48653 ``` 48654 @method classify 48655 @param {String} str the string to classify 48656 @return {String} the classified string 48657 @public 48658 */ 48659 classify: classify, 48660 48661 /** 48662 More general than decamelize. Returns the lower\_case\_and\_underscored 48663 form of a string. 48664 ```javascript 48665 'innerHTML'.underscore(); // 'inner_html' 48666 'action_name'.underscore(); // 'action_name' 48667 'css-class-name'.underscore(); // 'css_class_name' 48668 'my favorite items'.underscore(); // 'my_favorite_items' 48669 'privateDocs/ownerInvoice'.underscore(); // 'private_docs/owner_invoice' 48670 ``` 48671 @method underscore 48672 @param {String} str The string to underscore. 48673 @return {String} the underscored string. 48674 @public 48675 */ 48676 underscore: underscore, 48677 48678 /** 48679 Returns the Capitalized form of a string 48680 ```javascript 48681 'innerHTML'.capitalize() // 'InnerHTML' 48682 'action_name'.capitalize() // 'Action_name' 48683 'css-class-name'.capitalize() // 'Css-class-name' 48684 'my favorite items'.capitalize() // 'My favorite items' 48685 'privateDocs/ownerInvoice'.capitalize(); // 'PrivateDocs/ownerInvoice' 48686 ``` 48687 @method capitalize 48688 @param {String} str The string to capitalize. 48689 @return {String} The capitalized string. 48690 @public 48691 */ 48692 capitalize: capitalize 48693 }; 48694 exports.fmt = fmt; 48695 exports.loc = loc; 48696 exports.w = w; 48697 exports.decamelize = decamelize; 48698 exports.dasherize = dasherize; 48699 exports.camelize = camelize; 48700 exports.classify = classify; 48701 exports.underscore = underscore; 48702 exports.capitalize = capitalize; 48703}); 48704enifed('ember-runtime/utils', ['exports', 'ember-runtime/mixins/array', 'ember-runtime/system/object'], function (exports, _emberRuntimeMixinsArray, _emberRuntimeSystemObject) { 48705 'use strict'; 48706 48707 exports.isArray = isArray; 48708 exports.typeOf = typeOf; 48709 48710 // ........................................ 48711 // TYPING & ARRAY MESSAGING 48712 // 48713 var TYPE_MAP = { 48714 '[object Boolean]': 'boolean', 48715 '[object Number]': 'number', 48716 '[object String]': 'string', 48717 '[object Function]': 'function', 48718 '[object Array]': 'array', 48719 '[object Date]': 'date', 48720 '[object RegExp]': 'regexp', 48721 '[object Object]': 'object' 48722 }; 48723 48724 var toString = Object.prototype.toString; 48725 48726 /** 48727 Returns true if the passed object is an array or Array-like. 48728 48729 Objects are considered Array-like if any of the following are true: 48730 48731 - the object is a native Array 48732 - the object has an objectAt property 48733 - the object is an Object, and has a length property 48734 48735 Unlike `Ember.typeOf` this method returns true even if the passed object is 48736 not formally an array but appears to be array-like (i.e. implements `Ember.Array`) 48737 48738 ```javascript 48739 Ember.isArray(); // false 48740 Ember.isArray([]); // true 48741 Ember.isArray(Ember.ArrayProxy.create({ content: [] })); // true 48742 ``` 48743 48744 @method isArray 48745 @for Ember 48746 @param {Object} obj The object to test 48747 @return {Boolean} true if the passed object is an array or Array-like 48748 @public 48749 */ 48750 48751 function isArray(obj) { 48752 if (!obj || obj.setInterval) { 48753 return false;
48754 } 48755 if (Array.isArray(obj)) { 48756 return true; 48757 } 48758 if (_emberRuntimeMixinsArray.default.detect(obj)) { 48759 return true; 48760 } 48761 48762 var type = typeOf(obj); 48763 if ('array' === type) { 48764 return true; 48765 } 48766 if (obj.length !== undefined && 'object' === type) { 48767 return true; 48768 } 48769 return false; 48770 } 48771 48772 /** 48773 Returns a consistent type for the passed object. 48774 48775 Use this instead of the built-in `typeof` to get the type of an item. 48776 It will return the same result across all browsers and includes a bit 48777 more detail. Here is what will be returned: 48778 48779 | Return Value | Meaning | 48780 |---------------|------------------------------------------------------| 48781 | 'string' | String primitive or String object. | 48782 | 'number' | Number primitive or Number object. | 48783 | 'boolean' | Boolean primitive or Boolean object. | 48784 | 'null' | Null value | 48785 | 'undefined' | Undefined value | 48786 | 'function' | A function | 48787 | 'array' | An instance of Array | 48788 | 'regexp' | An instance of RegExp | 48789 | 'date' | An instance of Date | 48790 | 'class' | An Ember class (created using Ember.Object.extend()) | 48791 | 'instance' | An Ember object instance | 48792 | 'error' | An instance of the Error object | 48793 | 'object' | A JavaScript object not inheriting from Ember.Object | 48794 48795 Examples: 48796 48797 ```javascript 48798 Ember.typeOf(); // 'undefined' 48799 Ember.typeOf(null); // 'null' 48800 Ember.typeOf(undefined); // 'undefined' 48801 Ember.typeOf('michael'); // 'string' 48802 Ember.typeOf(new String('michael')); // 'string' 48803 Ember.typeOf(101); // 'number' 48804 Ember.typeOf(new Number(101)); // 'number' 48805 Ember.typeOf(true); // 'boolean' 48806 Ember.typeOf(new Boolean(true)); // 'boolean' 48807 Ember.typeOf(Ember.makeArray); // 'function' 48808 Ember.typeOf([1, 2, 90]); // 'array' 48809 Ember.typeOf(/abc/); // 'regexp' 48810 Ember.typeOf(new Date()); // 'date' 48811 Ember.typeOf(Ember.Object.extend()); // 'class' 48812 Ember.typeOf(Ember.Object.create()); // 'instance' 48813 Ember.typeOf(new Error('teamocil')); // 'error' 48814 48815 // 'normal' JavaScript object 48816 Ember.typeOf({ a: 'b' }); // 'object' 48817 ``` 48818 48819 @method typeOf 48820 @for Ember 48821 @param {Object} item the item to check 48822 @return {String} the type 48823 @public 48824 */ 48825 48826 function typeOf(item) { 48827 if (item === null) { 48828 return 'null'; 48829 } 48830 if (item === undefined) { 48831 return 'undefined'; 48832 } 48833 var ret = TYPE_MAP[toString.call(item)] || 'object'; 48834 48835 if (ret === 'function') { 48836 if (_emberRuntimeSystemObject.default.detect(item)) { 48837 ret = 'class'; 48838 } 48839 } else if (ret === 'object') { 48840 if (item instanceof Error) { 48841 ret = 'error'; 48842 } else if (item instanceof _emberRuntimeSystemObject.default) { 48843 ret = 'instance'; 48844 } else if (item instanceof Date) { 48845 ret = 'date'; 48846 } 48847 } 48848 48849 return ret; 48850 } 48851}); 48852enifed('ember-template-compiler/compat/precompile', ['exports', 'require', 'ember-template-compiler/system/compile_options'], function (exports, _require, _emberTemplateCompilerSystemCompile_options) { 48853 /** 48854 @module ember 48855 @submodule ember-template-compiler 48856 */ 48857 'use strict'; 48858 48859 var compile, compileSpec; 48860 48861 exports.default = function (string) { 48862 if ((!compile || !compileSpec) && _require.has('htmlbars-compiler/compiler')) { 48863 var Compiler = _require.default('htmlbars-compiler/compiler'); 48864 48865 compile = Compiler.compile; 48866 compileSpec = Compiler.compileSpec; 48867 } 48868 48869 if (!compile || !compileSpec) { 48870 throw new Error('Cannot call `precompile` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `precompile`.'); 48871 } 48872 48873 var asObject = arguments[1] === undefined ? true : arguments[1]; 48874 var compileFunc = asObject ? compile : compileSpec; 48875 48876 return compileFunc(string, _emberTemplateCompilerSystemCompile_options.default()); 48877 }; 48878}); 48879enifed('ember-template-compiler/compat', ['exports', 'ember-metal/core', 'ember-template-compiler/compat/precompile', 'ember-template-compiler/system/compile', 'ember-template-compiler/system/template'], function (exports, _emberMetalCore, _emberTemplateCompilerCompatPrecompile, _emberTemplateCompilerSystemCompile, _emberTemplateCompilerSystemTemplate) { 48880 'use strict'; 48881 48882 var EmberHandlebars = _emberMetalCore.default.Handlebars = _emberMetalCore.default.Handlebars || {}; 48883 48884 EmberHandlebars.precompile = _emberTemplateCompilerCompatPrecompile.default; 48885 EmberHandlebars.compile = _emberTemplateCompilerSystemCompile.default; 48886 EmberHandlebars.template = _emberTemplateCompilerSystemTemplate.default; 48887}); 48888enifed('ember-template-compiler/index', ['exports', 'ember-metal', 'ember-template-compiler/system/precompile', 'ember-template-compiler/system/compile', 'ember-template-compiler/system/template', 'ember-template-compiler/plugins', 'ember-template-compiler/plugins/transform-old-binding-syntax', 'ember-template-compiler/plugins/transform-old-class-binding-syntax', 'ember-template-compiler/plugins/transform-item-class', 'ember-template-compiler/plugins/transform-closure-component-attrs-into-mut', 'ember-template-compiler/plugins/transform-component-attrs-into-mut', 'ember-template-compiler/plugins/transform-component-curly-to-readonly', 'ember-template-compiler/plugins/transform-angle-bracket-components', 'ember-template-compiler/plugins/transform-input-on-to-onEvent', 'ember-template-compiler/plugins/transform-top-level-components', 'ember-template-compiler/plugins/transform-each-into-collection', 'ember-template-compiler/plugins/transform-unescaped-inline-link-to', 'ember-template-compiler/plugins/deprecate-render-block', 'ember-template-compiler/plugins/assert-no-view-and-controller-paths', 'ember-template-compiler/plugins/assert-no-view-helper', 'ember-template-compiler/plugins/assert-no-each-in', 'ember-template-compiler/compat'], function (exports, _emberMetal, _emberTemplateCompilerSystemPrecompile, _emberTemplateCompilerSystemCompile, _emberTemplateCompilerSystemTemplate, _emberTemplateCompilerPlugins, _emberTemplateCompilerPluginsTransformOldBindingSyntax, _emberTemplateCompilerPluginsTransformOldClassBindingSyntax, _emberTemplateCompilerPluginsTransformItemClass, _emberTemplateCompilerPluginsTransformClosureComponentAttrsIntoMut, _emberTemplateCompilerPluginsTransformComponentAttrsIntoMut, _emberTemplateCompilerPluginsTransformComponentCurlyToReadonly, _emberTemplateCompilerPluginsTransformAngleBracketComponents, _emberTemplateCompilerPluginsTransformInputOnToOnEvent, _emberTemplateCompilerPluginsTransformTopLevelComponents, _emberTemplateCompilerPluginsTransformEachIntoCollection, _emberTemplateCompilerPluginsTransformUnescapedInlineLinkTo, _emberTemplateCompilerPluginsDeprecateRenderBlock, _emberTemplateCompilerPluginsAssertNoViewAndControllerPaths, _emberTemplateCompilerPluginsAssertNoViewHelper, _emberTemplateCompilerPluginsAssertNoEachIn, _emberTemplateCompilerCompat) { 48889 'use strict'; 48890 48891 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformOldBindingSyntax.default); 48892 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformOldClassBindingSyntax.default); 48893 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformItemClass.default); 48894 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformClosureComponentAttrsIntoMut.default); 48895 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformComponentAttrsIntoMut.default); 48896 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformComponentCurlyToReadonly.default); 48897 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformAngleBracketComponents.default); 48898 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformInputOnToOnEvent.default); 48899 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformTopLevelComponents.default); 48900 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformUnescapedInlineLinkTo.default); 48901 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsDeprecateRenderBlock.default); 48902 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsAssertNoEachIn.default); 48903 48904 if (_emberMetal.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 48905 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformEachIntoCollection.default); 48906 } else { 48907 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsAssertNoViewAndControllerPaths.default); 48908 _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsAssertNoViewHelper.default); 48909 } 48910 48911 exports._Ember = _emberMetal.default; 48912 exports.precompile = _emberTemplateCompilerSystemPrecompile.default; 48913 exports.compile = _emberTemplateCompilerSystemCompile.default; 48914 exports.template = _emberTemplateCompilerSystemTemplate.default; 48915 exports.registerPlugin = _emberTemplateCompilerPlugins.registerPlugin; 48916}); 48917 48918// used for adding Ember.Handlebars.compile for backwards compat 48919enifed('ember-template-compiler/plugins/assert-no-each-in', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-template-compiler/system/calculate-location-display'], function (exports, _emberMetalCore, _emberMetalDebug, _emberTemplateCompilerSystemCalculateLocationDisplay) { 48920 'use strict'; 48921 48922 function AssertNoEachIn() { 48923 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 48924 48925 this.syntax = null; 48926 this.options = options; 48927 } 48928 48929 AssertNoEachIn.prototype.transform = function AssertNoEachIn_transform(ast) { 48930 if (!!_emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 48931 return ast; 48932 } 48933 var walker = new this.syntax.Walker(); 48934 var moduleName = this.options && this.options.moduleName; 48935
48936 walker.visit(ast, function (node) { 48937 if (!validate(node)) { 48938 return; 48939 } 48940 assertHelper(moduleName, node); 48941 }); 48942 48943 return ast; 48944 }; 48945 48946 function assertHelper(moduleName, node) { 48947 var moduleInfo = _emberTemplateCompilerSystemCalculateLocationDisplay.default(moduleName, node.loc); 48948 var singular = node.params[0].original; 48949 var plural = node.params[2].original; 48950 48951 _emberMetalDebug.assert('Using {{#each ' + singular + ' in ' + plural + '}} ' + moduleInfo + 'is no longer supported in Ember 2.0+, please use {{#each ' + plural + ' as |' + singular + '|}}'); 48952 } 48953 48954 function validate(node) { 48955 return (node.type === 'BlockStatement' || node.type === 'MustacheStatement') && node.path.original === 'each' && node.params.length === 3 && node.params[1].type === 'PathExpression' && node.params[1].original === 'in'; 48956 } 48957 48958 exports.default = AssertNoEachIn; 48959}); 48960enifed('ember-template-compiler/plugins/assert-no-view-and-controller-paths', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-template-compiler/system/calculate-location-display'], function (exports, _emberMetalCore, _emberMetalDebug, _emberTemplateCompilerSystemCalculateLocationDisplay) { 48961 'use strict'; 48962 48963 function AssertNoViewAndControllerPaths() { 48964 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 48965 48966 // set later within HTMLBars to the syntax package 48967 this.syntax = null; 48968 this.options = options; 48969 } 48970 48971 /** 48972 @private 48973 @method transform 48974 @param {AST} ast The AST to be transformed. 48975 */ 48976 AssertNoViewAndControllerPaths.prototype.transform = function AssertNoViewAndControllerPaths_transform(ast) { 48977 var walker = new this.syntax.Walker(); 48978 var moduleName = this.options && this.options.moduleName; 48979 48980 walker.visit(ast, function (node) { 48981 if (!validate(node)) { 48982 return; 48983 } 48984 48985 assertPath(moduleName, node, node.path); 48986 assertPaths(moduleName, node, node.params); 48987 assertHash(moduleName, node, node.hash); 48988 }); 48989 48990 return ast; 48991 }; 48992 48993 function assertHash(moduleName, node, hash) { 48994 if (!hash || !hash.pairs) { 48995 return; 48996 } 48997 var i, l, pair, paths; 48998 for (i = 0, l = hash.pairs.length; i < l; i++) { 48999 pair = hash.pairs[i]; 49000 paths = pair.value.params; 49001 assertPaths(moduleName, pair, paths); 49002 } 49003 } 49004 49005 function assertPaths(moduleName, node, paths) { 49006 if (!paths) { 49007 return; 49008 } 49009 var i, l, path; 49010 for (i = 0, l = paths.length; i < l; i++) { 49011 path = paths[i]; 49012 assertPath(moduleName, node, path); 49013 } 49014 } 49015 49016 function assertPath(moduleName, node, path) { 49017 _emberMetalDebug.assert('Using `{{' + (path && path.type === 'PathExpression' && path.parts[0]) + '}}` or any path based on it ' + _emberTemplateCompilerSystemCalculateLocationDisplay.default(moduleName, node.loc) + 'has been removed in Ember 2.0', (function () { 49018 var noAssertion = true; 49019 49020 var viewKeyword = path && path.type === 'PathExpression' && path.parts && path.parts[0]; 49021 if (viewKeyword === 'view') { 49022 noAssertion = _emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT; 49023 } else if (viewKeyword === 'controller') { 49024 noAssertion = _emberMetalCore.default.ENV._ENABLE_LEGACY_CONTROLLER_SUPPORT; 49025 } 49026 49027 return noAssertion; 49028 })(), { 49029 id: path.parts && path.parts[0] === 'view' ? 'view.keyword.view' : 'view.keyword.controller', 49030 until: '2.0.0' 49031 }); 49032 } 49033 49034 function validate(node) { 49035 return node.type === 'MustacheStatement' || node.type === 'BlockStatement'; 49036 } 49037 49038 exports.default = AssertNoViewAndControllerPaths; 49039}); 49040enifed('ember-template-compiler/plugins/assert-no-view-helper', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-template-compiler/system/calculate-location-display'], function (exports, _emberMetalCore, _emberMetalDebug, _emberTemplateCompilerSystemCalculateLocationDisplay) { 49041 'use strict'; 49042 49043 function AssertNoViewHelper() { 49044 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 49045 49046 // set later within HTMLBars to the syntax package 49047 this.syntax = null; 49048 this.options = options; 49049 } 49050 49051 /** 49052 @private 49053 @method transform 49054 @param {AST} ast The AST to be transformed. 49055 */ 49056 AssertNoViewHelper.prototype.transform = function AssertNoViewHelper_transform(ast) { 49057 if (!!_emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 49058 return ast; 49059 } 49060 var walker = new this.syntax.Walker(); 49061 var moduleName = this.options && this.options.moduleName; 49062
49063 walker.visit(ast, function (node) { 49064 if (!validate(node)) { 49065 return; 49066 } 49067 49068 assertHelper(moduleName, node); 49069 }); 49070 49071 return ast; 49072 }; 49073 49074 function assertHelper(moduleName, node) { 49075 var paramValue = node.params.length && node.params[0].value; 49076 49077 if (!paramValue) { 49078 return; 49079 } else { 49080 _emberMetalDebug.assert('Using the `{{view "string"}}` helper is removed in 2.0. ' + _emberTemplateCompilerSystemCalculateLocationDisplay.default(moduleName, node.loc), _emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT, { id: 'view.helper', until: '2.0.0' }); 49081 } 49082 } 49083 49084 function validate(node) { 49085 return (node.type === 'MustacheStatement' || node.type === 'BlockStatement') && node.path.parts[0] === 'view'; 49086 } 49087 49088 exports.default = AssertNoViewHelper; 49089}); 49090enifed('ember-template-compiler/plugins/deprecate-render-block', ['exports', 'ember-metal/debug', 'ember-template-compiler/system/calculate-location-display'], function (exports, _emberMetalDebug, _emberTemplateCompilerSystemCalculateLocationDisplay) { 49091 'use strict'; 49092 49093 exports.default = DeprecateRenderBlock; 49094 49095 function DeprecateRenderBlock(options) { 49096 this.syntax = null; 49097 this.options = options; 49098 } 49099 49100 DeprecateRenderBlock.prototype.transform = function DeprecateRenderBlock_transform(ast) { 49101 var moduleName = this.options.moduleName; 49102 var walker = new this.syntax.Walker(); 49103 49104 walker.visit(ast, function (node) { 49105 if (!validate(node)) { 49106 return; 49107 } 49108 49109 _emberMetalDebug.deprecate(deprecationMessage(moduleName, node), false, { 49110 id: 'ember-template-compiler.deprecate-render-block', 49111 until: '2.4.0', 49112 url: 'http://emberjs.com/deprecations/v2.x#toc_render-helper-with-block' 49113 }); 49114 }); 49115 49116 return ast; 49117 }; 49118 49119 function validate(node) { 49120 return node.type === 'BlockStatement' && node.path.original === 'render'; 49121 } 49122 49123 function deprecationMessage(moduleName, node) { 49124 var sourceInformation = _emberTemplateCompilerSystemCalculateLocationDisplay.default(moduleName, node.loc); 49125 49126 return 'Usage of `render` in block form is deprecated ' + sourceInformation + '.'; 49127 } 49128}); 49129enifed('ember-template-compiler/plugins/transform-angle-bracket-components', ['exports'], function (exports) { 49130 'use strict'; 49131 49132 function TransformAngleBracketComponents() { 49133 // set later within HTMLBars to the syntax package 49134 this.syntax = null; 49135 } 49136 49137 /** 49138 @private 49139 @method transform 49140 @param {AST} ast The AST to be transformed. 49141 */ 49142 TransformAngleBracketComponents.prototype.transform = function TransformAngleBracketComponents_transform(ast) { 49143 var walker = new this.syntax.Walker(); 49144 49145 walker.visit(ast, function (node) { 49146 if (!validate(node)) { 49147 return; 49148 } 49149 49150 node.tag = '<' + node.tag + '>'; 49151 }); 49152 49153 return ast; 49154 }; 49155 49156 function validate(node) { 49157 return node.type === 'ComponentNode'; 49158 } 49159 49160 exports.default = TransformAngleBracketComponents; 49161}); 49162enifed('ember-template-compiler/plugins/transform-closure-component-attrs-into-mut', ['exports'], function (exports) { 49163 'use strict'; 49164 49165 function TransformClosureComponentAttrsIntoMut() { 49166 // set later within HTMLBars to the syntax package 49167 this.syntax = null; 49168 } 49169 49170 /** 49171 @private 49172 @method transform 49173 @param {AST} ast The AST to be transformed. 49174 */ 49175 TransformClosureComponentAttrsIntoMut.prototype.transform = function TransformClosureComponentAttrsIntoMut_transform(ast) { 49176 var b = this.syntax.builders; 49177 var walker = new this.syntax.Walker(); 49178 49179 walker.visit(ast, function (node) { 49180 if (validate(node)) { 49181 processExpression(b, node); 49182 } 49183 }); 49184 49185 return ast; 49186 }; 49187 49188 function processExpression(builder, node) { 49189 processSubExpressionsInNode(builder, node); 49190 49191 if (isComponentClosure(node)) { 49192 mutParameters(builder, node); 49193 } 49194 } 49195 49196 function processSubExpressionsInNode(builder, node) { 49197 for (var i = 0; i < node.params.length; i++) { 49198 if (node.params[i].type === 'SubExpression') { 49199 processExpression(builder, node.params[i]); 49200 } 49201 } 49202 49203 each(node.hash.pairs, function (pair) { 49204 var value = pair.value; 49205 49206 if (value.type === 'SubExpression') { 49207 processExpression(builder, value); 49208 } 49209 }); 49210 } 49211 49212 function isComponentClosure(node) { 49213 return node.type === 'SubExpression' && node.path.original === 'component'; 49214 } 49215 49216 function mutParameters(builder, node) { 49217 for (var i = 1; i < node.params.length; i++) { 49218 if (node.params[i].type === 'PathExpression') { 49219 node.params[i] = builder.sexpr(builder.path('@mut'), [node.params[i]]); 49220 } 49221 } 49222 49223 each(node.hash.pairs, function (pair) { 49224 var value = pair.value; 49225 49226 if (value.type === 'PathExpression') { 49227 pair.value = builder.sexpr(builder.path('@mut'), [pair.value]); 49228 } 49229 }); 49230 } 49231 49232 function validate(node) { 49233 return node.type === 'BlockStatement' || node.type === 'MustacheStatement'; 49234 } 49235 49236 function each(list, callback) { 49237 for (var i = 0, l = list.length; i < l; i++) { 49238 callback(list[i]); 49239 } 49240 } 49241 49242 exports.default = TransformClosureComponentAttrsIntoMut; 49243}); 49244enifed('ember-template-compiler/plugins/transform-component-attrs-into-mut', ['exports'], function (exports) { 49245 'use strict'; 49246 49247 function TransformComponentAttrsIntoMut() { 49248 // set later within HTMLBars to the syntax package 49249 this.syntax = null; 49250 } 49251 49252 /** 49253 @private 49254 @method transform 49255 @param {AST} ast The AST to be transformed. 49256 */ 49257 TransformComponentAttrsIntoMut.prototype.transform = function TransformComponentAttrsIntoMut_transform(ast) { 49258 var b = this.syntax.builders; 49259 var walker = new this.syntax.Walker(); 49260
49261 walker.visit(ast, function (node) { 49262 if (!validate(node)) { 49263 return; 49264 } 49265 49266 each(node.hash.pairs, function (pair) { 49267 var value = pair.value; 49268 49269 if (value.type === 'PathExpression') { 49270 pair.value = b.sexpr(b.path('@mut'), [pair.value]); 49271 } 49272 }); 49273 }); 49274 49275 return ast; 49276 }; 49277 49278 function validate(node) { 49279 return node.type === 'BlockStatement' || node.type === 'MustacheStatement'; 49280 } 49281 49282 function each(list, callback) { 49283 for (var i = 0, l = list.length; i < l; i++) { 49284 callback(list[i]); 49285 } 49286 } 49287 49288 exports.default = TransformComponentAttrsIntoMut; 49289}); 49290enifed('ember-template-compiler/plugins/transform-component-curly-to-readonly', ['exports'], function (exports) { 49291 'use strict'; 49292 49293 function TransformComponentCurlyToReadonly() { 49294 // set later within HTMLBars to the syntax package 49295 this.syntax = null; 49296 } 49297 49298 /** 49299 @private 49300 @method transform 49301 @param {AST} ast The AST to be transformed. 49302 */ 49303 TransformComponentCurlyToReadonly.prototype.transform = function TransformComponetnCurlyToReadonly_transform(ast) { 49304 var b = this.syntax.builders; 49305 var walker = new this.syntax.Walker(); 49306 49307 walker.visit(ast, function (node) { 49308 if (!validate(node)) { 49309 return; 49310 } 49311 49312 each(node.attributes, function (attr) { 49313 if (attr.value.type !== 'MustacheStatement') { 49314 return; 49315 } 49316 if (attr.value.params.length || attr.value.hash.pairs.length) { 49317 return; 49318 } 49319 49320 attr.value = b.mustache(b.path('readonly'), [attr.value.path], null, !attr.value.escape); 49321 }); 49322 }); 49323 49324 return ast; 49325 }; 49326 49327 function validate(node) { 49328 return node.type === 'ComponentNode'; 49329 } 49330 49331 function each(list, callback) { 49332 for (var i = 0, l = list.length; i < l; i++) { 49333 callback(list[i]); 49334 } 49335 } 49336 49337 exports.default = TransformComponentCurlyToReadonly; 49338}); 49339enifed('ember-template-compiler/plugins/transform-each-into-collection', ['exports', 'ember-metal/debug', 'ember-template-compiler/system/calculate-location-display'], function (exports, _emberMetalDebug, _emberTemplateCompilerSystemCalculateLocationDisplay) { 49340 'use strict'; 49341 49342 exports.default = TransformEachIntoCollection; 49343 49344 function TransformEachIntoCollection(options) { 49345 this.options = options; 49346 this.syntax = null; 49347 } 49348 49349 TransformEachIntoCollection.prototype.transform = function TransformEachIntoCollection_transform(ast) { 49350 var moduleName = this.options.moduleName; 49351 var b = this.syntax.builders; 49352 var walker = new this.syntax.Walker(); 49353 49354 walker.visit(ast, function (node) { 49355 var legacyHashKey = validate(node); 49356 if (!legacyHashKey) { 49357 return; 49358 } 49359 49360 var moduleInfo = _emberTemplateCompilerSystemCalculateLocationDisplay.default(moduleName, legacyHashKey.loc); 49361 49362 _emberMetalDebug.deprecate('Using \'' + legacyHashKey.key + '\' with \'{{each}}\' ' + moduleInfo + 'is deprecated. Please refactor to a component.', false, { id: 'ember-template-compiler.transform-each-into-collection', until: '2.0.0' }); 49363 49364 var list = node.params.shift(); 49365 node.path = b.path('collection'); 49366 49367 node.params.unshift(b.string('-legacy-each')); 49368 49369 var pair = b.pair('content', list); 49370 pair.loc = list.loc; 49371 49372 node.hash.pairs.push(pair); 49373 49374 //pair = b.pair('dataSource', list); 49375 //node.hash.pairs.push(pair); 49376 }); 49377 49378 return ast; 49379 }; 49380 49381 function validate(node) { 49382 if ((node.type === 'BlockStatement' || node.type === 'MustacheStatement') && node.path.original === 'each') { 49383 return any(node.hash.pairs, function (pair) { 49384 var key = pair.key; 49385 return key === 'itemController' || key === 'itemView' || key === 'itemViewClass' || key === 'tagName' || key === 'emptyView' || key === 'emptyViewClass'; 49386 }); 49387 } 49388 49389 return false; 49390 } 49391 49392 function any(list, predicate) { 49393 for (var i = 0, l = list.length; i < l; i++) { 49394 if (predicate(list[i])) { 49395 return list[i]; 49396 } 49397 } 49398 49399 return false; 49400 } 49401}); 49402enifed('ember-template-compiler/plugins/transform-input-on-to-onEvent', ['exports', 'ember-metal/debug', 'ember-template-compiler/system/calculate-location-display'], function (exports, _emberMetalDebug, _emberTemplateCompilerSystemCalculateLocationDisplay) { 49403 'use strict'; 49404 49405 /** 49406 @module ember 49407 @submodule ember-htmlbars 49408 */ 49409 49410 /** 49411 An HTMLBars AST transformation that replaces all instances of 49412 49413 ```handlebars 49414 {{input on="enter" action="doStuff"}} 49415 {{input on="key-press" action="doStuff"}} 49416 ``` 49417 49418 with 49419 49420 ```handlebars 49421 {{input enter="doStuff"}} 49422 {{input key-press="doStuff"}} 49423 ``` 49424 49425 @private 49426 @class TransformInputOnToOnEvent 49427 */ 49428 function TransformInputOnToOnEvent() { 49429 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 49430 49431 // set later within HTMLBars to the syntax package 49432 this.syntax = null; 49433 this.options = options; 49434 } 49435 49436 /** 49437 @private 49438 @method transform 49439 @param {AST} ast The AST to be transformed. 49440 */ 49441 TransformInputOnToOnEvent.prototype.transform = function TransformInputOnToOnEvent_transform(ast) { 49442 var pluginContext = this; 49443 var b = pluginContext.syntax.builders; 49444 var walker = new pluginContext.syntax.Walker(); 49445 var moduleName = pluginContext.options.moduleName; 49446
49447 walker.visit(ast, function (node) { 49448 if (pluginContext.validate(node)) { 49449 var action = hashPairForKey(node.hash, 'action'); 49450 var on = hashPairForKey(node.hash, 'on'); 49451 var onEvent = hashPairForKey(node.hash, 'onEvent'); 49452 var normalizedOn = on || onEvent; 49453 var moduleInfo = _emberTemplateCompilerSystemCalculateLocationDisplay.default(moduleName, node.loc); 49454 49455 if (normalizedOn && normalizedOn.value.type !== 'StringLiteral') { 49456 _emberMetalDebug.deprecate('Using a dynamic value for \'#{normalizedOn.key}=\' with the \'{{input}}\' helper ' + moduleInfo + 'is deprecated.', false, { id: 'ember-template-compiler.transform-input-on-to-onEvent.dynamic-value', until: '3.0.0' }); 49457 49458 normalizedOn.key = 'onEvent'; 49459 return; // exit early, as we cannot transform further 49460 } 49461 49462 removeFromHash(node.hash, normalizedOn); 49463 removeFromHash(node.hash, action); 49464 49465 if (!action) { 49466 _emberMetalDebug.deprecate('Using \'{{input ' + normalizedOn.key + '="' + normalizedOn.value.value + '" ...}}\' without specifying an action ' + moduleInfo + 'will do nothing.', false, { id: 'ember-template-compiler.transform-input-on-to-onEvent.no-action', until: '3.0.0' }); 49467 49468 return; // exit early, if no action was available there is nothing to do 49469 } 49470 49471 var specifiedOn = normalizedOn ? normalizedOn.key + '="' + normalizedOn.value.value + '" ' : ''; 49472 if (normalizedOn && normalizedOn.value.value === 'keyPress') { 49473 // using `keyPress` in the root of the component will 49474 // clobber the keyPress event handler 49475 normalizedOn.value.value = 'key-press'; 49476 } 49477 49478 var expected = (normalizedOn ? normalizedOn.value.value : 'enter') + '="' + action.value.original + '"'; 49479 49480 _emberMetalDebug.deprecate('Using \'{{input ' + specifiedOn + 'action="' + action.value.original + '"}}\' ' + moduleInfo + 'is deprecated. Please use \'{{input ' + expected + '}}\' instead.', false, { id: 'ember-template-compiler.transform-input-on-to-onEvent.normalized-on', until: '3.0.0' }); 49481 if (!normalizedOn) { 49482 normalizedOn = b.pair('onEvent', b.string('enter')); 49483 } 49484 49485 node.hash.pairs.push(b.pair(normalizedOn.value.value, action.value)); 49486 } 49487 }); 49488 49489 return ast; 49490 }; 49491 49492 TransformInputOnToOnEvent.prototype.validate = function TransformWithAsToHash_validate(node) { 49493 return node.type === 'MustacheStatement' && node.path.original === 'input' && (hashPairForKey(node.hash, 'action') || hashPairForKey(node.hash, 'on') || hashPairForKey(node.hash, 'onEvent')); 49494 }; 49495 49496 function hashPairForKey(hash, key) { 49497 for (var i = 0, l = hash.pairs.length; i < l; i++) { 49498 var pair = hash.pairs[i]; 49499 if (pair.key === key) { 49500 return pair; 49501 } 49502 } 49503 49504 return false; 49505 } 49506 49507 function removeFromHash(hash, pairToRemove) { 49508 var newPairs = []; 49509 for (var i = 0, l = hash.pairs.length; i < l; i++) { 49510 var pair = hash.pairs[i]; 49511 49512 if (pair !== pairToRemove) { 49513 newPairs.push(pair); 49514 } 49515 } 49516 49517 hash.pairs = newPairs; 49518 } 49519 49520 exports.default = TransformInputOnToOnEvent; 49521}); 49522enifed('ember-template-compiler/plugins/transform-item-class', ['exports'], function (exports) { 49523 'use strict'; 49524 49525 exports.default = TransformItemClass; 49526 49527 function TransformItemClass() { 49528 this.syntax = null; 49529 } 49530 49531 TransformItemClass.prototype.transform = function TransformItemClass_transform(ast) { 49532 var b = this.syntax.builders; 49533 var walker = new this.syntax.Walker(); 49534 49535 walker.visit(ast, function (node) { 49536 if (!validate(node)) { 49537 return; 49538 } 49539 49540 each(node.hash.pairs, function (pair) { 49541 var key = pair.key; 49542 var value = pair.value; 49543 49544 if (key !== 'itemClass') { 49545 return; 49546 } 49547 if (value.type === 'StringLiteral') { 49548 return; 49549 } 49550 49551 var propName = value.original; 49552 var params = [value]; 49553 var sexprParams = [b.string(propName), b.path(propName)]; 49554 49555 params.push(b.sexpr(b.string('-normalize-class'), sexprParams));
49556 var sexpr = b.sexpr(b.string('if'), params); 49557 49558 pair.value = sexpr; 49559 }); 49560 }); 49561 49562 return ast; 49563 }; 49564 49565 function validate(node) { 49566 return (node.type === 'BlockStatement' || node.type === 'MustacheStatement') && node.path.original === 'collection'; 49567 } 49568 49569 function each(list, callback) { 49570 for (var i = 0, l = list.length; i < l; i++) { 49571 callback(list[i]); 49572 } 49573 } 49574}); 49575enifed('ember-template-compiler/plugins/transform-old-binding-syntax', ['exports', 'ember-metal/debug', 'ember-template-compiler/system/calculate-location-display'], function (exports, _emberMetalDebug, _emberTemplateCompilerSystemCalculateLocationDisplay) { 49576 'use strict'; 49577 49578 exports.default = TransformOldBindingSyntax; 49579 49580 function TransformOldBindingSyntax(options) { 49581 this.syntax = null; 49582 this.options = options; 49583 } 49584 49585 TransformOldBindingSyntax.prototype.transform = function TransformOldBindingSyntax_transform(ast) { 49586 var moduleName = this.options.moduleName; 49587 var b = this.syntax.builders; 49588 var walker = new this.syntax.Walker(); 49589 49590 walker.visit(ast, function (node) { 49591 if (!validate(node)) { 49592 return; 49593 } 49594 49595 each(node.hash.pairs, function (pair) { 49596 var key = pair.key; 49597 var value = pair.value; 49598 49599 var sourceInformation = _emberTemplateCompilerSystemCalculateLocationDisplay.default(moduleName, pair.loc); 49600 49601 if (key === 'classBinding') { 49602 return; 49603 } 49604 49605 _emberMetalDebug.assert('Setting \'attributeBindings\' via template helpers is not allowed ' + sourceInformation, key !== 'attributeBindings'); 49606 49607 if (key.substr(-7) === 'Binding') { 49608 var newKey = key.slice(0, -7); 49609 49610 _emberMetalDebug.deprecate('You\'re using legacy binding syntax: ' + key + '=' + exprToString(value) + ' ' + sourceInformation + '. Please replace with ' + newKey + '=' + value.original, false, { id: 'ember-template-compiler.transform-old-binding-syntax', until: '3.0.0' }); 49611 49612 pair.key = newKey; 49613 if (value.type === 'StringLiteral') { 49614 pair.value = b.path(value.original); 49615 } 49616 } 49617 }); 49618 }); 49619 49620 return ast; 49621 }; 49622 49623 function validate(node) { 49624 return node.type === 'BlockStatement' || node.type === 'MustacheStatement'; 49625 } 49626 49627 function each(list, callback) { 49628 for (var i = 0, l = list.length; i < l; i++) { 49629 callback(list[i]); 49630 } 49631 } 49632 49633 function exprToString(expr) { 49634 switch (expr.type) { 49635 case 'StringLiteral': 49636 return '"' + expr.original + '"'; 49637 case 'PathExpression': 49638 return expr.original; 49639 } 49640 } 49641}); 49642enifed('ember-template-compiler/plugins/transform-old-class-binding-syntax', ['exports'], function (exports) { 49643 'use strict'; 49644 49645 exports.default = TransformOldClassBindingSyntax; 49646 49647 function TransformOldClassBindingSyntax(options) { 49648 this.syntax = null; 49649 this.options = options; 49650 } 49651 49652 TransformOldClassBindingSyntax.prototype.transform = function TransformOldClassBindingSyntax_transform(ast) { 49653 var b = this.syntax.builders; 49654 var walker = new this.syntax.Walker(); 49655 49656 walker.visit(ast, function (node) { 49657 if (!validate(node)) { 49658 return; 49659 } 49660 49661 var allOfTheMicrosyntaxes = []; 49662 var allOfTheMicrosyntaxIndexes = []; 49663 var classPair = undefined; 49664 49665 each(node.hash.pairs, function (pair, index) { 49666 var key = pair.key; 49667 49668 if (key === 'classBinding' || key === 'classNameBindings') { 49669 allOfTheMicrosyntaxIndexes.push(index); 49670 allOfTheMicrosyntaxes.push(pair); 49671 } else if (key === 'class') { 49672 classPair = pair; 49673 } 49674 }); 49675 49676 if (allOfTheMicrosyntaxes.length === 0) { 49677 return; 49678 } 49679 49680 var classValue = []; 49681 49682 if (classPair) { 49683 classValue.push(classPair.value); 49684 classValue.push(b.string(' ')); 49685 } else { 49686 classPair = b.pair('class', null); 49687 node.hash.pairs.push(classPair); 49688 } 49689 49690 each(allOfTheMicrosyntaxIndexes, function (index) { 49691 node.hash.pairs.splice(index, 1); 49692 }); 49693 49694 each(allOfTheMicrosyntaxes, function (_ref) { 49695 var value = _ref.value; 49696 var loc = _ref.loc; 49697
49698 var sexprs = []; 49699 // TODO: add helpful deprecation when both `classNames` and `classNameBindings` can 49700 // be removed. 49701 49702 if (value.type === 'StringLiteral') { 49703 var microsyntax = parseMicrosyntax(value.original); 49704 49705 buildSexprs(microsyntax, sexprs, b); 49706 49707 classValue.push.apply(classValue, sexprs); 49708 } 49709 }); 49710 49711 var hash = b.hash(); 49712 classPair.value = b.sexpr(b.string('concat'), classValue, hash); 49713 }); 49714 49715 return ast; 49716 }; 49717 49718 function buildSexprs(microsyntax, sexprs, b) { 49719 for (var i = 0, l = microsyntax.length; i < l; i++) { 49720 var _microsyntax$i = microsyntax[i]; 49721 var propName = _microsyntax$i[0]; 49722 var activeClass = _microsyntax$i[1]; 49723 var inactiveClass = _microsyntax$i[2]; 49724 49725 var sexpr = undefined; 49726 49727 // :my-class-name microsyntax for static values 49728 if (propName === '') { 49729 sexpr = b.string(activeClass); 49730 } else { 49731 var params = [b.path(propName)]; 49732 49733 if (activeClass) { 49734 params.push(b.string(activeClass)); 49735 } else { 49736 var sexprParams = [b.string(propName), b.path(propName)]; 49737 49738 var hash = b.hash(); 49739 if (activeClass !== undefined) { 49740 hash.pairs.push(b.pair('activeClass', b.string(activeClass))); 49741 } 49742 49743 if (inactiveClass !== undefined) { 49744 hash.pairs.push(b.pair('inactiveClass', b.string(inactiveClass))); 49745 } 49746 49747 params.push(b.sexpr(b.string('-normalize-class'), sexprParams, hash)); 49748 } 49749 49750 if (inactiveClass) { 49751 params.push(b.string(inactiveClass)); 49752 } 49753 49754 sexpr = b.sexpr(b.string('if'), params); 49755 } 49756 49757 sexprs.push(sexpr); 49758 sexprs.push(b.string(' ')); 49759 } 49760 } 49761 49762 function validate(node) { 49763 return node.type === 'BlockStatement' || node.type === 'MustacheStatement'; 49764 } 49765 49766 function each(list, callback) { 49767 for (var i = 0, l = list.length; i < l; i++) { 49768 callback(list[i], i); 49769 } 49770 } 49771 49772 function parseMicrosyntax(string) { 49773 var segments = string.split(' '); 49774 49775 for (var i = 0, l = segments.length; i < l; i++) { 49776 segments[i] = segments[i].split(':'); 49777 } 49778 49779 return segments; 49780 } 49781}); 49782enifed('ember-template-compiler/plugins/transform-top-level-components', ['exports'], function (exports) { 49783 'use strict'; 49784 49785 function TransformTopLevelComponents() { 49786 // set later within HTMLBars to the syntax package 49787 this.syntax = null; 49788 } 49789 49790 /** 49791 @private 49792 @method transform 49793 @param {AST} The AST to be transformed. 49794 */ 49795 TransformTopLevelComponents.prototype.transform = function TransformTopLevelComponents_transform(ast) { 49796 var b = this.syntax.builders; 49797 49798 hasSingleComponentNode(ast, function (component) { 49799 if (component.type === 'ComponentNode') { 49800 component.tag = '@' + component.tag; 49801 component.isStatic = true; 49802 } 49803 }, function (element) { 49804 var hasTripleCurlies = element.attributes.some(function (attr) { 49805 return attr.value.escaped === false; 49806 }); 49807 49808 if (element.modifiers.length || hasTripleCurlies) { 49809 return element; 49810 } else { 49811 // TODO: Properly copy loc from children 49812 var program = b.program(element.children); 49813 var component = b.component('@<' + element.tag + '>', element.attributes, program, element.loc); 49814 component.isStatic = true; 49815 return component; 49816 } 49817 }); 49818 49819 return ast; 49820 }; 49821 49822 function hasSingleComponentNode(program, componentCallback, elementCallback) { 49823 var loc = program.loc; 49824 var body = program.body; 49825 49826 if (!loc || loc.start.line !== 1 || loc.start.column !== 0) { 49827 return; 49828 } 49829 49830 var lastComponentNode = undefined; 49831 var lastIndex = undefined; 49832 var nodeCount = 0; 49833 49834 for (var i = 0, l = body.length; i < l; i++) { 49835 var curr = body[i]; 49836 49837 // text node with whitespace only 49838 if (curr.type === 'TextNode' && /^[\s]*$/.test(curr.chars)) { 49839 continue; 49840 } 49841 49842 // has multiple root elements if we've been here before 49843 if (nodeCount++ > 0) { 49844 return false; 49845 } 49846 49847 if (curr.type === 'ComponentNode' || curr.type === 'ElementNode') { 49848 lastComponentNode = curr; 49849 lastIndex = i; 49850 } 49851 } 49852 49853 if (!lastComponentNode) { 49854 return; 49855 } 49856 49857 if (lastComponentNode.type === 'ComponentNode') { 49858 componentCallback(lastComponentNode); 49859 } 49860 } 49861 49862 exports.default = TransformTopLevelComponents; 49863}); 49864enifed('ember-template-compiler/plugins/transform-unescaped-inline-link-to', ['exports'], function (exports) { 49865 'use strict'; 49866 49867 exports.default = TransformUnescapedInlineLinkTo; 49868 49869 function TransformUnescapedInlineLinkTo(options) { 49870 this.options = options; 49871 this.syntax = null; 49872 } 49873 49874 TransformUnescapedInlineLinkTo.prototype.transform = function TransformUnescapedInlineLinkTo_transform(ast) { 49875 var b = this.syntax.builders; 49876 var walker = new this.syntax.Walker(); 49877
49878 walker.visit(ast, function (node) { 49879 if (!validate(node)) { 49880 return; 49881 } 49882 49883 node.escaped = true; 49884 node.params[0] = b.sexpr(b.string('-html-safe'), [node.params[0]]); 49885 }); 49886 49887 return ast; 49888 }; 49889 49890 function validate(node) { 49891 return node.type === 'MustacheStatement' && node.path.original === 'link-to' && !node.escaped; 49892 } 49893}); 49894enifed('ember-template-compiler/plugins', ['exports'], function (exports) { 49895 /** 49896 @module ember 49897 @submodule ember-template-compiler 49898 */ 49899 49900 /** 49901 @private 49902 @property helpers 49903 */ 49904 'use strict'; 49905 49906 exports.registerPlugin = registerPlugin; 49907 var plugins = { 49908 ast: [] 49909 }; 49910 49911 /** 49912 Adds an AST plugin to be used by Ember.HTMLBars.compile. 49913 49914 @private 49915 @method registerASTPlugin 49916 */ 49917 49918 function registerPlugin(type, Plugin) { 49919 if (!plugins[type]) { 49920 throw new Error('Attempting to register "' + Plugin + '" as "' + type + '" which is not a valid HTMLBars plugin type.'); 49921 } 49922 49923 plugins[type].push(Plugin); 49924 } 49925 49926 exports.default = plugins; 49927}); 49928enifed('ember-template-compiler/system/calculate-location-display', ['exports'], function (exports) { 49929 'use strict'; 49930 49931 exports.default = calculateLocationDisplay; 49932 49933 function calculateLocationDisplay(moduleName) { 49934 var loc = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 49935 49936 var _ref = loc.start || {}; 49937 49938 var column = _ref.column; 49939 var line = _ref.line; 49940 49941 var moduleInfo = ''; 49942 if (moduleName) { 49943 moduleInfo += '\'' + moduleName + '\' '; 49944 } 49945 49946 if (line !== undefined && column !== undefined) { 49947 if (moduleName) { 49948 // only prepend @ if the moduleName was present 49949 moduleInfo += '@ '; 49950 } 49951 moduleInfo += 'L' + line + ':C' + column; 49952 } 49953 49954 if (moduleInfo) { 49955 moduleInfo = '(' + moduleInfo + ') '; 49956 } 49957 49958 return moduleInfo; 49959 } 49960}); 49961enifed('ember-template-compiler/system/compile', ['exports', 'require', 'ember-template-compiler/system/compile_options', 'ember-template-compiler/system/template'], function (exports, _require, _emberTemplateCompilerSystemCompile_options, _emberTemplateCompilerSystemTemplate) { 49962 /** 49963 @module ember 49964 @submodule ember-template-compiler 49965 */ 49966 49967 'use strict'; 49968 49969 var compile; 49970 49971 /** 49972 Uses HTMLBars `compile` function to process a string into a compiled template. 49973 49974 This is not present in production builds. 49975 49976 @private 49977 @method compile 49978 @param {String} templateString This is the string to be compiled by HTMLBars. 49979 @param {Object} options This is an options hash to augment the compiler options. 49980 */ 49981 49982 exports.default = function (templateString, options) { 49983 if (!compile && _require.has('htmlbars-compiler/compiler')) { 49984 compile = _require.default('htmlbars-compiler/compiler').compile; 49985 } 49986 49987 if (!compile) { 49988 throw new Error('Cannot call `compile` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `compile`.'); 49989 } 49990 49991 var templateSpec = compile(templateString, _emberTemplateCompilerSystemCompile_options.default(options)); 49992 49993 return _emberTemplateCompilerSystemTemplate.default(templateSpec); 49994 }; 49995}); 49996enifed('ember-template-compiler/system/compile_options', ['exports', 'ember-metal/assign', 'ember-template-compiler/plugins'], function (exports, _emberMetalAssign, _emberTemplateCompilerPlugins) { 49997 /** 49998 @module ember 49999 @submodule ember-template-compiler 50000 */ 50001 50002 'use strict'; 50003 50004 /** 50005 @private 50006 @property compileOptions 50007 */ 50008 50009 exports.default = function (_options) { 50010 var disableComponentGeneration = true; 50011 50012 var options = undefined; 50013 // When calling `Ember.Handlebars.compile()` a second argument of `true` 50014 // had a special meaning (long since lost), this just gaurds against 50015 // `options` being true, and causing an error during compilation. 50016 if (_options === true) { 50017 options = {}; 50018 } else { 50019 options = _emberMetalAssign.default({}, _options); 50020 } 50021 50022 options.disableComponentGeneration = disableComponentGeneration; 50023 50024 var plugins = { 50025 ast: _emberTemplateCompilerPlugins.default.ast.slice() 50026 }; 50027 50028 if (options.plugins && options.plugins.ast) { 50029 plugins.ast = plugins.ast.concat(options.plugins.ast); 50030 } 50031 options.plugins = plugins; 50032 50033 options.buildMeta = function buildMeta(program) { 50034 return { 50035 fragmentReason: fragmentReason(program), 50036 revision: '[email protected]', 50037 loc: program.loc, 50038 moduleName: options.moduleName 50039 }; 50040 }; 50041 50042 return options; 50043 }; 50044 50045 function fragmentReason(program) { 50046 var loc = program.loc; 50047 var body = program.body; 50048 50049 if (!loc || loc.start.line !== 1 || loc.start.column !== 0) { 50050 return false;
50051 } 50052 50053 var candidate = undefined; 50054 var nodeCount = 0; 50055 50056 var problems = {}; 50057 50058 for (var i = 0, l = body.length; i < l; i++) { 50059 var curr = body[i]; 50060 50061 // text node with whitespace only 50062 if (curr.type === 'TextNode' && /^[\s]*$/.test(curr.chars)) { 50063 continue; 50064 } 50065 50066 // has multiple root elements if we've been here before 50067 if (nodeCount++ > 0) { 50068 problems['multiple-nodes'] = true; 50069 } 50070 50071 if (curr.type === 'ComponentNode' || curr.type === 'ElementNode') { 50072 candidate = curr; 50073 } else { 50074 problems['wrong-type'] = true; 50075 } 50076 } 50077 50078 if (nodeCount === 0) { 50079 return { name: 'missing-wrapper', problems: ['empty-body'] }; 50080 } 50081 50082 var problemList = Object.keys(problems); 50083 if (problemList.length) { 50084 return { name: 'missing-wrapper', problems: problemList }; 50085 } 50086 50087 if (candidate.type === 'ComponentNode') { 50088 return false; 50089 } else if (candidate.modifiers.length) { 50090 return { name: 'modifiers', modifiers: candidate.modifiers.map(function (m) { 50091 return m.path.original; 50092 }) }; 50093 } else if (candidate.attributes.some(function (attr) { 50094 return !attr.value.escaped; 50095 })) { 50096 return { name: 'triple-curlies' }; 50097 } else { 50098 return false; 50099 } 50100 } 50101}); 50102enifed('ember-template-compiler/system/precompile', ['exports', 'require', 'ember-template-compiler/system/compile_options'], function (exports, _require, _emberTemplateCompilerSystemCompile_options) { 50103 /** 50104 @module ember 50105 @submodule ember-template-compiler 50106 */ 50107 'use strict'; 50108 50109 var compileSpec; 50110 50111 /** 50112 Uses HTMLBars `compile` function to process a string into a compiled template string. 50113 The returned string must be passed through `Ember.HTMLBars.template`. 50114 50115 This is not present in production builds. 50116 50117 @private 50118 @method precompile 50119 @param {String} templateString This is the string to be compiled by HTMLBars. 50120 */ 50121 50122 exports.default = function (templateString, options) { 50123 if (!compileSpec && _require.has('htmlbars-compiler/compiler')) { 50124 compileSpec = _require.default('htmlbars-compiler/compiler').compileSpec; 50125 } 50126 50127 if (!compileSpec) { 50128 throw new Error('Cannot call `compileSpec` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `compileSpec`.'); 50129 } 50130 50131 return compileSpec(templateString, _emberTemplateCompilerSystemCompile_options.default(options)); 50132 }; 50133}); 50134enifed('ember-template-compiler/system/template', ['exports', 'htmlbars-runtime/hooks'], function (exports, _htmlbarsRuntimeHooks) { 50135 'use strict'; 50136 50137 /** 50138 @module ember 50139 @submodule ember-template-compiler 50140 */ 50141 50142 /** 50143 Augments the default precompiled output of an HTMLBars template with 50144 additional information needed by Ember. 50145 50146 @private 50147 @method template 50148 @param {Function} templateSpec This is the compiled HTMLBars template spec. 50149 */ 50150 50151 exports.default = function (templateSpec) { 50152 if (!templateSpec.render) { 50153 templateSpec = _htmlbarsRuntimeHooks.wrap(templateSpec); 50154 } 50155 50156 templateSpec.isTop = true; 50157 templateSpec.isMethod = false; 50158 50159 return templateSpec; 50160 }; 50161}); 50162enifed('ember-testing/adapters/adapter', ['exports', 'ember-runtime/system/object'], function (exports, _emberRuntimeSystemObject) { 50163 'use strict'; 50164 50165 function K() { 50166 return this; 50167 } 50168 50169 /** 50170 @module ember 50171 @submodule ember-testing 50172 */ 50173 50174 /** 50175 The primary purpose of this class is to create hooks that can be implemented 50176 by an adapter for various test frameworks. 50177 50178 @class Adapter 50179 @namespace Ember.Test 50180 @public 50181 */ 50182 var Adapter = _emberRuntimeSystemObject.default.extend({ 50183 /** 50184 This callback will be called whenever an async operation is about to start. 50185 Override this to call your framework's methods that handle async 50186 operations. 50187 @public 50188 @method asyncStart 50189 */ 50190 asyncStart: K, 50191 50192 /** 50193 This callback will be called whenever an async operation has completed. 50194 @public 50195 @method asyncEnd 50196 */ 50197 asyncEnd: K, 50198 50199 /** 50200 Override this method with your testing framework's false assertion. 50201 This function is called whenever an exception occurs causing the testing 50202 promise to fail. 50203 QUnit example: 50204 ```javascript 50205 exception: function(error) { 50206 ok(false, error); 50207 }; 50208 ``` 50209 @public 50210 @method exception 50211 @param {String} error The exception to be raised. 50212 */ 50213 exception: function (error) { 50214 throw error; 50215 } 50216 }); 50217 50218 exports.default = Adapter; 50219}); 50220enifed('ember-testing/adapters/qunit', ['exports', 'ember-testing/adapters/adapter', 'ember-metal/utils'], function (exports, _emberTestingAdaptersAdapter, _emberMetalUtils) { 50221 'use strict'; 50222 50223 /** 50224 This class implements the methods defined by Ember.Test.Adapter for the 50225 QUnit testing framework. 50226 50227 @class QUnitAdapter 50228 @namespace Ember.Test
50229 @extends Ember.Test.Adapter 50230 @public 50231 */ 50232 exports.default = _emberTestingAdaptersAdapter.default.extend({ 50233 asyncStart: function () { 50234 QUnit.stop(); 50235 }, 50236 asyncEnd: function () { 50237 QUnit.start(); 50238 }, 50239 exception: function (error) { 50240 ok(false, _emberMetalUtils.inspect(error)); 50241 } 50242 }); 50243}); 50244enifed('ember-testing/helpers', ['exports', 'ember-metal/property_get', 'ember-metal/error', 'ember-metal/run_loop', 'ember-views/system/jquery', 'ember-testing/test', 'ember-runtime/ext/rsvp', 'ember-metal/features'], function (exports, _emberMetalProperty_get, _emberMetalError, _emberMetalRun_loop, _emberViewsSystemJquery, _emberTestingTest, _emberRuntimeExtRsvp, _emberMetalFeatures) { 50245 'use strict'; 50246 50247 /** 50248 @module ember 50249 @submodule ember-testing 50250 */ 50251 50252 var helper = _emberTestingTest.default.registerHelper; 50253 var asyncHelper = _emberTestingTest.default.registerAsyncHelper; 50254 50255 var keyboardEventTypes, mouseEventTypes, buildKeyboardEvent, buildMouseEvent, buildBasicEvent, fireEvent, focus; 50256 50257 var defaultEventOptions = { canBubble: true, cancelable: true }; 50258 keyboardEventTypes = ['keydown', 'keypress', 'keyup']; 50259 mouseEventTypes = ['click', 'mousedown', 'mouseup', 'dblclick', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover']; 50260 50261 buildKeyboardEvent = function buildKeyboardEvent(type) { 50262 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 50263 50264 var event = undefined; 50265 try { 50266 event = document.createEvent('KeyEvents'); 50267 var eventOpts = _emberViewsSystemJquery.default.extend({}, defaultEventOptions, options); 50268 event.initKeyEvent(type, eventOpts.canBubble, eventOpts.cancelable, window, eventOpts.ctrlKey, eventOpts.altKey, eventOpts.shiftKey, eventOpts.metaKey, eventOpts.keyCode, eventOpts.charCode); 50269 } catch (e) { 50270 event = buildBasicEvent(type, options); 50271 } 50272 return event; 50273 }; 50274 50275 buildMouseEvent = function buildMouseEvent(type) { 50276 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 50277 50278 var event = undefined; 50279 try { 50280 event = document.createEvent('MouseEvents'); 50281 var eventOpts = _emberViewsSystemJquery.default.extend({}, defaultEventOptions, options); 50282 event.initMouseEvent(type, eventOpts.canBubble, eventOpts.cancelable, window, eventOpts.detail, eventOpts.screenX, eventOpts.screenY, eventOpts.clientX, eventOpts.clientY, eventOpts.ctrlKey, eventOpts.altKey, eventOpts.shiftKey, eventOpts.metaKey, eventOpts.button, eventOpts.relatedTarget); 50283 } catch (e) { 50284 event = buildBasicEvent(type, options); 50285 } 50286 return event; 50287 }; 50288 50289 buildBasicEvent = function buildBasicEvent(type) { 50290 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 50291 50292 var event = document.createEvent('Events'); 50293 event.initEvent(type, true, true); 50294 _emberViewsSystemJquery.default.extend(event, options); 50295 return event; 50296 }; 50297 50298 fireEvent = function fireEvent(element, type) { 50299 var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 50300 50301 if (!element) { 50302 return; 50303 } 50304 var event = undefined; 50305 if (keyboardEventTypes.indexOf(type) > -1) { 50306 event = buildKeyboardEvent(type, options); 50307 } else if (mouseEventTypes.indexOf(type) > -1) { 50308 var rect = element.getBoundingClientRect(); 50309 var x = rect.left + 1; 50310 var y = rect.top + 1; 50311 var simulatedCoordinates = { 50312 screenX: x + 5, 50313 screenY: y + 95, 50314 clientX: x, 50315 clientY: y 50316 }; 50317 event = buildMouseEvent(type, _emberViewsSystemJquery.default.extend(simulatedCoordinates, options)); 50318 } else { 50319 event = buildBasicEvent(type, options); 50320 } 50321 element.dispatchEvent(event); 50322 }; 50323 50324 focus = function focus(el) { 50325 if (!el) { 50326 return; 50327 } 50328 var $el = _emberViewsSystemJquery.default(el); 50329 if ($el.is(':input, [contenteditable=true]')) { 50330 var type = $el.prop('type'); 50331 if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { 50332 _emberMetalRun_loop.default(null, function () { 50333 // Firefox does not trigger the `focusin` event if the window 50334 // does not have focus. If the document doesn't have focus just 50335 // use trigger('focusin') instead. 50336 50337 if (!document.hasFocus || document.hasFocus()) { 50338 el.focus(); 50339 } else { 50340 $el.trigger('focusin'); 50341 } 50342 }); 50343 } 50344 } 50345 }; 50346 50347 function currentRouteName(app) { 50348 var routingService = app.__container__.lookup('service:-routing'); 50349 50350 return _emberMetalProperty_get.get(routingService, 'currentRouteName'); 50351 } 50352 50353 function currentPath(app) { 50354 var routingService = app.__container__.lookup('service:-routing'); 50355 50356 return _emberMetalProperty_get.get(routingService, 'currentPath'); 50357 } 50358 50359 function currentURL(app) { 50360 var router = app.__container__.lookup('router:main'); 50361 50362 return _emberMetalProperty_get.get(router, 'location').getURL(); 50363 } 50364 50365 function pauseTest() { 50366 _emberTestingTest.default.adapter.asyncStart(); 50367 return new _emberRuntimeExtRsvp.default.Promise(function () {}, 'TestAdapter paused promise'); 50368 } 50369 50370 function visit(app, url) { 50371 var router = app.__container__.lookup('router:main'); 50372 var shouldHandleURL = false;
50373 50374 app.boot().then(function () { 50375 router.location.setURL(url); 50376 50377 if (shouldHandleURL) { 50378 _emberMetalRun_loop.default(app.__deprecatedInstance__, 'handleURL', url); 50379 } 50380 }); 50381 50382 if (app._readinessDeferrals > 0) { 50383 router['initialURL'] = url; 50384 _emberMetalRun_loop.default(app, 'advanceReadiness'); 50385 delete router['initialURL']; 50386 } else { 50387 shouldHandleURL = true; 50388 } 50389 50390 return app.testHelpers.wait(); 50391 } 50392 50393 function click(app, selector, context) { 50394 var $el = app.testHelpers.findWithAssert(selector, context); 50395 var el = $el[0]; 50396 50397 _emberMetalRun_loop.default(null, fireEvent, el, 'mousedown'); 50398 50399 focus(el); 50400 50401 _emberMetalRun_loop.default(null, fireEvent, el, 'mouseup'); 50402 _emberMetalRun_loop.default(null, fireEvent, el, 'click'); 50403 50404 return app.testHelpers.wait(); 50405 } 50406 50407 function triggerEvent(app, selector, contextOrType, typeOrOptions, possibleOptions) { 50408 var arity = arguments.length; 50409 var context, type, options; 50410 50411 if (arity === 3) { 50412 // context and options are optional, so this is 50413 // app, selector, type 50414 context = null; 50415 type = contextOrType; 50416 options = {}; 50417 } else if (arity === 4) { 50418 // context and options are optional, so this is 50419 if (typeof typeOrOptions === 'object') { 50420 // either 50421 // app, selector, type, options 50422 context = null; 50423 type = contextOrType; 50424 options = typeOrOptions; 50425 } else { 50426 // or 50427 // app, selector, context, type 50428 context = contextOrType; 50429 type = typeOrOptions; 50430 options = {}; 50431 } 50432 } else { 50433 context = contextOrType; 50434 type = typeOrOptions; 50435 options = possibleOptions; 50436 } 50437 50438 var $el = app.testHelpers.findWithAssert(selector, context); 50439 var el = $el[0]; 50440 50441 _emberMetalRun_loop.default(null, fireEvent, el, type, options); 50442 50443 return app.testHelpers.wait(); 50444 } 50445 50446 function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { 50447 var context, type; 50448 50449 if (typeof keyCode === 'undefined') { 50450 context = null; 50451 keyCode = typeOrKeyCode; 50452 type = contextOrType; 50453 } else { 50454 context = contextOrType; 50455 type = typeOrKeyCode; 50456 } 50457 50458 return app.testHelpers.triggerEvent(selector, context, type, { keyCode: keyCode, which: keyCode }); 50459 } 50460 50461 function fillIn(app, selector, contextOrText, text) { 50462 var $el, el, context; 50463 if (typeof text === 'undefined') { 50464 text = contextOrText; 50465 } else { 50466 context = contextOrText; 50467 } 50468 $el = app.testHelpers.findWithAssert(selector, context); 50469 el = $el[0]; 50470 focus(el); 50471 _emberMetalRun_loop.default(function () { 50472 $el.val(text); 50473 fireEvent(el, 'input'); 50474 fireEvent(el, 'change'); 50475 }); 50476 return app.testHelpers.wait(); 50477 } 50478 50479 function findWithAssert(app, selector, context) { 50480 var $el = app.testHelpers.find(selector, context); 50481 if ($el.length === 0) { 50482 throw new _emberMetalError.default('Element ' + selector + ' not found.'); 50483 } 50484 return $el; 50485 } 50486 50487 function find(app, selector, context) { 50488 var $el; 50489 context = context || _emberMetalProperty_get.get(app, 'rootElement'); 50490 $el = app.$(selector, context); 50491 50492 return $el; 50493 } 50494 50495 function andThen(app, callback) { 50496 return app.testHelpers.wait(callback(app)); 50497 } 50498 50499 function wait(app, value) { 50500 return new _emberRuntimeExtRsvp.default.Promise(function (resolve) { 50501 var router = app.__container__.lookup('router:main'); 50502 50503 // Every 10ms, poll for the async thing to have finished 50504 var watcher = setInterval(function () { 50505 // 1. If the router is loading, keep polling 50506 var routerIsLoading = router.router && !!router.router.activeTransition; 50507 if (routerIsLoading) { 50508 return; 50509 } 50510 50511 // 2. If there are pending Ajax requests, keep polling 50512 if (_emberTestingTest.default.pendingAjaxRequests) { 50513 return; 50514 } 50515 50516 // 3. If there are scheduled timers or we are inside of a run loop, keep polling 50517 if (_emberMetalRun_loop.default.hasScheduledTimers() || _emberMetalRun_loop.default.currentRunLoop) { 50518 return; 50519 } 50520 if (_emberTestingTest.default.waiters && _emberTestingTest.default.waiters.any(function (waiter) { 50521 var context = waiter[0]; 50522 var callback = waiter[1]; 50523 return !callback.call(context); 50524 })) { 50525 return; 50526 } 50527 // Stop polling 50528 clearInterval(watcher); 50529 50530 // Synchronously resolve the promise 50531 _emberMetalRun_loop.default(null, resolve, value); 50532 }, 10); 50533 }); 50534 } 50535 50536 /** 50537 Loads a route, sets up any controllers, and renders any templates associated 50538 with the route as though a real user had triggered the route change while 50539 using your app. 50540 50541 Example: 50542 50543 ```javascript 50544 visit('posts/index').then(function() { 50545 // assert something 50546 }); 50547 ``` 50548 50549 @method visit 50550 @param {String} url the name of the route 50551 @return {RSVP.Promise} 50552 @public 50553 */ 50554 asyncHelper('visit', visit); 50555 50556 /** 50557 Clicks an element and triggers any actions triggered by the element's `click` 50558 event. 50559 50560 Example: 50561 50562 ```javascript 50563 click('.some-jQuery-selector').then(function() { 50564 // assert something 50565 }); 50566 ``` 50567 50568 @method click 50569 @param {String} selector jQuery selector for finding element on the DOM 50570 @return {RSVP.Promise} 50571 @public 50572 */ 50573 asyncHelper('click', click); 50574 50575 /** 50576 Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode 50577 50578 Example: 50579 50580 ```javascript 50581 keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() { 50582 // assert something 50583 }); 50584 ``` 50585 50586 @method keyEvent 50587 @param {String} selector jQuery selector for finding element on the DOM 50588 @param {String} type the type of key event, e.g. `keypress`, `keydown`, `keyup` 50589 @param {Number} keyCode the keyCode of the simulated key event 50590 @return {RSVP.Promise} 50591 @since 1.5.0 50592 @public 50593 */ 50594 asyncHelper('keyEvent', keyEvent); 50595 50596 /** 50597 Fills in an input element with some text. 50598 50599 Example: 50600 50601 ```javascript 50602 fillIn('#email', '[email protected]').then(function() { 50603 // assert something 50604 }); 50605 ``` 50606 50607 @method fillIn 50608 @param {String} selector jQuery selector finding an input element on the DOM 50609 to fill text with 50610 @param {String} text text to place inside the input element 50611 @return {RSVP.Promise} 50612 @public 50613 */ 50614 asyncHelper('fillIn', fillIn); 50615 50616 /** 50617 Finds an element in the context of the app's container element. A simple alias 50618 for `app.$(selector)`. 50619 50620 Example: 50621 50622 ```javascript 50623 var $el = find('.my-selector'); 50624 ``` 50625 50626 @method find 50627 @param {String} selector jQuery string selector for element lookup 50628 @return {Object} jQuery object representing the results of the query 50629 @public 50630 */ 50631 helper('find', find); 50632 50633 /** 50634 Like `find`, but throws an error if the element selector returns no results. 50635 50636 Example: 50637 50638 ```javascript 50639 var $el = findWithAssert('.doesnt-exist'); // throws error 50640 ``` 50641 50642 @method findWithAssert 50643 @param {String} selector jQuery selector string for finding an element within 50644 the DOM 50645 @return {Object} jQuery object representing the results of the query 50646 @throws {Error} throws error if jQuery object returned has a length of 0 50647 @public 50648 */ 50649 helper('findWithAssert', findWithAssert); 50650 50651 /** 50652 Causes the run loop to process any pending events. This is used to ensure that 50653 any async operations from other helpers (or your assertions) have been processed. 50654 50655 This is most often used as the return value for the helper functions (see 'click', 50656 'fillIn','visit',etc). 50657 50658 Example: 50659 50660 ```javascript 50661 Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) { 50662 visit('secured/path/here') 50663 .fillIn('#username', username) 50664 .fillIn('#password', password) 50665 .click('.submit') 50666 50667 return app.testHelpers.wait(); 50668 }); 50669 50670 @method wait 50671 @param {Object} value The value to be returned. 50672 @return {RSVP.Promise} 50673 @public 50674 */ 50675 asyncHelper('wait', wait); 50676 asyncHelper('andThen', andThen); 50677 50678 /** 50679 Returns the currently active route name. 50680 50681 Example: 50682 50683 ```javascript 50684 function validateRouteName() { 50685 equal(currentRouteName(), 'some.path', "correct route was transitioned into."); 50686 } 50687
50688 visit('/some/path').then(validateRouteName) 50689 ``` 50690 50691 @method currentRouteName 50692 @return {Object} The name of the currently active route. 50693 @since 1.5.0 50694 @public 50695 */ 50696 helper('currentRouteName', currentRouteName); 50697 50698 /** 50699 Returns the current path. 50700 50701 Example: 50702 50703 ```javascript 50704 function validateURL() { 50705 equal(currentPath(), 'some.path.index', "correct path was transitioned into."); 50706 } 50707 50708 click('#some-link-id').then(validateURL); 50709 ``` 50710 50711 @method currentPath 50712 @return {Object} The currently active path. 50713 @since 1.5.0 50714 @public 50715 */ 50716 helper('currentPath', currentPath); 50717 50718 /** 50719 Returns the current URL. 50720 50721 Example: 50722 50723 ```javascript 50724 function validateURL() { 50725 equal(currentURL(), '/some/path', "correct URL was transitioned into."); 50726 } 50727 50728 click('#some-link-id').then(validateURL); 50729 ``` 50730 50731 @method currentURL 50732 @return {Object} The currently active URL. 50733 @since 1.5.0 50734 @public 50735 */ 50736 helper('currentURL', currentURL); 50737 50738 /** 50739 Pauses the current test - this is useful for debugging while testing or for test-driving. 50740 It allows you to inspect the state of your application at any point. 50741 50742 Example (The test will pause before clicking the button): 50743 50744 ```javascript 50745 visit('/') 50746 return pauseTest(); 50747 50748 click('.btn'); 50749 ``` 50750 50751 @since 1.9.0 50752 @method pauseTest 50753 @return {Object} A promise that will never resolve 50754 @public 50755 */ 50756 helper('pauseTest', pauseTest); 50757 50758 /** 50759 Triggers the given DOM event on the element identified by the provided selector. 50760 50761 Example: 50762 50763 ```javascript 50764 triggerEvent('#some-elem-id', 'blur'); 50765 ``` 50766 50767 This is actually used internally by the `keyEvent` helper like so: 50768 50769 ```javascript 50770 triggerEvent('#some-elem-id', 'keypress', { keyCode: 13 }); 50771 ``` 50772 50773 @method triggerEvent 50774 @param {String} selector jQuery selector for finding element on the DOM 50775 @param {String} [context] jQuery selector that will limit the selector 50776 argument to find only within the context's children 50777 @param {String} type The event type to be triggered. 50778 @param {Object} [options] The options to be passed to jQuery.Event. 50779 @return {RSVP.Promise} 50780 @since 1.5.0 50781 @public 50782 */ 50783 asyncHelper('triggerEvent', triggerEvent); 50784}); 50785 50786// Firefox does not trigger the `focusin` event if the window 50787// does not have focus. If the document doesn't have focus just 50788// use trigger('focusin') instead. 50789enifed('ember-testing/index', ['exports', 'ember-metal/core', 'ember-testing/initializers', 'ember-testing/support', 'ember-testing/setup_for_testing', 'ember-testing/test', 'ember-testing/adapters/adapter', 'ember-testing/adapters/qunit', 'ember-testing/helpers'], function (exports, _emberMetalCore, _emberTestingInitializers, _emberTestingSupport, _emberTestingSetup_for_testing, _emberTestingTest, _emberTestingAdaptersAdapter, _emberTestingAdaptersQunit, _emberTestingHelpers) { 50790 'use strict'; 50791 50792 // adds helpers to helpers object in Test 50793 50794 /** 50795 @module ember 50796 @submodule ember-testing 50797 */ 50798 50799 _emberMetalCore.default.Test = _emberTestingTest.default; 50800 _emberMetalCore.default.Test.Adapter = _emberTestingAdaptersAdapter.default; 50801 _emberMetalCore.default.Test.QUnitAdapter = _emberTestingAdaptersQunit.default; 50802 _emberMetalCore.default.setupForTesting = _emberTestingSetup_for_testing.default; 50803}); 50804// to setup initializer 50805// to handle various edge cases 50806enifed('ember-testing/initializers', ['exports', 'ember-runtime/system/lazy_load'], function (exports, _emberRuntimeSystemLazy_load) { 50807 'use strict'; 50808 50809 var name = 'deferReadiness in `testing` mode'; 50810 50811 _emberRuntimeSystemLazy_load.onLoad('Ember.Application', function (Application) { 50812 if (!Application.initializers[name]) { 50813 Application.initializer({ 50814 name: name, 50815 50816 initialize: function (application) { 50817 if (application.testing) { 50818 application.deferReadiness(); 50819 } 50820 } 50821 }); 50822 } 50823 }); 50824}); 50825enifed('ember-testing/setup_for_testing', ['exports', 'ember-metal/core', 'ember-testing/adapters/qunit', 'ember-views/system/jquery'], function (exports, _emberMetalCore, _emberTestingAdaptersQunit, _emberViewsSystemJquery) { 50826 'use strict'; 50827 50828 exports.default = setupForTesting; 50829 50830 var Test, requests; 50831 50832 function incrementAjaxPendingRequests(_, xhr) { 50833 requests.push(xhr); 50834 Test.pendingAjaxRequests = requests.length; 50835 } 50836 50837 function decrementAjaxPendingRequests(_, xhr) { 50838 for (var i = 0; i < requests.length; i++) { 50839 if (xhr === requests[i]) { 50840 requests.splice(i, 1); 50841 } 50842 } 50843 Test.pendingAjaxRequests = requests.length; 50844 } 50845 50846 /** 50847 Sets Ember up for testing. This is useful to perform 50848 basic setup steps in order to unit test. 50849 50850 Use `App.setupForTesting` to perform integration tests (full 50851 application testing). 50852
50853 @method setupForTesting 50854 @namespace Ember 50855 @since 1.5.0 50856 @private 50857 */ 50858 50859 function setupForTesting() { 50860 if (!Test) { 50861 Test = requireModule('ember-testing/test')['default']; 50862 } 50863 50864 _emberMetalCore.default.testing = true; 50865 50866 // if adapter is not manually set default to QUnit 50867 if (!Test.adapter) { 50868 Test.adapter = _emberTestingAdaptersQunit.default.create(); 50869 } 50870 50871 requests = []; 50872 Test.pendingAjaxRequests = requests.length; 50873 50874 _emberViewsSystemJquery.default(document).off('ajaxSend', incrementAjaxPendingRequests); 50875 _emberViewsSystemJquery.default(document).off('ajaxComplete', decrementAjaxPendingRequests); 50876 _emberViewsSystemJquery.default(document).on('ajaxSend', incrementAjaxPendingRequests); 50877 _emberViewsSystemJquery.default(document).on('ajaxComplete', decrementAjaxPendingRequests); 50878 } 50879}); 50880 50881// import Test from "ember-testing/test"; // ES6TODO: fix when cycles are supported 50882enifed('ember-testing/support', ['exports', 'ember-metal/debug', 'ember-views/system/jquery', 'ember-metal/environment'], function (exports, _emberMetalDebug, _emberViewsSystemJquery, _emberMetalEnvironment) { 50883 'use strict'; 50884 50885 /** 50886 @module ember 50887 @submodule ember-testing 50888 */ 50889 50890 var $ = _emberViewsSystemJquery.default; 50891 50892 /** 50893 This method creates a checkbox and triggers the click event to fire the 50894 passed in handler. It is used to correct for a bug in older versions 50895 of jQuery (e.g 1.8.3). 50896 50897 @private 50898 @method testCheckboxClick 50899 */ 50900 function testCheckboxClick(handler) { 50901 $('<input type="checkbox">').css({ position: 'absolute', left: '-1000px', top: '-1000px' }).appendTo('body').on('click', handler).trigger('click').remove(); 50902 } 50903 50904 if (_emberMetalEnvironment.default.hasDOM) { 50905 $(function () { 50906 /* 50907 Determine whether a checkbox checked using jQuery's "click" method will have 50908 the correct value for its checked property. 50909 If we determine that the current jQuery version exhibits this behavior, 50910 patch it to work correctly as in the commit for the actual fix: 50911 https://github.com/jquery/jquery/commit/1fb2f92. 50912 */ 50913 testCheckboxClick(function () { 50914 if (!this.checked && !$.event.special.click) { 50915 $.event.special.click = { 50916 // For checkbox, fire native event so checked state will be right 50917 trigger: function () { 50918 if ($.nodeName(this, 'input') && this.type === 'checkbox' && this.click) { 50919 this.click(); 50920 return false; 50921 } 50922 } 50923 }; 50924 } 50925 }); 50926 50927 // Try again to verify that the patch took effect or blow up. 50928 testCheckboxClick(function () { 50929 _emberMetalDebug.warn('clicked checkboxes should be checked! the jQuery patch didn\'t work', this.checked, { id: 'ember-testing.test-checkbox-click' }); 50930 }); 50931 }); 50932 } 50933}); 50934enifed('ember-testing/test', ['exports', 'ember-metal/run_loop', 'ember-runtime/ext/rsvp', 'ember-testing/setup_for_testing', 'ember-application/system/application', 'ember-runtime/system/native_array'], function (exports, _emberMetalRun_loop, _emberRuntimeExtRsvp, _emberTestingSetup_for_testing, _emberApplicationSystemApplication, _emberRuntimeSystemNative_array) { 50935 'use strict'; 50936 50937 /** 50938 @module ember 50939 @submodule ember-testing 50940 */ 50941 var helpers = {}; 50942 var injectHelpersCallbacks = []; 50943 50944 /** 50945 This is a container for an assortment of testing related functionality: 50946 50947 * Choose your default test adapter (for your framework of choice). 50948 * Register/Unregister additional test helpers. 50949 * Setup callbacks to be fired when the test helpers are injected into 50950 your application. 50951 50952 @class Test 50953 @namespace Ember 50954 @public 50955 */ 50956 var Test = { 50957 /** 50958 Hash containing all known test helpers. 50959 @property _helpers 50960 @private 50961 @since 1.7.0 50962 */ 50963 _helpers: helpers, 50964 50965 /** 50966 `registerHelper` is used to register a test helper that will be injected 50967 when `App.injectTestHelpers` is called. 50968 The helper method will always be called with the current Application as 50969 the first parameter. 50970 For example: 50971 ```javascript 50972 Ember.Test.registerHelper('boot', function(app) { 50973 Ember.run(app, app.advanceReadiness); 50974 }); 50975 ``` 50976 This helper can later be called without arguments because it will be 50977 called with `app` as the first parameter. 50978 ```javascript 50979 App = Ember.Application.create(); 50980 App.injectTestHelpers(); 50981 boot(); 50982 ``` 50983 @public 50984 @method registerHelper 50985 @param {String} name The name of the helper method to add. 50986 @param {Function} helperMethod 50987 @param options {Object} 50988 */ 50989 registerHelper: function (name, helperMethod) { 50990 helpers[name] = { 50991 method: helperMethod, 50992 meta: { wait: false } 50993 }; 50994 }, 50995 50996 /** 50997 `registerAsyncHelper` is used to register an async test helper that will be injected 50998 when `App.injectTestHelpers` is called. 50999 The helper method will always be called with the current Application as 51000 the first parameter. 51001 For example: 51002 ```javascript 51003 Ember.Test.registerAsyncHelper('boot', function(app) { 51004 Ember.run(app, app.advanceReadiness); 51005 }); 51006 ``` 51007 The advantage of an async helper is that it will not run 51008 until the last async helper has completed. All async helpers 51009 after it will wait for it complete before running. 51010 For example: 51011 ```javascript 51012 Ember.Test.registerAsyncHelper('deletePost', function(app, postId) { 51013 click('.delete-' + postId); 51014 }); 51015 // ... in your test 51016 visit('/post/2'); 51017 deletePost(2); 51018 visit('/post/3'); 51019 deletePost(3); 51020 ``` 51021 @public 51022 @method registerAsyncHelper 51023 @param {String} name The name of the helper method to add. 51024 @param {Function} helperMethod 51025 @since 1.2.0 51026 */ 51027 registerAsyncHelper: function (name, helperMethod) { 51028 helpers[name] = { 51029 method: helperMethod, 51030 meta: { wait: true } 51031 }; 51032 }, 51033 51034 /** 51035 Remove a previously added helper method. 51036 Example: 51037 ```javascript 51038 Ember.Test.unregisterHelper('wait'); 51039 ``` 51040 @public 51041 @method unregisterHelper 51042 @param {String} name The helper to remove. 51043 */ 51044 unregisterHelper: function (name) { 51045 delete helpers[name]; 51046 delete Test.Promise.prototype[name]; 51047 }, 51048 51049 /** 51050 Used to register callbacks to be fired whenever `App.injectTestHelpers` 51051 is called. 51052 The callback will receive the current application as an argument. 51053 Example: 51054 ```javascript 51055 Ember.Test.onInjectHelpers(function() { 51056 Ember.$(document).ajaxSend(function() { 51057 Test.pendingAjaxRequests++; 51058 }); 51059 Ember.$(document).ajaxComplete(function() { 51060 Test.pendingAjaxRequests--; 51061 }); 51062 }); 51063 ``` 51064 @public 51065 @method onInjectHelpers 51066 @param {Function} callback The function to be called. 51067 */ 51068 onInjectHelpers: function (callback) { 51069 injectHelpersCallbacks.push(callback); 51070 }, 51071 51072 /** 51073 This returns a thenable tailored for testing. It catches failed 51074 `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception` 51075 callback in the last chained then. 51076 This method should be returned by async helpers such as `wait`. 51077 @public 51078 @method promise 51079 @param {Function} resolver The function used to resolve the promise. 51080 @param {String} label An optional string for identifying the promise. 51081 */ 51082 promise: function (resolver, label) { 51083 var fullLabel = 'Ember.Test.promise: ' + (label || '<Unknown Promise>'); 51084 return new Test.Promise(resolver, fullLabel); 51085 }, 51086 51087 /** 51088 Used to allow ember-testing to communicate with a specific testing 51089 framework. 51090 You can manually set it before calling `App.setupForTesting()`. 51091 Example: 51092 ```javascript 51093 Ember.Test.adapter = MyCustomAdapter.create() 51094 ``` 51095 If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`. 51096 @public 51097 @property adapter 51098 @type {Class} The adapter to be used. 51099 @default Ember.Test.QUnitAdapter 51100 */ 51101 adapter: null, 51102 51103 /** 51104 Replacement for `Ember.RSVP.resolve` 51105 The only difference is this uses 51106 an instance of `Ember.Test.Promise` 51107 @public 51108 @method resolve 51109 @param {Mixed} The value to resolve 51110 @since 1.2.0 51111 */ 51112 resolve: function (val) { 51113 return Test.promise(function (resolve) { 51114 return resolve(val); 51115 }); 51116 }, 51117 51118 /** 51119 This allows ember-testing to play nicely with other asynchronous 51120 events, such as an application that is waiting for a CSS3 51121 transition or an IndexDB transaction. 51122 For example: 51123 ```javascript 51124 Ember.Test.registerWaiter(function() { 51125 return myPendingTransactions() == 0; 51126 }); 51127 ``` 51128 The `context` argument allows you to optionally specify the `this` 51129 with which your callback will be invoked. 51130 For example: 51131 ```javascript 51132 Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions); 51133 ``` 51134 @public 51135 @method registerWaiter 51136 @param {Object} context (optional) 51137 @param {Function} callback 51138 @since 1.2.0 51139 */ 51140 registerWaiter: function (context, callback) { 51141 if (arguments.length === 1) { 51142 callback = context; 51143 context = null; 51144 } 51145 if (!this.waiters) { 51146 this.waiters = _emberRuntimeSystemNative_array.A(); 51147 }
51148 this.waiters.push([context, callback]); 51149 }, 51150 /** 51151 `unregisterWaiter` is used to unregister a callback that was 51152 registered with `registerWaiter`. 51153 @public 51154 @method unregisterWaiter 51155 @param {Object} context (optional) 51156 @param {Function} callback 51157 @since 1.2.0 51158 */ 51159 unregisterWaiter: function (context, callback) { 51160 if (!this.waiters) { 51161 return; 51162 } 51163 if (arguments.length === 1) { 51164 callback = context; 51165 context = null; 51166 } 51167 this.waiters = _emberRuntimeSystemNative_array.A(this.waiters.filter(function (elt) { 51168 return !(elt[0] === context && elt[1] === callback); 51169 })); 51170 } 51171 }; 51172 51173 function helper(app, name) { 51174 var fn = helpers[name].method; 51175 var meta = helpers[name].meta; 51176 51177 return function () { 51178 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 51179 args[_key] = arguments[_key]; 51180 } 51181 51182 var lastPromise; 51183 51184 args.unshift(app); 51185 51186 // some helpers are not async and 51187 // need to return a value immediately. 51188 // example: `find` 51189 if (!meta.wait) { 51190 return fn.apply(app, args); 51191 } 51192 51193 lastPromise = run(function () { 51194 return Test.resolve(Test.lastPromise); 51195 }); 51196 51197 // wait for last helper's promise to resolve and then 51198 // execute. To be safe, we need to tell the adapter we're going 51199 // asynchronous here, because fn may not be invoked before we 51200 // return. 51201 Test.adapter.asyncStart(); 51202 return lastPromise.then(function () { 51203 return fn.apply(app, args); 51204 }).finally(function () { 51205 Test.adapter.asyncEnd(); 51206 }); 51207 }; 51208 } 51209 51210 function run(fn) { 51211 if (!_emberMetalRun_loop.default.currentRunLoop) { 51212 return _emberMetalRun_loop.default(fn); 51213 } else { 51214 return fn(); 51215 } 51216 } 51217 51218 _emberApplicationSystemApplication.default.reopen({ 51219 /** 51220 This property contains the testing helpers for the current application. These 51221 are created once you call `injectTestHelpers` on your `Ember.Application` 51222 instance. The included helpers are also available on the `window` object by 51223 default, but can be used from this object on the individual application also. 51224 @property testHelpers 51225 @type {Object} 51226 @default {} 51227 @public 51228 */ 51229 testHelpers: {}, 51230 51231 /** 51232 This property will contain the original methods that were registered 51233 on the `helperContainer` before `injectTestHelpers` is called. 51234 When `removeTestHelpers` is called, these methods are restored to the 51235 `helperContainer`. 51236 @property originalMethods 51237 @type {Object} 51238 @default {} 51239 @private 51240 @since 1.3.0 51241 */ 51242 originalMethods: {}, 51243 51244 /** 51245 This property indicates whether or not this application is currently in 51246 testing mode. This is set when `setupForTesting` is called on the current 51247 application. 51248 @property testing 51249 @type {Boolean} 51250 @default false 51251 @since 1.3.0 51252 @public 51253 */ 51254 testing: false, 51255 51256 /** 51257 This hook defers the readiness of the application, so that you can start 51258 the app when your tests are ready to run. It also sets the router's 51259 location to 'none', so that the window's location will not be modified 51260 (preventing both accidental leaking of state between tests and interference 51261 with your testing framework). 51262 Example: 51263 ``` 51264 App.setupForTesting(); 51265 ``` 51266 @method setupForTesting 51267 @public 51268 */ 51269 setupForTesting: function () { 51270 _emberTestingSetup_for_testing.default(); 51271 51272 this.testing = true; 51273 51274 this.Router.reopen({ 51275 location: 'none' 51276 }); 51277 }, 51278 51279 /** 51280 This will be used as the container to inject the test helpers into. By 51281 default the helpers are injected into `window`. 51282 @property helperContainer 51283 @type {Object} The object to be used for test helpers. 51284 @default window 51285 @since 1.2.0 51286 @private 51287 */ 51288 helperContainer: null, 51289 51290 /** 51291 This injects the test helpers into the `helperContainer` object. If an object is provided 51292 it will be used as the helperContainer. If `helperContainer` is not set it will default 51293 to `window`. If a function of the same name has already been defined it will be cached 51294 (so that it can be reset if the helper is removed with `unregisterHelper` or
51295 `removeTestHelpers`). 51296 Any callbacks registered with `onInjectHelpers` will be called once the 51297 helpers have been injected. 51298 Example: 51299 ``` 51300 App.injectTestHelpers(); 51301 ``` 51302 @method injectTestHelpers 51303 @public 51304 */ 51305 injectTestHelpers: function (helperContainer) { 51306 if (helperContainer) { 51307 this.helperContainer = helperContainer; 51308 } else { 51309 this.helperContainer = window; 51310 } 51311 51312 this.reopen({ 51313 willDestroy: function () { 51314 this._super.apply(this, arguments); 51315 this.removeTestHelpers(); 51316 } 51317 }); 51318 51319 this.testHelpers = {}; 51320 for (var name in helpers) { 51321 this.originalMethods[name] = this.helperContainer[name]; 51322 this.testHelpers[name] = this.helperContainer[name] = helper(this, name); 51323 protoWrap(Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait); 51324 } 51325 51326 for (var i = 0, l = injectHelpersCallbacks.length; i < l; i++) { 51327 injectHelpersCallbacks[i](this); 51328 } 51329 }, 51330 51331 /** 51332 This removes all helpers that have been registered, and resets and functions 51333 that were overridden by the helpers. 51334 Example: 51335 ```javascript 51336 App.removeTestHelpers(); 51337 ``` 51338 @public 51339 @method removeTestHelpers 51340 */ 51341 removeTestHelpers: function () { 51342 if (!this.helperContainer) { 51343 return; 51344 } 51345 51346 for (var name in helpers) { 51347 this.helperContainer[name] = this.originalMethods[name]; 51348 delete Test.Promise.prototype[name]; 51349 delete this.testHelpers[name]; 51350 delete this.originalMethods[name]; 51351 } 51352 } 51353 }); 51354 51355 // This method is no longer needed 51356 // But still here for backwards compatibility 51357 // of helper chaining 51358 function protoWrap(proto, name, callback, isAsync) { 51359 proto[name] = function () { 51360 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { 51361 args[_key2] = arguments[_key2]; 51362 } 51363 51364 if (isAsync) { 51365 return callback.apply(this, args); 51366 } else { 51367 return this.then(function () { 51368 return callback.apply(this, args); 51369 }); 51370 } 51371 }; 51372 } 51373 51374 Test.Promise = function () { 51375 _emberRuntimeExtRsvp.default.Promise.apply(this, arguments); 51376 Test.lastPromise = this; 51377 }; 51378 51379 Test.Promise.prototype = Object.create(_emberRuntimeExtRsvp.default.Promise.prototype); 51380 Test.Promise.prototype.constructor = Test.Promise; 51381 Test.Promise.resolve = Test.resolve; 51382 51383 // Patch `then` to isolate async methods 51384 // specifically `Ember.Test.lastPromise` 51385 var originalThen = _emberRuntimeExtRsvp.default.Promise.prototype.then; 51386 Test.Promise.prototype.then = function (onSuccess, onFailure) { 51387 return originalThen.call(this, function (val) { 51388 return isolate(onSuccess, val); 51389 }, onFailure); 51390 }; 51391 51392 // This method isolates nested async methods 51393 // so that they don't conflict with other last promises. 51394 // 51395 // 1. Set `Ember.Test.lastPromise` to null 51396 // 2. Invoke method 51397 // 3. Return the last promise created during method 51398 function isolate(fn, val) { 51399 var value, lastPromise; 51400 51401 // Reset lastPromise for nested helpers 51402 Test.lastPromise = null; 51403 51404 value = fn(val); 51405 51406 lastPromise = Test.lastPromise; 51407 Test.lastPromise = null; 51408 51409 // If the method returned a promise 51410 // return that promise. If not, 51411 // return the last async helper's promise 51412 if (value && value instanceof Test.Promise || !lastPromise) { 51413 return value; 51414 } else { 51415 return run(function () { 51416 return Test.resolve(lastPromise).then(function () { 51417 return value; 51418 }); 51419 }); 51420 } 51421 } 51422 51423 exports.default = Test; 51424}); 51425enifed('ember-views/compat/attrs-proxy', ['exports', 'ember-metal/mixin', 'ember-metal/symbol', 'ember-metal/property_events'], function (exports, _emberMetalMixin, _emberMetalSymbol, _emberMetalProperty_events) { 51426 'use strict'; 51427 51428 exports.deprecation = deprecation; 51429 51430 function deprecation(key) { 51431 return 'You tried to look up an attribute directly on the component. This is deprecated. Use attrs.' + key + ' instead.'; 51432 } 51433 51434 var MUTABLE_CELL = _emberMetalSymbol.default('MUTABLE_CELL'); 51435 51436 exports.MUTABLE_CELL = MUTABLE_CELL; 51437 function isCell(val) { 51438 return val && val[MUTABLE_CELL]; 51439 } 51440 51441 var AttrsProxyMixin = { 51442 attrs: null, 51443 51444 getAttr: function (key) { 51445 var attrs = this.attrs; 51446 if (!attrs) { 51447 return; 51448 } 51449 return this.getAttrFor(attrs, key); 51450 }, 51451 51452 getAttrFor: function (attrs, key) { 51453 var val = attrs[key]; 51454 return isCell(val) ? val.value : val; 51455 }, 51456 51457 setAttr: function (key, value) { 51458 var attrs = this.attrs; 51459 var val = attrs[key]; 51460 51461 if (!isCell(val)) { 51462 throw new Error('You can\'t update attrs.' + key + ', because it\'s not mutable'); 51463 } 51464 51465 val.update(value); 51466 }, 51467 51468 _propagateAttrsToThis: function (attrs) { 51469 this._isDispatchingAttrs = true; 51470 this.setProperties(attrs); 51471 this._isDispatchingAttrs = false;
51472 } 51473 }; 51474 51475 AttrsProxyMixin[_emberMetalProperty_events.PROPERTY_DID_CHANGE] = function (key) { 51476 if (this._isAngleBracket) { 51477 return; 51478 } 51479 if (this._isDispatchingAttrs) { 51480 return; 51481 } 51482 51483 if (this._currentState) { 51484 this._currentState.legacyPropertyDidChange(this, key); 51485 } 51486 }; 51487 51488 exports.default = _emberMetalMixin.Mixin.create(AttrsProxyMixin); 51489}); 51490enifed('ember-views/compat/metamorph_view', ['exports', 'ember-metal/debug', 'ember-views/views/view', 'ember-metal/mixin'], function (exports, _emberMetalDebug, _emberViewsViewsView, _emberMetalMixin) { 51491 'use strict'; 51492 51493 /** 51494 @module ember 51495 @submodule ember-views 51496 */ 51497 51498 // The `morph` and `outerHTML` properties are internal only 51499 // and not observable. 51500 51501 /** 51502 @class _Metamorph 51503 @namespace Ember 51504 @private 51505 */ 51506 var _Metamorph = _emberMetalMixin.Mixin.create({ 51507 tagName: '', 51508 __metamorphType: 'Ember._Metamorph', 51509 51510 instrumentName: 'metamorph', 51511 51512 init: function () { 51513 this._super.apply(this, arguments); 51514 _emberMetalDebug.deprecate('Supplying a tagName to Metamorph views is unreliable and is deprecated. ' + 'You may be setting the tagName on a Handlebars helper that creates a Metamorph.', !this.tagName, { id: 'ember-views.metamorph-tag-name', until: '2.4.0' }); 51515 51516 _emberMetalDebug.deprecate('Using ' + this.__metamorphType + ' is deprecated.', false, { id: 'ember-views.metamorph', until: '2.4.0' }); 51517 } 51518 }); 51519 51520 exports._Metamorph = _Metamorph; 51521 /** 51522 @class _MetamorphView 51523 @namespace Ember 51524 @extends Ember.View 51525 @uses Ember._Metamorph 51526 @private 51527 */ 51528 exports.default = _emberViewsViewsView.default.extend(_Metamorph, { 51529 __metamorphType: 'Ember._MetamorphView' 51530 }); 51531}); 51532enifed('ember-views/component_lookup', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-runtime/system/object', 'ember-htmlbars/system/lookup-helper', 'container/owner'], function (exports, _emberMetalCore, _emberMetalDebug, _emberRuntimeSystemObject, _emberHtmlbarsSystemLookupHelper, _containerOwner) { 51533 'use strict'; 51534 51535 exports.default = _emberRuntimeSystemObject.default.extend({ 51536 invalidName: function (name) { 51537 if (!_emberHtmlbarsSystemLookupHelper.CONTAINS_DASH_CACHE.get(name)) { 51538 _emberMetalDebug.assert('You cannot use \'' + name + '\' as a component name. Component names must contain a hyphen.'); 51539 return true; 51540 } 51541 }, 51542 51543 lookupFactory: function (name, owner) { 51544 owner = owner || _containerOwner.getOwner(this); 51545 51546 var fullName = 'component:' + name; 51547 var templateFullName = 'template:components/' + name; 51548 var templateRegistered = owner && owner.hasRegistration(templateFullName); 51549 51550 if (templateRegistered) { 51551 owner.inject(fullName, 'layout', templateFullName); 51552 } 51553 51554 var Component = owner._lookupFactory(fullName); 51555 51556 // Only treat as a component if either the component 51557 // or a template has been registered. 51558 if (templateRegistered || Component) { 51559 if (!Component) { 51560 owner.register(fullName, _emberMetalCore.default.Component); 51561 Component = owner._lookupFactory(fullName); 51562 } 51563 return Component; 51564 } 51565 }, 51566 51567 componentFor: function (name, owner, options) { 51568 if (this.invalidName(name)) { 51569 return; 51570 } 51571 51572 var fullName = 'component:' + name; 51573 return owner._lookupFactory(fullName, options); 51574 }, 51575 51576 layoutFor: function (name, owner, options) { 51577 if (this.invalidName(name)) { 51578 return; 51579 } 51580 51581 var templateFullName = 'template:components/' + name; 51582 return owner.lookup(templateFullName, options); 51583 } 51584 }); 51585}); 51586enifed('ember-views/components/component', ['exports', 'ember-metal/debug', 'ember-metal/environment', 'ember-runtime/mixins/target_action_support', 'ember-views/views/view', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/is_none', 'ember-metal/utils', 'ember-metal/computed', 'ember-views/compat/attrs-proxy', 'container/owner'], function (exports, _emberMetalDebug, _emberMetalEnvironment, _emberRuntimeMixinsTarget_action_support, _emberViewsViewsView, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalIs_none, _emberMetalUtils, _emberMetalComputed, _emberViewsCompatAttrsProxy, _containerOwner) { 51587 'use strict'; 51588 51589 function validateAction(component, actionName) { 51590 if (actionName && actionName[_emberViewsCompatAttrsProxy.MUTABLE_CELL]) { 51591 actionName = actionName.value; 51592 } 51593 _emberMetalDebug.assert('The default action was triggered on the component ' + component.toString() + ', but the action name (' + actionName + ') was not a string.', _emberMetalIs_none.default(actionName) || typeof actionName === 'string' || typeof actionName === 'function'); 51594 return actionName; 51595 } 51596 51597 /** 51598 @module ember 51599 @submodule ember-views 51600 */ 51601 51602 /** 51603 An `Ember.Component` is a view that is completely 51604 isolated. Properties accessed in its templates go 51605 to the view object and actions are targeted at 51606 the view object. There is no access to the 51607 surrounding context or outer controller; all 51608 contextual information must be passed in. 51609 51610 The easiest way to create an `Ember.Component` is via 51611 a template. If you name a template 51612 `components/my-foo`, you will be able to use 51613 `{{my-foo}}` in other templates, which will make 51614 an instance of the isolated component. 51615 51616 ```handlebars 51617 {{app-profile person=currentUser}} 51618 ``` 51619 51620 ```handlebars 51621 <!-- app-profile template --> 51622 <h1>{{person.title}}</h1> 51623 <img src={{person.avatar}}> 51624 <p class='signature'>{{person.signature}}</p> 51625 ``` 51626 51627 You can use `yield` inside a template to 51628 include the **contents** of any block attached to 51629 the component. The block will be executed in the 51630 context of the surrounding context or outer controller: 51631 51632 ```handlebars 51633 {{#app-profile person=currentUser}} 51634 <p>Admin mode</p> 51635 {{! Executed in the controller's context. }} 51636 {{/app-profile}} 51637 ``` 51638 51639 ```handlebars 51640 <!-- app-profile template --> 51641 <h1>{{person.title}}</h1> 51642 {{! Executed in the components context. }} 51643 {{yield}} {{! block contents }} 51644 ``` 51645 51646 If you want to customize the component, in order to 51647 handle events or actions, you implement a subclass 51648 of `Ember.Component` named after the name of the 51649 component. Note that `Component` needs to be appended to the name of 51650 your subclass like `AppProfileComponent`. 51651 51652 For example, you could implement the action 51653 `hello` for the `app-profile` component: 51654 51655 ```javascript 51656 App.AppProfileComponent = Ember.Component.extend({ 51657 actions: { 51658 hello: function(name) { 51659 console.log("Hello", name); 51660 } 51661 } 51662 }); 51663 ``` 51664 51665 And then use it in the component's template: 51666 51667 ```handlebars 51668 <!-- app-profile template --> 51669 51670 <h1>{{person.title}}</h1> 51671 {{yield}} <!-- block contents --> 51672 51673 <button {{action 'hello' person.name}}> 51674 Say Hello to {{person.name}} 51675 </button> 51676 ``` 51677 51678 Components must have a `-` in their name to avoid 51679 conflicts with built-in controls that wrap HTML 51680 elements. This is consistent with the same 51681 requirement in web components. 51682 51683 @class Component 51684 @namespace Ember
51685 @extends Ember.View 51686 @uses Ember.ViewTargetActionSupport 51687 @public 51688 */ 51689 var Component = _emberViewsViewsView.default.extend(_emberRuntimeMixinsTarget_action_support.default, { 51690 isComponent: true, 51691 /* 51692 This is set so that the proto inspection in appendTemplatedView does not 51693 think that it should set the components `context` to that of the parent view. 51694 */ 51695 controller: null, 51696 context: null, 51697 51698 instrumentName: 'component', 51699 instrumentDisplay: _emberMetalComputed.computed(function () { 51700 if (this._debugContainerKey) { 51701 return '{{' + this._debugContainerKey.split(':')[1] + '}}'; 51702 } 51703 }), 51704 51705 init: function () { 51706 var _this = this; 51707 51708 this._super.apply(this, arguments); 51709 _emberMetalProperty_set.set(this, 'controller', this); 51710 _emberMetalProperty_set.set(this, 'context', this); 51711 51712 if (!this.layout && this.layoutName && _containerOwner.getOwner(this)) { 51713 var layoutName = _emberMetalProperty_get.get(this, 'layoutName'); 51714 51715 this.layout = this.templateForName(layoutName); 51716 } 51717 51718 // If a `defaultLayout` was specified move it to the `layout` prop. 51719 // `layout` is no longer a CP, so this just ensures that the `defaultLayout` 51720 // logic is supported with a deprecation 51721 if (this.defaultLayout && !this.layout) { 51722 _emberMetalDebug.deprecate('Specifying `defaultLayout` to ' + this + ' is deprecated. Please use `layout` instead.', false, { 51723 id: 'ember-views.component.defaultLayout', 51724 until: '3.0.0', 51725 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-component-defaultlayout' 51726 }); 51727 51728 this.layout = this.defaultLayout; 51729 } 51730 51731 // If in a tagless component, assert that no event handlers are defined 51732 _emberMetalDebug.assert('You can not define a function that handles DOM events in the `' + this + '` tagless component since it doesn\'t have any DOM element.', this.tagName !== '' || !_emberMetalEnvironment.default.hasDOM || !(function () { 51733 var eventDispatcher = _containerOwner.getOwner(_this).lookup('event_dispatcher:main'); 51734 var events = eventDispatcher && eventDispatcher._finalEvents || {}; 51735 51736 for (var key in events) { 51737 var methodName = events[key]; 51738 51739 if (typeof _this[methodName] === 'function') { 51740 return true; // indicate that the assertion should be triggered 51741 } 51742 } 51743 })()); 51744 }, 51745 51746 template: null, 51747 layoutName: null, 51748 layout: null, 51749 51750 /** 51751 If the component is currently inserted into the DOM of a parent view, this 51752 property will point to the controller of the parent view. 51753 @property targetObject 51754 @type Ember.Controller 51755 @default null 51756 @private 51757 */ 51758 targetObject: _emberMetalComputed.computed('controller', function (key) { 51759 if (this._targetObject) { 51760 return this._targetObject; 51761 } 51762 if (this._controller) { 51763 return this._controller; 51764 } 51765 var parentView = _emberMetalProperty_get.get(this, 'parentView'); 51766 return parentView ? _emberMetalProperty_get.get(parentView, 'controller') : null; 51767 }), 51768 51769 /** 51770 Calls a action passed to a component. 51771 For example a component for playing or pausing music may translate click events 51772 into action notifications of "play" or "stop" depending on some internal state 51773 of the component: 51774 ```javascript 51775
51775// app/components/play-button.js 51776 export default Ember.Component.extend({ 51777 click() { 51778 if (this.get('isPlaying')) { 51779 this.sendAction('play'); 51780 } else { 51781 this.sendAction('stop'); 51782 } 51783 } 51784 }); 51785 ``` 51786 The actions "play" and "stop" must be passed to this `play-button` component: 51787 ```handlebars 51788 {{! app/templates/application.hbs }} 51789 {{play-button play=(action "musicStarted") stop=(action "musicStopped")}} 51790 ``` 51791 When the component receives a browser `click` event it translate this 51792 interaction into application-specific semantics ("play" or "stop") and 51793 calls the specified action. 51794 ```javascript 51795
51795// app/controller/application.js 51796 export default Ember.Controller.extend({ 51797 actions: { 51798 musicStarted() { 51799 // called when the play button is clicked 51800 // and the music started playing 51801 }, 51802 musicStopped() { 51803 // called when the play button is clicked 51804 // and the music stopped playing 51805 } 51806 } 51807 }); 51808 ``` 51809 If no action is passed to `sendAction` a default name of "action" 51810 is assumed. 51811 ```javascript 51812
51812// app/components/next-button.js 51813 export default Ember.Component.extend({ 51814 click() { 51815 this.sendAction(); 51816 } 51817 }); 51818 ``` 51819 ```handlebars 51820 {{! app/templates/application.hbs }} 51821 {{next-button action=(action "playNextSongInAlbum")}} 51822 ``` 51823 ```javascript 51824
51824// app/controllers/application.js 51825 App.ApplicationController = Ember.Controller.extend({ 51826 actions: { 51827 playNextSongInAlbum() { 51828 ... 51829 } 51830 } 51831 }); 51832 ``` 51833 @method sendAction 51834 @param [action] {String} the action to call 51835 @param [params] {*} arguments for the action 51836 @public 51837 */ 51838 sendAction: function (action) { 51839 for (var _len = arguments.length, contexts = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 51840 contexts[_key - 1] = arguments[_key]; 51841 } 51842 51843 var actionName; 51844 51845 // Send the default action 51846 if (action === undefined) { 51847 action = 'action'; 51848 } 51849 actionName = _emberMetalProperty_get.get(this, 'attrs.' + action) || _emberMetalProperty_get.get(this, action); 51850 actionName = validateAction(this, actionName); 51851 51852 // If no action name for that action could be found, just abort. 51853 if (actionName === undefined) { 51854 return; 51855 } 51856 51857 if (typeof actionName === 'function') { 51858 actionName.apply(undefined, contexts); 51859 } else { 51860 this.triggerAction({ 51861 action: actionName, 51862 actionContext: contexts 51863 }); 51864 } 51865 }, 51866 51867 send: function (actionName) { 51868 for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 51869 args[_key2 - 1] = arguments[_key2]; 51870 } 51871 51872 var target; 51873 var action = this.actions && this.actions[actionName]; 51874 51875 if (action) { 51876 var shouldBubble = action.apply(this, args) === true; 51877 if (!shouldBubble) { 51878 return; 51879 } 51880 } 51881 51882 if (target = _emberMetalProperty_get.get(this, 'target')) { 51883 var _target; 51884 51885 _emberMetalDebug.assert('The `target` for ' + this + ' (' + target + ') does not have a `send` method', typeof target.send === 'function'); 51886 (_target = target).send.apply(_target, arguments); 51887 } else { 51888 if (!action) { 51889 throw new Error(_emberMetalUtils.inspect(this) + ' had no action handler for: ' + actionName); 51890 } 51891 } 51892 } 51893 51894 /** 51895 Returns true when the component was invoked with a block template. 51896 Example (`hasBlock` will be `false`): 51897 ```hbs 51898 {{! templates/application.hbs }} 51899 {{foo-bar}} 51900 {{! templates/components/foo-bar.hbs }} 51901 {{#if hasBlock}} 51902 This will not be printed, because no block was provided 51903 {{/if}} 51904 ``` 51905 Example (`hasBlock` will be `true`): 51906 ```hbs 51907 {{! templates/application.hbs }} 51908 {{#foo-bar}} 51909 Hi! 51910 {{/foo-bar}} 51911 {{! templates/components/foo-bar.hbs }} 51912 {{#if hasBlock}} 51913 This will be printed because a block was provided 51914 {{yield}} 51915 {{/if}} 51916 ``` 51917 This helper accepts an argument with the name of the block we want to check the presence of. 51918 This is useful for checking for the presence of the optional inverse block in components. 51919 ```hbs 51920 {{! templates/application.hbs }} 51921 {{#foo-bar}} 51922 Hi! 51923 {{else}} 51924 What's up? 51925 {{/foo-bar}} 51926 {{! templates/components/foo-bar.hbs }} 51927 {{yield}} 51928 {{#if (hasBlock "inverse")}} 51929 {{yield to="inverse"}} 51930 {{else}} 51931 How are you? 51932 {{/if}} 51933 ``` 51934 @public 51935 @property hasBlock 51936 @param {String} [blockName="default"] The name of the block to check presence of. 51937 @returns Boolean 51938 @since 1.13.0 51939 */ 51940 51941 /** 51942 Returns true when the component was invoked with a block parameter 51943 supplied. 51944 Example (`hasBlockParams` will be `false`): 51945 ```hbs 51946 {{! templates/application.hbs }} 51947 {{#foo-bar}} 51948 No block parameter. 51949 {{/foo-bar}} 51950 {{! templates/components/foo-bar.hbs }} 51951 {{#if hasBlockParams}} 51952 This will not be printed, because no block was provided 51953 {{yield this}} 51954 {{/if}} 51955 ``` 51956 Example (`hasBlockParams` will be `true`): 51957 ```hbs 51958 {{! templates/application.hbs }} 51959 {{#foo-bar as |foo|}} 51960 Hi! 51961 {{/foo-bar}} 51962 {{! templates/components/foo-bar.hbs }} 51963 {{#if hasBlockParams}} 51964 This will be printed because a block was provided 51965 {{yield this}} 51966 {{/if}} 51967 ``` 51968 @public 51969 @property hasBlockParams 51970 @returns Boolean 51971 @since 1.13.0 51972 */ 51973 51974 /** 51975 Enables components to take a list of parameters as arguments 51976 For example a component that takes two parameters with the names 51977 `name` and `age`: 51978 ```javascript 51979 let MyComponent = Ember.Component.extend; 51980 MyComponent.reopenClass({ 51981 positionalParams: ['name', 'age'] 51982 }); 51983 ``` 51984 It can then be invoked like this: 51985 ```hbs 51986 {{my-component "John" 38}} 51987 ``` 51988 The parameters can be refered to just like named parameters: 51989 ```hbs 51990 Name: {{attrs.name}}, Age: {{attrs.age}}. 51991 ``` 51992 Using a string instead of an array allows for an arbitrary number of 51993 parameters: 51994 ```javascript 51995 let MyComponent = Ember.Component.extend; 51996 MyComponent.reopenClass({ 51997 positionalParams: 'names' 51998 }); 51999 ``` 52000 It can then be invoked like this: 52001 ```hbs 52002 {{my-component "John" "Michael" "Scott"}} 52003 ``` 52004 The parameters can then be refered to by enumerating over the list: 52005 ```hbs 52006 {{#each attrs.names as |name|}}{{name}}{{/each}} 52007 ``` 52008 @static 52009 @public 52010 @property positionalParams 52011 @since 1.13.0 52012 */ 52013 52014 /** 52015 Called when the attributes passed into the component have been updated. 52016 Called both during the initial render of a container and during a rerender. 52017 Can be used in place of an observer; code placed here will be executed 52018 every time any attribute updates. 52019 @method didReceiveAttrs 52020 @public 52021 @since 1.13.0 52022 */ 52023 52024 /** 52025 Called when the attributes passed into the component have been updated. 52026 Called both during the initial render of a container and during a rerender. 52027 Can be used in place of an observer; code placed here will be executed 52028 every time any attribute updates. 52029 @event didReceiveAttrs 52030 @public 52031 @since 1.13.0 52032 */ 52033 52034 /** 52035 Called after a component has been rendered, both on initial render and 52036 in subsequent rerenders. 52037 @method didRender 52038 @public 52039 @since 1.13.0 52040 */ 52041 52042 /** 52043 Called after a component has been rendered, both on initial render and 52044 in subsequent rerenders. 52045 @event didRender 52046 @public 52047 @since 1.13.0 52048 */ 52049 52050 /** 52051 Called before a component has been rendered, both on initial render and 52052 in subsequent rerenders. 52053 @method willRender 52054 @public 52055 @since 1.13.0 52056 */ 52057 52058 /** 52059 Called before a component has been rendered, both on initial render and 52060 in subsequent rerenders. 52061 @event willRender 52062 @public 52063 @since 1.13.0 52064 */ 52065 52066 /** 52067 Called when the attributes passed into the component have been changed. 52068 Called only during a rerender, not during an initial render. 52069 @method didUpdateAttrs 52070 @public 52071 @since 1.13.0 52072 */ 52073 52074 /** 52075 Called when the attributes passed into the component have been changed. 52076 Called only during a rerender, not during an initial render. 52077 @event didUpdateAttrs 52078 @public 52079 @since 1.13.0 52080 */ 52081 52082 /** 52083 Called when the component is about to update and rerender itself. 52084 Called only during a rerender, not during an initial render. 52085 @method willUpdate 52086 @public 52087 @since 1.13.0 52088 */ 52089 52090 /** 52091 Called when the component is about to update and rerender itself. 52092 Called only during a rerender, not during an initial render. 52093 @event willUpdate 52094 @public 52095 @since 1.13.0 52096 */ 52097 52098 /** 52099 Called when the component has updated and rerendered itself. 52100 Called only during a rerender, not during an initial render. 52101 @event didUpdate 52102 @public 52103 @since 1.13.0 52104 */ 52105 52106 /** 52107 Called when the component has updated and rerendered itself. 52108 Called only during a rerender, not during an initial render. 52109 @event didUpdate 52110 @public 52111 @since 1.13.0 52112 */ 52113 }); 52114 52115 Component.reopenClass({ 52116 isComponentFactory: true 52117 }); 52118 52119 exports.default = Component; 52120}); 52121enifed('ember-views/index', ['exports', 'ember-runtime', 'ember-views/system/jquery', 'ember-views/system/utils', 'ember-views/system/ext', 'ember-views/views/states', 'ember-metal-views', 'ember-views/views/core_view', 'ember-views/views/view', 'ember-views/views/container_view', 'ember-views/views/collection_view', 'ember-views/components/component', 'ember-views/system/event_dispatcher', 'ember-views/mixins/view_target_action_support', 'ember-views/component_lookup', 'ember-views/views/checkbox', 'ember-views/mixins/text_support', 'ember-views/views/text_field', 'ember-views/views/text_area', 'ember-views/views/select', 'ember-views/compat/metamorph_view', 'ember-views/views/legacy_each_view'], function (exports, _emberRuntime, _emberViewsSystemJquery, _emberViewsSystemUtils, _emberViewsSystemExt, _emberViewsViewsStates, _emberMetalViews, _emberViewsViewsCore_view, _emberViewsViewsView, _emberViewsViewsContainer_view, _emberViewsViewsCollection_view, _emberViewsComponentsComponent, _emberViewsSystemEvent_dispatcher, _emberViewsMixinsView_target_action_support, _emberViewsComponent_lookup, _emberViewsViewsCheckbox, _emberViewsMixinsText_support, _emberViewsViewsText_field, _emberViewsViewsText_area, _emberViewsViewsSelect, _emberViewsCompatMetamorph_view, _emberViewsViewsLegacy_each_view) { 52122 /** 52123 @module ember 52124 @submodule ember-views 52125 */ 52126 52127 // BEGIN IMPORTS 52128 'use strict'; 52129 52130 // END IMPORTS 52131 52132 /** 52133 Alias for jQuery 52134 52135 @method $ 52136 @for Ember 52137 @public 52138 */ 52139 52140 // BEGIN EXPORTS 52141 _emberRuntime.default.$ = _emberViewsSystemJquery.default; 52142 52143 _emberRuntime.default.ViewTargetActionSupport = _emberViewsMixinsView_target_action_support.default; 52144 52145 var ViewUtils = _emberRuntime.default.ViewUtils = {}; 52146 ViewUtils.isSimpleClick = _emberViewsSystemUtils.isSimpleClick; 52147 ViewUtils.getViewClientRects = _emberViewsSystemUtils.getViewClientRects; 52148 ViewUtils.getViewBoundingClientRect = _emberViewsSystemUtils.getViewBoundingClientRect; 52149 52150 if (_emberRuntime.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 52151 _emberRuntime.default.CoreView = _emberViewsViewsCore_view.DeprecatedCoreView; 52152 _emberRuntime.default.View = _emberViewsViewsView.DeprecatedView; 52153 _emberRuntime.default.View.states = _emberViewsViewsStates.states; 52154 _emberRuntime.default.View.cloneStates = _emberViewsViewsStates.cloneStates;
52155 _emberRuntime.default.View._Renderer = _emberMetalViews.Renderer; 52156 _emberRuntime.default.ContainerView = _emberViewsViewsContainer_view.DeprecatedContainerView; 52157 _emberRuntime.default.CollectionView = _emberViewsViewsCollection_view.default; 52158 } 52159 52160 _emberRuntime.default._Renderer = _emberMetalViews.Renderer; 52161 52162 _emberRuntime.default.Checkbox = _emberViewsViewsCheckbox.default; 52163 _emberRuntime.default.TextField = _emberViewsViewsText_field.default; 52164 _emberRuntime.default.TextArea = _emberViewsViewsText_area.default; 52165 52166 if (_emberRuntime.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 52167 _emberRuntime.default.Select = _emberViewsViewsSelect.Select; 52168 } 52169 52170 _emberRuntime.default.SelectOption = _emberViewsViewsSelect.SelectOption; 52171 _emberRuntime.default.SelectOptgroup = _emberViewsViewsSelect.SelectOptgroup; 52172 52173 _emberRuntime.default.TextSupport = _emberViewsMixinsText_support.default; 52174 _emberRuntime.default.ComponentLookup = _emberViewsComponent_lookup.default; 52175 _emberRuntime.default.Component = _emberViewsComponentsComponent.default; 52176 _emberRuntime.default.EventDispatcher = _emberViewsSystemEvent_dispatcher.default; 52177 52178 // Deprecated: 52179 if (_emberRuntime.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { 52180 _emberRuntime.default._Metamorph = _emberViewsCompatMetamorph_view._Metamorph; 52181 _emberRuntime.default._MetamorphView = _emberViewsCompatMetamorph_view.default; 52182 _emberRuntime.default._LegacyEachView = _emberViewsViewsLegacy_each_view.default; 52183 } 52184 52185 // END EXPORTS 52186 52187 exports.default = _emberRuntime.default; 52188}); 52189// for the side effect of extending Ember.run.queues 52190enifed('ember-views/mixins/aria_role_support', ['exports', 'ember-metal/mixin'], function (exports, _emberMetalMixin) { 52191 /** 52192 @module ember 52193 @submodule ember-views 52194 */ 52195 52196 'use strict'; 52197 52198 /** 52199 @class AriaRoleSupport 52200 @namespace Ember 52201 @private 52202 */ 52203 exports.default = _emberMetalMixin.Mixin.create({ 52204 attributeBindings: ['ariaRole:role'], 52205 52206 /** 52207 The WAI-ARIA role of the control represented by this view. For example, a 52208 button may have a role of type 'button', or a pane may have a role of 52209 type 'alertdialog'. This property is used by assistive software to help 52210 visually challenged users navigate rich web applications. 52211 The full list of valid WAI-ARIA roles is available at: 52212 [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) 52213 @property ariaRole 52214 @type String 52215 @default null 52216 @public 52217 */ 52218 ariaRole: null 52219 }); 52220}); 52221enifed('ember-views/mixins/class_names_support', ['exports', 'ember-metal/debug', 'ember-metal/mixin', 'ember-runtime/system/native_array'], function (exports, _emberMetalDebug, _emberMetalMixin, _emberRuntimeSystemNative_array) { 52222 /** 52223 @module ember 52224 @submodule ember-views 52225 */ 52226 'use strict'; 52227 52228 var EMPTY_ARRAY = []; 52229 52230 /** 52231 @class ClassNamesSupport 52232 @namespace Ember 52233 @private 52234 */ 52235 exports.default = _emberMetalMixin.Mixin.create({ 52236 concatenatedProperties: ['classNames', 'classNameBindings'], 52237 52238 init: function () { 52239 this._super.apply(this, arguments); 52240 52241 _emberMetalDebug.assert('Only arrays are allowed for \'classNameBindings\'', Array.isArray(this.classNameBindings)
52241); 52242 this.classNameBindings = _emberRuntimeSystemNative_array.A(this.classNameBindings.slice()); 52243 52244 _emberMetalDebug.assert('Only arrays of static class strings are allowed for \'classNames\'. For dynamic classes, use \'classNameBindings\'.', Array.isArray(this.classNames)); 52245 this.classNames = _emberRuntimeSystemNative_array.A(this.classNames.slice()); 52246 }, 52247 52248 /** 52249 Standard CSS class names to apply to the view's outer element. This 52250 property automatically inherits any class names defined by the view's 52251 superclasses as well. 52252 @property classNames 52253 @type Array 52254 @default ['ember-view'] 52255 @public 52256 */ 52257 classNames: ['ember-view'], 52258 52259 /** 52260 A list of properties of the view to apply as class names. If the property 52261 is a string value, the value of that string will be applied as a class 52262 name. 52263 ```javascript 52264 // Applies the 'high' class to the view element 52265 Ember.View.extend({ 52266 classNameBindings: ['priority'], 52267 priority: 'high' 52268 }); 52269 ``` 52270 If the value of the property is a Boolean, the name of that property is 52271 added as a dasherized class name. 52272 ```javascript 52273 // Applies the 'is-urgent' class to the view element 52274 Ember.View.extend({ 52275 classNameBindings: ['isUrgent'], 52276 isUrgent: true 52277 }); 52278 ``` 52279 If you would prefer to use a custom value instead of the dasherized 52280 property name, you can pass a binding like this: 52281 ```javascript 52282 // Applies the 'urgent' class to the view element 52283 Ember.View.extend({ 52284 classNameBindings: ['isUrgent:urgent'], 52285 isUrgent: true 52286 }); 52287 ``` 52288 This list of properties is inherited from the view's superclasses as well. 52289 @property classNameBindings 52290 @type Array 52291 @default [] 52292 @public 52293 */ 52294 classNameBindings: EMPTY_ARRAY 52295 }); 52296}); 52297enifed('ember-views/mixins/empty_view_support', ['exports', 'ember-metal/mixin', 'ember-views/views/view', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/computed'], function (exports, _emberMetalMixin, _emberViewsViewsView, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalComputed) { 52298 /** 52299 @module ember 52300 @submodule ember-views 52301 */ 52302 52303 'use strict'; 52304 52305 /** 52306 @class EmptyViewSupport 52307 @namespace Ember 52308 @private 52309 */ 52310 exports.default = _emberMetalMixin.Mixin.create({ 52311 /** 52312 This provides metadata about what kind of empty view class this 52313 collection would like if it is being instantiated from another 52314 system (like Handlebars) 52315 @private 52316 @property emptyViewClass 52317 */ 52318 emptyViewClass: _emberViewsViewsView.default, 52319 52320 /** 52321 An optional view to display if content is set to an empty array. 52322 @property emptyView 52323 @type Ember.View 52324 @default null 52325 @private 52326 */ 52327 emptyView: null, 52328 52329 _emptyView: _emberMetalComputed.computed('emptyView', 'attrs.emptyViewClass', 'emptyViewClass', function () { 52330 var emptyView = _emberMetalProperty_get.get(this, 'emptyView'); 52331 var attrsEmptyViewClass = this.getAttr('emptyViewClass'); 52332 var emptyViewClass = _emberMetalProperty_get.get(this, 'emptyViewClass'); 52333 var inverse = _emberMetalProperty_get.get(this, '_itemViewInverse'); 52334 var actualEmpty = emptyView || attrsEmptyViewClass; 52335 52336 // Somehow, our previous semantics differed depending on whether the 52337 // `emptyViewClass` was provided on the JavaScript class or via the 52338 // Handlebars template. 52339 // In Glimmer, we disambiguate between the two by checking first (and 52340 // preferring) the attrs-supplied class. 52341 // If not present, we fall back to the class's `emptyViewClass`, but only 52342 // if an inverse has been provided via an `{{else}}`. 52343 if (inverse && actualEmpty) { 52344 if (actualEmpty.extend) { 52345 return actualEmpty.extend({ template: inverse }); 52346 } else { 52347 _emberMetalProperty_set.set(actualEmpty, 'template', inverse); 52348 } 52349 } else if (inverse && emptyViewClass) { 52350 return emptyViewClass.extend({ template: inverse }); 52351 } 52352 52353 return actualEmpty; 52354 }) 52355 }); 52356}); 52357enifed('ember-views/mixins/instrumentation_support', ['exports', 'ember-metal/mixin', 'ember-metal/computed', 'ember-metal/property_get'], function (exports, _emberMetalMixin, _emberMetalComputed, _emberMetalProperty_get) { 52358 /** 52359 @module ember 52360 @submodule ember-views 52361 */ 52362 'use strict'; 52363 52364 /** 52365 @class InstrumentationSupport 52366 @namespace Ember 52367 @public 52368 */ 52369 var InstrumentationSupport = _emberMetalMixin.Mixin.create({ 52370 /** 52371 Used to identify this view during debugging 52372 @property instrumentDisplay
52373 @type String 52374 @public 52375 */ 52376 instrumentDisplay: _emberMetalComputed.computed(function () { 52377 if (this.helperName) { 52378 return '{{' + this.helperName + '}}'; 52379 } 52380 }), 52381 52382 instrumentName: 'view', 52383 52384 instrumentDetails: function (hash) { 52385 hash.template = _emberMetalProperty_get.get(this, 'templateName'); 52386 this._super(hash); 52387 } 52388 }); 52389 52390 exports.default = InstrumentationSupport; 52391}); 52392enifed('ember-views/mixins/legacy_child_views_support', ['exports', 'ember-metal/mixin', 'ember-metal/property_get', 'ember-metal/property_set', 'container/owner'], function (exports, _emberMetalMixin, _emberMetalProperty_get, _emberMetalProperty_set, _containerOwner) { 52393 'use strict'; 52394 52395 exports.default = _emberMetalMixin.Mixin.create({ 52396 linkChild: function (instance) { 52397 if (!instance[_containerOwner.OWNER]) { 52398 _containerOwner.setOwner(instance, _containerOwner.getOwner(this)); 52399 } 52400 52401 if (_emberMetalProperty_get.get(instance, 'parentView') !== this) { 52402 // linkChild should be idempotent 52403 _emberMetalProperty_set.set(instance, 'parentView', this); 52404 instance.trigger('parentViewDidChange'); 52405 } 52406 instance.ownerView = this.ownerView; 52407 }, 52408 52409 unlinkChild: function (instance) { 52410 _emberMetalProperty_set.set(instance, 'parentView', null); 52411 instance.trigger('parentViewDidChange'); 52412 } 52413 }); 52414}); 52415enifed('ember-views/mixins/legacy_view_support', ['exports', 'ember-metal/debug', 'ember-metal/mixin', 'ember-metal/property_get'], function (exports, _emberMetalDebug, _emberMetalMixin, _emberMetalProperty_get) { 52416 /** 52417 @module ember 52418 @submodule ember-views 52419 */ 52420 'use strict'; 52421 52422 /** 52423 @class LegacyViewSupport 52424 @namespace Ember 52425 @private 52426 */ 52427 var LegacyViewSupport = _emberMetalMixin.Mixin.create({ 52428 beforeRender: function (buffer) {}, 52429 52430 afterRender: function (buffer) {}, 52431 52432 mutateChildViews: function (callback) { 52433 var childViews = _emberMetalProperty_get.get(this, 'childViews'); 52434 var idx = childViews.length; 52435 var view; 52436 52437 while (--idx >= 0) { 52438 view = childViews[idx]; 52439 callback(this, view, idx); 52440 } 52441 52442 return this; 52443 }, 52444 52445 /** 52446 Removes all children from the `parentView`. 52447 @method removeAllChildren 52448 @return {Ember.View} receiver 52449 @private 52450 */ 52451 removeAllChildren: function () { 52452 return this.mutateChildViews(function (parentView, view) { 52453 parentView.removeChild(view); 52454 }); 52455 }, 52456 52457 destroyAllChildren: function () { 52458 return this.mutateChildViews(function (parentView, view) { 52459 view.destroy(); 52460 }); 52461 }, 52462 52463 /** 52464 Return the nearest ancestor whose parent is an instance of 52465 `klass`. 52466 @method nearestChildOf 52467 @param {Class} klass Subclass of Ember.View (or Ember.View itself) 52468 @return Ember.View 52469 @deprecated 52470 @private 52471 */ 52472 nearestChildOf: function (klass) { 52473 _emberMetalDebug.deprecate('nearestChildOf has been deprecated.', false, { id: 'ember-views.nearest-child-of', until: '3.0.0' }); 52474 52475 var view = _emberMetalProperty_get.get(this, 'parentView'); 52476 52477 while (view) { 52478 if (_emberMetalProperty_get.get(view, 'parentView') instanceof klass) { 52479 return view; 52480 } 52481 view = _emberMetalProperty_get.get(view, 'parentView'); 52482 } 52483 }, 52484 52485 /** 52486 Return the nearest ancestor that is an instance of the provided 52487 class. 52488 @method nearestInstanceOf 52489 @param {Class} klass Subclass of Ember.View (or Ember.View itself) 52490 @return Ember.View 52491 @deprecated 52492 @private 52493 */ 52494 nearestInstanceOf: function (klass) { 52495 _emberMetalDebug.deprecate('nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType.', false, { id: 'ember-views.nearest-instance-of', until: '3.0.0' }); 52496 52497 var view = _emberMetalProperty_get.get(this, 'parentView'); 52498 52499 while (view) { 52500 if (view instanceof klass) { 52501 return view; 52502 } 52503 view = _emberMetalProperty_get.get(view, 'parentView'); 52504 } 52505 }, 52506 52507 /** 52508 If a value that affects template rendering changes, the view should be 52509 re-rendered to reflect the new value.
52510 @method _contextDidChange 52511 @private 52512 @private 52513 */ 52514 _contextDidChange: _emberMetalMixin.observer('context', function () { 52515 this.rerender(); 52516 }) 52517 }); 52518 52519 exports.default = LegacyViewSupport; 52520}); 52521enifed('ember-views/mixins/template_rendering_support', ['exports', 'ember-metal/mixin'], function (exports, _emberMetalMixin) { 52522 /** 52523 @module ember 52524 @submodule ember-views 52525 */ 52526 'use strict'; 52527 52528 // Circular dep 52529 var _renderView; 52530 52531 /** 52532 @class TemplateRenderingSupport 52533 @namespace Ember 52534 @private 52535 */ 52536 var TemplateRenderingSupport = _emberMetalMixin.Mixin.create({ 52537 /** 52538 Called on your view when it should push strings of HTML into a 52539 `Ember.RenderBuffer`. Most users will want to override the `template` 52540 or `templateName` properties instead of this method. 52541 By default, `Ember.View` will look for a function in the `template` 52542 property and invoke it with the value of `context`. The value of 52543 `context` will be the view's controller unless you overri
52543de it. 52544 @method renderBlock 52545 @param {Ember.RenderBuffer} buffer The render buffer 52546 @private 52547 */ 52548 52549 renderBlock: function (block, renderNode) { 52550 if (_renderView === undefined) { 52551 _renderView = require('ember-htmlbars/system/render-view'); 52552 } 52553 52554 return _renderView.renderHTMLBarsBlock(this, block, renderNode); 52555 } 52556 }); 52557 52558 exports.default = TemplateRenderingSupport; 52559}); 52560enifed('ember-views/mixins/text_support', ['exports', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/mixin', 'ember-runtime/mixins/target_action_support'], function (exports, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalMixin, _emberRuntimeMixinsTarget_action_support) { 52561 /** 52562 @module ember 52563 @submodule ember-views 52564 */ 52565 52566 'use strict'; 52567 52568 var KEY_EVENTS = { 52569 13: 'insertNewline', 52570 27: 'cancel' 52571 }; 52572 52573 /** 52574 `TextSupport` is a shared mixin used by both `Ember.TextField` and 52575 `Ember.TextArea`. `TextSupport` adds a number of methods that allow you to 52576 specify a controller action to invoke when a certain event is fired on your 52577 text field or textarea. The specifed controller action would get the current 52578 value of the field passed in as the only argument unless the value of 52579 the field is empty. In that case, the instance of the field itself is passed 52580 in as the only argument. 52581 52582 Let's use the pressing of the escape key as an example. If you wanted to 52583 invoke a controller action when a user presses the escape key while on your 52584 field, you would use the `escape-press` attribute on your field like so: 52585 52586 ```handlebars 52587 {{! application.hbs}} 52588 52589 {{input escape-press='alertUser'}} 52590 ``` 52591 52592 ```javascript 52593 App = Ember.Application.create(); 52594 52595 App.ApplicationController = Ember.Controller.extend({ 52596 actions: { 52597 alertUser: function ( currentValue ) { 52598 alert( 'escape pressed, current value: ' + currentValue ); 52599 } 52600 } 52601 }); 52602 ``` 52603 52604 The following chart is a visual representation of what takes place when the 52605 escape key is pressed in this scenario: 52606 52607 ``` 52608 The Template 52609 +---------------------------+ 52610 | | 52611 | escape-press='alertUser' | 52612 | | TextSupport Mixin 52613 +----+----------------------+ +-------------------------------+ 52614 | | cancel method | 52615 | escape button pressed | | 52616 +-------------------------------> | checks for the `escape-press` | 52617 | attribute and pulls out the | 52618 +-------------------------------+ | `alertUser` value | 52619 | action name 'alertUser' +-------------------------------+ 52620 | sent to controller 52621 v 52622 Controller 52623 +------------------------------------------ + 52624 | | 52625 | actions: { | 52626 | alertUser: function( currentValue ){ | 52627 | alert( 'the esc key was pressed!' ) | 52628 | } | 52629 | } | 52630 | | 52631 +-------------------------------------------+ 52632 ``` 52633 52634 Here are the events that we currently support along with the name of the 52635 attribute you would need to use on your field. To reiterate, you would use the 52636 attribute name like so: 52637 52638 ```handlebars 52639 {{input attribute-name='controllerAction'}} 52640 ``` 52641 52642 ``` 52643 +--------------------+----------------+ 52644 | | | 52645 | event | attribute name | 52646 +--------------------+----------------+ 52647 | new line inserted | insert-newline | 52648 | | | 52649 | enter key pressed | insert-newline | 52650 | | | 52651 | cancel key pressed | escape-press | 52652 | | | 52653 | focusin | focus-in | 52654 | | | 52655 | focusout | focus-out | 52656 | | | 52657 | keypress | key-press | 52658 | | | 52659 | keyup | key-up | 52660 | | | 52661 | keydown | key-down | 52662 +--------------------+----------------+ 52663 ``` 52664 52665 @class TextSupport 52666 @namespace Ember 52667 @uses Ember.TargetActionSupport
52668 @extends Ember.Mixin 52669 @private 52670 */ 52671 var TextSupport = _emberMetalMixin.Mixin.create(_emberRuntimeMixinsTarget_action_support.default, { 52672 value: '', 52673 52674 attributeBindings: ['autocapitalize', 'autocorrect', 'autofocus', 'disabled', 'form', 'maxlength', 'placeholder', 'readonly', 'required', 'selectionDirection', 'spellcheck', 'tabindex', 'title'], 52675 placeholder: null, 52676 disabled: false, 52677 maxlength: null, 52678 52679 init: function () { 52680 this._super.apply(this, arguments); 52681 this.on('paste', this, this._elementValueDidChange); 52682 this.on('cut', this, this._elementValueDidChange); 52683 this.on('input', this, this._elementValueDidChange); 52684 }, 52685 52686 /** 52687 The action to be sent when the user presses the return key. 52688 This is similar to the `{{action}}` helper, but is fired when 52689 the user presses the return key when editing a text field, and sends 52690 the value of the field as the context. 52691 @property action 52692 @type String 52693 @default null 52694 @private 52695 */ 52696 action: null, 52697 52698 /** 52699 The event that should send the action. 52700 Options are: 52701 * `enter`: the user pressed enter 52702 * `keyPress`: the user pressed a key 52703 @property onEvent 52704 @type String 52705 @default enter 52706 @private 52707 */ 52708 onEvent: 'enter', 52709 52710 /** 52711 Whether the `keyUp` event that triggers an `action` to be sent continues 52712 propagating to other views. 52713 By default, when the user presses the return key on their keyboard and 52714 the text field has an `action` set, the action will be sent to the view's 52715 controller and the key event will stop propagating. 52716 If you would like parent views to receive the `keyUp` event even after an 52717 action has been dispatched, set `bubbles` to true. 52718 @property bubbles 52719 @type Boolean 52720 @default false 52721 @private 52722 */ 52723 bubbles: false, 52724 52725 interpretKeyEvents: function (event) { 52726 var map = KEY_EVENTS; 52727 var method = map[event.keyCode]; 52728 52729 this._elementValueDidChange(); 52730 if (method) { 52731 return this[method](event); 52732 } 52733 }, 52734 52735 _elementValueDidChange: function () { 52736 // Using readDOMAttr will ensure that HTMLBars knows the last 52737 // value. 52738 _emberMetalProperty_set.set(this, 'value', this.readDOMAttr('value')); 52739 }, 52740 52741 change: function (event) { 52742 this._elementValueDidChange(event); 52743 }, 52744 52745 /** 52746 Allows you to specify a controller action to invoke when either the `enter` 52747 key is pressed or, in the case of the field being a textarea, when a newline 52748 is inserted. To use this method, give your field an `insert-newline` 52749 attribute. The value of that attribute should be the name of the action 52750 in your controller that you wish to invoke. 52751 For an example on how to use the `insert-newline` attribute, please 52752 reference the example near the top of this file. 52753 @method insertNewline 52754 @param {Event} event 52755 @private 52756 */ 52757 insertNewline: function (event) { 52758 sendAction('enter', this, event); 52759 sendAction('insert-newline', this, event); 52760 }, 52761 52762 /** 52763 Allows you to specify a controller action to invoke when the escape button 52764 is pressed. To use this method, give your field an `escape-press` 52765 attribute. The value of that attribute should be the name of the action 52766 in your controller that you wish to invoke. 52767 For an example on how to use the `escape-press` attribute, please reference 52768 the example near the top of this file. 52769 @method cancel 52770 @param {Event} event 52771 @private 52772 */ 52773 cancel: function (event) { 52774 sendAction('escape-press', this, event); 52775 }, 52776 52777 /** 52778 Allows you to specify a controller action to invoke when a field receives 52779 focus. To use this method, give your field a `focus-in` attribute. The value 52780 of that attribute should be the name of the action in your controller 52781 that you wish to invoke. 52782 For an example on how to use the `focus-in` attribute, please reference the 52783 example near the top of this file.
52784 @method focusIn 52785 @param {Event} event 52786 @private 52787 */ 52788 focusIn: function (event) { 52789 sendAction('focus-in', this, event); 52790 }, 52791 52792 /** 52793 Allows you to specify a controller action to invoke when a field loses 52794 focus. To use this method, give your field a `focus-out` attribute. The value 52795 of that attribute should be the name of the action in your controller 52796 that you wish to invoke. 52797 For an example on how to use the `focus-out` attribute, please reference the 52798 example near the top of this file. 52799 @method focusOut 52800 @param {Event} event 52801 @private 52802 */ 52803 focusOut: function (event) { 52804 this._elementValueDidChange(event); 52805 sendAction('focus-out', this, event); 52806 }, 52807 52808 /** 52809 Allows you to specify a controller action to invoke when a key is pressed. 52810 To use this method, give your field a `key-press` attribute. The value of 52811 that attribute should be the name of the action in your controller you 52812 that wish to invoke. 52813 For an example on how to use the `key-press` attribute, please reference the 52814 example near the top of this file. 52815 @method keyPress 52816 @param {Event} event 52817 @private 52818 */ 52819 keyPress: function (event) { 52820 sendAction('key-press', this, event); 52821 }, 52822 52823 /** 52824 Allows you to specify a controller action to invoke when a key-up event is 52825 fired. To use this method, give your field a `key-up` attribute. The value 52826 of that attribute should be the name of the action in your controller 52827 that you wish to invoke. 52828 For an example on how to use the `key-up` attribute, please reference the 52829 example near the top of this file. 52830 @method keyUp 52831 @param {Event} event 52832 @private 52833 */ 52834 keyUp: function (event) { 52835 this.interpretKeyEvents(event); 52836 52837 this.sendAction('key-up', _emberMetalProperty_get.get(this, 'value'), event); 52838 }, 52839 52840 /** 52841 Allows you to specify a controller action to invoke when a key-down event is 52842 fired. To use this method, give your field a `key-down` attribute. The value 52843 of that attribute should be the name of the action in your controller that 52844 you wish to invoke. 52845 For an example on how to use the `key-down` attribute, please reference the 52846 example near the top of this file. 52847 @method keyDown 52848 @param {Event} event 52849 @private 52850 */ 52851 keyDown: function (event) { 52852 this.sendAction('key-down', _emberMetalProperty_get.get(this, 'value'), event); 52853 } 52854 }); 52855 52856 // In principle, this shouldn't be necessary, but the legacy 52857 // sendAction semantics for TextField are different from 52858 // the component semantics so this method normalizes them. 52859 function sendAction(eventName, view, event) { 52860 var action = _emberMetalProperty_get.get(view, 'attrs.' + eventName) || _emberMetalProperty_get.get(view, eventName); 52861 var on = _emberMetalProperty_get.get(view, 'onEvent'); 52862 var value = _emberMetalProperty_get.get(view, 'value'); 52863 52864 // back-compat support for keyPress as an event name even though 52865 // it's also a method name that consumes the event (and therefore 52866 // incompatible with sendAction semantics). 52867 if (on === eventName || on === 'keyPress' && eventName === 'key-press') { 52868 view.sendAction('action', value); 52869 } 52870 52871 view.sendAction(eventName, value); 52872 52873 if (action || on === eventName) { 52874 if (!_emberMetalProperty_get.get(view, 'bubbles')) { 52875 event.stopPropagation(); 52876 } 52877 } 52878 } 52879 52880 exports.default = TextSupport; 52881}); 52882enifed('ember-views/mixins/view_child_views_support', ['exports', 'ember-metal/debug', 'ember-metal/mixin', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/set_properties', 'ember-runtime/system/native_array', 'container/owner'], function (exports, _emberMetalDebug, _emberMetalMixin, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalSet_properties, _emberRuntimeSystemNative_array, _containerOwner) { 52883 /** 52884 @module ember 52885 @submodule ember-views 52886 */ 52887 'use strict'; 52888 52889 var EMPTY_ARRAY = []; 52890 52891 exports.default = _emberMetalMixin.Mixin.create({ 52892 /** 52893 Array of child views. You should never edit this array directly. 52894 Instead, use `appendChild` and `removeFromParent`. 52895 @property childViews 52896 @type Array 52897 @default [] 52898 @private 52899 */ 52900 childViews: EMPTY_ARRAY, 52901 52902 init: function () { 52903 this._super.apply(this, arguments); 52904 52905 // setup child views. be sure to clone the child views array first
52906 // 2.0TODO: Remove Ember.A() here 52907 this.childViews = _emberRuntimeSystemNative_array.A(this.childViews.slice()); 52908 this.ownerView = this.ownerView || this; 52909 }, 52910 52911 appendChild: function (view) { 52912 this.linkChild(view); 52913 this.childViews.push(view); 52914 }, 52915 52916 destroyChild: function (view) { 52917 view.destroy(); 52918 }, 52919 52920 /** 52921 Removes the child view from the parent view. 52922 @method removeChild 52923 @param {Ember.View} view 52924 @return {Ember.View} receiver 52925 @private 52926 */ 52927 removeChild: function (view) { 52928 // If we're destroying, the entire subtree will be 52929 // freed, and the DOM will be handled separately, 52930 // so no need to mess with childViews. 52931 if (this.isDestroying) { 52932 return; 52933 } 52934 52935 // update parent node 52936 this.unlinkChild(view); 52937 52938 // remove view from childViews array. 52939 var childViews = _emberMetalProperty_get.get(this, 'childViews'); 52940 52941 var index = childViews.indexOf(view); 52942 if (index !== -1) { 52943 childViews.splice(index, 1); 52944 } 52945 52946 return this; 52947 }, 52948 52949 /** 52950 Instantiates a view to be added to the childViews array during view 52951 initialization. You generally will not call this method directly unless 52952 you are overriding `createChildViews()`. Note that this method will 52953 automatically configure the correct settings on the new view instance to 52954 act as a child of the parent. 52955 @method createChildView 52956 @param {Class|String} viewClass 52957 @param {Object} [attrs] Attributes to add 52958 @return {Ember.View} new instance 52959 @private 52960 */ 52961 createChildView: function (maybeViewClass) { 52962 var attrs = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 52963 52964 if (!maybeViewClass) { 52965 throw new TypeError('createChildViews first argument must exist'); 52966 } 52967 52968 var owner = _containerOwner.getOwner(this); 52969 52970 if (maybeViewClass.isView && maybeViewClass.parentView === this && _containerOwner.getOwner(maybeViewClass) === owner) { 52971 return maybeViewClass; 52972 } 52973 52974 var view; 52975 52976 attrs.parentView = this; 52977 attrs.renderer = this.renderer; 52978 attrs._viewRegistry = this._viewRegistry; 52979 52980 if (maybeViewClass.isViewFactory) { 52981 _containerOwner.setOwner(attrs, owner); 52982 52983 view = maybeViewClass.create(attrs); 52984 52985 if (view.viewName) { 52986 _emberMetalProperty_set.set(this, view.viewName, view); 52987 } 52988 } else if ('string' === typeof maybeViewClass) { 52989 var fullName = 'view:' + maybeViewClass; 52990 var ViewKlass = owner._lookupFactory(fullName); 52991 52992 _emberMetalDebug.assert('Could not find view: \'' + fullName + '\'', !!ViewKlass); 52993 52994 view = ViewKlass.create(attrs); 52995 } else { 52996 view = maybeViewClass; 52997 _emberMetalDebug.assert('You must pass instance or subclass of View', view.isView); 52998 52999 _containerOwner.setOwner(attrs, owner); 53000 _emberMetalSet_properties.default(view, attrs); 53001 } 53002 53003 this.linkChild(view); 53004 53005 return view; 53006 }, 53007 53008 linkChild: function (instance) { 53009 if (!instance[_containerOwner.OWNER]) { 53010 _containerOwner.setOwner(instance, _containerOwner.getOwner(this)); 53011 } 53012 53013 instance.parentView = this; 53014 instance.ownerView = this.ownerView; 53015 }, 53016 53017 unlinkChild: function (instance) { 53018 instance.parentView = null; 53019 } 53020 }); 53021}); 53022enifed('ember-views/mixins/view_context_support', ['exports', 'ember-metal/mixin', 'ember-metal/computed', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-views/mixins/legacy_view_support', 'ember-metal/events'], function (exports, _emberMetalMixin, _emberMetalComputed, _emberMetalProperty_get, _emberMetalProperty_set, _emberViewsMixinsLegacy_view_support, _emberMetalEvents) { 53023 /** 53024 @module ember 53025 @submodule ember-views 53026 */ 53027 'use strict'; 53028 53029 var ViewContextSupport = _emberMetalMixin.Mixin.create(_emberViewsMixinsLegacy_view_support.default, { 53030 /** 53031 The object from which templates should access properties. 53032 This object will be passed to the template function each time the render 53033 method is called, but it is up to the individual function to decide what 53034 to do with it. 53035 By default, this will be the view's controller. 53036 @property context 53037 @type Object 53038 @private 53039 */ 53040 context: _emberMetalComputed.computed({ 53041 get: function () { 53042 return _emberMetalProperty_get.get(this, '_context'); 53043 }, 53044 set: function (key, value) { 53045 _emberMetalProperty_set.set(this, '_context', value); 53046 return value; 53047 } 53048 }), 53049 53050 /** 53051 Private copy of the view's template context. This can be set directly 53052 by Handlebars without triggering the observer that causes the view 53053 to be re-rendered. 53054 The context of a view is looked up as follows: 53055 1. Supplied context (usually by Handlebars) 53056 2. Specified controller 53057 3. `parentView`'s context (for a child of a ContainerView) 53058 The code in Handlebars that overrides the `_context` property first 53059 checks to see whether the view has a specified controller. This is 53060 something of a hack and should be revisited. 53061 @property _context 53062 @private 53063 */ 53064 _context: _emberMetalComputed.computed({ 53065 get: function () { 53066 var parentView, controller; 53067 53068 if (controller = _emberMetalProperty_get.get(this, 'controller')) { 53069 return controller; 53070 } 53071 53072 parentView = this.parentView; 53073 if (parentView) { 53074 return _emberMetalProperty_get.get(parentView, '_context'); 53075 } 53076 return null; 53077 }, 53078 set: function (key, value) { 53079 return value; 53080 } 53081 }), 53082 53083 _controller: null, 53084 53085 /** 53086 The controller managing this view. If this property is set, it will be 53087 made available for use by the template. 53088 @property controller 53089 @type Object 53090 @private 53091 */ 53092 controller: _emberMetalComputed.computed({ 53093 get: function () { 53094 if (this._controller) { 53095 return this._controller; 53096 } 53097 53098 return this.parentView ? _emberMetalProperty_get.get(this.parentView, 'controller') : null; 53099 }, 53100 set: function (_, value) { 53101 this._controller = value; 53102 return value; 53103 } 53104 }), 53105 53106 _legacyControllerDidChange: _emberMetalMixin.observer('controller', function () { 53107 this.childViews.forEach(function (view) { 53108 return view.notifyPropertyChange('controller'); 53109 }); 53110 }), 53111 53112 _notifyControllerChange: _emberMetalEvents.on('parentViewDidChange', function () { 53113 this.notifyPropertyChange('controller'); 53114 }) 53115 }); 53116 53117 exports.default = ViewContextSupport; 53118}); 53119enifed('ember-views/mixins/view_state_support', ['exports', 'ember-metal/debug', 'ember-metal/mixin'], function (exports, _emberMetalDebug, _emberMetalMixin) { 53120 'use strict'; 53121 53122 var ViewStateSupport = _emberMetalMixin.Mixin.create({ 53123 transitionTo: function (state) { 53124 _emberMetalDebug.deprecate('Ember.View#transitionTo has been deprecated, it is for internal use only', false, { id: 'ember-views.view-transition-to', until: '2.4.0' }); 53125 this._transitionTo(state); 53126 }, 53127 53128 _transitionTo: function (state) { 53129 var priorState = this._currentState; 53130 var currentState = this._currentState = this._states[state]; 53131 this._state = state; 53132 53133 if (priorState && priorState.exit) { 53134 priorState.exit(this); 53135 } 53136 if (currentState.enter) { 53137 currentState.enter(this); 53138 } 53139 } 53140 }); 53141 53142 exports.default = ViewStateSupport; 53143}); 53144enifed('ember-views/mixins/view_support', ['exports', 'ember-metal/debug', 'ember-metal/error', 'ember-metal/property_get', 'ember-metal/run_loop', 'ember-metal/observer', 'ember-metal/utils', 'ember-metal/computed', 'ember-metal/mixin', 'ember-runtime/system/core_object', 'ember-metal/features', 'ember-metal/symbol', 'container/owner', 'ember-views/system/jquery'], function (exports, _emberMetalDebug, _emberMetalError, _emberMetalProperty_get, _emberMetalRun_loop, _emberMetalObserver, _emberMetalUtils, _emberMetalComputed, _emberMetalMixin, _emberRuntimeSystemCore_object, _emberMetalFeatures, _emberMetalSymbol, _containerOwner, _emberViewsSystemJquery) { 53145 'use strict'; 53146 53147 var _Mixin$create; 53148 53149 var INIT_WAS_CALLED = _emberMetalSymbol.default('INIT_WAS_CALLED'); 53150 53151 function K() { 53152 return this; 53153 } 53154 53155 exports.default = _emberMetalMixin.Mixin.create((_Mixin$create = { 53156 concatenatedProperties: ['attributeBindings'], 53157 53158 /** 53159 @property isView 53160 @type Boolean 53161 @default true 53162 @static 53163 @private 53164 */ 53165 isView: true, 53166 53167 // .......................................................... 53168 // TEMPLATE SUPPORT 53169 // 53170 53171 /** 53172 The name of the template to lookup if no template is provided. 53173 By default `Ember.View` will lookup a template with this name in 53174 `Ember.TEMPLATES` (a shared global object). 53175 @property templateName
53176 @type String 53177 @default null 53178 @private 53179 */ 53180 templateName: null, 53181 53182 /** 53183 The name of the layout to lookup if no layout is provided. 53184 By default `Ember.View` will lookup a template with this name in 53185 `Ember.TEMPLATES` (a shared global object). 53186 @property layoutName 53187 @type String 53188 @default null 53189 @private 53190 */ 53191 layoutName: null, 53192 53193 /** 53194 The template used to render the view. This should be a function that 53195 accepts an optional context parameter and returns a string of HTML that 53196 will be inserted into the DOM relative to its parent view. 53197 In general, you should set the `templateName` property instead of setting 53198 the template yourself. 53199 @property template 53200 @type Function 53201 @private 53202 */ 53203 template: _emberMetalComputed.computed({ 53204 get: function () { 53205 var templateName = _emberMetalProperty_get.get(this, 'templateName'); 53206 var template = this.templateForName(templateName, 'template'); 53207 _emberMetalDebug.assert('You specified the templateName ' + templateName + ' for ' + this + ', but it did not exist.', !templateName || !!template); 53208 return template || _emberMetalProperty_get.get(this, 'defaultTemplate'); 53209 }, 53210 set: function (key, value) { 53211 if (value !== undefined) { 53212 return value; 53213 } 53214 return _emberMetalProperty_get.get(this, key); 53215 } 53216 }), 53217 53218 /** 53219 A view may contain a layout. A layout is a regular template but 53220 supersedes the `template` property during rendering. It is the 53221 responsibility of the layout template to retrieve the `template` 53222 property from the view (or alternatively, call `Handlebars.helpers.yield`, 53223 `{{yield}}`) to render it in the correct location. 53224 This is useful for a view that has a shared wrapper, but which delegates 53225 the rendering of the contents of the wrapper to the `template` property 53226 on a subclass. 53227 @property layout 53228 @type Function 53229 @private 53230 */ 53231 layout: _emberMetalComputed.computed({ 53232 get: function (key) { 53233 var layoutName = _emberMetalProperty_get.get(this, 'layoutName'); 53234 var layout = this.templateForName(layoutName, 'layout'); 53235 53236 _emberMetalDebug.assert('You specified the layoutName ' + layoutName + ' for ' + this + ', but it did not exist.', !layoutName || !!layout); 53237 53238 return layout || _emberMetalProperty_get.get(this, 'defaultLayout'); 53239 }, 53240 53241 set: function (key, value) { 53242 return value; 53243 } 53244 }), 53245 53246 templateForName: function (name, type) { 53247 if (!name) { 53248 return; 53249 } 53250 _emberMetalDebug.assert('templateNames are not allowed to contain periods: ' + name, name.indexOf('.') === -1); 53251 53252 var owner = _containerOwner.getOwner(this); 53253 53254 if (!owner) { 53255 throw new _emberMetalError.default('Container was not found when looking up a views template. ' + 'This is most likely due to manually instantiating an Ember.View. ' + 'See: http://git.io/EKPpnA'); 53256 } 53257 53258 return owner.lookup('template:' + name); 53259 }, 53260 53261 /** 53262 Return the nearest ancestor that is an instance of the provided 53263 class or mixin. 53264 @method nearestOfType 53265 @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), 53266 or an instance of Ember.Mixin. 53267 @return Ember.View 53268 @private 53269 */ 53270 nearestOfType: function (klass) { 53271 var view = _emberMetalProperty_get.get(this, 'parentView'); 53272 var isOfType = klass instanceof _emberMetalMixin.Mixin ? function (view) { 53273 return klass.detect(view); 53274 } : function (view) { 53275 return klass.detect(view.constructor); 53276 }; 53277 53278 while (view) { 53279 if (isOfType(view)) { 53280 return view; 53281 } 53282 view = _emberMetalProperty_get.get(view, 'parentView'); 53283 } 53284 }, 53285 53286 /** 53287 Return the nearest ancestor that has a given property. 53288 @method nearestWithProperty 53289 @param {String} property A property name 53290 @return Ember.View 53291 @private 53292 */ 53293 nearestWithProperty: function (property) { 53294 var view = _emberMetalProperty_get.get(this, 'parentView'); 53295 53296 while (view) { 53297 if (property in view) { 53298 return view; 53299 } 53300 view = _emberMetalProperty_get.get(view, 'parentView'); 53301 } 53302 }, 53303 53304 /** 53305 Renders the view again. This will work regardless of whether the 53306 view is already in the DOM or not. If the view is in the DOM, the 53307 rendering process will be deferred to give bindings a chance 53308 to synchronize. 53309 If children were added during the rendering process using `appendChild`, 53310 `rerender` will remove them, because they will be added again 53311 if needed by the next `render`. 53312 In general, if the display of your view changes, you should modify 53313 the DOM element directly instead of manually calling `rerender`, which can 53314 be slow. 53315 @method rerender 53316 @public 53317 */ 53318 rerender: function () { 53319 return this._currentState.rerender(this); 53320 }, 53321 53322 // .......................................................... 53323 // ELEMENT SUPPORT 53324 // 53325 53326 /** 53327 Returns the current DOM element for the view. 53328 @property element 53329 @type DOMElement 53330 @public 53331 */ 53332 element: null, 53333 53334 /** 53335 Returns a jQuery object for this view's element. If you pass in a selector
53336 string, this method will return a jQuery object, using the current element 53337 as its buffer. 53338 For example, calling `view.$('li')` will return a jQuery object containing 53339 all of the `li` elements inside the DOM element of this view. 53340 @method $ 53341 @param {String} [selector] a jQuery-compatible selector string 53342 @return {jQuery} the jQuery object for the DOM node 53343 @public 53344 */ 53345 $: function (sel) { 53346 _emberMetalDebug.assert('You cannot access this.$() on a component with `tagName: \'\'` specified.', this.tagName !== ''); 53347 return this._currentState.$(this, sel); 53348 }, 53349 53350 forEachChildView: function (callback) { 53351 var childViews = this.childViews; 53352 53353 if (!childViews) { 53354 return this; 53355 } 53356 53357 var len = childViews.length; 53358 var view, idx; 53359 53360 for (idx = 0; idx < len; idx++) { 53361 view = childViews[idx]; 53362 callback(view); 53363 } 53364 53365 return this; 53366 }, 53367 53368 /** 53369 Appends the view's element to the specified parent element. 53370 If the view does not have an HTML representation yet, `createElement()` 53371 will be called automatically. 53372 Note that this method just schedules the view to be appended; the DOM 53373 element will not be appended to the given element until all bindings have 53374 finished synchronizing. 53375 This is not typically a function that you will need to call directly when 53376 building your application. You might consider using `Ember.ContainerView` 53377 instead. If you do need to use `appendTo`, be sure that the target element 53378 you are providing is associated with an `Ember.Application` and does not 53379 have an ancestor element that is associated with an Ember view. 53380 @method appendTo 53381 @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object 53382 @return {Ember.View} receiver 53383 @private 53384 */ 53385 appendTo: function (selector) { 53386 var $ = this._environment ? this._environment.options.jQuery : _emberViewsSystemJquery.default; 53387 53388 if ($) { 53389 var target = $(selector); 53390 53391 _emberMetalDebug.assert('You tried to append to (' + selector + ') but that isn\'t in the DOM', target.length > 0); 53392 _emberMetalDebug.assert('You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.', !target.is('.ember-view') && !target.parents().is('.ember-view')); 53393 53394 this.renderer.appendTo(this, target[0]); 53395 } else { 53396 var target = selector; 53397 53398 _emberMetalDebug.assert('You tried to append to a selector string (' + selector + ') in an environment without jQuery', typeof target !== 'string'); 53399 _emberMetalDebug.assert('You tried to append to a non-Element (' + selector + ') in an environment without jQuery', typeof selector.appendChild === 'function'); 53400 53401 this.renderer.appendTo(this, target); 53402 } 53403 53404 return this; 53405 }, 53406 53407 /** 53408 @private 53409 Creates a new DOM element, renders the view into it, then returns the 53410 element. 53411 By default, the element created and rendered into will be a `BODY` element, 53412 since this is the default context that views are rendered into when being 53413 inserted directly into the DOM. 53414 ```js 53415 var element = view.renderToElement(); 53416 element.tagName; // => "BODY" 53417 ``` 53418 You can override the kind of element rendered into and returned by 53419 specifying an optional tag name as the first argument. 53420 ```js 53421 var element = view.renderToElement('table'); 53422 element.tagName; // => "TABLE" 53423 ``` 53424 This method is useful if you want to render the view into an element that 53425 is not in the document's body. Instead, a new `body` element, detached from 53426 the DOM is returned. FastBoot uses this to serialize the rendered view into 53427 a string for transmission over the network. 53428 ```js 53429 app.visit('/').then(function(instance) { 53430 var element; 53431 Ember.run(function() { 53432 element = renderToElement(instance); 53433 }); 53434 res.send(serialize(element)); 53435 }); 53436 ``` 53437 @method renderToElement 53438 @param {String} tagName The tag of the element to create and render into. Defaults to "body". 53439 @return {HTMLBodyElement} element 53440 @private 53441 */ 53442 renderToElement: function (tagName) { 53443 tagName = tagName || 'body'; 53444 53445 var element = this.renderer._dom.createElement(tagName); 53446 53447 this.renderer.appendTo(this, element); 53448 return element; 53449 }, 53450 53451 /** 53452 Replaces the content of the specified parent element with this view's 53453 element. If the view does not have an HTML representation yet, 53454 the element will be generated automatically. 53455 Note that this method just schedules the view to be appended; the DOM 53456 element will not be appended to the given element until all bindings have 53457 finished synchronizing 53458 @method replaceIn 53459 @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object 53460 @return {Ember.View} received 53461 @private 53462 */ 53463 replaceIn: function (selector) { 53464 var target = _emberViewsSystemJquery.default(selector); 53465 53466 _emberMetalDebug.assert('You tried to replace in (' + selector + ') but that isn\'t in the DOM', target.length > 0); 53467 _emberMetalDebug.assert('You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.', !target.is('.ember-view') && !target.parents().is('.ember-view')); 53468 53469 this.renderer.replaceIn(this, target[0]); 53470 53471 return this; 53472 }, 53473 53474 /** 53475 Appends the view's element to the document body. If the view does 53476 not have an HTML representation yet 53477 the element will be generated automatically. 53478 If your application uses the `rootElement` property, you must append
53479 the view within that element. Rendering views outside of the `rootElement` 53480 is not supported. 53481 Note that this method just schedules the view to be appended; the DOM 53482 element will not be appended to the document body until all bindings have 53483 finished synchronizing. 53484 @method append 53485 @return {Ember.View} receiver 53486 @private 53487 */ 53488 append: function () { 53489 return this.appendTo(document.body); 53490 }, 53491 53492 /** 53493 Removes the view's element from the element to which it is attached. 53494 @method remove 53495 @return {Ember.View} receiver 53496 @private 53497 */ 53498 remove: function () { 53499 // What we should really do here is wait until the end of the run loop 53500 // to determine if the element has been re-appended to a different 53501 // element. 53502 // In the interim, we will just re-render if that happens. It is more 53503 // important than elements get garbage collected. 53504 if (!this.removedFromDOM) { 53505 this.destroyElement(); 53506 } 53507 53508 // Set flag to avoid future renders 53509 this._willInsert = false; 53510 }, 53511 53512 /** 53513 The HTML `id` of the view's element in the DOM. You can provide this 53514 value yourself but it must be unique (just as in HTML): 53515 ```handlebars 53516 {{my-component elementId="a-really-cool-id"}} 53517 ``` 53518 If not manually set a default value will be provided by the framework. 53519 Once rendered an element's `elementId` is considered immutable and you 53520 should never change it. If you need to compute a dynamic value for the 53521 `elementId`, you should do this when the component or element is being 53522 instantiated: 53523 ```javascript 53524 export default Ember.Component.extend({ 53525 setElementId: Ember.on('init', function() { 53526 var index = this.get('index'); 53527 this.set('elementId', 'component-id' + index); 53528 }) 53529 }); 53530 ``` 53531 @property elementId 53532 @type String 53533 @public 53534 */ 53535 elementId: null, 53536 53537 /** 53538 Attempts to discover the element in the parent element. The default 53539 implementation looks for an element with an ID of `elementId` (or the 53540 view's guid if `elementId` is null). You can override this method to 53541 provide your own form of lookup. For example, if you want to discover your 53542 element using a CSS class name instead of an ID. 53543 @method findElementInParentElement 53544 @param {DOMElement} parentElement The parent's DOM element 53545 @return {DOMElement} The discovered element 53546 @private 53547 */ 53548 findElementInParentElement: function (parentElem) { 53549 var id = '#' + this.elementId; 53550 return _emberViewsSystemJquery.default(id)[0] || _emberViewsSystemJquery.default(id, parentElem)[0]; 53551 }, 53552 53553 /** 53554 Creates a DOM representation of the view and all of its child views by 53555 recursively calling the `render()` method. Once the element is created, 53556 it sets the `element` property of the view to the rendered element. 53557 After the element has been inserted into the DOM, `didInsertElement` will 53558 be called on this view and all of its child views. 53559 @method createElement 53560 @return {Ember.View} receiver 53561 @private 53562 */ 53563 createElement: function () { 53564 if (this.element) { 53565 return this; 53566 } 53567 53568 this.renderer.createElement(this); 53569 53570 return this; 53571 }, 53572 53573 /** 53574 Called when a view is going to insert an element into the DOM. 53575 @event willInsertElement 53576 @public 53577 */ 53578 willInsertElement: K, 53579 53580 /** 53581 Called when the element of the view has been inserted into the DOM 53582 or after the view was re-rendered. Override this function to do any 53583 set up that requires an element in the document body. 53584 When a view has children, didInsertElement will be called on the 53585 child view(s) first, bubbling upwards through the hierarchy. 53586 @event didInsertElement 53587 @public 53588 */ 53589 didInsertElement: K, 53590 53591 /** 53592 Called when the view is about to rerender, but before anything has 53593 been torn down. This is a good opportunity to tear down any manual 53594 observers you have installed based on the DOM state 53595 @event willClearRender 53596 @public 53597 */ 53598 willClearRender: K, 53599 53600 /** 53601 Destroys any existing element along with the element for any child views 53602 as well. If the view does not currently have a element, then this method 53603 will do nothing. 53604 If you implement `willDestroyElement()` on your view, then this method will 53605 be invoked on your view before your element is destroyed to give you a 53606 chance to clean up any event handlers, etc. 53607 If you write a `willDestroyElement()` handler, you can assume that your 53608 `didInsertElement()` handler was called earlier for the same element. 53609 You should not call or override this method yourself, but you may 53610 want to implement the above callbacks. 53611 @method destroyElement 53612 @return {Ember.View} receiver 53613 @private 53614 */ 53615 destroyElement: function () { 53616 return this._currentState.destroyElement(this); 53617 }, 53618 53619 /** 53620 Called when the element of the view is going to be destroyed. Override 53621 this function to do any teardown that requires an element, like remov
53621ing 53622 event listeners. 53623 Please note: any property changes made during this event will have no 53624 effect on object observers. 53625 @event willDestroyElement 53626 @public 53627 */ 53628 willDestroyElement: K, 53629 53630 /** 53631 Called when the parentView property has changed. 53632 @event parentViewDidChange 53633 @private 53634 */ 53635 parentViewDidChange: K, 53636 53637 // .......................................................... 53638 // STANDARD RENDER PROPERTIES 53639 // 53640 53641 /** 53642 Tag name for the view's outer element. The tag name is only used when an 53643 element is first created. If you change the `tagName` for an element, you 53644 must destroy and recreate the view element. 53645 By default, the render buffer will use a `<div>` tag for views. 53646 @property tagName 53647 @type String 53648 @default null 53649 @public 53650 */ 53651 53652 // We leave this null by default so we can tell the difference between 53653 // the default case and a user-specified tag. 53654 tagName: null, 53655 53656 /* 53657 Used to specify a default tagName that can be overridden when extending 53658 or invoking from a template. 53659 @property _defaultTagName 53660 @private 53661 */ 53662 53663 /** 53664 Normally, Ember's component model is "write-only". The component takes a 53665 bunch of attributes that it got passed in, and uses them to render its 53666 template. 53667 One nice thing about this model is that if you try to set a value to the 53668 same thing as last time, Ember (through HTMLBars) will avoid doing any 53669 work on the DOM. 53670 This is not just a performance optimization. If an attribute has not 53671 changed, it is important not to clobber the element's "hidden state". 53672 For example, if you set an input's `value` to the same value as before, 53673 it will clobber selection state and cursor position. In other words, 53674 setting an attribute is not **always** idempotent. 53675 This method provides a way to read an element's attribute and also 53676 update the last value Ember knows about at the same time. This makes 53677 setting an attribute idempotent. 53678 In particular, what this means is that if you get an `<input>` element's 53679 `value` attribute and then re-render the template with the same value, 53680 it will avoid clobbering the cursor and selection position. 53681 Since most attribute sets are idempotent in the browser, you typically 53682 can get away with reading attributes using jQuery, but the most reliable 53683 way to do so is through this method. 53684 @method readDOMAttr 53685 @param {String} name the name of the attribute 53686 @return String 53687 @public 53688 */ 53689 readDOMAttr: function (name) { 53690 var attr = this._renderNode.childNodes.filter(function (node) { 53691 return node.attrName === name; 53692 })[0]; 53693 if (!attr) { 53694 return null; 53695 } 53696 return attr.getContent(); 53697 }, 53698 53699 // ....................................................... 53700 // CORE DISPLAY METHODS 53701 // 53702 53703 /** 53704 Setup a view, but do not finish waking it up. 53705 * configure `childViews` 53706 * register the view with the global views hash, which is used for event 53707 dispatch 53708 @method init 53709 @private 53710 */ 53711 init: function () { 53712 this._super.apply(this, arguments); 53713 53714 if (!this.elementId) { 53715 this.elementId = _emberMetalUtils.guidFor(this); 53716 } 53717 53718 this.scheduledRevalidation = false; 53719 53720 this[INIT_WAS_CALLED] = true; 53721 53722 _emberMetalDebug.assert('Using a custom `.render` function is no longer supported.', !this.render); 53723 } 53724 53725 }, _Mixin$create[_emberRuntimeSystemCore_object.POST_INIT] = function () { 53726 this._super.apply(this, arguments); 53727 53728 _emberMetalDebug.assert('You must call `this._super(...arguments);` when implementing `init` in a component. Please update ' + this + ' to call `this._super` from `init`.', this[INIT_WAS_CALLED]); 53729 53730 this.renderer.componentInitAttrs(this, this.attrs || {}); 53731 }, _Mixin$create.__defineNonEnumerable = function (property) { 53732 this[property.name] = property.descriptor.value; 53733 }, _Mixin$create.revalidate = function () { 53734 this.renderer.revalidateTopLevelView(this); 53735 this.scheduledRevalidation = false;
53736 }, _Mixin$create.scheduleRevalidate = function (node, label, manualRerender) { 53737 if (node && !this._dispatching && this.env.renderedNodes.has(node)) { 53738 if (manualRerender) { 53739 _emberMetalDebug.deprecate('You manually rerendered ' + label + ' (a parent component) from a child component during the rendering process. This rarely worked in Ember 1.x and will be removed in Ember 3.0', false, { id: 'ember-views.manual-parent-rerender', until: '3.0.0' }); 53740 } else { 53741 _emberMetalDebug.deprecate('You modified ' + label + ' twice in a single render. This was unreliable in Ember 1.x and will be removed in Ember 3.0', false, { id: 'ember-views.render-double-modify', until: '3.0.0' }); 53742 } 53743 _emberMetalRun_loop.default.scheduleOnce('render', this, this.revalidate); 53744 return; 53745 } 53746 53747 _emberMetalDebug.deprecate('A property of ' + this + ' was modified inside the ' + this._dispatching + ' hook. You should never change properties on components, services or models during ' + this._dispatching + ' because it causes significant performance degradation.', !this._dispatching, { id: 'ember-views.dispatching-modify-property', until: '3.0.0' }); 53748 53749 if (!this.scheduledRevalidation || this._dispatching) { 53750 this.scheduledRevalidation = true; 53751 _emberMetalRun_loop.default.scheduleOnce('render', this, this.revalidate); 53752 } 53753 }, _Mixin$create.templateRenderer = null, _Mixin$create.removeFromParent = function () { 53754 var parent = this.parentView; 53755 53756 // Remove DOM element from parent 53757 this.remove(); 53758 53759 if (parent) { 53760 parent.removeChild(this); 53761 } 53762 return this; 53763 }, _Mixin$create.destroy = function () { 53764 // get parentView before calling super because it'll be destroyed 53765 var parentView = this.parentView; 53766 var viewName = this.viewName; 53767 53768 if (!this._super.apply(this, arguments)) { 53769 return; 53770 } 53771 53772 // remove from non-virtual parent view if viewName was specified 53773 if (viewName && parentView) { 53774 parentView.set(viewName, null); 53775 } 53776 53777 // Destroy HTMLbars template 53778 if (this.lastResult) { 53779 this.lastResult.destroy(); 53780 } 53781 53782 return this; 53783 }, _Mixin$create.handleEvent = function (eventName, evt) { 53784 return this._currentState.handleEvent(this, eventName, evt); 53785 }, _Mixin$create._register = function () { 53786 _emberMetalDebug.assert('Attempted to register a view with an id already in use: ' + this.elementId, !this._viewRegistry[this.elementId]); 53787 this._viewRegistry[this.elementId] = this; 53788 }, _Mixin$create._unregister = function () { 53789 delete this._viewRegistry[this.elementId]; 53790 }, _Mixin$create.registerObserver = function (root, path, target, observer) { 53791 if (!observer && 'function' === typeof target) { 53792 observer = target; 53793 target = null; 53794 } 53795 53796 if (!root || typeof root !== 'object') { 53797 return; 53798 } 53799 53800 var scheduledObserver = this._wrapAsScheduled(observer); 53801 53802 _emberMetalObserver.addObserver(root, path, target, scheduledObserver); 53803 53804 this.one('willClearRender', function () { 53805 _emberMetalObserver.removeObserver(root, path, target, scheduledObserver); 53806 }); 53807 }, _Mixin$create._wrapAsScheduled = function (fn) { 53808 var view = this; 53809 var stateCheckedFn = function () { 53810 view._currentState.invokeObserver(this, fn); 53811 }; 53812 var scheduledFn = function () { 53813 _emberMetalRun_loop.default.scheduleOnce('render', this, stateCheckedFn); 53814 }; 53815 return scheduledFn; 53816 }, _Mixin$create)); 53817}); 53818/*
53819 This is a special hook implemented in CoreObject, that allows Views/Components 53820 to have a way to ensure that `init` fires before `didInitAttrs` / `didReceiveAttrs` 53821 (so that `this._super` in init does not trigger `didReceiveAttrs` before the classes 53822 own `init` is finished). 53823 @method __postInitInitialization 53824 @private 53825 */ 53826 53827/** 53828 Removes the view from its `parentView`, if one is found. Otherwise 53829 does nothing. 53830 @method removeFromParent 53831 @return {Ember.View} receiver 53832 @private 53833*/ 53834 53835/** 53836 You must call `destroy` on a view to destroy the view (and all of its 53837 child views). This will remove the view from any parent node, then make 53838 sure that the DOM element managed by the view can be released by the 53839 memory manager. 53840 @method destroy 53841 @private 53842*/ 53843 53844// ....................................................... 53845// EVENT HANDLING 53846// 53847 53848/** 53849 Handle events from `Ember.EventDispatcher` 53850 @method handleEvent 53851 @param eventName {String} 53852 @param evt {Event} 53853 @private 53854*/ 53855 53856/** 53857 Registers the view in the view registry, keyed on the view's `elementId`. 53858 This is used by the EventDispatcher to locate the view in response to 53859 events. 53860 This method should only be called once the view has been inserted into the 53861 DOM. 53862 @method _register 53863 @private 53864*/ 53865 53866/** 53867 Removes the view from the view registry. This should be called when the 53868 view is removed from DOM. 53869 @method _unregister 53870 @private 53871*/ 53872enifed('ember-views/mixins/view_target_action_support', ['exports', 'ember-metal/mixin', 'ember-runtime/mixins/target_action_support', 'ember-metal/alias'], function (exports, _emberMetalMixin, _emberRuntimeMixinsTarget_action_support, _emberMetalAlias) { 53873 'use strict'; 53874 53875 /** 53876 `Ember.ViewTargetActionSupport` is a mixin that can be included in a 53877 view class to add a `triggerAction` method with semantics similar to 53878 the Handlebars `{{action}}` helper. It provides intelligent defaults 53879 for the action's target: the view's controller; and the context that is 53880 sent with the action: the view's context. 53881 53882 Note: In normal Ember usage, the `{{action}}` helper is usually the best 53883 choice. This mixin is most often useful when you are doing more complex 53884 event handling in custom View subclasses. 53885 53886 For example: 53887 53888 ```javascript 53889 App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { 53890 action: 'save', 53891 click: function() { 53892 this.triggerAction(); // Sends the `save` action, along with the current context 53893 // to the current controller 53894 } 53895 }); 53896 ``` 53897 53898 The `action` can be provided as properties of an optional object argument 53899 to `triggerAction` as well. 53900 53901 ```javascript 53902 App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { 53903 click: function() { 53904 this.triggerAction({ 53905 action: 'save' 53906 }); // Sends the `save` action, along with the current context 53907 // to the current controller 53908 } 53909 }); 53910 ``` 53911 53912 @class ViewTargetActionSupport 53913 @namespace Ember 53914 @extends Ember.TargetActionSupport 53915 @private 53916 */ 53917 exports.default = _emberMetalMixin.Mixin.create(_emberRuntimeMixinsTarget_action_support.default, { 53918 /** 53919 @property target 53920 @private 53921 */ 53922 target: _emberMetalAlias.default('controller'), 53923 /** 53924 @property actionContext 53925 @private 53926 */ 53927 actionContext: _emberMetalAlias.default('context') 53928 }); 53929}); 53930enifed('ember-views/mixins/visibility_support', ['exports', 'ember-metal/mixin', 'ember-metal/property_get', 'ember-metal/run_loop'], function (exports, _emberMetalMixin, _emberMetalProperty_get, _emberMetalRun_loop) { 53931 /** 53932 @module ember 53933 @submodule ember-views 53934 */ 53935 'use strict'; 53936 53937 function K() { 53938 return this; 53939 } 53940 53941 /** 53942 @class VisibilitySupport 53943 @namespace Ember 53944 @public 53945 */ 53946 var VisibilitySupport = _emberMetalMixin.Mixin.create({ 53947 /** 53948 If `false`, the view will appear hidden in DOM. 53949 @property isVisible 53950 @type Boolean 53951 @default null 53952 @public 53953 */ 53954 isVisible: true, 53955 53956 becameVisible: K, 53957 becameHidden: K, 53958 53959 /** 53960 When the view's `isVisible` property changes, toggle the visibility 53961 element of the actual DOM element. 53962 @method _isVisibleDidChange 53963 @private 53964 */ 53965 _isVisibleDidChange: _emberMetalMixin.observer('isVisible', function () { 53966 if (this._isVisible === _emberMetalProperty_get.get(this, 'isVisible')) { 53967 return; 53968 } 53969 _emberMetalRun_loop.default.scheduleOnce('render', this, this._toggleVisibility); 53970 }), 53971 53972 _toggleVisibility: function () { 53973 var $el = this.$(); 53974 var isVisible = _emberMetalProperty_get.get(this, 'isVisible'); 53975 53976 if (this._isVisible === isVisible) { 53977 return; 53978 } 53979 53980 // It's important to keep these in sync, even if we don't yet have 53981 // an element in the DOM to manipulate: 53982 this._isVisible = isVisible; 53983 53984 if (!$el) { 53985 return; 53986 } 53987 53988 $el.toggle(isVisible); 53989 53990 if (this._isAncestorHidden()) { 53991 return; 53992 } 53993 53994 if (isVisible) { 53995 this._notifyBecameVisible(); 53996 } else { 53997 this._notifyBecameHidden(); 53998 } 53999 }, 54000 54001 _notifyBecameVisible: function () { 54002 this.trigger('becameVisible'); 54003 54004 this.forEachChildView(function (view) { 54005 var isVisible = _emberMetalProperty_get.get(view, 'isVisible'); 54006 54007 if (isVisible || isVisible === null) { 54008 view._notifyBecameVisible(); 54009 } 54010 }); 54011 }, 54012 54013 _notifyBecameHidden: function () { 54014 this.trigger('becameHidden'); 54015 this.forEachChildView(function (view) { 54016 var isVisible = _emberMetalProperty_get.get(view, 'isVisible'); 54017 54018 if (isVisible || isVisible === null) { 54019 view._notifyBecameHidden(); 54020 } 54021 }); 54022 }, 54023 54024 _isAncestorHidden: function () { 54025 var parent = _emberMetalProperty_get.get(this, 'parentView'); 54026 54027 while (parent) { 54028 if (_emberMetalProperty_get.get(parent, 'isVisible') === false) { 54029 return true; 54030 } 54031 54032 parent = _emberMetalProperty_get.get(parent, 'parentView'); 54033 } 54034 54035 return false;
54036 } 54037 }); 54038 54039 exports.default = VisibilitySupport; 54040}); 54041enifed('ember-views/streams/class_name_binding', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/utils', 'ember-metal/streams/utils', 'ember-runtime/system/string'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalUtils, _emberMetalStreamsUtils, _emberRuntimeSystemString) { 54042 'use strict'; 54043 54044 exports.parsePropertyPath = parsePropertyPath; 54045 exports.classStringForValue = classStringForValue; 54046 exports.streamifyClassNameBinding = streamifyClassNameBinding; 54047 54048 /** 54049 Parse a path and return an object which holds the parsed properties. 54050 54051 For example a path like "content.isEnabled:enabled:disabled" will return the 54052 following object: 54053 54054 ```javascript 54055 { 54056 path: "content.isEnabled", 54057 className: "enabled", 54058 falsyClassName: "disabled", 54059 classNames: ":enabled:disabled" 54060 } 54061 ``` 54062 54063 @method parsePropertyPath 54064 @static 54065 @private 54066 */ 54067 54068 function parsePropertyPath(path) { 54069 var split = path.split(':'); 54070 var propertyPath = split[0]; 54071 var classNames = ''; 54072 var className, falsyClassName; 54073 54074 // check if the property is defined as prop:class or prop:trueClass:falseClass 54075 if (split.length > 1) { 54076 className = split[1]; 54077 if (split.length === 3) { 54078 falsyClassName = split[2]; 54079 } 54080 54081 classNames = ':' + className; 54082 if (falsyClassName) { 54083 classNames += ':' + falsyClassName; 54084 } 54085 } 54086 54087 return { 54088 path: propertyPath, 54089 classNames: classNames, 54090 className: className === '' ? undefined : className, 54091 falsyClassName: falsyClassName 54092 }; 54093 } 54094 54095 /** 54096 Get the class name for a given value, based on the path, optional 54097 `className` and optional `falsyClassName`. 54098 54099 - if a `className` or `falsyClassName` has been specified: 54100 - if the value is truthy and `className` has been specified, 54101 `className` is returned 54102 - if the value is falsy and `falsyClassName` has been specified, 54103 `falsyClassName` is returned 54104 - otherwise `null` is returned 54105 - if the value is `true`, the dasherized last part of the supplied path 54106 is returned 54107 - if the value is not `false`, `undefined` or `null`, the `value` 54108 is returned 54109 - if none of the above rules apply, `null` is returned 54110 54111 @method classStringForValue 54112 @param path 54113 @param val 54114 @param className 54115 @param falsyClassName 54116 @static 54117 @private 54118 */ 54119 54120 function classStringForValue(path, val, className, falsyClassName) { 54121 if (_emberMetalUtils.isArray(val)) { 54122 val = _emberMetalProperty_get.get(val, 'length') !== 0; 54123 } 54124 54125 // When using the colon syntax, evaluate the truthiness or falsiness 54126 // of the value to determine which className to return 54127 if (className || falsyClassName) { 54128 if (className && !!val) { 54129 return className; 54130 } else if (falsyClassName && !val) { 54131 return falsyClassName; 54132 } else { 54133 return null; 54134 } 54135 54136 // If value is a Boolean and true, return the dasherized property 54137 // name. 54138 } else if (val === true) { 54139 // Normalize property path to be suitable for use 54140 // as a class name. For exaple, content.foo.barBaz 54141 // becomes bar-baz. 54142 var parts = path.split('.'); 54143 return _emberRuntimeSystemString.dasherize(parts[parts.length - 1]); 54144 54145 // If the value is not false, undefined, or null, return the current 54146 // value of the property. 54147 } else if (val !== false && val != null) { 54148 return val; 54149 54150 // Nothing to display. Return null so that the old class is removed 54151 // but no new class is added. 54152 } else { 54153 return null; 54154 } 54155 } 54156 54157 function streamifyClassNameBinding(view, classNameBinding, prefix) { 54158 prefix = prefix || ''; 54159 _emberMetalDebug.assert('classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. [\'foo\', \':bar\']', classNameBinding.indexOf(' ') === -1); 54160 var parsedPath = parsePropertyPath(classNameBinding); 54161 if (parsedPath.path === '') { 54162 return classStringForValue(parsedPath.path, true, parsedPath.className, parsedPath.falsyClassName); 54163 } else { 54164 var pathValue = view.getStream(prefix + parsedPath.path); 54165 return _emberMetalStreamsUtils.chain(pathValue, function () { 54166 return classStringForValue(parsedPath.path, _emberMetalStreamsUtils.read(pathValue), parsedPath.className, parsedPath.falsyClassName); 54167 }); 54168 } 54169 } 54170}); 54171enifed('ember-views/streams/should_display', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-runtime/utils', 'ember-metal/stream
54171s/stream', 'ember-metal/streams/utils'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberRuntimeUtils, _emberMetalStreamsStream, _emberMetalStreamsUtils) { 54172 'use strict'; 54173 54174 exports.default = shouldDisplay; 54175 54176 var ShouldDisplayStream = _emberMetalStreamsStream.default.extend({ 54177 init: function (predicate) { 54178 _emberMetalDebug.assert('ShouldDisplayStream error: predicate must be a stream', _emberMetalStreamsUtils.isStream(predicate)); 54179 54180 var isTruthy = predicate.get('isTruthy'); 54181 54182 this.init(); 54183 this.predicate = predicate; 54184 this.isTruthy = isTruthy; 54185 this.lengthDep = null; 54186 54187 this.addDependency(predicate); 54188 this.addDependency(isTruthy); 54189 }, 54190 54191 compute: function () { 54192 var truthy = _emberMetalStreamsUtils.read(this.isTruthy); 54193 54194 if (typeof truthy === 'boolean') { 54195 return truthy; 54196 } 54197 54198 if (this.lengthDep) { 54199 return this.lengthDep.getValue() !== 0; 54200 } else { 54201 return !!_emberMetalStreamsUtils.read(this.predicate); 54202 } 54203 }, 54204 54205 revalidate: function () { 54206 if (_emberRuntimeUtils.isArray(_emberMetalStreamsUtils.read(this.predicate))) { 54207 if (!this.lengthDep) { 54208 this.lengthDep = this.addMutableDependency(this.predicate.get('length')); 54209 } 54210 } else { 54211 if (this.lengthDep) { 54212 this.lengthDep.destroy(); 54213 this.lengthDep = null; 54214 } 54215 } 54216 } 54217 }); 54218 54219 function shouldDisplay(predicate) { 54220 if (_emberMetalStreamsUtils.isStream(predicate)) { 54221 return new ShouldDisplayStream(predicate); 54222 } 54223 54224 var type = typeof predicate; 54225 54226 if (type === 'boolean') { 54227 return predicate; 54228 } 54229 54230 if (type && type === 'object' && predicate !== null) { 54231 var isTruthy = _emberMetalProperty_get.get(predicate, 'isTruthy'); 54232 if (typeof isTruthy === 'boolean') { 54233 return isTruthy; 54234 } 54235 } 54236 54237 if (_emberRuntimeUtils.isArray(predicate)) { 54238 return _emberMetalProperty_get.get(predicate, 'length') !== 0; 54239 } else { 54240 return !!predicate; 54241 } 54242 } 54243}); 54244enifed('ember-views/streams/utils', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/streams/utils', 'ember-runtime/mixins/controller'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalStreamsUtils, _emberRuntimeMixinsController) { 54245 'use strict'; 54246 54247 exports.readViewFactory = readViewFactory; 54248 exports.readComponentFactory = readComponentFactory; 54249 exports.readUnwrappedModel = readUnwrappedModel; 54250 54251 function readViewFactory(object, owner) { 54252 var value = _emberMetalStreamsUtils.read(object); 54253 var viewClass; 54254 54255 if (typeof value === 'string') { 54256 _emberMetalDebug.assert('View requires an owner to resolve views not passed in through the context', !!owner); 54257 viewClass = owner._lookupFactory('view:' + value); 54258 } else { 54259 viewClass = value; 54260 } 54261 54262 _emberMetalDebug.assert(value + ' must be a subclass or an instance of Ember.View, not ' + viewClass, (function (viewClass) { 54263 return viewClass && (viewClass.isViewFactory || viewClass.isView || viewClass.isComponentFactory || viewClass.isComponent); 54264 })(viewClass)); 54265 54266 return viewClass; 54267 } 54268 54269 function readComponentFactory(nameOrStream, owner) { 54270 var name = _emberMetalStreamsUtils.read(nameOrStream); 54271 var componentLookup = owner.lookup('component-lookup:main'); 54272 _emberMetalDebug.assert('Could not find \'component-lookup:main\' on the provided container, ' + 'which is necessary for performing component lookups', componentLookup); 54273 54274 return componentLookup.lookupFactory(name, owner); 54275 } 54276 54277 function readUnwrappedModel(object) { 54278 if (_emberMetalStreamsUtils.isStream(object)) { 54279 var result = object.value(); 54280 54281 // If the path is exactly `controller` then we don't unwrap it. 54282 if (object.label !== 'controller') { 54283 while (_emberRuntimeMixinsController.default.detect(result)) { 54284 result = _emberMetalProperty_get.get(result, 'model'); 54285 } 54286 } 54287 54288 return result; 54289 } else { 54290 return object; 54291 } 54292 } 54293}); 54294enifed("ember-views/system/action_manager", ["exports"], function (exports) { 54295 /** 54296 @module ember 54297 @submodule ember-views 54298 */ 54299 54300 "use strict"; 54301 54302 function ActionManager() {} 54303 54304 /** 54305 Global action id hash. 54306 54307 @private 54308 @property registeredActions 54309 @type Object 54310 */ 54311 ActionManager.registeredActions = {}; 54312 54313 exports.default = ActionManager; 54314}); 54315enifed('ember-views/system/build-component-template', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/assign', 'htmlbars-runtime', 'ember-htmlbars/hooks/get-value', 'ember-metal/stream
54315s/utils'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalAssign, _htmlbarsRuntime, _emberHtmlbarsHooksGetValue, _emberMetalStreamsUtils) { 54316 'use strict'; 54317 54318 exports.default = buildComponentTemplate; 54319 exports.buildHTMLTemplate = buildHTMLTemplate; 54320 54321 function buildComponentTemplate(_ref, attrs, content) { 54322 var component = _ref.component; 54323 var tagName = _ref.tagName; 54324 var layout = _ref.layout; 54325 var isAngleBracket = _ref.isAngleBracket; 54326 var isComponentElement = _ref.isComponentElement; 54327 var outerAttrs = _ref.outerAttrs; 54328 54329 var blockToRender, meta; 54330 54331 if (component === undefined) { 54332 component = null; 54333 } 54334 54335 if (layout && layout.raw) { 54336 var yieldTo = createContentBlocks(content.templates, content.scope, content.self, component); 54337 blockToRender = createLayoutBlock(layout.raw, yieldTo, content.self, component, attrs); 54338 meta = layout.raw.meta; 54339 } else if (content.templates && content.templates.default) { 54340 blockToRender = createContentBlock(content.templates.default, content.scope, content.self, component); 54341 meta = content.templates.default.meta; 54342 } 54343 54344 if (component && !component._isAngleBracket || isComponentElement) { 54345 tagName = tagName || tagNameFor(component); 54346 54347 // If this is not a tagless component, we need to create the wrapping 54348 // element. We use `manualElement` to create a template that represents 54349 // the wrapping element and yields to the previous block. 54350 if (tagName !== '') { 54351 if (isComponentElement) { 54352 attrs = mergeAttrs(attrs, outerAttrs); 54353 } 54354 var attributes = normalizeComponentAttributes(component, isAngleBracket, attrs); 54355 var elementTemplate = _htmlbarsRuntime.internal.manualElement(tagName, attributes); 54356 elementTemplate.meta = meta; 54357 54358 blockToRender = createElementBlock(elementTemplate, blockToRender, component); 54359 } else { 54360 validateTaglessComponent(component); 54361 } 54362 } 54363 54364 // tagName is one of: 54365 // * `undefined` if no component is present 54366 // * the falsy value "" if set explicitly on the component 54367 // * an actual tagName set explicitly on the component 54368 return { createdElement: !!tagName, block: blockToRender }; 54369 } 54370 54371 function buildHTMLTemplate(tagName, _attrs, content) { 54372 var attrs = {}; 54373 54374 for (var prop in _attrs) { 54375 var val = _attrs[prop]; 54376 54377 if (typeof val === 'string') { 54378 attrs[prop] = val; 54379 } else { 54380 attrs[prop] = ['value', val]; 54381 } 54382 } 54383 54384 var childTemplate = content.templates.default; 54385 var elementTemplate = _htmlbarsRuntime.internal.manualElement(tagName, attrs, childTemplate.isEmpty); 54386 54387 if (childTemplate.isEmpty) { 54388 return blockFor(elementTemplate, { scope: content.scope }); 54389 } else { 54390 var blockToRender = blockFor(content.templates.default, content); 54391 return blockFor(elementTemplate, { yieldTo: blockToRender, scope: content.scope }); 54392 } 54393 } 54394 54395 function mergeAttrs(innerAttrs, outerAttrs) { 54396 var result = _emberMetalAssign.default({}, innerAttrs, outerAttrs); 54397 54398 if (innerAttrs.class && outerAttrs.class) { 54399 result.class = ['subexpr', '-join-classes', [['value', innerAttrs.class], ['value', outerAttrs.class]], []]; 54400 } 54401 54402 return result; 54403 } 54404 54405 function blockFor(template, options) { 54406 _emberMetalDebug.assert('BUG: Must pass a template to blockFor', !!template); 54407 return _htmlbarsRuntime.internal.blockFor(_htmlbarsRuntime.render, template, options); 54408 } 54409 54410 function createContentBlock(template, scope, self, component) { 54411 _emberMetalDebug.assert('BUG: buildComponentTemplate can take a scope or a self, but not both', !(scope && self)); 54412 54413 return blockFor(template, { 54414 scope: scope, 54415 self: self, 54416 options: { view: component } 54417 }); 54418 } 54419 54420 function createContentBlocks(templates, scope, self, component) { 54421 if (!templates) { 54422 return; 54423 } 54424 var output = {}; 54425 for (var name in templates) { 54426 if (templates.hasOwnProperty(name)) { 54427 var template = templates[name]; 54428 if (template) { 54429 output[name] = createContentBlock(templates[name], scope, self, component); 54430 } 54431 } 54432 } 54433 return output; 54434 } 54435 54436 function createLayoutBlock(template, yieldTo, self, component, attrs) { 54437 return blockFor(template, { 54438 yieldTo: yieldTo, 54439 54440 // If we have an old-style Controller with a template it will be 54441 // passed as our `self` argument, and it should be the context for 54442 // the template. Otherwise, we must have a real Component and it 54443 // should be its own template context. 54444 self: self || component, 54445 54446 options: { view: component, attrs: attrs } 54447 }); 54448 } 54449
54450 function createElementBlock(template, yieldTo, component) { 54451 return blockFor(template, { 54452 yieldTo: yieldTo, 54453 self: component, 54454 options: { view: component } 54455 }); 54456 } 54457 54458 function tagNameFor(view) { 54459 var tagName = view.tagName; 54460 54461 if (tagName !== null && typeof tagName === 'object' && tagName.isDescriptor) { 54462 tagName = _emberMetalProperty_get.get(view, 'tagName'); 54463 _emberMetalDebug.deprecate('In the future using a computed property to define tagName will not be permitted. That value will be respected, but changing it will not update the element.', !tagName, { id: 'ember-views.computed-tag-name', until: '2.0.0' }); 54464 } 54465 54466 if (tagName === null || tagName === undefined) { 54467 tagName = view._defaultTagName || 'div'; 54468 } 54469 54470 return tagName; 54471 } 54472 54473 // Takes a component and builds a normalized set of attribute 54474 // bindings consumable by HTMLBars' `attribute` hook. 54475 function normalizeComponentAttributes(component, isAngleBracket, attrs) { 54476 var normalized = {}; 54477 var attributeBindings = component.attributeBindings; 54478 var streamBasePath = component.isComponent ? '' : 'view.'; 54479 var i, l; 54480 54481 if (attrs.id && _emberHtmlbarsHooksGetValue.default(attrs.id)) { 54482 // Do not allow binding to the `id` 54483 normalized.id = _emberHtmlbarsHooksGetValue.default(attrs.id); 54484 component.elementId = normalized.id; 54485 } else { 54486 normalized.id = component.elementId; 54487 } 54488 54489 if (attributeBindings) { 54490 for (i = 0, l = attributeBindings.length; i < l; i++) { 54491 var attr = attributeBindings[i]; 54492 var colonIndex = attr.indexOf(':'); 54493 54494 var attrName, expression; 54495 if (colonIndex !== -1) { 54496 var attrProperty = attr.substring(0, colonIndex); 54497 attrName = attr.substring(colonIndex + 1); 54498 expression = ['get', '' + streamBasePath + attrProperty]; 54499 } else if (attrs[attr]) { 54500 // TODO: For compatibility with 1.x, we probably need to `set` 54501 // the component's attribute here if it is a CP, but we also 54502 // probably want to suspend observers and allow the 54503 // willUpdateAttrs logic to trigger observers at the correct time. 54504 attrName = attr; 54505 expression = ['value', attrs[attr]]; 54506 } else { 54507 attrName = attr; 54508 expression = ['get', '' + streamBasePath + attr]; 54509 } 54510 54511 _emberMetalDebug.assert('You cannot use class as an attributeBinding, use classNameBindings instead.', attrName !== 'class'); 54512 54513 normalized[attrName] = expression; 54514 } 54515 } 54516 54517 if (isAngleBracket) { 54518 for (var prop in attrs) { 54519 var val = attrs[prop]; 54520 if (!val) { 54521 continue; 54522 } 54523 54524 if (typeof val === 'string' || val.isConcat) { 54525 normalized[prop] = ['value', val]; 54526 } 54527 } 54528 } 54529 54530 if (attrs.tagName) { 54531 component.tagName = attrs.tagName; 54532 } 54533 54534 var normalizedClass = normalizeClass(component, attrs, streamBasePath); 54535 54536 if (normalizedClass) { 54537 normalized.class = normalizedClass; 54538 } 54539 54540 if (_emberMetalProperty_get.get(component, 'isVisible') === false) { 54541 var hiddenStyle = ['subexpr', '-html-safe', ['display: none;'], []]; 54542 var existingStyle = normalized.style; 54543 54544 if (existingStyle) { 54545 normalized.style = ['subexpr', 'concat', [existingStyle, ' ', hiddenStyle], []]; 54546 } else { 54547 normalized.style = hiddenStyle; 54548 } 54549 } 54550 54551 return normalized; 54552 } 54553 54554 function normalizeClass(component, attrs, streamBasePath) { 54555 var i, l; 54556 var normalizedClass = []; 54557 var classNames = _emberMetalProperty_get.get(component, 'classNames'); 54558 var classNameBindings = _emberMetalProperty_get.get(component, 'classNameBindings'); 54559 54560 if (attrs.class) { 54561 if (_emberMetalStreamsUtils.isStream(attrs.class)) { 54562 normalizedClass.push(['subexpr', '-normalize-class', [['value', attrs.class.path], ['value', attrs.class]], []]); 54563 } else { 54564 normalizedClass.push(attrs.class); 54565 } 54566 } 54567 54568 if (attrs.classBinding) { 54569 normalizeClasses(attrs.classBinding.split(' '), normalizedClass, streamBasePath); 54570 } 54571 54572 if (classNames) { 54573 for (i = 0, l = classNames.length; i < l; i++) { 54574 normalizedClass.push(classNames[i]); 54575 } 54576 } 54577 54578 if (classNameBindings) { 54579 normalizeClasses(classNameBindings, normalizedClass, streamBasePath); 54580 } 54581 54582 if (normalizeClass.length) { 54583 return ['subexpr', '-join-classes', normalizedClass, []]; 54584 } 54585 } 54586 54587 function normalizeClasses(classes, output, streamBasePath) { 54588 var i, l; 54589 54590 for (i = 0, l = classes.length; i < l; i++) { 54591 var className = classes[i]; 54592 _emberMetalDebug.assert('classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. [\'foo\', \':bar\']', className.indexOf(' ') === -1); 54593 54594 var _className$split = className.split(':'); 54595 54596 var propName = _className$split[0]; 54597 var activeClass = _className$split[1]; 54598 var inactiveClass = _className$split[2]; 54599 54600 // Legacy :class microsyntax for static class names 54601 if (propName === '') { 54602 output.push(activeClass); 54603 continue; 54604 } 54605 54606 var prop = '' + streamBasePath + propName; 54607 54608 output.push(['subexpr', '-normalize-class', [ 54609 // params 54610 ['value', propName], ['get', prop]], [ 54611 // hash 54612 'activeClass', activeClass, 'inactiveClass', inactiveClass]]); 54613 } 54614 } 54615 54616 function validateTaglessComponent(component) { 54617 _emberMetalDebug.assert('You cannot use `classNameBindings` on a tag-less component: ' + component.toString(), (function () { 54618 var classNameBindings = component.classNameBindings; 54619 return !classNameBindings || classNameBindings.length === 0; 54620 })()); 54621 } 54622}); 54623enifed('ember-views/system/event_dispatcher', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/is_none', 'ember-metal/run_loop', 'ember-runtime/system/object', 'ember-views/system/jquery', 'ember-views/system/action_manager', 'ember-views/views/view', 'ember-metal/assign', 'container/owner', 'ember-metal/environment'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalIs_none, _emberMetalRun_loop, _emberRuntimeSystemObject, _emberViewsSystemJquery, _emberViewsSystemAction_manager, _emberViewsViewsView, _emberMetalAssign, _containerOwner, _emberMetalEnvironment) { 54624 /** 54625 @module ember 54626 @submodule ember-views 54627 */ 54628 54629 'use strict'; 54630
54631 var ROOT_ELEMENT_CLASS = 'ember-application'; 54632 var ROOT_ELEMENT_SELECTOR = '.' + ROOT_ELEMENT_CLASS; 54633 54634 /** 54635 `Ember.EventDispatcher` handles delegating browser events to their 54636 corresponding `Ember.Views.` For example, when you click on a view, 54637 `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets 54638 called. 54639 54640 @class EventDispatcher 54641 @namespace Ember 54642 @private 54643 @extends Ember.Object 54644 */ 54645 exports.default = _emberRuntimeSystemObject.default.extend({ 54646 54647 /** 54648 The set of events names (and associated handler function names) to be setup 54649 and dispatched by the `EventDispatcher`. Modifications to this list can be done 54650 at setup time, generally via the `Ember.Application.customEvents` hash. 54651 To add new events to be listened to: 54652 ```javascript 54653 var App = Ember.Application.create({ 54654 customEvents: { 54655 paste: 'paste' 54656 } 54657 }); 54658 ``` 54659 To prevent default events from being listened to: 54660 ```javascript 54661 var App = Ember.Application.create({ 54662 customEvents: { 54663 mouseenter: null, 54664 mouseleave: null 54665 } 54666 }); 54667 ``` 54668 @property events 54669 @type Object 54670 @private 54671 */ 54672 events: { 54673 touchstart: 'touchStart', 54674 touchmove: 'touchMove', 54675 touchend: 'touchEnd', 54676 touchcancel: 'touchCancel', 54677 keydown: 'keyDown', 54678 keyup: 'keyUp', 54679 keypress: 'keyPress', 54680 mousedown: 'mouseDown', 54681 mouseup: 'mouseUp', 54682 contextmenu: 'contextMenu', 54683 click: 'click', 54684 dblclick: 'doubleClick', 54685 mousemove: 'mouseMove', 54686 focusin: 'focusIn', 54687 focusout: 'focusOut', 54688 mouseenter: 'mouseEnter', 54689 mouseleave: 'mouseLeave', 54690 submit: 'submit', 54691 input: 'input', 54692 change: 'change', 54693 dragstart: 'dragStart', 54694 drag: 'drag', 54695 dragenter: 'dragEnter', 54696 dragleave: 'dragLeave', 54697 dragover: 'dragOver', 54698 drop: 'drop', 54699 dragend: 'dragEnd' 54700 }, 54701 54702 /** 54703 The root DOM element to which event listeners should be attached. Event 54704 listeners will be attached to the document unless this is overridden. 54705 Can be specified as a DOMElement or a selector string. 54706 The default body is a string since this may be evaluated before document.body 54707 exists in the DOM. 54708 @private 54709 @property rootElement 54710 @type DOMElement 54711 @default 'body' 54712 */ 54713 rootElement: 'body', 54714 54715 /** 54716 It enables events to be dispatched to the view's `eventManager.` When present, 54717 this object takes precedence over handling of events on the view itself. 54718 Note that most Ember applications do not use this feature. If your app also 54719 does not use it, consider setting this property to false to gain some performance 54720 improvement by allowing the EventDispatcher to skip the search for the 54721 `eventManager` on the view tree. 54722 ```javascript 54723 var EventDispatcher = Em.EventDispatcher.extend({ 54724 events: { 54725 click : 'click', 54726 focusin : 'focusIn', 54727 focusout : 'focusOut', 54728 change : 'change' 54729 }, 54730 canDispatchToEventManager: false 54731 }); 54732 container.register('event_dispatcher:main', EventDispatcher); 54733 ``` 54734 @property canDispatchToEventManager 54735 @type boolean 54736 @default 'true' 54737 @since 1.7.0 54738 @private 54739 */ 54740 canDispatchToEventManager: true, 54741 54742 init: function () { 54743 this._super(); 54744 _emberMetalDebug.assert('EventDispatcher should never be instantiated in fastboot mode. Please report this as an Ember bug.', _emberMetalEnvironment.default.hasDOM); 54745 }, 54746 54747 /** 54748 Sets up event listeners for standard browser events. 54749 This will be called after the browser sends a `DOMContentReady` event. By 54750 default, it will set up all of the listeners on the document body. If you 54751 would like to register the listeners on a different element, set the event 54752 dispatcher's `root` property. 54753 @private 54754 @method setup 54755 @param addedEvents {Object} 54756 */ 54757 setup: function (addedEvents, rootElement) { 54758 var event; 54759 var events = this._finalEvents = _emberMetalAssign.default({}, _emberMetalProperty_get.get(this, 'events'), addedEvents); 54760 54761 if (!_emberMetalIs_none.default(rootElement)) { 54762 _emberMetalProperty_set.set(this, 'rootElement', rootElement); 54763 } 54764 54765 rootElement = _emberViewsSystemJquery.default(_emberMetalProperty_get.get(this, 'rootElement')); 54766 54767 _emberMetalDebug.assert('You cannot use the same root element (' + (rootElement.selector || rootElement[0].tagName) + ') multiple times in an Ember.Application', !rootElement.is(ROOT_ELEMENT_SELECTOR)); 54768 _emberMetalDebug.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest(ROOT_ELEMENT_SELECTOR).length); 54769 _emberMetalDebug.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find(ROOT_ELEMENT_SELECTOR).length); 54770 54771 rootElement.addClass(ROOT_ELEMENT_CLASS); 54772 54773 _emberMetalDebug.assert('Unable to add \'' + ROOT_ELEMENT_CLASS + '\' class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is(ROOT_ELEMENT_SELECTOR)); 54774 54775 for (event in events) { 54776 if (events.hasOwnProperty(event)) { 54777 this.setupHandler(rootElement, event, events[event]); 54778 } 54779 } 54780 }, 54781 54782 /** 54783 Registers an event listener on the rootElement. If the given event is 54784 triggered, the provided event handler will be triggered on the target view. 54785 If the target view does not implement the event handler, or if the handler 54786 returns `false`, the parent view will be called. The event will continue to 54787 bubble to each successive parent view until it reaches the top. 54788 @private 54789 @method setupHandler 54790 @param {Element} rootElement 54791 @param {String} event the browser-originated event to listen to 54792 @param {String} eventName the name of the method to call on the view 54793 */ 54794 setupHandler: function (rootElement, event, eventName) { 54795 var self = this; 54796 54797 var owner = _containerOwner.getOwner(this); 54798 var viewRegistry = owner && owner.lookup('-view-registry:main') || _emberViewsViewsView.default.views; 54799 54800 if (eventName === null) { 54801 return; 54802 } 54803 54804 rootElement.on(event + '.ember', '.ember-view', function (evt, triggeringManager) { 54805 var view = viewRegistry[this.id]; 54806 var result = true; 54807 54808 var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null; 54809 54810 if (manager && manager !== triggeringManager) { 54811 result = self._dispatchEvent(manager, evt, eventName, view); 54812 } else if (view) { 54813 result = self._bubbleEvent(view, evt, eventName); 54814 } 54815 54816 return result; 54817 }); 54818 54819 rootElement.on(event + '.ember', '[data-ember-action]', function (evt) { 54820 var actionId = _emberViewsSystemJquery.default(evt.currentTarget).attr('data-ember-action'); 54821 var actions = _emberViewsSystemAction_manager.default.registeredActions[actionId]; 54822 54823 // We have to check for actions here since in some cases, jQuery will trigger 54824 // an event on `removeChild` (i.e. focusout) after we've already torn down the 54825 // action handlers for the view. 54826 if (!actions) { 54827 return; 54828 } 54829 54830 for (var index = 0, _length = actions.length; index < _length; index++) { 54831 var action = actions[index]; 54832 54833 if (action && action.eventName === eventName) { 54834 return action.handler(evt); 54835 } 54836 } 54837 }); 54838 }, 54839 54840 _findNearestEventManager: function (view, eventName) { 54841 var manager = null; 54842 54843 while (view) { 54844 manager = _emberMetalProperty_get.get(view, 'eventManager'); 54845 if (manager && manager[eventName]) { 54846 break; 54847 } 54848 54849 view = _emberMetalProperty_get.get(view, 'parentView'); 54850 } 54851 54852 return manager; 54853 }, 54854 54855 _dispatchEvent: function (object, evt, eventName, view) { 54856 var result = true; 54857 54858 var handler = object[eventName]; 54859 if (typeof handler === 'function') { 54860 result = _emberMetalRun_loop.default(object, handler, evt, view);
54861 // Do not preventDefault in eventManagers. 54862 evt.stopPropagation(); 54863 } else { 54864 result = this._bubbleEvent(view, evt, eventName); 54865 } 54866 54867 return result; 54868 }, 54869 54870 _bubbleEvent: function (view, evt, eventName) { 54871 return view.handleEvent(eventName, evt); 54872 }, 54873 54874 destroy: function () { 54875 var rootElement = _emberMetalProperty_get.get(this, 'rootElement'); 54876 _emberViewsSystemJquery.default(rootElement).off('.ember', '**').removeClass(ROOT_ELEMENT_CLASS); 54877 return this._super.apply(this, arguments); 54878 }, 54879 54880 toString: function () { 54881 return '(EventDispatcher)'; 54882 } 54883 }); 54884}); 54885enifed('ember-views/system/ext', ['exports', 'ember-metal/run_loop'], function (exports, _emberMetalRun_loop) { 54886 /** 54887 @module ember 54888 @submodule ember-views 54889 */ 54890 54891 'use strict'; 54892 54893 // Add a new named queue for rendering views that happens 54894 // after bindings have synced, and a queue for scheduling actions 54895 // that should occur after view rendering. 54896 _emberMetalRun_loop.default._addQueue('render', 'actions'); 54897 _emberMetalRun_loop.default._addQueue('afterRender', 'render'); 54898}); 54899enifed('ember-views/system/jquery', ['exports', 'ember-metal/core', 'ember-metal/environment'], function (exports, _emberMetalCore, _emberMetalEnvironment) { 54900 'use strict'; 54901 54902 var jQuery; 54903 54904 if (_emberMetalEnvironment.default.hasDOM) { 54905 // mainContext is set in `package/loader/lib/main.js` to the `this` context before entering strict mode 54906 jQuery = _emberMetalCore.default.imports && _emberMetalCore.default.imports.jQuery || mainContext && mainContext.jQuery; //jshint ignore:line 54907 if (!jQuery && typeof require === 'function') { 54908 jQuery = require('jquery'); 54909 } 54910 54911 if (jQuery) { 54912 // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents 54913 var dragEvents = ['dragstart', 'drag', 'dragenter', 'dragleave', 'dragover', 'drop', 'dragend']; 54914 54915 // Copies the `dataTransfer` property from a browser event object onto the 54916 // jQuery event object for the specified events 54917 dragEvents.forEach(function (eventName) { 54918 jQuery.event.fixHooks[eventName] = { 54919 props: ['dataTransfer'] 54920 }; 54921 }); 54922 } 54923 } 54924 54925 exports.default = jQuery; 54926}); 54927 54928// ES6TODO: the functions on EnumerableUtils need their own exports 54929enifed('ember-views/system/lookup_partial', ['exports', 'ember-metal/debug', 'ember-metal/error'], function (exports, _emberMetalDebug, _emberMetalError) { 54930 'use strict'; 54931 54932 exports.default = lookupPartial; 54933 54934 function lookupPartial(env, templateName) { 54935 if (templateName == null) { 54936 return; 54937 } 54938 54939 var nameParts = templateName.split('/'); 54940 var lastPart = nameParts[nameParts.length - 1]; 54941 54942 nameParts[nameParts.length - 1] = '_' + lastPart; 54943 54944 var underscoredName = nameParts.join('/'); 54945 var template = templateFor(env, underscoredName, templateName); 54946 54947 _emberMetalDebug.assert('Unable to find partial with name "' + templateName + '"', !!template); 54948 54949 return template; 54950 } 54951 54952 function templateFor(env, underscored, name) { 54953 if (!name) { 54954 return; 54955 } 54956 _emberMetalDebug.assert('templateNames are not allowed to contain periods: ' + name, name.indexOf('.') === -1); 54957 54958 if (!env.owner) { 54959 throw new _emberMetalError.default('Container was not found when looking up a views template. ' + 'This is most likely due to manually instantiating an Ember.View. ' + 'See: http://git.io/EKPpnA'); 54960 } 54961 54962 return env.owner.lookup('template:' + underscored) || env.owner.lookup('template:' + name); 54963 } 54964}); 54965enifed('ember-views/system/platform', ['exports', 'ember-metal/environment'], function (exports, _emberMetalEnvironment) { 54966 'use strict'; 54967 54968 // IE 6/7 have bugs around setting names on inputs during creation. 54969 // From http://msdn.microsoft.com/en-us/library/ie/ms536389(v=vs.85).aspx: 54970 // "To include the NAME attribute at run time on objects created with the createElement method, use the eTag." 54971 var canSetNameOnInputs = _emberMetalEnvironment.default.hasDOM && (function () { 54972 var div = document.createElement('div'); 54973 var el = document.createElement('input'); 54974 54975 el.setAttribute('name', 'foo'); 54976 div.appendChild(el); 54977 54978 return !!div.innerHTML.match('foo'); 54979 })(); 54980 exports.canSetNameOnInputs = canSetNameOnInputs; 54981}); 54982enifed("ember-views/system/utils", ["exports"], function (exports) { 54983 /** 54984 @module ember 54985 @submodule ember-views 54986 */ 54987 54988 "use strict"; 54989 54990 exports.isSimpleClick = isSimpleClick; 54991 exports.getViewClientRects = getViewClientRects; 54992 exports.getViewBoundingClientRect = getViewBoundingClientRect; 54993 54994 function isSimpleClick(event) { 54995 var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey; 54996 var secondaryClick = event.which > 1; // IE9 may return undefined 54997 54998 return !modifier && !secondaryClick; 54999 } 55000 55001 /** 55002 @private 55003 @method getViewRange 55004 @param {Ember.View} view 55005 */ 55006 function getViewRange(view) { 55007 var range = document.createRange(); 55008 range.setStartBefore(view._renderNode.firstNode); 55009 range.setEndAfter(view._renderNode.lastNode); 55010 return range; 55011 } 55012 55013 /** 55014 `getViewClientRects` provides information about the position of the border 55015 box edges of a view relative to the viewport. 55016 55017 It is only intended to be used by development tools like the Ember Inspector 55018 and may not work on older browsers. 55019 55020 @private 55021 @method getViewClientRects 55022 @param {Ember.View} view 55023 */ 55024 55025 function getViewClientRects(view) { 55026 var range = getViewRange(view); 55027 return range.getClientRects(); 55028 } 55029 55030 /** 55031 `getViewBoundingClientRect` provides information about the position of the 55032 bounding border box edges of a view relative to the viewport. 55033 55034 It is only intended to be used by development tools like the Ember Inpsector 55035 and may not work on older browsers. 55036 55037 @private 55038 @method getViewBoundingClientRect 55039 @param {Ember.View} view 55040 */ 55041 55042 function getViewBoundingClientRect(view) { 55043 var range = getViewRange(view); 55044 return range.getBoundingClientRect(); 55045 } 55046}); 55047enifed('ember-views/views/checkbox', ['exports', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-views/components/component'], function (exports, _emberMetalProperty_get, _emberMetalProperty_set, _emberViewsComponentsComponent) { 55048 'use strict'; 55049 55050 /** 55051 @module ember 55052 @submodule ember-views 55053 */ 55054 55055 /**
55056 The internal class used to create text inputs when the `{{input}}` 55057 helper is used with `type` of `checkbox`. 55058 55059 See [Ember.Templates.helpers.input](/api/classes/Ember.Templates.helpers.html#method_input) for usage details. 55060 55061 ## Direct manipulation of `checked` 55062 55063 The `checked` attribute of an `Ember.Checkbox` object should always be set 55064 through the Ember object or by interacting with its rendered element 55065 representation via the mouse, keyboard, or touch. Updating the value of the 55066 checkbox via jQuery will result in the checked value of the object and its 55067 element losing synchronization. 55068 55069 ## Layout and LayoutName properties 55070 55071 Because HTML `input` elements are self closing `layout` and `layoutName` 55072 properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s 55073 layout section for more information. 55074 55075 @class Checkbox 55076 @namespace Ember 55077 @extends Ember.Component 55078 @public 55079 */ 55080 exports.default = _emberViewsComponentsComponent.default.extend({ 55081 instrumentDisplay: '{{input type="checkbox"}}', 55082 55083 classNames: ['ember-checkbox'], 55084 55085 tagName: 'input', 55086 55087 attributeBindings: ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name', 'autofocus', 'required', 'form'], 55088 55089 type: 'checkbox', 55090 checked: false, 55091 disabled: false, 55092 indeterminate: false, 55093 55094 didInsertElement: function () { 55095 this._super.apply(this, arguments); 55096 _emberMetalProperty_get.get(this, 'element').indeterminate = !!_emberMetalProperty_get.get(this, 'indeterminate'); 55097 }, 55098 55099 change: function () { 55100 _emberMetalProperty_set.set(this, 'checked', this.$().prop('checked')); 55101 } 55102 }); 55103}); 55104enifed('ember-views/views/collection_view', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-views/views/container_view', 'ember-views/views/view', 'ember-runtime/mixins/array', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/computed', 'ember-metal/mixin', 'ember-views/streams/utils', 'ember-views/mixins/empty_view_support', 'container/owner'], function (exports, _emberMetalCore, _emberMetalDebug, _emberViewsViewsContainer_view, _emberViewsViewsView, _emberRuntimeMixinsArray, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalComputed, _emberMetalMixin, _emberViewsStreamsUtils, _emberViewsMixinsEmpty_view_support, _containerOwner) { 55105 /** 55106 @module ember 55107 @submodule ember-views 55108 */ 55109 55110 'use strict'; 55111 55112 /** 55113 `Ember.CollectionView` is an `Ember.View` descendent responsible for managing 55114 a collection (an array or array-like object) by maintaining a child view object 55115 and associated DOM representation for each item in the array and ensuring 55116 that child views and their associated rendered HTML are updated when items in 55117 the array are added, removed, or replaced. 55118 55119 ## Setting content 55120 55121 The managed collection of objects is referenced as the `Ember.CollectionView` 55122 instance's `content` property. 55123 55124 ```javascript 55125 someItemsView = Ember.CollectionView.create({ 55126 content: ['A', 'B','C'] 55127 }) 55128 ``` 55129 55130 The view for each item in the collection will have its `content` property set 55131 to the item. 55132 55133 ## Specifying `itemViewClass` 55134 55135 By default the view class for each item in the managed collection will be an 55136 instance of `Ember.View`. You can supply a different class by setting the
55137 `CollectionView`'s `itemViewClass` property. 55138 55139 Given the following application code: 55140 55141 ```javascript 55142 var App = Ember.Application.create(); 55143 App.ItemListView = Ember.CollectionView.extend({ 55144 classNames: ['a-collection'], 55145 content: ['A','B','C'], 55146 itemViewClass: Ember.View.extend({ 55147 template: Ember.HTMLBars.compile("the letter: {{view.content}}") 55148 }) 55149 }); 55150 ``` 55151 55152 And a simple application template: 55153 55154 ```handlebars 55155 {{view 'item-list'}} 55156 ``` 55157 55158 The following HTML will result: 55159 55160 ```html 55161 <div class="ember-view a-collection"> 55162 <div class="ember-view">the letter: A</div> 55163 <div class="ember-view">the letter: B</div> 55164 <div class="ember-view">the letter: C</div> 55165 </div> 55166 ``` 55167 55168 ## Automatic matching of parent/child tagNames 55169 55170 Setting the `tagName` property of a `CollectionView` to any of 55171 "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result 55172 in the item views receiving an appropriately matched `tagName` property. 55173 55174 Given the following application code: 55175 55176 ```javascript 55177 var App = Ember.Application.create(); 55178 App.UnorderedListView = Ember.CollectionView.create({ 55179 tagName: 'ul', 55180 content: ['A','B','C'], 55181 itemViewClass: Ember.View.extend({ 55182 template: Ember.HTMLBars.compile("the letter: {{view.content}}") 55183 }) 55184 }); 55185 ``` 55186 55187 And a simple application template: 55188 55189 ```handlebars 55190 {{view 'unordered-list-view'}} 55191 ``` 55192 55193 The following HTML will result: 55194 55195 ```html 55196 <ul class="ember-view a-collection"> 55197 <li class="ember-view">the letter: A</li> 55198 <li class="ember-view">the letter: B</li> 55199 <li class="ember-view">the letter: C</li> 55200 </ul> 55201 ``` 55202 55203 Additional `tagName` pairs can be provided by adding to 55204 `Ember.CollectionView.CONTAINER_MAP`. For example: 55205 55206 ```javascript 55207 Ember.CollectionView.CONTAINER_MAP['article'] = 'section' 55208 ``` 55209 55210 ## Programmatic creation of child views 55211 55212 For cases where additional customization beyond the use of a single 55213 `itemViewClass` or `tagName` matching is required CollectionView's 55214 `createChildView` method can be overridden: 55215 55216 ```javascript 55217 App.CustomCollectionView = Ember.CollectionView.extend({ 55218 createChildView: function(viewClass, attrs) { 55219 if (attrs.content.kind == 'album') { 55220 viewClass = App.AlbumView; 55221 } else { 55222 viewClass = App.SongView; 55223 } 55224 return this._super(viewClass, attrs); 55225 } 55226 }); 55227 ``` 55228 55229 ## Empty View 55230 55231 You can provide an `Ember.View` subclass to the `Ember.CollectionView` 55232 instance as its `emptyView` property. If the `content` property of a 55233 `CollectionView` is set to `null` or an empty array, an instance of this view 55234 will be the `CollectionView`s only child. 55235 55236 ```javascript 55237 var App = Ember.Application.create(); 55238 App.ListWithNothing = Ember.CollectionView.create({ 55239 classNames: ['nothing'], 55240 content: null, 55241 emptyView: Ember.View.extend({ 55242 template: Ember.HTMLBars.compile("The collection is empty") 55243 }) 55244 }); 55245 ``` 55246 55247 And a simple application template: 55248 55249 ```handlebars 55250 {{view 'list-with-nothing'}} 55251 ``` 55252 55253 The following HTML will result: 55254 55255 ```html 55256 <div class="ember-view nothing"> 55257 <div class="ember-view"> 55258 The collection is empty 55259 </div> 55260 </div> 55261 ``` 55262 55263 ## Adding and Removing items 55264 55265 The `childViews` property of a `CollectionView` should not be directly 55266 manipulated. Instead, add, remove, replace items from its `content` property. 55267 This will trigger appropriate changes to its rendered HTML. 55268 55269 55270 @class CollectionView 55271 @namespace Ember 55272 @extends Ember.ContainerView 55273 @uses Ember.EmptyViewSupport 55274 @since Ember 0.9 55275 @private 55276 */ 55277 var CollectionView = _emberViewsViewsContainer_view.default.extend(_emberViewsMixinsEmpty_view_support.default, { 55278 55279 /** 55280 A list of items to be displayed by the `Ember.CollectionView`. 55281 @property content 55282 @type Ember.Array 55283 @default null 55284 @private 55285 */ 55286 content: null, 55287 55288 /** 55289 @property itemViewClass 55290 @type Ember.View 55291 @default Ember.View 55292 @private 55293 */ 55294 itemViewClass: _emberViewsViewsView.default, 55295 55296 /** 55297 Setup a CollectionView 55298 @method init 55299 @private 55300 */ 55301 init: function () { 55302 var ret = this._super.apply(this, arguments); 55303 this._contentDidChange(); 55304 return ret; 55305 }, 55306 55307 /** 55308 Check to make sure that the content has changed, and if so, 55309 update the children directly. This is always scheduled 55310 asynchronously, to allow the element to be created before 55311 bindings have synchronized and vice versa. 55312 @private
55313 @method _contentDidChange 55314 */ 55315 _contentDidChange: _emberMetalMixin.observer('content', function () { 55316 var prevContent = this._prevContent; 55317 if (prevContent) { 55318 _emberRuntimeMixinsArray.removeArrayObserver(prevContent, this); 55319 } 55320 var len = prevContent ? _emberMetalProperty_get.get(prevContent, 'length') : 0; 55321 this.arrayWillChange(prevContent, 0, len); 55322 55323 var content = _emberMetalProperty_get.get(this, 'content'); 55324 55325 if (content) { 55326 this._prevContent = content; 55327 this._assertArrayLike(content); 55328 _emberRuntimeMixinsArray.addArrayObserver(content, this); 55329 } 55330 55331 len = content ? _emberMetalProperty_get.get(content, 'length') : 0; 55332 this.arrayDidChange(content, 0, null, len); 55333 }), 55334 55335 /** 55336 Ensure that the content implements Ember.Array 55337 @private 55338 @method _assertArrayLike 55339 */ 55340 _assertArrayLike: function (content) { 55341 _emberMetalDebug.assert('an Ember.CollectionView\'s content must implement Ember.Array. You passed ' + content, _emberRuntimeMixinsArray.default.detect(content)); 55342 }, 55343 55344 /** 55345 Removes the content and content observers. 55346 @method destroy 55347 @private 55348 */ 55349 destroy: function () { 55350 if (!this._super.apply(this, arguments)) { 55351 return; 55352 } 55353 55354 var content = _emberMetalProperty_get.get(this, 'content'); 55355 if (content) { 55356 _emberRuntimeMixinsArray.removeArrayObserver(content, this); 55357 } 55358 55359 if (this._createdEmptyView) { 55360 this._createdEmptyView.destroy(); 55361 } 55362 55363 return this; 55364 }, 55365 55366 /** 55367 Called when a mutation to the underlying content array will occur. 55368 This method will remove any views that are no longer in the underlying 55369 content array. 55370 Invokes whenever the content array itself will change. 55371 @method arrayWillChange 55372 @param {Array} content the managed collection of objects 55373 @param {Number} start the index at which the changes will occur 55374 @param {Number} removed number of object to be removed from content 55375 @private 55376 */ 55377 arrayWillChange: function (content, start, removedCount) { 55378 this.replace(start, removedCount, []); 55379 }, 55380 55381 /** 55382 Called when a mutation to the underlying content array occurs. 55383 This method will replay that mutation against the views that compose the 55384 `Ember.CollectionView`, ensuring that the view reflects the model. 55385 This array observer is added in `contentDidChange`. 55386 @method arrayDidChange 55387 @param {Array} content the managed collection of objects 55388 @param {Number} start the index at which the changes occurred 55389 @param {Number} removed number of object removed from content 55390 @param {Number} added number of object added to content 55391 @private 55392 */ 55393 arrayDidChange: function (content, start, removed, added) { 55394 var addedViews = []; 55395 var view, item, idx, len, itemViewClass, itemViewProps; 55396 55397 len = content ? _emberMetalProperty_get.get(content, 'length') : 0; 55398 55399 if (len) { 55400 itemViewProps = this._itemViewProps || {}; 55401 itemViewClass = this.getAttr('itemViewClass') || _emberMetalProperty_get.get(this, 'itemViewClass'); 55402 55403 itemViewClass = _emberViewsStreamsUtils.readViewFactory(itemViewClass, _containerOwner.getOwner(this)); 55404 55405 for (idx = start; idx < start + added; idx++) { 55406 item = _emberRuntimeMixinsArray.objectAt(content, idx); 55407 itemViewProps._context = this.keyword ? this.get('context') : item; 55408 itemViewProps.content = item; 55409 itemViewProps.contentIndex = idx; 55410 55411 view = this.createChildView(itemViewClass, itemViewProps); 55412 55413 addedViews.push(view); 55414 } 55415 55416 this.replace(start, 0, addedViews); 55417 } 55418 }, 55419 55420 /** 55421 Instantiates a view to be added to the childViews array during view 55422 initialization. You generally will not call this method directly unless 55423 you are overriding `createChildViews()`. Note that this method will 55424 automatically configure the correct settings on the new view instance to 55425 act as a child of the parent. 55426 The tag name for the view will be set to the tagName of the viewClass 55427 passed in. 55428 @method createChildView 55429 @param {Class} viewClass 55430 @param {Object} [attrs] Attributes to add 55431 @return {Ember.View} new instance 55432 @private 55433 */ 55434 createChildView: function (_view, attrs) { 55435 var view = this._super(_view, attrs); 55436 55437 var itemTagName = _emberMetalProperty_get.get(view, 'tagName'); 55438 55439 if (itemTagName === null || itemTagName === undefined) { 55440 itemTagName = CollectionView.CONTAINER_MAP[_emberMetalProperty_get.get(this, 'tagName')]; 55441 _emberMetalProperty_set.set(view, 'tagName', itemTagName); 55442 } 55443 55444 return view; 55445 }, 55446 55447 _willRender: function () { 55448 var attrs = this.attrs; 55449 var itemProps = buildItemViewProps(this._itemViewTemplate, attrs); 55450 this._itemViewProps = itemProps; 55451 var childViews = _emberMetalProperty_get.get(this, 'childViews'); 55452 55453 for (var i = 0, l = childViews.length; i < l; i++) { 55454 childViews[i].setProperties(itemProps); 55455 } 55456
55457 if ('content' in attrs) { 55458 _emberMetalProperty_set.set(this, 'content', this.getAttr('content')); 55459 } 55460 55461 if ('emptyView' in attrs) { 55462 _emberMetalProperty_set.set(this, 'emptyView', this.getAttr('emptyView')); 55463 } 55464 }, 55465 55466 _emptyViewTagName: _emberMetalComputed.computed('tagName', function () { 55467 var tagName = _emberMetalProperty_get.get(this, 'tagName'); 55468 return CollectionView.CONTAINER_MAP[tagName] || 'div'; 55469 }) 55470 }); 55471 55472 /** 55473 A map of parent tags to their default child tags. You can add 55474 additional parent tags if you want collection views that use 55475 a particular parent tag to default to a child tag. 55476 55477 @property CONTAINER_MAP 55478 @type Object 55479 @static 55480 @final 55481 @private 55482 */ 55483 CollectionView.CONTAINER_MAP = { 55484 ul: 'li', 55485 ol: 'li', 55486 table: 'tr', 55487 thead: 'tr', 55488 tbody: 'tr', 55489 tfoot: 'tr', 55490 tr: 'td', 55491 select: 'option' 55492 }; 55493 55494 var CONTAINER_MAP = CollectionView.CONTAINER_MAP; 55495 55496 exports.CONTAINER_MAP = CONTAINER_MAP; 55497 function buildItemViewProps(template, attrs) { 55498 var props = {}; 55499 55500 // Go through options passed to the {{collection}} helper and extract options 55501 // that configure item views instead of the collection itself. 55502 for (var prop in attrs) { 55503 if (prop === 'itemViewClass' || prop === 'itemController' || prop === 'itemClassBinding') { 55504 continue; 55505 } 55506 if (attrs.hasOwnProperty(prop)) { 55507 var match = prop.match(/^item(.)(.*)$/); 55508 if (match) { 55509 var childProp = match[1].toLowerCase() + match[2]; 55510 55511 if (childProp === 'class' || childProp === 'classNames') { 55512 props.classNames = [attrs[prop]]; 55513 } else { 55514 props[childProp] = attrs[prop]; 55515 } 55516 55517 delete attrs[prop]; 55518 } 55519 } 55520 } 55521 55522 if (template) { 55523 props.template = template; 55524 } 55525 55526 return props; 55527 } 55528 55529 function viewDeprecationMessage() { 55530 _emberMetalDebug.deprecate('Ember.CollectionView is deprecated. Consult the Deprecations Guide for a migration strategy.', !!_emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT, { 55531 url: 'http://emberjs.com/deprecations/v1.x/#toc_ember-collectionview', 55532 id: 'ember-views.collection-view-deprecated', 55533 until: '2.4.0' 55534 }); 55535 } 55536 55537 var DeprecatedCollectionView = CollectionView.extend({ 55538 init: function () { 55539 viewDeprecationMessage(); 55540 this._super.apply(this, arguments); 55541 } 55542 }); 55543 55544 DeprecatedCollectionView.reopen = function () { 55545 viewDeprecationMessage(); 55546 CollectionView.reopen.apply(CollectionView, arguments); 55547 return this; 55548 }; 55549 55550 DeprecatedCollectionView.CONTAINER_MAP = CONTAINER_MAP; 55551 55552 exports.default = CollectionView; 55553 exports.DeprecatedCollectionView = DeprecatedCollectionView; 55554}); 55555enifed('ember-views/views/container_view', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-runtime/mixins/mutable_array', 'ember-runtime/system/native_array', 'ember-views/views/view', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/mixin', 'ember-metal/events', 'ember-htmlbars/templates/container-view'], function (exports, _emberMetalCore, _emberMetalDebug, _emberRuntimeMixinsMutable_array, _emberRuntimeSystemNative_array, _emberViewsViewsView, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalMixin, _emberMetalEvents, _emberHtmlbarsTemplatesContainerView) { 55556 'use strict'; 55557 55558 _emberHtmlbarsTemplatesContainerView.default.meta.revision = '[email protected]'; 55559 55560 /** 55561 @module ember 55562 @submodule ember-views 55563 */ 55564 55565 /** 55566 A `ContainerView` is an `Ember.View` subclass that implements `Ember.MutableArray` 55567 allowing programmatic management of its child views. 55568 55569 ## Setting Initial Child Views 55570 55571 The initial array of child views can be set in one of two ways. You can 55572 provide a `childViews` property at creation time that contains instance of 55573 `Ember.View`: 55574 55575 ```javascript 55576 aContainer = Ember.ContainerView.create({ 55577 childViews: [Ember.View.create(), Ember.View.create()] 55578 }); 55579 ``` 55580 55581 You can also provide a list of property names whose values are instances of 55582 `Ember.View`: 55583 55584 ```javascript 55585 aContainer = Ember.ContainerView.create({ 55586 childViews: ['aView', 'bView', 'cView'], 55587 aView: Ember.View.create(), 55588 bView: Ember.View.create(), 55589 cView: Ember.View.create() 55590 }); 55591 ``` 55592 55593 The two strategies can be combined: 55594 55595 ```javascript 55596 aContainer = Ember.ContainerView.create({ 55597 childViews: ['aView', Ember.View.create()], 55598 aView: Ember.View.create() 55599 }); 55600 ``` 55601 55602 Each child view's rendering will be inserted into the container's rendered 55603 HTML in the same order as its position in the `childViews` property. 55604
55605 ## Adding and Removing Child Views 55606 55607 The container view implements `Ember.MutableArray` allowing programmatic management of its child views. 55608 55609 To remove a view, pass that view into a `removeObject` call on the container view. 55610 55611 Given an empty `<body>` the following code 55612 55613 ```javascript 55614 aContainer = Ember.ContainerView.create({ 55615 classNames: ['the-container'], 55616 childViews: ['aView', 'bView'], 55617 aView: Ember.View.create({ 55618 template: Ember.HTMLBars.compile("A") 55619 }), 55620 bView: Ember.View.create({ 55621 template: Ember.HTMLBars.compile("B") 55622 }) 55623 }); 55624 55625 aContainer.appendTo('body'); 55626 ``` 55627 55628 Results in the HTML 55629 55630 ```html 55631 <div class="ember-view the-container"> 55632 <div class="ember-view">A</div> 55633 <div class="ember-view">B</div> 55634 </div> 55635 ``` 55636 55637 Removing a view 55638 55639 ```javascript 55640 aContainer.toArray(); // [aContainer.aView, aContainer.bView] 55641 aContainer.removeObject(aContainer.get('bView')); 55642 aContainer.toArray(); // [aContainer.aView] 55643 ``` 55644 55645 Will result in the following HTML 55646 55647 ```html 55648 <div class="ember-view the-container"> 55649 <div class="ember-view">A</div> 55650 </div> 55651 ``` 55652 55653 Similarly, adding a child view is accomplished by adding `Ember.View` instances to the 55654 container view. 55655 55656 Given an empty `<body>` the following code 55657 55658 ```javascript 55659 aContainer = Ember.ContainerView.create({ 55660 classNames: ['the-container'], 55661 childViews: ['aView', 'bView'], 55662 aView: Ember.View.create({ 55663 template: Ember.HTMLBars.compile("A") 55664 }), 55665 bView: Ember.View.create({ 55666 template: Ember.HTMLBars.compile("B") 55667 }) 55668 }); 55669 55670 aContainer.appendTo('body'); 55671 ``` 55672 55673 Results in the HTML 55674 55675 ```html 55676 <div class="ember-view the-container"> 55677 <div class="ember-view">A</div> 55678 <div class="ember-view">B</div> 55679 </div> 55680 ``` 55681 55682 Adding a view 55683 55684 ```javascript 55685 AnotherViewClass = Ember.View.extend({ 55686 template: Ember.HTMLBars.compile("Another view") 55687 }); 55688 55689 aContainer.toArray(); // [aContainer.aView, aContainer.bView] 55690 aContainer.pushObject(AnotherViewClass.create()); 55691 aContainer.toArray(); // [aContainer.aView, aContainer.bView, <AnotherViewClass instance>] 55692 ``` 55693 55694 Will result in the following HTML 55695 55696 ```html 55697 <div class="ember-view the-container"> 55698 <div class="ember-view">A</div> 55699 <div class="ember-view">B</div> 55700 <div class="ember-view">Another view</div> 55701 </div> 55702 ``` 55703 55704 ## Templates and Layout 55705 55706 A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or 55707 `defaultLayout` property on a container view will not result in the template 55708 or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM 55709 representation will only be the rendered HTML of its child views. 55710 55711 @class ContainerView 55712 @namespace Ember 55713 @extends Ember.View 55714 @deprecated See http://emberjs.com/deprecations/v1.x/#toc_ember-containerview 55715 @private 55716 */ 55717 var ContainerView = _emberViewsViewsView.default.extend(_emberRuntimeMixinsMutable_array.default, { 55718 willWatchProperty: function (prop) { 55719 _emberMetalDebug.deprecate('ContainerViews should not be observed as arrays. This behavior will change in future implementations of ContainerView.', !prop.match(/\[]/) && prop.indexOf('@') !== 0, { id: 'ember-views.container-views-array-observed', until: '2.4.0' }); 55720 }, 55721 55722 init: function () { 55723 var _this = this; 55724 55725 this._super.apply(this, arguments); 55726 this._prevCurrentView = undefined; 55727 var userChildViews = _emberMetalProperty_get.get(this, 'childViews'); 55728 _emberMetalDebug.deprecate('Setting `childViews` on a Container is deprecated.', _emberMetalCore.default.isEmpty(userChildViews), { id: 'ember-views.container-child-views', until: '2.4.0' }); 55729 55730 // redefine view's childViews property that was obliterated 55731 // 2.0TODO: Don't Ember.A() this so users disabling prototype extensions 55732 // don't pay a penalty. 55733 var childViews = this.childViews = _emberRuntimeSystemNative_array.A(); 55734 55735 userChildViews.forEach(function (viewName, idx) { 55736 var view; 55737 55738 if ('string' === typeof viewName) { 55739 view = _emberMetalProperty_get.get(_this, viewName); 55740 view = _this.createChildView(view); 55741 _emberMetalProperty_set.set(_this, viewName, view); 55742 } else { 55743 view = _this.createChildView(viewName); 55744 } 55745 55746 childViews[idx] = view; 55747 }); 55748 55749 var currentView = _emberMetalProperty_get.get(this, 'currentView'); 55750 if (currentView) { 55751 if (!childViews.length) { 55752 childViews = this.childViews = _emberRuntimeSystemNative_array.A(this.childViews.slice()); 55753 } 55754 childViews.push(this.createChildView(currentView)); 55755 } 55756 55757 _emberMetalProperty_set.set(this, 'length', childViews.length); 55758 }, 55759 55760 // Normally parentView and childViews are managed at render time. However, 55761 // the ContainerView is an unusual legacy case. People expect to be able to 55762 // push a child view into the ContainerView and have its parentView set 55763 // appropriately. As a result, we link the child nodes ahead of time and 55764 // ignore render-time linking. 55765 appendChild: function (view) { 55766 // This occurs if the view being appended is the empty view, rather than 55767 // a view eagerly inserted into the childViews array.
55768 if (view.parentView !== this) { 55769 this.linkChild(view); 55770 } 55771 }, 55772 55773 _currentViewDidChange: _emberMetalMixin.observer('currentView', function () { 55774 var prevView = this._prevCurrentView; 55775 if (prevView) { 55776 prevView.destroy(); 55777 } 55778 var currentView = _emberMetalProperty_get.get(this, 'currentView'); 55779 this._prevCurrentView = currentView; 55780 if (currentView) { 55781 _emberMetalDebug.assert('You tried to set a current view that already has a parent. Make sure you don\'t have multiple outlets in the same view.', !currentView.parentView); 55782 this.pushObject(currentView); 55783 } 55784 }), 55785 55786 layout: _emberHtmlbarsTemplatesContainerView.default, 55787 55788 replace: function (idx, removedCount) { 55789 var _this2 = this; 55790 55791 var addedViews = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2]; 55792 55793 var addedCount = _emberMetalProperty_get.get(addedViews, 'length'); 55794 var childViews = _emberMetalProperty_get.get(this, 'childViews'); 55795 55796 _emberMetalDebug.assert('You can\'t add a child to a container - the child is already a child of another view', (function () { 55797 for (var i = 0, l = addedViews.length; i < l; i++) { 55798 var item = addedViews[i]; 55799 if (item.parentView && item.parentView !== _this2) { 55800 return false; 55801 } 55802 } 55803 return true; 55804 })()); 55805 55806 this.arrayContentWillChange(idx, removedCount, addedCount); 55807 55808 // Normally parentView and childViews are managed at render time. However, 55809 // the ContainerView is an unusual legacy case. People expect to be able to 55810 // push a child view into the ContainerView and have its parentView set 55811 // appropriately. 55812 // 55813 // Because of this, we synchronously fix up the parentView/childViews tree 55814 // as soon as views are added or removed, despite the fact that this will 55815 // happen automatically when we render. 55816 var removedViews = childViews.slice(idx, idx + removedCount); 55817 removedViews.forEach(function (view) { 55818 return _this2.unlinkChild(view); 55819 }); 55820 addedViews.forEach(function (view) { 55821 return _this2.linkChild(view); 55822 }); 55823 55824 childViews.splice.apply(childViews, [idx, removedCount].concat(addedViews)); 55825 55826 this.notifyPropertyChange('childViews'); 55827 this.arrayContentDidChange(idx, removedCount, addedCount); 55828 55829 // assert("You can't add a child to a container - the child is already a child of another view", emberA(addedViews).every(function(item) { return !item.parentView || item.parentView === self; })); 55830 55831 _emberMetalProperty_set.set(this, 'length', childViews.length); 55832 55833 return this; 55834 }, 55835 55836 objectAt: function (idx) { 55837 return this.childViews[idx]; 55838 }, 55839 55840 _triggerChildWillDestroyElement: _emberMetalEvents.on('willDestroyElement', function () { 55841 var childViews = this.childViews; 55842 if (childViews) { 55843 for (var i = 0; i < childViews.length; i++) { 55844 this.renderer.willDestroyElement(childViews[i]); 55845 } 55846 } 55847 }), 55848 55849 _triggerChildDidDestroyElement: _emberMetalEvents.on('didDestroyElement', function () { 55850 var childViews = this.childViews; 55851 if (childViews) { 55852 for (var i = 0; i < childViews.length; i++) { 55853 this.renderer.didDestroyElement(childViews[i]); 55854 } 55855 } 55856 }) 55857 }); 55858 55859 function containerViewDeprecationMessage() { 55860 _emberMetalDebug.deprecate('Ember.ContainerView is deprecated.', !!_emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT, { 55861 url: 'http://emberjs.com/deprecations/v1.x/#toc_ember-containerview', 55862 id: 'ember-views.container-view', 55863 until: '2.4.0' 55864 }); 55865 } 55866 55867 var DeprecatedContainerView = ContainerView.extend({ 55868 init: function () { 55869 containerViewDeprecationMessage(); 55870 this._super.apply(this, arguments); 55871 } 55872 }); 55873 55874 exports.DeprecatedContainerView = DeprecatedContainerView; 55875 DeprecatedContainerView.reopen = function () { 55876 containerViewDeprecationMessage(); 55877 ContainerView.reopen.apply(ContainerView, arguments); 55878 return this; 55879 }; 55880 55881 exports.default = ContainerView; 55882}); 55883enifed('ember-views/views/core_view', ['exports', 'ember-metal/debug', 'ember-metal/property_get', 'ember-runtime/system/object', 'ember-runtime/mixins/evented', 'ember-runtime/mixins/action_handler', 'ember-runtime/utils', 'ember-metal-views', 'ember-views/views/states', 'htmlbars-runtime', 'require'], function (exports, _emberMetalDebug, _emberMetalProperty_get, _emberRuntimeSystemObject, _emberRuntimeMixinsEvented, _emberRuntimeMixinsAction_handler, _emberRuntimeUtils, _emberMetalViews, _emberViewsViewsStates, _htmlbarsRuntime, _require) { 55884 'use strict'; 55885 55886 function K() { 55887 return this; 55888 } 55889 55890 // Normally, the renderer is injected by the container when the view is looked 55891 // up. However, if someone creates a view without looking it up via the 55892 // container (e.g. `Ember.View.create().append()`) then we create a fallback 55893 // DOM renderer that is shared. In general, this path should be avoided since 55894 // views created this way cannot run in a node environment. 55895 var renderer; 55896 55897 /** 55898 `Ember.CoreView` is an abstract class that exists to give view-like behavior 55899 to both Ember's main view class `Ember.View` and other classes that don't need 55900 the fully functionaltiy of `Ember.View`. 55901 55902 Unless you have specific needs for `CoreView`, you will use `Ember.View`
55903 in your applications. 55904 55905 @class CoreView 55906 @namespace Ember 55907 @extends Ember.Object 55908 @deprecated Use `Ember.View` instead. 55909 @uses Ember.Evented 55910 @uses Ember.ActionHandler 55911 @private 55912 */ 55913 var CoreView = _emberRuntimeSystemObject.default.extend(_emberRuntimeMixinsEvented.default, _emberRuntimeMixinsAction_handler.default, { 55914 isView: true, 55915 55916 _states: _emberViewsViewsStates.cloneStates(_emberViewsViewsStates.states), 55917 55918 init: function () { 55919 this._super.apply(this, arguments); 55920 this._state = 'preRender'; 55921 this._currentState = this._states.preRender; 55922 this._isVisible = _emberMetalProperty_get.get(this, 'isVisible'); 55923 55924 // Fallback for legacy cases where the view was created directly 55925 // via `create()` instead of going through the container. 55926 if (!this.renderer) { 55927 var DOMHelper = domHelper(); 55928 renderer = renderer || new _emberMetalViews.Renderer(new DOMHelper()); 55929 this.renderer = renderer; 55930 } 55931 55932 this._destroyingSubtreeForView = null; 55933 this._dispatching = null; 55934 }, 55935 55936 /** 55937 If the view is currently inserted into the DOM of a parent view, this 55938 property will point to the parent of the view. 55939 @property parentView 55940 @type Ember.View 55941 @default null 55942 @private 55943 */ 55944 parentView: null, 55945 55946 _state: null, 55947 55948 instrumentName: 'core_view', 55949 55950 instrumentDetails: function (hash) { 55951 hash.object = this.toString(); 55952 hash.containerKey = this._debugContainerKey; 55953 hash.view = this; 55954 }, 55955 55956 /** 55957 Override the default event firing from `Ember.Evented` to 55958 also call methods with the given name. 55959 @method trigger 55960 @param name {String} 55961 @private 55962 */ 55963 trigger: function () { 55964 this._super.apply(this, arguments); 55965 var name = arguments[0]; 55966 var method = this[name]; 55967 if (method) { 55968 var length = arguments.length; 55969 var args = new Array(length - 1); 55970 for (var i = 1; i < length; i++) { 55971 args[i - 1] = arguments[i]; 55972 } 55973 return method.apply(this, args); 55974 } 55975 }, 55976 55977 has: function (name) { 55978 return _emberRuntimeUtils.typeOf(this[name]) === 'function' || this._super(name); 55979 }, 55980 55981 destroy: function () { 55982 if (!this._super.apply(this, arguments)) { 55983 return; 55984 } 55985 55986 this._currentState.cleanup(this); 55987 55988 // If the destroyingSubtreeForView property is not set but we have an 55989 // associated render node, it means this view is being destroyed from user 55990 // code and not via a change in the templating layer (like an {{if}} 55991 // becoming falsy, for example). In this case, it is our responsibility to 55992 // make sure that any render nodes created as part of the rendering process 55993 // are cleaned up. 55994 if (!this.ownerView._destroyingSubtreeForView && this._renderNode) { 55995 _emberMetalDebug.assert('BUG: Render node exists without concomitant env.', this.ownerView.env); 55996 _htmlbarsRuntime.internal.clearMorph(this._renderNode, this.ownerView.env, true); 55997 } 55998 55999 return this; 56000 }, 56001 56002 clearRenderedChildren: K, 56003 _transitionTo: K, 56004 destroyElement: K 56005 }); 56006 56007 _emberRuntimeMixinsAction_handler.deprecateUnderscoreActions(CoreView); 56008 56009 CoreView.reopenClass({ 56010 isViewFactory: true 56011 }); 56012 56013 var DeprecatedCoreView = CoreView.extend({ 56014 init: function () { 56015 _emberMetalDebug.deprecate('Ember.CoreView is deprecated. Please use Ember.View.', false, { id: 'ember-views.core-view', until: '2.4.0' }); 56016 this._super.apply(this, arguments); 56017 } 56018 }); 56019 56020 exports.DeprecatedCoreView = DeprecatedCoreView; 56021 var _domHelper; 56022 function domHelper() { 56023 return _domHelper = _domHelper || _require.default('ember-htmlbars/system/dom-helper').default; 56024 } 56025 56026 exports.default = CoreView; 56027}); 56028enifed('ember-views/views/legacy_each_view', ['exports', 'ember-htmlbars/templates/legacy-each', 'ember-metal/property_get', 'ember-metal/computed', 'ember-views/views/view', 'ember-views/views/collection_view', 'ember-views/mixins/empty_view_support'], function (exports, _emberHtmlbarsTemplatesLegacyEach, _emberMetalProperty_get, _emberMetalComputed, _emberViewsViewsView, _emberViewsViewsCollection_view, _emberViewsMixinsEmpty_view_support) { 56029 //2.0TODO: Remove this in 2.0 56030 //This is a fallback path for the `{{#each}}` helper that supports deprecated 56031 //behavior such as itemController. 56032 56033 'use strict'; 56034 56035 exports.default = _emberViewsViewsView.default.extend(_emberViewsMixinsEmpty_view_support.default, { 56036 template: _emberHtmlbarsTemplatesLegacyEach.default, 56037 tagName: '', 56038 56039 /* 56040 Support for ArrayController has been extracted to the ember-legacy-controllers addon. 56041 */ 56042 56043 _arrangedContent: _emberMetalComputed.computed('attrs.content', function () { 56044 return this.getAttr('content'); 56045 }), 56046 56047 _itemTagName: _emberMetalComputed.computed(function () { 56048 var tagName = _emberMetalProperty_get.get(this, 'tagName'); 56049 return _emberViewsViewsCollection_view.CONTAINER_MAP[tagName]; 56050 }) 56051 }); 56052}); 56053enifed('ember-views/views/select', ['exports', 'ember-metal/replace', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-views/views/view', 'ember-runtime/utils', 'ember-metal/is_none', 'ember-metal/computed', 'ember-runtime/system/native_array', 'ember-metal/mixin', 'ember-metal/properties', 'ember-htmlbars/templates/select', 'ember-htmlbars/templates/select-option', 'ember-htmlbars/templates/select-optgroup', 'ember-runtime/mixins/array'], function (exports, _emberMetalReplace, _emberMetalProperty_get, _emberMetalProperty_set, _emberViewsViewsView, _emberRuntimeUtils, _emberMetalIs_none, _emberMetalComputed, _emberRuntimeSystemNative_array, _emberMetalMixin, _emberMetalProperties, _emberHtmlbarsTemplatesSelect, _emberHtmlbarsTemplatesSelectOption, _emberHtmlbarsTemplatesSelectOptgroup, _emberRuntimeMixinsArray) { 56054 /** 56055 @module ember 56056 @submodule ember-views 56057 */ 56058 56059 'use strict'; 56060 56061 var defaultTemplate = _emberHtmlbarsTemplatesSelect.default; 56062 56063 var SelectOption = _emberViewsViewsView.default.extend({ 56064 instrumentDisplay: 'Ember.SelectOption', 56065 56066 tagName: 'option', 56067 attributeBindings: ['value', 'selected'], 56068 56069 defaultTemplate: _emberHtmlbarsTemplatesSelectOption.default, 56070 56071 content: null, 56072 56073 _willRender: function () { 56074 this.labelPathDidChange(); 56075 this.valuePathDidChange(); 56076 }, 56077 56078 selected: _emberMetalComputed.computed('attrs.content', 'attrs.selection', function () { 56079 var value = _emberMetalProperty_get.get(this, 'value'); 56080 var selection = _emberMetalProperty_get.get(this, 'attrs.selection'); 56081 if (_emberMetalProperty_get.get(this, 'attrs.multiple')) { 56082 return selection && selection.indexOf(value) > -1; 56083 } else { 56084 // Primitives get passed through bindings as objects... since 56085 // `new Number(4) !== 4`, we use `==` below 56086 return value == _emberMetalProperty_get.get(this, 'attrs.parentValue'); // jshint ignore:line 56087 } 56088 }), 56089 56090 labelPathDidChange: _emberMetalMixin.observer('attrs.optionLabelPath', function () { 56091 var labelPath = _emberMetalProperty_get.get(this, 'attrs.optionLabelPath'); 56092 _emberMetalProperties.defineProperty(this, 'label', _emberMetalComputed.computed.alias(labelPath)); 56093 }), 56094 56095 valuePathDidChange: _emberMetalMixin.observer('attrs.optionValuePath', function () {
56096 var valuePath = _emberMetalProperty_get.get(this, 'attrs.optionValuePath'); 56097 _emberMetalProperties.defineProperty(this, 'value', _emberMetalComputed.computed.alias(valuePath)); 56098 }) 56099 }); 56100 56101 var SelectOptgroup = _emberViewsViewsView.default.extend({ 56102 instrumentDisplay: 'Ember.SelectOptgroup', 56103 56104 tagName: 'optgroup', 56105 defaultTemplate: _emberHtmlbarsTemplatesSelectOptgroup.default, 56106 attributeBindings: ['label'] 56107 }); 56108 56109 /** 56110 The `Ember.Select` view class renders a 56111 [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, 56112 allowing the user to choose from a list of options. 56113 56114 The text and `value` property of each `<option>` element within the 56115 `<select>` element are populated from the objects in the `Element.Select`'s 56116 `content` property. The underlying data object of the selected `<option>` is 56117 stored in the `Element.Select`'s `value` property. 56118 56119 ## The Content Property (array of strings) 56120 56121 The simplest version of an `Ember.Select` takes an array of strings as its 56122 `content` property. The string will be used as both the `value` property and 56123 the inner text of each `<option>` element inside the rendered `<select>`. 56124 56125 Example: 56126 56127 ```javascript 56128 App.ApplicationController = Ember.Controller.extend({ 56129 names: ["Yehuda", "Tom"] 56130 }); 56131 ``` 56132 56133 ```handlebars 56134 {{view "select" content=names}} 56135 ``` 56136 56137 Would result in the following HTML: 56138 56139 ```html 56140 <select class="ember-select"> 56141 <option value="Yehuda">Yehuda</option> 56142 <option value="Tom">Tom</option> 56143 </select> 56144 ``` 56145 56146 You can control which `<option>` is selected through the `Ember.Select`'s 56147 `value` property: 56148 56149 ```javascript 56150 App.ApplicationController = Ember.Controller.extend({ 56151 selectedName: 'Tom', 56152 names: ["Yehuda", "Tom"] 56153 }); 56154 ``` 56155 56156 ```handlebars 56157 {{view "select" content=names value=selectedName}} 56158 ``` 56159 56160 Would result in the following HTML with the `<option>` for 'Tom' selected: 56161 56162 ```html 56163 <select class="ember-select"> 56164 <option value="Yehuda">Yehuda</option> 56165 <option value="Tom" selected="selected">Tom</option> 56166 </select> 56167 ``` 56168 56169 A user interacting with the rendered `<select>` to choose "Yehuda" would 56170 update the value of `selectedName` to "Yehuda". 56171 56172 ## The Content Property (array of Objects) 56173 56174 An `Ember.Select` can also take an array of JavaScript or Ember objects as 56175 its `content` property. 56176 56177 When using objects you need to tell the `Ember.Select` which property should 56178 be accessed on each object to supply the `value` attribute of the `<option>` 56179 and which property should be used to supply the element text. 56180 56181 The `optionValuePath` option is used to specify the path on each object to 56182 the desired property for the `value` attribute. The `optionLabelPath` 56183 specifies the path on each object to the desired property for the 56184 element's text. Both paths must reference each object itself as `content`: 56185 56186 ```javascript 56187 App.ApplicationController = Ember.Controller.extend({ 56188 programmers: [ 56189 {firstName: "Yehuda", id: 1}, 56190 {firstName: "Tom", id: 2} 56191 ] 56192 }); 56193 ``` 56194 56195 ```handlebars 56196 {{view "select" 56197 content=programmers 56198 optionValuePath="content.id" 56199 optionLabelPath="content.firstName"}} 56200 ``` 56201 56202 Would result in the following HTML: 56203 56204 ```html 56205 <select class="ember-select"> 56206 <option value="1">Yehuda</option> 56207 <option value="2">Tom</option> 56208 </select> 56209 ``` 56210 56211 The `value` attribute of the selected `<option>` within an `Ember.Select` 56212 can be bound to a property on another object: 56213 56214 ```javascript 56215 App.ApplicationController = Ember.Controller.extend({ 56216 programmers: [ 56217 {firstName: "Yehuda", id: 1}, 56218 {firstName: "Tom", id: 2} 56219 ], 56220 currentProgrammer: { 56221 id: 2 56222 } 56223 }); 56224 ``` 56225 56226 ```handlebars 56227 {{view "select" 56228 content=programmers 56229 optionValuePath="content.id" 56230 optionLabelPath="content.firstName" 56231 value=currentProgrammer.id}} 56232 ``` 56233 56234 Would result in the following HTML with a selected option: 56235 56236 ```html 56237 <select class="ember-select"> 56238 <option value="1">Yehuda</option> 56239 <option value="2" selected="selected">Tom</option> 56240 </select> 56241 ``` 56242 56243 Interacting with the rendered element by selecting the first option 56244 ('Yehuda') will update the `id` of `currentProgrammer` 56245 to match the `value` property of the newly selected `<option>`. 56246 56247 Alternatively, you can control selection through the underlying objects 56248 used to render each object by binding the `selection` option. When the selected 56249 `<option>` is changed, the property path provided to `selection` 56250 will be updated to match the content object of the rendered `<option>` 56251 element: 56252 56253 ```javascript 56254 56255 var yehuda = {firstName: "Yehuda", id: 1, bff4eva: 'tom'} 56256 var tom = {firstName: "Tom", id: 2, bff4eva: 'yehuda'}; 56257 56258 App.ApplicationController = Ember.Controller.extend({ 56259 selectedPerson: tom, 56260 programmers: [ yehuda, tom ] 56261 }); 56262 ``` 56263 56264 ```handlebars 56265 {{view "select" 56266 content=programmers 56267 optionValuePath="content.id" 56268 optionLabelPath="content.firstName" 56269 selection=selectedPerson}} 56270 ``` 56271 56272 Would result in the following HTML with a selected option: 56273 56274 ```html 56275 <select class="ember-select"> 56276 <option value="1">Yehuda</option> 56277 <option value="2" selected="selected">Tom</option> 56278 </select> 56279 ``` 56280 56281 Interacting with the rendered element by selecting the first option 56282 ('Yehuda') will update the `selectedPerson` to match the object of 56283 the newly selected `<option>`. In this case it is the first object 56284 in the `programmers` 56285 56286 ## Supplying a Prompt 56287 56288 A `null` value for the `Ember.Select`'s `value` or `selection` property 56289 results in there being no `<option>` with a `selected` attribute: 56290 56291 ```javascript 56292 App.ApplicationController = Ember.Controller.extend({ 56293 selectedProgrammer: null, 56294 programmers: ["Yehuda", "Tom"] 56295 }); 56296 ``` 56297 56298 ``` handlebars 56299 {{view "select" 56300 content=programmers 56301 value=selectedProgrammer 56302 }} 56303 ``` 56304 56305 Would result in the following HTML: 56306 56307 ```html 56308 <select class="ember-select"> 56309 <option value="Yehuda">Yehuda</option> 56310 <option value="Tom">Tom</option> 56311 </select> 56312 ``` 56313 56314 Although `selectedProgrammer` is `null` and no `<option>` 56315 has a `selected` attribute the rendered HTML will display the 56316 first item as though it were selected. You can supply a string 56317 value for the `Ember.Select` to display when there is no selection 56318 with the `prompt` option: 56319 56320 ```javascript 56321 App.ApplicationController = Ember.Controller.extend({ 56322 selectedProgrammer: null, 56323 programmers: [ "Yehuda", "Tom" ] 56324 }); 56325 ``` 56326 56327 ```handlebars 56328 {{view "select" 56329 content=programmers 56330 value=selectedProgrammer 56331 prompt="Please select a name" 56332 }} 56333 ``` 56334 56335 Would result in the following HTML: 56336 56337 ```html 56338 <select class="ember-select"> 56339 <option>Please select a name</option> 56340 <option value="Yehuda">Yehuda</option> 56341 <option value="Tom">Tom</option> 56342 </select> 56343 ``` 56344 56345 @class Select 56346 @namespace Ember
56347 @extends Ember.View 56348 @public 56349 @deprecated See http://emberjs.com/deprecations/v1.x/#toc_ember-select 56350 */ 56351 var Select = _emberViewsViewsView.default.extend({ 56352 instrumentDisplay: 'Ember.Select', 56353 56354 tagName: 'select', 56355 classNames: ['ember-select'], 56356 defaultTemplate: defaultTemplate, 56357 attributeBindings: ['autofocus', 'autocomplete', 'disabled', 'form', 'multiple', 'name', 'required', 'size', 'tabindex'], 56358 56359 /** 56360 The `multiple` attribute of the select element. Indicates whether multiple 56361 options can be selected. 56362 @property multiple 56363 @type Boolean 56364 @default false 56365 @public 56366 */ 56367 multiple: false, 56368 56369 /** 56370 The `disabled` attribute of the select element. Indicates whether 56371 the element is disabled from interactions. 56372 @property disabled 56373 @type Boolean 56374 @default false 56375 @public 56376 */ 56377 disabled: false, 56378 56379 /** 56380 The `required` attribute of the select element. Indicates whether 56381 a selected option is required for form validation. 56382 @property required 56383 @type Boolean 56384 @default false 56385 @since 1.5.0 56386 @public 56387 */ 56388 required: false, 56389 56390 /** 56391 The list of options. 56392 If `optionLabelPath` and `optionValuePath` are not overridden, this should 56393 be a list of strings, which will serve simultaneously as labels and values. 56394 Otherwise, this should be a list of objects. For instance: 56395 ```javascript 56396 var App = Ember.Application.create(); 56397 var App.MySelect = Ember.Select.extend({ 56398 content: Ember.A([ 56399 { id: 1, firstName: 'Yehuda' }, 56400 { id: 2, firstName: 'Tom' } 56401 ]), 56402 optionLabelPath: 'content.firstName', 56403 optionValuePath: 'content.id' 56404 }); 56405 ``` 56406 @property content 56407 @type Array 56408 @default null 56409 @public 56410 */ 56411 content: null, 56412 56413 /** 56414 When `multiple` is `false`, the element of `content` that is currently 56415 selected, if any. 56416 When `multiple` is `true`, an array of such elements. 56417 @property selection 56418 @type Object or Array 56419 @default null 56420 @public 56421 */ 56422 selection: null, 56423 56424 /** 56425 In single selection mode (when `multiple` is `false`), value can be used to 56426 get the current selection's value or set the selection by its value. 56427 It is not currently supported in multiple selection mode. 56428 @property value 56429 @type String 56430 @default null 56431 @public 56432 */ 56433 value: _emberMetalComputed.computed('_valuePath', 'selection', { 56434 get: function (key) { 56435 var valuePath = _emberMetalProperty_get.get(this, '_valuePath'); 56436 return valuePath ? _emberMetalProperty_get.get(this, 'selection.' + valuePath) : _emberMetalProperty_get.get(this, 'selection'); 56437 }, 56438 set: function (key, value) { 56439 return value; 56440 } 56441 }), 56442 56443 /** 56444 If given, a top-most dummy option will be rendered to serve as a user 56445 prompt. 56446 @property prompt 56447 @type String 56448 @default null 56449 @public 56450 */ 56451 prompt: null, 56452 56453 /** 56454 The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). 56455 @property optionLabelPath 56456 @type String 56457 @default 'content' 56458 @public 56459 */ 56460 optionLabelPath: 'content', 56461 56462 /** 56463 The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). 56464 @property optionValuePath 56465 @type String 56466 @default 'content' 56467 @public 56468 */ 56469 optionValuePath: 'content', 56470 56471 /** 56472 The path of the option group. 56473 When this property is used, `content` should be sorted by `optionGroupPath`. 56474 @property optionGroupPath 56475 @type String 56476 @default null 56477 @public 56478 */ 56479 optionGroupPath: null, 56480 56481 /** 56482 The view class for optgroup. 56483 @property groupView 56484 @type Ember.View 56485 @default Ember.SelectOptgroup 56486 @public 56487 */ 56488 groupView: SelectOptgroup, 56489 56490 groupedContent: _emberMetalComputed.computed('optionGroupPath', 'content.[]', function () { 56491 var groupPath = _emberMetalProperty_get.get(this, 'optionGroupPath'); 56492 var groupedContent = _emberRuntimeSystemNative_array.A(); 56493 var content = _emberMetalProperty_get.get(this, 'content') || []; 56494 56495 content.forEach(function (item) { 56496 var label = _emberMetalProperty_get.get(item, groupPath); 56497 56498 if (_emberMetalProperty_get.get(groupedContent, 'lastObject.label') !== label) { 56499 groupedContent.pushObject({ 56500 label: label, 56501 content: _emberRuntimeSystemNative_array.A() 56502 }); 56503 } 56504 56505 _emberMetalProperty_get.get(groupedContent, 'lastObject.content').push(item); 56506 }); 56507 56508 return groupedContent; 56509 }), 56510 56511 /** 56512 The view class for option. 56513 @property optionView 56514 @type Ember.View 56515 @default Ember.SelectOption 56516 @private 56517 */ 56518 optionView: SelectOption, 56519 56520 _change: function (hasDOM) { 56521 if (_emberMetalProperty_get.get(this, 'multiple')) { 56522 this._changeMultiple(hasDOM); 56523 } else { 56524 this._changeSingle(hasDOM); 56525 } 56526 }, 56527 56528 selectionDidChange: _emberMetalMixin.observer('selection.[]', function () { 56529 var selection = _emberMetalProperty_get.get(this, 'selection'); 56530 if (_emberMetalProperty_get.get(this, 'multiple')) { 56531 if (!_emberRuntimeUtils.isArray(selection)) { 56532 _emberMetalProperty_set.set(this, 'selection', _emberRuntimeSystemNative_array.A([selection])); 56533 return; 56534 } 56535 this._selectionDidChangeMultiple(); 56536 } else { 56537 this._selectionDidChangeSingle(); 56538 } 56539 }), 56540 56541 valueDidChange: _emberMetalMixin.observer('value', function () { 56542 var content = _emberMetalProperty_get.get(this, 'content'); 56543 var value = _emberMetalProperty_get.get(this, 'value');
56544 var valuePath = _emberMetalProperty_get.get(this, 'optionValuePath').replace(/^content\.?/, ''); 56545 var selectedValue = valuePath ? _emberMetalProperty_get.get(this, 'selection.' + valuePath) : _emberMetalProperty_get.get(this, 'selection'); 56546 var selection; 56547 56548 if (value !== selectedValue) { 56549 selection = content ? content.find(function (obj) { 56550 return value === (valuePath ? _emberMetalProperty_get.get(obj, valuePath) : obj); 56551 }) : null; 56552 56553 this.set('selection', selection); 56554 } 56555 }), 56556 56557 _setDefaults: function () { 56558 var selection = _emberMetalProperty_get.get(this, 'selection'); 56559 var value = _emberMetalProperty_get.get(this, 'value'); 56560 56561 if (!_emberMetalIs_none.default(selection)) { 56562 this.selectionDidChange(); 56563 } 56564 if (!_emberMetalIs_none.default(value)) { 56565 this.valueDidChange(); 56566 } 56567 if (_emberMetalIs_none.default(selection)) { 56568 this._change(false); 56569 } 56570 }, 56571 56572 _changeSingle: function (hasDOM) { 56573 var value = this.get('value'); 56574 var selectedIndex = hasDOM !== false ? this.$()[0].selectedIndex : this._selectedIndex(value); 56575 var content = _emberMetalProperty_get.get(this, 'content'); 56576 var prompt = _emberMetalProperty_get.get(this, 'prompt'); 56577 56578 if (!content || !_emberMetalProperty_get.get(content, 'length')) { 56579 return; 56580 } 56581 if (prompt && selectedIndex === 0) { 56582 _emberMetalProperty_set.set(this, 'selection', null); 56583 return; 56584 } 56585 56586 if (prompt) { 56587 selectedIndex -= 1; 56588 } 56589 _emberMetalProperty_set.set(this, 'selection', _emberRuntimeMixinsArray.objectAt(content, selectedIndex)); 56590 }, 56591 56592 _selectedIndex: function (value) { 56593 var defaultIndex = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1]; 56594 56595 var content = _emberMetalProperty_get.get(this, 'contentValues'); 56596 56597 var selectionIndex = content.indexOf(value); 56598 56599 var prompt = _emberMetalProperty_get.get(this, 'prompt'); 56600 if (prompt) { 56601 selectionIndex += 1; 56602 } 56603 56604 if (selectionIndex < 0) { 56605 selectionIndex = defaultIndex; 56606 } 56607 56608 return selectionIndex; 56609 }, 56610 56611 _changeMultiple: function (hasDOM) { 56612 var options = hasDOM !== false ? this.$('option:selected') : []; 56613 var prompt = _emberMetalProperty_get.get(this, 'prompt'); 56614 var offset = prompt ? 1 : 0; 56615 var content = _emberMetalProperty_get.get(this, 'content'); 56616 var selection = _emberMetalProperty_get.get(this, 'selection'); 56617 56618 if (!content) { 56619 return; 56620 } 56621 if (options) { 56622 var selectedIndexes = options.map(function () { 56623 return this.index - offset; 56624 }); 56625 var newSelection = content.objectsAt([].slice.call(selectedIndexes)); 56626 56627 if (_emberRuntimeUtils.isArray(selection)) { 56628 _emberMetalReplace.default(selection, 0, _emberMetalProperty_get.get(selection, 'length'), newSelection); 56629 } else { 56630 _emberMetalProperty_set.set(this, 'selection', newSelection); 56631 } 56632 } 56633 }, 56634 56635 _selectionDidChangeSingle: function () { 56636 var value = _emberMetalProperty_get.get(this, 'value'); 56637 var self = this; 56638 if (value && value.then) { 56639 value.then(function (resolved) { 56640 // Ensure that we don't overwrite new value 56641 if (_emberMetalProperty_get.get(self, 'value') === value) { 56642 self._setSelectedIndex(resolved); 56643 } 56644 }); 56645 } else { 56646 this._setSelectedIndex(value); 56647 } 56648 }, 56649 56650 _setSelectedIndex: function (selectionValue) { 56651 var el = _emberMetalProperty_get.get(this, 'element'); 56652 if (!el) { 56653 return; 56654 } 56655 56656 el.selectedIndex = this._selectedIndex(selectionValue, -1); 56657 }, 56658 56659 _valuePath: _emberMetalComputed.computed('optionValuePath', function () { 56660 var optionValuePath = _emberMetalProperty_get.get(this, 'optionValuePath'); 56661 return optionValuePath.replace(/^content\.?/, ''); 56662 }), 56663 56664 contentValues: _emberMetalComputed.computed('content.[]', '_valuePath', function () {
56665 var valuePath = _emberMetalProperty_get.get(this, '_valuePath'); 56666 var content = _emberMetalProperty_get.get(this, 'content') || []; 56667 56668 if (valuePath) { 56669 return content.map(function (el) { 56670 return _emberMetalProperty_get.get(el, valuePath); 56671 }); 56672 } else { 56673 return content.slice(); 56674 } 56675 }), 56676 56677 _selectionDidChangeMultiple: function () { 56678 var content = _emberMetalProperty_get.get(this, 'content'); 56679 var selection = _emberMetalProperty_get.get(this, 'selection'); 56680 var selectedIndexes = content ? indexesOf(content, selection) : [-1]; 56681 var prompt = _emberMetalProperty_get.get(this, 'prompt'); 56682 var offset = prompt ? 1 : 0; 56683 var options = this.$('option'); 56684 var adjusted; 56685 56686 if (options) { 56687 options.each(function () { 56688 adjusted = this.index > -1 ? this.index - offset : -1; 56689 this.selected = selectedIndexes.indexOf(adjusted) > -1; 56690 }); 56691 } 56692 }, 56693 56694 _willRender: function () { 56695 this._setDefaults(); 56696 }, 56697 56698 init: function () { 56699 this._super.apply(this, arguments); 56700 this.on('change', this, this._change); 56701 } 56702 }); 56703 56704 function indexesOf(iterable, elements) { 56705 return elements === undefined ? [] : elements.map(function (item) { 56706 return iterable.indexOf(item); 56707 }); 56708 } 56709 56710 exports.default = Select; 56711 exports.Select = Select; 56712 exports.SelectOption = SelectOption; 56713 exports.SelectOptgroup = SelectOptgroup; 56714}); 56715enifed('ember-views/views/states/default', ['exports', 'ember-metal/error', 'ember-metal/property_get', 'ember-views/compat/attrs-proxy'], function (exports, _emberMetalError, _emberMetalProperty_get, _emberViewsCompatAttrsProxy) { 56716 'use strict'; 56717 56718 /** 56719 @module ember 56720 @submodule ember-views 56721 */ 56722 exports.default = { 56723 // appendChild is only legal while rendering the buffer. 56724 appendChild: function () { 56725 throw new _emberMetalError.default('You can\'t use appendChild outside of the rendering process'); 56726 }, 56727 56728 $: function () { 56729 return undefined; 56730 }, 56731 56732 getElement: function () { 56733 return null; 56734 }, 56735 56736 legacyPropertyDidChange: function (view, key) { 56737 var attrs = view.attrs; 56738 if (attrs && key in attrs) { 56739 var possibleCell = attrs[key]; 56740 56741 if (possibleCell && possibleCell[_emberViewsCompatAttrsProxy.MUTABLE_CELL]) { 56742 var value = _emberMetalProperty_get.get(view, key); 56743 if (value === possibleCell.value) { 56744 return; 56745 } 56746 possibleCell.update(value); 56747 } 56748 } 56749 }, 56750 56751 // Handle events from `Ember.EventDispatcher` 56752 handleEvent: function () { 56753 return true; // continue event propagation 56754 }, 56755 56756 cleanup: function () {}, 56757 destroyElement: function () {}, 56758 56759 rerender: function (view) { 56760 view.renderer.ensureViewNotRendering(view); 56761 }, 56762 invokeObserver: function () {} 56763 }; 56764}); 56765enifed('ember-views/views/states/destroying', ['exports', 'ember-metal/assign', 'ember-views/views/states/default', 'ember-metal/error'], function (exports, _emberMetalAssign, _emberViewsViewsStatesDefault, _emberMetalError) { 56766 'use strict'; 56767 56768 /** 56769 @module ember 56770 @submodule ember-views 56771 */ 56772 56773 var destroying = Object.create(_emberViewsViewsStatesDefault.default); 56774 56775 _emberMetalAssign.default(destroying, { 56776 appendChild: function () { 56777 throw new _emberMetalError.default('You can\'t call appendChild on a view being destroyed'); 56778 }, 56779 rerender: function () { 56780 throw new _emberMetalError.default('You can\'t call rerender on a view being destroyed'); 56781 }, 56782 destroyElement: function () { 56783 throw new _emberMetalError.default('You can\'t call destroyElement on a view being destroyed'); 56784 } 56785 }); 56786 56787 exports.default = destroying; 56788}); 56789enifed('ember-views/views/states/has_element', ['exports', 'ember-views/views/states/default', 'ember-metal/assign', 'ember-views/system/jquery', 'ember-metal/run_loop', 'ember-metal/property_get'], function (exports, _emberViewsViewsStatesDefault, _emberMetalAssign, _emberViewsSystemJquery, _emberMetalRun_loop, _emberMetalProperty_get) { 56790 'use strict'; 56791 56792 var hasElement = Object.create(_emberViewsViewsStatesDefault.default); 56793 56794 _emberMetalAssign.default(hasElement, { 56795 $: function (view, sel) { 56796 var elem = view.element; 56797 return sel ? _emberViewsSystemJquery.default(sel, elem) : _emberViewsSystemJquery.default(elem); 56798 }, 56799 56800 getElement: function (view) { 56801 var parent = _emberMetalProperty_get.get(view, 'parentView'); 56802 if (parent) { 56803 parent = _emberMetalProperty_get.get(parent, 'element'); 56804 } 56805 if (parent) { 56806 return view.findElementInParentElement(parent); 56807 } 56808 return _emberViewsSystemJquery.default('#' + _emberMetalProperty_get.get(view, 'elementId'))[0]; 56809 }, 56810 56811 // once the view has been inserted into the DOM, rerendering is 56812 // deferred to allow bindings to synchronize. 56813 rerender: function (view) { 56814 view.renderer.ensureViewNotRendering(view); 56815 view.renderer.rerender(view); 56816 }, 56817 56818 cleanup: function (view) { 56819 view._currentState.destroyElement(view); 56820 }, 56821 56822 // once the view is already in the DOM, destroying it removes it 56823 // from the DOM, nukes its element, and puts it back into the 56824 // preRender state if inDOM. 56825 56826 destroyElement: function (view) { 56827 view.renderer.remove(view, false); 56828 return view; 56829 }, 56830 56831 // Handle events from `Ember.EventDispatcher` 56832 handleEvent: function (view, eventName, evt) { 56833 if (view.has(eventName)) { 56834 // Handler should be able to re-dispatch events, so we don't 56835 // preventDefault or stopPropagation. 56836 return _emberMetalRun_loop.default.join(view, view.trigger, eventName, evt); 56837 } else { 56838 return true; // continue event propagation 56839 } 56840 }, 56841 56842 invokeObserver: function (target, observer) { 56843 observer.call(target); 56844 } 56845 }); 56846 56847 exports.default = hasElement; 56848}); 56849 56850/** 56851@module ember 56852@submodule ember-views 56853*/ 56854enifed('ember-views/views/states/in_dom', ['exports', 'ember-metal/debug', 'ember-metal/assign', 'ember-metal/error', 'ember-metal/observer', 'ember-views/views/states/has_element'], function (exports, _emberMetalDebug, _emberMetalAssign, _emberMetalError, _emberMetalObserver, _emberViewsViewsStatesHas_element) { 56855 'use strict'; 56856 56857 /** 56858 @module ember 56859 @submodule ember-views 56860 */ 56861 56862 var inDOM = Object.create(_emberViewsViewsStatesHas_element.default); 56863 56864 _emberMetalAssign.default(inDOM, { 56865 enter: function (view) { 56866 // Register the view for event handling. This hash is used by 56867 // Ember.EventDispatcher to dispatch incoming events. 56868 if (view.tagName !== '') { 56869 view._register(); 56870 } 56871 56872 _emberMetalDebug.runInDebug(function () { 56873 _emberMetalObserver._addBeforeObserver(view, 'elementId', function () { 56874 throw new _emberMetalError.default('Changing a view\'s elementId after creation is not allowed'); 56875 }); 56876 }); 56877 }, 56878 56879 exit: function (view) { 56880 view._unregister(); 56881 } 56882 }); 56883 56884 exports.default = inDOM; 56885}); 56886enifed('ember-views/views/states/pre_render', ['exports', 'ember-views/views/states/default', 'ember-metal/assign'], function (exports, _emberViewsViewsStatesDefault, _emberMetalAssign) { 56887 'use strict'; 56888 56889 /** 56890 @module ember 56891 @submodule ember-views 56892 */ 56893 56894 var preRender = Object.create(_emberViewsViewsStatesDefault.default); 56895 56896 _emberMetalAssign.default(preRender, { 56897 legacyPropertyDidChange: function (view, key) {} 56898 }); 56899 56900 exports.default = preRender; 56901}); 56902enifed('ember-views/views/states', ['exports', 'ember-metal/assign', 'ember-views/views/states/default', 'ember-views/views/states/pre_render', 'ember-views/views/states/has_element', 'ember-views/views/states/in_dom', 'ember-views/views/states/destroying'], function (exports, _emberMetalAssign, _emberViewsViewsStatesDefault, _emberViewsViewsStatesPre_render, _emberViewsViewsStatesHas_element, _emberViewsViewsStatesIn_dom, _emberViewsViewsStatesDestroying) { 56903 'use strict'; 56904 56905 exports.cloneStates = cloneStates; 56906 56907 function cloneStates(from) { 56908 var into = {}; 56909 56910 into._default = {}; 56911 into.preRender = Object.create(into._default); 56912 into.destroying = Object.create(into._default); 56913 into.hasElement = Object.create(into._default); 56914 into.inDOM = Object.create(into.hasElement); 56915 56916 for (var stateName in from) { 56917 if (!from.hasOwnProperty(stateName)) { 56918 continue; 56919 } 56920 _emberMetalAssign.default(into[stateName], from[stateName]); 56921 } 56922 56923 return into; 56924 } 56925 56926 var states = { 56927 _default: _emberViewsViewsStatesDefault.default, 56928 preRender: _emberViewsViewsStatesPre_render.default, 56929 inDOM: _emberViewsViewsStatesIn_dom.default, 56930 hasElement: _emberViewsViewsStatesHas_element.default, 56931 destroying: _emberViewsViewsStatesDestroying.default 56932 }; 56933 exports.states = states; 56934}); 56935enifed('ember-views/views/text_area', ['exports', 'ember-views/components/component', 'ember-views/mixins/text_support'], function (exports, _emberViewsComponentsComponent, _emberViewsMixinsText_support) { 56936 /** 56937 @module ember 56938 @submodule ember-views 56939 */ 56940 'use strict'; 56941 56942 /**
56943 The internal class used to create textarea element when the `{{textarea}}` 56944 helper is used. 56945 56946 See [Ember.Templates.helpers.textarea](/api/classes/Ember.Templates.helpers.html#method_textarea) for usage details. 56947 56948 ## Layout and LayoutName properties 56949 56950 Because HTML `textarea` elements do not contain inner HTML the `layout` and 56951 `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s 56952 layout section for more information. 56953 56954 @class TextArea 56955 @namespace Ember 56956 @extends Ember.Component 56957 @uses Ember.TextSupport 56958 @public 56959 */ 56960 exports.default = _emberViewsComponentsComponent.default.extend(_emberViewsMixinsText_support.default, { 56961 instrumentDisplay: '{{textarea}}', 56962 56963 classNames: ['ember-text-area'], 56964 56965 tagName: 'textarea', 56966 attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap', 'lang', 'dir', 'value'], 56967 rows: null, 56968 cols: null 56969 }); 56970}); 56971enifed('ember-views/views/text_field', ['exports', 'ember-metal/computed', 'ember-metal/environment', 'ember-views/components/component', 'ember-views/mixins/text_support', 'ember-metal/empty_object'], function (exports, _emberMetalComputed, _emberMetalEnvironment, _emberViewsComponentsComponent, _emberViewsMixinsText_support, _emberMetalEmpty_object) { 56972 /** 56973 @module ember 56974 @submodule ember-views 56975 */ 56976 'use strict'; 56977 56978 var inputTypeTestElement; 56979 var inputTypes = new _emberMetalEmpty_object.default(); 56980 function canSetTypeOfInput(type) { 56981 if (type in inputTypes) { 56982 return inputTypes[type]; 56983 } 56984 56985 // if running in outside of a browser always return the 56986 // original type 56987 if (!_emberMetalEnvironment.default.hasDOM) { 56988 inputTypes[type] = type; 56989 56990 return type; 56991 } 56992 56993 if (!inputTypeTestElement) { 56994 inputTypeTestElement = document.createElement('input'); 56995 } 56996 56997 try { 56998 inputTypeTestElement.type = type; 56999 } catch (e) {} 57000 57001 return inputTypes[type] = inputTypeTestElement.type === type; 57002 } 57003 57004 /** 57005 57006 The internal class used to create text inputs when the `{{input}}` 57007 helper is used with `type` of `text`. 57008 57009 See [Ember.Templates.helpers.input](/api/classes/Ember.Templates.helpers.html#method_input) for usage details. 57010 57011 ## Layout and LayoutName properties 57012 57013 Because HTML `input` elements are self closing `layout` and `layoutName` 57014 properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s 57015 layout section for more information. 57016 57017 @class TextField 57018 @namespace Ember 57019 @extends Ember.Component 57020 @uses Ember.TextSupport 57021 @public 57022 */ 57023 exports.default = _emberViewsComponentsComponent.default.extend(_emberViewsMixinsText_support.default, { 57024 instrumentDisplay: '{{input type="text"}}', 57025 57026 classNames: ['ember-text-field'], 57027 tagName: 'input', 57028 attributeBindings: ['accept', 'autocomplete', 'autosave', 'dir', 'formaction', 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', 'height', 'inputmode', 'lang', 'list', 'max', 'min', 'multiple', 'name', 'pattern', 'size', 'step', 'type', 'value', 'width'], 57029 57030 defaultLayout: null, 57031 57032 /** 57033 The `value` attribute of the input element. As the user inputs text, this 57034 property is updated live. 57035 @property value 57036 @type String 57037 @default "" 57038 @public 57039 */ 57040 value: '', 57041 57042 /** 57043 The `type` attribute of the input element. 57044 @property type 57045 @type String 57046 @default "text" 57047 @public 57048 */ 57049 type: _emberMetalComputed.computed({ 57050 get: function () { 57051 return 'text'; 57052 }, 57053 57054 set: function (key, value) { 57055 var type = 'text'; 57056 57057 if (canSetTypeOfInput(value)) { 57058 type = value; 57059 } 57060 57061 return type; 57062 } 57063 }), 57064 57065 /** 57066 The `size` of the text field in characters. 57067 @property size 57068 @type String 57069 @default null 57070 @public 57071 */ 57072 size: null, 57073 57074 /** 57075 The `pattern` attribute of input element. 57076 @property pattern 57077 @type String 57078 @default null 57079 @public 57080 */ 57081 pattern: null, 57082 57083 /** 57084 The `min` attribute of input element used with `type="number"` or `type="range"`. 57085 @property min
57086 @type String 57087 @default null 57088 @since 1.4.0 57089 @public 57090 */ 57091 min: null, 57092 57093 /** 57094 The `max` attribute of input element used with `type="number"` or `type="range"`. 57095 @property max 57096 @type String 57097 @default null 57098 @since 1.4.0 57099 @public 57100 */ 57101 max: null 57102 }); 57103}); 57104enifed('ember-views/views/view', ['exports', 'ember-metal/core', 'ember-metal/debug', 'ember-views/system/ext', 'ember-views/views/core_view', 'ember-views/mixins/view_context_support', 'ember-views/mixins/view_child_views_support', 'ember-views/mixins/legacy_child_views_support', 'ember-views/mixins/view_state_support', 'ember-views/mixins/template_rendering_support', 'ember-views/mixins/class_names_support', 'ember-views/mixins/legacy_view_support', 'ember-views/mixins/instrumentation_support', 'ember-views/mixins/aria_role_support', 'ember-views/mixins/visibility_support', 'ember-views/compat/attrs-proxy', 'ember-views/mixins/view_support', 'ember-metal/deprecate_property'], function (exports, _emberMetalCore, _emberMetalDebug, _emberViewsSystemExt, _emberViewsViewsCore_view, _emberViewsMixinsView_context_support, _emberViewsMixinsView_child_views_support, _emberViewsMixinsLegacy_child_views_support, _emberViewsMixinsView_state_support, _emberViewsMixinsTemplate_rendering_support, _emberViewsMixinsClass_names_support, _emberViewsMixinsLegacy_view_support, _emberViewsMixinsInstrumentation_support, _emberViewsMixinsAria_role_support, _emberViewsMixinsVisibility_support, _emberViewsCompatAttrsProxy, _emberViewsMixinsView_support, _emberMetalDeprecate_property) { 57105 // jQuery, Ember.lookup, 57106 // Ember.ContainerView circular dependency 57107 // Ember.ENV 57108 'use strict'; 57109 57110 /** 57111 @module ember 57112 @submodule ember-views 57113 */ 57114 57115 /** 57116 `Ember.View` is the class in Ember responsible for encapsulating templates of 57117 HTML content, combining templates with data to render as sections of a page's 57118 DOM, and registering and responding to user-initiated events. 57119 57120 ## HTML Tag 57121 57122 The default HTML tag name used for a view's DOM representation is `div`. This 57123 can be customized by setting the `tagName` property. The following view 57124 class: 57125 57126 ```javascript 57127 ParagraphView = Ember.View.extend({ 57128 tagName: 'em' 57129 }); 57130 ``` 57131 57132 Would result in instances with the following HTML: 57133 57134 ```html 57135 <em id="ember1" class="ember-view"></em> 57136 ``` 57137 57138 ## HTML `class` Attribute 57139 57140 The HTML `class` attribute of a view's tag can be set by providing a 57141 `classNames` property that is set to an array of strings: 57142 57143 ```javascript 57144 MyView = Ember.View.extend({ 57145 classNames: ['my-class', 'my-other-class'] 57146 }); 57147 ``` 57148 57149 Will result in view instances with an HTML representation of: 57150 57151 ```html 57152 <div id="ember1" class="ember-view my-class my-other-class"></div> 57153 ``` 57154 57155 `class` attribute values can also be set by providing a `classNameBindings` 57156 property set to an array of properties names for the view. The return value 57157 of these properties will be added as part of the value for the view's `class` 57158 attribute. These properties can be computed properties: 57159 57160 ```javascript 57161 MyView = Ember.View.extend({ 57162 classNameBindings: ['propertyA', 'propertyB'], 57163 propertyA: 'from-a', 57164 propertyB: Ember.computed(function() { 57165 if (someLogic) { return 'from-b'; } 57166 }) 57167 }); 57168 ``` 57169 57170 Will result in view instances with an HTML representation of: 57171 57172 ```html 57173 <div id="ember1" class="ember-view from-a from-b"></div> 57174 ``` 57175 57176 If the value of a class name binding returns a boolean the property name 57177 itself will be used as the class name if the property is true. The class name 57178 will not be added if the value is `false` or `undefined`. 57179 57180 ```javascript 57181 MyView = Ember.View.extend({ 57182 classNameBindings: ['hovered'], 57183 hovered: true 57184 }); 57185 ``` 57186 57187 Will result in view instances with an HTML representation of: 57188 57189 ```html 57190 <div id="ember1" class="ember-view hovered"></div> 57191 ``` 57192 57193 When using boolean class name bindings you can supply a string value other 57194 than the property name for use as the `class` HTML attribute by appending the 57195 preferred value after a ":" character when defining the binding: 57196 57197 ```javascript 57198 MyView = Ember.View.extend({ 57199 classNameBindings: ['awesome:so-very-cool'], 57200 awesome: true 57201 }); 57202 ``` 57203 57204 Will result in view instances with an HTML representation of: 57205 57206 ```html 57207 <div id="ember1" class="ember-view so-very-cool"></div> 57208 ``` 57209 57210 Boolean value class name bindings whose property names are in a 57211 camelCase-style format will be converted to a dasherized format: 57212 57213 ```javascript 57214 MyView = Ember.View.extend({ 57215 classNameBindings: ['isUrgent'], 57216 isUrgent: true 57217 }); 57218 ``` 57219 57220 Will result in view instances with an HTML representation of: 57221 57222 ```html 57223 <div id="ember1" class="ember-view is-urgent"></div> 57224 ``` 57225 57226 Class name bindings can also refer to object values that are found by 57227 traversing a path relative to the view itself: 57228 57229 ```javascript 57230 MyView = Ember.View.extend({ 57231 classNameBindings: ['messages.empty'] 57232 messages: Ember.Object.create({ 57233 empty: true 57234 }) 57235 }); 57236 ``` 57237 57238 Will result in view instances with an HTML representation of: 57239 57240 ```html 57241 <div id="ember1" class="ember-view empty"></div> 57242 ``` 57243 57244 If you want to add a class name for a property which evaluates to true and 57245 and a different class name if it evaluates to false, you can pass a binding 57246 like this: 57247 57248 ```javascript 57249 // Applies 'enabled' class when isEnabled is true and 'disabled' when isEnabled is false 57250 Ember.View.extend({ 57251 classNameBindings: ['isEnabled:enabled:disabled'] 57252 isEnabled: true 57253 }); 57254 ``` 57255 57256 Will result in view instances with an HTML representation of: 57257 57258 ```html 57259 <div id="ember1" class="ember-view enabled"></div> 57260 ``` 57261 57262 When isEnabled is `false`, the resulting HTML representation looks like 57263 this: 57264 57265 ```html 57266 <div id="ember1" class="ember-view disabled"></div> 57267 ``` 57268 57269 This syntax offers the convenience to add a class if a property is `false`: 57270 57271 ```javascript 57272 // Applies no class when isEnabled is true and class 'disabled' when isEnabled is false 57273 Ember.View.extend({ 57274 classNameBindings: ['isEnabled::disabled'] 57275 isEnabled: true 57276 }); 57277 ``` 57278 57279 Will result in view instances with an HTML representation of: 57280 57281 ```html 57282 <div id="ember1" class="ember-view"></div> 57283 ``` 57284 57285 When the `isEnabled` property on the view is set to `false`, it will result 57286 in view instances with an HTML representation of: 57287 57288 ```html 57289 <div id="ember1" class="ember-view disabled"></div> 57290 ``` 57291 57292 Updates to the value of a class name binding will result in automatic 57293 update of the HTML `class` attribute in the view's rendered HTML 57294 representation. If the value becomes `false` or `undefined` the class name 57295 will be removed. 57296 57297 Both `classNames` and `classNameBindings` are concatenated properties. See 57298 [Ember.Object](/api/classes/Ember.Object.html) documentation for more 57299 information about concatenated properties. 57300 57301 ## HTML Attributes 57302 57303 The HTML attribute section of a view's tag can be set by providing an 57304 `attributeBindings` property set to an array of property names on the view. 57305 The return value of these properties will be used as the value of the view's 57306 HTML associated attribute: 57307 57308 ```javascript 57309 AnchorView = Ember.View.extend({ 57310 tagName: 'a', 57311 attributeBindings: ['href'], 57312 href: 'http://google.com' 57313 }); 57314 ``` 57315 57316 Will result in view instances with an HTML representation of: 57317 57318 ```html 57319 <a id="ember1" class="ember-view" href="http://google.com"></a> 57320 ``` 57321
57322 One property can be mapped on to another by placing a ":" between 57323 the source property and the destination property: 57324 57325 ```javascript 57326 AnchorView = Ember.View.extend({ 57327 tagName: 'a', 57328 attributeBindings: ['url:href'], 57329 url: 'http://google.com' 57330 }); 57331 ``` 57332 57333 Will result in view instances with an HTML representation of: 57334 57335 ```html 57336 <a id="ember1" class="ember-view" href="http://google.com"></a> 57337 ``` 57338 57339 Namespaced attributes (e.g. `xlink:href`) are supported, but have to be 57340 mapped, since `:` is not a valid character for properties in Javascript: 57341 57342 ```javascript 57343 UseView = Ember.View.extend({ 57344 tagName: 'use', 57345 attributeBindings: ['xlinkHref:xlink:href'], 57346 xlinkHref: '#triangle' 57347 }); 57348 ``` 57349 Will result in view instances with an HTML representation of: 57350 57351 ```html 57352 <use xlink:href="#triangle"></use> 57353 ``` 57354 57355 If the return value of an `attributeBindings` monitored property is a boolean 57356 the property's value will be set as a coerced string: 57357 57358 ```javascript 57359 MyTextInput = Ember.View.extend({ 57360 tagName: 'input', 57361 attributeBindings: ['disabled'], 57362 disabled: false 57363 }); 57364 ``` 57365 57366 Will result in a view instance with an HTML representation of: 57367 57368 ```html 57369 <input id="ember1" class="ember-view" disabled="false" /> 57370 ``` 57371 57372 `attributeBindings` can refer to computed properties: 57373 57374 ```javascript 57375 MyTextInput = Ember.View.extend({ 57376 tagName: 'input', 57377 attributeBindings: ['disabled'], 57378 disabled: Ember.computed(function() { 57379 if (someLogic) { 57380 return true; 57381 } else { 57382 return false; 57383 } 57384 }) 57385 }); 57386 ``` 57387 57388 To prevent setting an attribute altogether, use `null` or `undefined` as the 57389 return value of the `attributeBindings` monitored property: 57390 57391 ```javascript 57392 MyTextInput = Ember.View.extend({ 57393 tagName: 'form', 57394 attributeBindings: ['novalidate'], 57395 novalidate: null 57396 }); 57397 ``` 57398 57399 Updates to the property of an attribute binding will result in automatic 57400 update of the HTML attribute in the view's rendered HTML representation. 57401 57402 `attributeBindings` is a concatenated property. See [Ember.Object](/api/classes/Ember.Object.html) 57403 documentation for more information about concatenated properties. 57404 57405 ## Templates 57406 57407 The HTML contents of a view's rendered representation are determined by its 57408 template. Templates can be any function that accepts an optional context 57409 parameter and returns a string of HTML that will be inserted within the 57410 view's tag. Most typically in Ember this function will be a compiled 57411 template. 57412 57413 ```javascript 57414 AView = Ember.View.extend({ 57415 template: Ember.HTMLBars.compile('I am the template') 57416 }); 57417 ``` 57418 57419 Will result in view instances with an HTML representation of: 57420 57421 ```html 57422 <div id="ember1" class="ember-view">I am the template</div> 57423 ``` 57424 57425 Within an Ember application is more common to define a Handlebars templates as 57426 part of a page: 57427 57428 ```html 57429 <script type='text/x-handlebars' data-template-name='some-template'> 57430 Hello 57431 </script> 57432 ``` 57433 57434 And associate it by name using a view's `templateName` property: 57435 57436 ```javascript 57437 AView = Ember.View.extend({ 57438 templateName: 'some-template' 57439 }); 57440 ``` 57441 57442 If you have nested routes, your Handlebars template will look like this: 57443 57444 ```html 57445 <script type='text/x-handlebars' data-template-name='posts/new'> 57446 <h1>New Post</h1> 57447 </script> 57448 ``` 57449 57450 And `templateName` property: 57451 57452 ```javascript 57453 AView = Ember.View.extend({ 57454 templateName: 'posts/new' 57455 }); 57456 ``` 57457 57458 Using a value for `templateName` that does not have a template 57459 with a matching `data-template-name` attribute will throw an error. 57460 57461 For views classes that may have a template later defined (e.g. as the block 57462 portion of a `{{view}}` helper call in another template or in 57463 a subclass), you can provide a `defaultTemplate` property set to compiled 57464 template function. If a template is not later provided for the view instance 57465 the `defaultTemplate` value will be used: 57466 57467 ```javascript 57468 AView = Ember.View.extend({ 57469 defaultTemplate: Ember.HTMLBars.compile('I was the default'), 57470 template: null, 57471 templateName: null 57472 }); 57473 ``` 57474 57475 Will result in instances with an HTML representation of: 57476 57477 ```html 57478 <div id="ember1" class="ember-view">I was the default</div> 57479 ``` 57480 57481 If a `template` or `templateName` is provided it will take precedence over 57482 `defaultTemplate`: 57483 57484 ```javascript 57485 AView = Ember.View.extend({ 57486 defaultTemplate: Ember.HTMLBars.compile('I was the default') 57487 }); 57488 57489 aView = AView.create({ 57490 template: Ember.HTMLBars.compile('I was the template, not default') 57491 }); 57492 ``` 57493 57494 Will result in the following HTML representation when rendered: 57495 57496 ```html 57497 <div id="ember1" class="ember-view">I was the template, not default</div> 57498 ``` 57499 57500 ## View Context 57501 57502 The default context of the compiled template is the view's controller: 57503 57504 ```javascript 57505 AView = Ember.View.extend({ 57506 template: Ember.HTMLBars.compile('Hello {{excitedGreeting}}') 57507 }); 57508 57509 aController = Ember.Object.create({ 57510 firstName: 'Barry', 57511 excitedGreeting: Ember.computed('content.firstName', function() { 57512 return this.get('content.firstName') + '!!!'; 57513 }) 57514 }); 57515 57516 aView = AView.create({ 57517 controller: aController 57518 }); 57519 ``` 57520 57521 Will result in an HTML representation of: 57522 57523 ```html 57524 <div id="ember1" class="ember-view">Hello Barry!!!</div> 57525 ``` 57526
57527 A context can also be explicitly supplied through the view's `context` 57528 property. If the view has neither `context` nor `controller` properties, the 57529 `parentView`'s context will be used. 57530 57531 ## Layouts 57532 57533 Views can have a secondary template that wraps their main template. Like 57534 primary templates, layouts can be any function that accepts an optional 57535 context parameter and returns a string of HTML that will be inserted inside 57536 view's tag. Views whose HTML element is self closing (e.g. `<input />`) 57537 cannot have a layout and this property will be ignored. 57538 57539 Most typically in Ember a layout will be a compiled template. 57540 57541 A view's layout can be set directly with the `layout` property or reference 57542 an existing template by name with the `layoutName` property. 57543 57544 A template used as a layout must contain a single use of the 57545 `{{yield}}` helper. The HTML contents of a view's rendered `template` will be 57546 inserted at this location: 57547 57548 ```javascript 57549 AViewWithLayout = Ember.View.extend({ 57550 layout: Ember.HTMLBars.compile("<div class='my-decorative-class'>{{yield}}</div>"), 57551 template: Ember.HTMLBars.compile("I got wrapped") 57552 }); 57553 ``` 57554 57555 Will result in view instances with an HTML representation of: 57556 57557 ```html 57558 <div id="ember1" class="ember-view"> 57559 <div class="my-decorative-class"> 57560 I got wrapped 57561 </div> 57562 </div> 57563 ``` 57564 57565 See [Ember.Templates.helpers.yield](/api/classes/Ember.Templates.helpers.html#method_yield) 57566 for more information. 57567 57568 ## Responding to Browser Events 57569 57570 Views can respond to user-initiated events in one of three ways: method 57571 implementation, through an event manager, and through `{{action}}` helper use 57572 in their template or layout. 57573 57574 ### Method Implementation 57575 57576 Views can respond to user-initiated events by implementing a method that 57577 matches the event name. A `jQuery.Event` object will be passed as the 57578 argument to this method. 57579 57580 ```javascript 57581 AView = Ember.View.extend({ 57582 click: function(event) { 57583 // will be called when an instance's 57584 // rendered element is clicked 57585 } 57586 }); 57587 ``` 57588 57589 ### Event Managers 57590 57591 Views can define an object as their `eventManager` property. This object can 57592 then implement methods that match the desired event names. Matching events 57593 that occur on the view's rendered HTML or the rendered HTML of any of its DOM 57594 descendants will trigger this method. A `jQuery.Event` object will be passed 57595 as the first argument to the method and an `Ember.View` object as the 57596 second. The `Ember.View` will be the view whose rendered HTML was interacted 57597 with. This may be the view with the `eventManager` property or one of its 57598 descendant views. 57599 57600 ```javascript 57601 AView = Ember.View.extend({ 57602 eventManager: Ember.Object.create({ 57603 doubleClick: function(event, view) { 57604 // will be called when an instance's 57605 // rendered element or any rendering 57606 // of this view's descendant 57607 // elements is clicked 57608 } 57609 }) 57610 }); 57611 ``` 57612 57613 An event defined for an event manager takes precedence over events of the 57614 same name handled through methods on the view. 57615 57616 ```javascript 57617 AView = Ember.View.extend({ 57618 mouseEnter: function(event) { 57619 // will never trigger. 57620 }, 57621 eventManager: Ember.Object.create({ 57622 mouseEnter: function(event, view) { 57623 // takes precedence over AView#mouseEnter 57624 } 57625 }) 57626 }); 57627 ``` 57628 57629 Similarly a view's event manager will take precedence for events of any views 57630 rendered as a descendant. A method name that matches an event name will not 57631 be called if the view instance was rendered inside the HTML representation of 57632 a view that has an `eventManager` property defined that handles events of the 57633 name. Events not handled by the event manager will still trigger method calls 57634 on the descendant. 57635 57636 ```javascript 57637 var App = Ember.Application.create(); 57638 App.OuterView = Ember.View.extend({ 57639 template: Ember.HTMLBars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), 57640 eventManager: Ember.Object.create({ 57641 mouseEnter: function(event, view) { 57642 // view might be instance of either
57643 // OuterView or InnerView depending on 57644 // where on the page the user interaction occurred 57645 } 57646 }) 57647 }); 57648 57649 App.InnerView = Ember.View.extend({ 57650 click: function(event) { 57651 // will be called if rendered inside 57652 // an OuterView because OuterView's 57653 // eventManager doesn't handle click events 57654 }, 57655 mouseEnter: function(event) { 57656 // will never be called if rendered inside 57657 // an OuterView. 57658 } 57659 }); 57660 ``` 57661 57662 ### `{{action}}` Helper 57663 57664 See [Ember.Templates.helpers.action](/api/classes/Ember.Templates.helpers.html#method_action). 57665 57666 ### Event Names 57667 57668 All of the event handling approaches described above respond to the same set 57669 of events. The names of the built-in events are listed below. (The hash of 57670 built-in events exists in `Ember.EventDispatcher`.) Additional, custom events 57671 can be registered by using `Ember.Application.customEvents`. 57672 57673 Touch events: 57674 57675 * `touchStart` 57676 * `touchMove` 57677 * `touchEnd` 57678 * `touchCancel` 57679 57680 Keyboard events 57681 57682 * `keyDown` 57683 * `keyUp` 57684 * `keyPress` 57685 57686 Mouse events 57687 57688 * `mouseDown` 57689 * `mouseUp` 57690 * `contextMenu` 57691 * `click` 57692 * `doubleClick` 57693 * `mouseMove` 57694 * `focusIn` 57695 * `focusOut` 57696 * `mouseEnter` 57697 * `mouseLeave` 57698 57699 Form events: 57700 57701 * `submit` 57702 * `change` 57703 * `focusIn` 57704 * `focusOut` 57705 * `input` 57706 57707 HTML5 drag and drop events: 57708 57709 * `dragStart` 57710 * `drag` 57711 * `dragEnter` 57712 * `dragLeave` 57713 * `dragOver` 57714 * `dragEnd` 57715 * `drop` 57716 57717 ## `{{view}}` Helper 57718 57719 Other `Ember.View` instances can be included as part of a view's template by 57720 using the `{{view}}` helper. See [Ember.Templates.helpers.view](/api/classes/Ember.Templates.helpers.html#method_view) 57721 for additional information. 57722 57723 @class View 57724 @namespace Ember 57725 @extends Ember.CoreView 57726 @deprecated See http://emberjs.com/deprecations/v1.x/#toc_ember-view 57727 @uses Ember.ViewSupport 57728 @uses Ember.ViewContextSupport 57729 @uses Ember.ViewChildViewsSupport 57730 @uses Ember.TemplateRenderingSupport 57731 @uses Ember.ClassNamesSupport 57732 @uses Ember.AttributeBindingsSupport 57733 @uses Ember.LegacyViewSupport 57734 @uses Ember.InstrumentationSupport 57735 @uses Ember.VisibilitySupport 57736 @uses Ember.AriaRoleSupport 57737 @public 57738 */ 57739 // jscs:disable validateIndentation 57740 var View = _emberViewsViewsCore_view.default.extend(_emberViewsMixinsView_context_support.default, _emberViewsMixinsView_child_views_support.default, _emberViewsMixinsLegacy_child_views_support.default, _emberViewsMixinsView_state_support.default, _emberViewsMixinsTemplate_rendering_support.default, _emberViewsMixinsClass_names_support.default, _emberViewsMixinsLegacy_view_support.default, _emberViewsMixinsInstrumentation_support.default, _emberViewsMixinsVisibility_support.default, _emberViewsCompatAttrsProxy.default, _emberViewsMixinsAria_role_support.default, _emberViewsMixinsView_support.default, { 57741 init: function () { 57742 this._super.apply(this, arguments); 57743 57744 if (!this._viewRegistry) { 57745 this._viewRegistry = View.views; 57746 } 57747 }, 57748 57749 /** 57750 Given a property name, returns a dasherized version of that 57751 property name if the property evaluates to a non-falsy value. 57752 For example, if the view has property `isUrgent` that evaluates to true, 57753 passing `isUrgent` to this method will return `"is-urgent"`. 57754 @method _classStringForProperty 57755 @param property 57756 @private 57757 */ 57758 _classStringForProperty: function (parsedPath) { 57759 return View._classStringForValue(parsedPath.path, parsedPath.stream.value(), parsedPath.className, parsedPath.falsyClassName); 57760 } 57761 }); 57762 57763 _emberMetalDeprecate_property.deprecateProperty(View.prototype, 'currentState', '_currentState', { 57764 id: 'ember-view.current-state', 57765 until: '2.3.0', 57766 url: 'http://emberjs.com/deprecations/v2.x/#toc_ember-component-currentstate' 57767 }); 57768 57769 // jscs:enable validateIndentation 57770 57771 /* 57772 Describe how the specified actions should behave in the various 57773 states that a view can exist in. Possible states: 57774 57775 * preRender: when a view is first instantiated, and after its 57776 element was destroyed, it is in the preRender state 57777 * inBuffer: once a view has been rendered, but before it has 57778 been inserted into the DOM, it is in the inBuffer state 57779 * hasElement: the DOM representation of the view is created,
57780 and is ready to be inserted 57781 * inDOM: once a view has been inserted into the DOM it is in 57782 the inDOM state. A view spends the vast majority of its 57783 existence in this state. 57784 * destroyed: once a view has been destroyed (using the destroy 57785 method), it is in this state. No further actions can be invoked 57786 on a destroyed view. 57787 */ 57788 57789 // in the destroyed state, everything is illegal 57790 57791 // before rendering has begun, all legal manipulations are noops. 57792 57793 // inside the buffer, legal manipulations are done on the buffer 57794 57795 // once the view has been inserted into the DOM, legal manipulations 57796 // are done on the DOM element. 57797 57798 View.reopenClass({ 57799 /** 57800 Global views hash 57801 @property views 57802 @static 57803 @type Object 57804 @private 57805 */ 57806 views: {}, 57807 57808 // If someone overrides the child views computed property when 57809 // defining their class, we want to be able to process the user's 57810 // supplied childViews and then restore the original computed property 57811 // at view initialization time. This happens in Ember.ContainerView's init 57812 // method. 57813 childViewsProperty: _emberViewsMixinsView_child_views_support.childViewsProperty 57814 }); 57815 57816 function viewDeprecationMessage() { 57817 _emberMetalDebug.deprecate('Ember.View is deprecated. Consult the Deprecations Guide for a migration strategy.', !!_emberMetalCore.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT, { 57818 url: 'http://emberjs.com/deprecations/v1.x/#toc_ember-view', 57819 id: 'ember-views.view-deprecated', 57820 until: '2.4.0' 57821 }); 57822 } 57823 57824 var DeprecatedView = View.extend({ 57825 init: function () { 57826 viewDeprecationMessage(); 57827 this._super.apply(this, arguments); 57828 } 57829 }); 57830 57831 DeprecatedView.reopen = function () { 57832 viewDeprecationMessage(); 57833 View.reopen.apply(View, arguments); 57834 return this; 57835 }; 57836 57837 exports.default = View; 57838 exports.ViewContextSupport = _emberViewsMixinsView_context_support.default; 57839 exports.ViewChildViewsSupport = _emberViewsMixinsView_child_views_support.default; 57840 exports.ViewStateSupport = _emberViewsMixinsView_state_support.default; 57841 exports.TemplateRenderingSupport = _emberViewsMixinsTemplate_rendering_support.default; 57842 exports.ClassNamesSupport = _emberViewsMixinsClass_names_support.default; 57843 exports.DeprecatedView = DeprecatedView; 57844}); 57845// for the side effect of extending Ember.run.queues 57846enifed('htmlbars-runtime/expression-visitor', ['exports'], function (exports) { 57847 /** 57848 # Expression Nodes: 57849 57850 These nodes are not directly responsible for any part of the DOM, but are 57851 eventually passed to a Statement Node. 57852 57853 * get 57854 * subexpr 57855 * concat 57856 */ 57857 57858 'use strict'; 57859 57860 exports.acceptParams = acceptParams; 57861 exports.acceptHash = acceptHash; 57862 57863 function acceptParams(nodes, env, scope) { 57864 var array = []; 57865 57866 for (var i = 0, l = nodes.length; i < l; i++) { 57867 array.push(acceptExpression(nodes[i], env, scope).value); 57868 } 57869 57870 return array; 57871 } 57872 57873 function acceptHash(pairs, env, scope) { 57874 var object = {}; 57875 57876 for (var i = 0, l = pairs.length; i < l; i += 2) { 57877 var key = pairs[i]; 57878 var value = pairs[i + 1]; 57879 object[key] = acceptExpression(value, env, scope).value; 57880 } 57881 57882 return object; 57883 } 57884 57885 function acceptExpression(node, env, scope) { 57886 var ret = { value: null }; 57887 57888 // Primitive literals are unambiguously non-array representations of 57889 // themselves. 57890 if (typeof node !== 'object' || node === null) { 57891 ret.value = node; 57892 } else { 57893 ret.value = evaluateNode(node, env, scope); 57894 } 57895 57896 return ret; 57897 } 57898 57899 function evaluateNode(node, env, scope) { 57900 switch (node[0]) { 57901 // can be used by manualElement 57902 case 'value': 57903 return node[1]; 57904 case 'get': 57905 return evaluateGet(node, env, scope); 57906 case 'subexpr': 57907 return evaluateSubexpr(node, env, scope); 57908 case 'concat': 57909 return evaluateConcat(node, env, scope); 57910 } 57911 } 57912 57913 function evaluateGet(node, env, scope) { 57914 var path = node[1]; 57915 57916 return env.hooks.get(env, scope, path); 57917 } 57918 57919 function evaluateSubexpr(node, env, scope) { 57920 var path = node[1]; 57921 var rawParams = node[2]; 57922 var rawHash = node[3]; 57923 57924 var params = acceptParams(rawParams, env, scope); 57925 var hash = acceptHash(rawHash, env, scope); 57926 57927 return env.hooks.subexpr(env, scope, path, params, hash); 57928 } 57929 57930 function evaluateConcat(node, env, scope) { 57931 var rawParts = node[1]; 57932 57933 var parts = acceptParams(rawParts, env, scope); 57934 57935 return env.hooks.concat(env, parts); 57936 } 57937}); 57938enifed("htmlbars-runtime/hooks", ["exports", "htmlbars-runtime/render", "morph-range/morph-list", "htmlbars-util/object-utils", "htmlbars-util/morph-utils", "htmlbars-util/template-utils"], function (exports, _htmlbarsRuntimeRender, _morphRangeMorphList, _htmlbarsUtilObjectUtils, _htmlbarsUtilMorphUtils, _htmlbarsUtilTemplateUtils) { 57939 "use strict"; 57940 57941 exports.wrap = wrap; 57942 exports.wrapForHelper = wrapForHelper; 57943 exports.createScope = createScope; 57944 exports.createFreshScope = createFreshScope; 57945 exports.bindShadowScope = bindShadowScope; 57946 exports.createChildScope = createChildScope; 57947 exports.bindSelf = bindSelf; 57948 exports.updateSelf = updateSelf; 57949 exports.bindLocal = bindLocal; 57950 exports.updateLocal = updateLocal; 57951 exports.bindBlock = bindBlock; 57952 exports.block = block; 57953 exports.continueBlock = continueBlock; 57954 exports.hostBlock = hostBlock; 57955 exports.handleRedirect = handleRedirect; 57956 exports.handleKeyword = handleKeyword; 57957 exports.linkRenderNode = linkRenderNode;
57958 exports.inline = inline; 57959 exports.keyword = keyword; 57960 exports.invokeHelper = invokeHelper; 57961 exports.classify = classify; 57962 exports.partial = partial; 57963 exports.range = range; 57964 exports.element = element; 57965 exports.attribute = attribute; 57966 exports.subexpr = subexpr; 57967 exports.get = get; 57968 exports.getRoot = getRoot; 57969 exports.getBlock = getBlock; 57970 exports.getChild = getChild; 57971 exports.getValue = getValue; 57972 exports.getCellOrValue = getCellOrValue; 57973 exports.component = component; 57974 exports.concat = concat; 57975 exports.hasHelper = hasHelper; 57976 exports.lookupHelper = lookupHelper; 57977 exports.bindScope = bindScope; 57978 exports.updateScope = updateScope; 57979 57980 /** 57981 HTMLBars delegates the runtime behavior of a template to 57982 hooks provided by the host environment. These hooks explain 57983 the lexical environment of a Handlebars template, the internal 57984 representation of references, and the interaction between an 57985 HTMLBars template and the DOM it is managing. 57986 57987 While HTMLBars host hooks have access to all of this internal 57988 machinery, templates and helpers have access to the abstraction 57989 provided by the host hooks. 57990 57991 ## The Lexical Environment 57992 57993 The default lexical environment of an HTMLBars template includes: 57994 57995 * Any local variables, provided by *block arguments* 57996 * The current value of `self` 57997 57998 ## Simple Nesting 57999 58000 Let's look at a simple template with a nested block: 58001 58002 ```hbs 58003 <h1>{{title}}</h1> 58004 58005 {{#if author}} 58006 <p class="byline">{{author}}</p> 58007 {{/if}} 58008 ``` 58009 58010 In this case, the lexical environment at the top-level of the 58011 template does not change inside of the `if` block. This is 58012 achieved via an implementation of `if` that looks like this: 58013 58014 ```js 58015 registerHelper('if', function(params) { 58016 if (!!params[0]) { 58017 return this.yield(); 58018 } 58019 }); 58020 ``` 58021 58022 A call to `this.yield` invokes the child template using the 58023 current lexical environment. 58024 58025 ## Block Arguments 58026 58027 It is possible for nested blocks to introduce new local 58028 variables: 58029 58030 ```hbs 58031 {{#count-calls as |i|}} 58032 <h1>{{title}}</h1> 58033 <p>Called {{i}} times</p> 58034 {{/count}} 58035 ``` 58036 58037 In this example, the child block inherits its surrounding 58038 lexical environment, but augments it with a single new 58039 variable binding. 58040 58041 The implementation of `count-calls` supplies the value of 58042 `i`, but does not otherwise alter the environment: 58043 58044 ```js 58045 var count = 0; 58046 registerHelper('count-calls', function() { 58047 return this.yield([ ++count ]); 58048 }); 58049 ``` 58050 */ 58051 58052 function wrap(template) { 58053 if (template === null) { 58054 return null; 58055 } 58056 58057 return { 58058 meta: template.meta, 58059 arity: template.arity, 58060 raw: template, 58061 render: function (self, env, options, blockArguments) { 58062 var scope = env.hooks.createFreshScope(); 58063 58064 var contextualElement = options && options.contextualElement; 58065 var renderOptions = new _htmlbarsRuntimeRender.RenderOptions(null, self, blockArguments, contextualElement); 58066 58067 return _htmlbarsRuntimeRender.default(template, env, scope, renderOptions); 58068 } 58069 }; 58070 } 58071 58072 function wrapForHelper(template, env, scope, morph, renderState, visitor) { 58073 if (!template) { 58074 return {}; 58075 } 58076 58077 var yieldArgs = yieldTemplate(template, env, scope, morph, renderState, visitor); 58078 58079 return { 58080 meta: template.meta, 58081 arity: template.arity, 58082 'yield': yieldArgs, // quoted since it's a reserved word, see issue #420 58083 yieldItem: yieldItem(template, env, scope, morph, renderState, visitor), 58084 raw: template, 58085 58086 render: function (self, blockArguments) { 58087 yieldArgs(blockArguments, self); 58088 } 58089 }; 58090 } 58091 58092 // Called by a user-land helper to render a template. 58093 function yieldTemplate(template, env, parentScope, morph, renderState, visitor) { 58094 return function (blockArguments, self) { 58095 // Render state is used to track the progress of the helper (since it 58096 // may call into us multiple times). As the user-land helper calls 58097 // into library code, we track what needs to be cleaned up after the 58098 // helper has returned. 58099 // 58100 // Here, we remember that a template has been yielded and so we do not 58101 // need to remove the previous template. (If no template is yielded 58102 // this render by the helper, we assume nothing should be shown and 58103 // remove any previous rendered templates.) 58104 renderState.morphToClear = null; 58105 58106 // In this conditional is true, it means that on the previous rendering pass 58107 // the helper yielded multiple items via `yieldItem()`, but this time they 58108 // are yielding a single template. In that case, we mark the morph list for 58109 // cleanup so it is removed from the DOM. 58110 if (morph.morphList) { 58111 _htmlbarsUtilTemplateUtils.clearMorphList(morph.morphList, morph, env); 58112 renderState.morphListToClear = null; 58113 } 58114 58115 var scope = parentScope; 58116 58117 if (morph.lastYielded && isStableTemplate(template, morph.lastYielded)) { 58118 return morph.lastResult.revalidateWith(env, undefined, self, blockArguments, visitor); 58119 } 58120 58121 // Check to make sure that we actually **need** a new scope, and can't 58122 // share the parent scope. Note that we need to move this check into 58123 // a host hook, because the host's notion of scope may require a new 58124 // scope in more cases than the ones we can determine statically. 58125 if (self !== undefined || parentScope === null || template.arity) { 58126 scope = env.hooks.createChildScope(parentScope); 58127 } 58128 58129 morph.lastYielded = { self: self, template: template, shadowTemplate: null }; 58130 58131 // Render the template that was selected by the helper 58132 var renderOptions = new _htmlbarsRuntimeRender.RenderOptions(morph, self, blockArguments); 58133 _htmlbarsRuntimeRender.default(template, env, scope, renderOptions); 58134 }; 58135 } 58136 58137 function yieldItem(template, env, parentScope, morph, renderState, visitor) { 58138 // Initialize state that tracks multiple items being 58139 // yielded in. 58140 var currentMorph = null; 58141
58142 // Candidate morphs for deletion. 58143 var candidates = {}; 58144 58145 // Reuse existing MorphList if this is not a first-time 58146 // render. 58147 var morphList = morph.morphList; 58148 if (morphList) { 58149 currentMorph = morphList.firstChildMorph; 58150 } 58151 58152 // Advances the currentMorph pointer to the morph in the previously-rendered 58153 // list that matches the yielded key. While doing so, it marks any morphs 58154 // that it advances past as candidates for deletion. Assuming those morphs 58155 // are not yielded in later, they will be removed in the prune step during 58156 // cleanup. 58157 // Note that this helper function assumes that the morph being seeked to is 58158 // guaranteed to exist in the previous MorphList; if this is called and the 58159 // morph does not exist, it will result in an infinite loop 58160 function advanceToKey(key) { 58161 var seek = currentMorph; 58162 58163 while (seek.key !== key) { 58164 candidates[seek.key] = seek; 58165 seek = seek.nextMorph; 58166 } 58167 58168 currentMorph = seek.nextMorph; 58169 return seek; 58170 } 58171 58172 return function (_key, blockArguments, self) { 58173 if (typeof _key !== 'string') { 58174 throw new Error("You must provide a string key when calling `yieldItem`; you provided " + _key); 58175 } 58176 58177 // At least one item has been yielded, so we do not wholesale 58178 // clear the last MorphList but instead apply a prune operation. 58179 renderState.morphListToClear = null; 58180 morph.lastYielded = null; 58181 58182 var morphList, morphMap; 58183 58184 if (!morph.morphList) { 58185 morph.morphList = new _morphRangeMorphList.default(); 58186 morph.morphMap = {}; 58187 morph.setMorphList(morph.morphList); 58188 } 58189 58190 morphList = morph.morphList; 58191 morphMap = morph.morphMap; 58192 58193 // A map of morphs that have been yielded in on this 58194 // rendering pass. Any morphs that do not make it into 58195 // this list will be pruned from the MorphList during the cleanup 58196 // process. 58197 var handledMorphs = renderState.handledMorphs; 58198 var key = undefined; 58199 58200 if (_key in handledMorphs) { 58201 // In this branch we are dealing with a duplicate key. The strategy 58202 // is to take the original key and append a counter to it that is 58203 // incremented every time the key is reused. In order to greatly 58204 // reduce the chance of colliding with another valid key we also add 58205 // an extra string "--z8mS2hvDW0A--" to the new key. 58206 var collisions = renderState.collisions; 58207 if (collisions === undefined) { 58208 collisions = renderState.collisions = {}; 58209 } 58210 var count = collisions[_key] | 0; 58211 collisions[_key] = ++count; 58212 58213 key = _key + '--z8mS2hvDW0A--' + count; 58214 } else { 58215 key = _key; 58216 } 58217 58218 if (currentMorph && currentMorph.key === key) { 58219 yieldTemplate(template, env, parentScope, currentMorph, renderState, visitor)(blockArguments, self); 58220 currentMorph = currentMorph.nextMorph; 58221 handledMorphs[key] = currentMorph; 58222 } else if (morphMap[key] !== undefined) { 58223 var foundMorph = morphMap[key]; 58224 58225 if (key in candidates) { 58226 // If we already saw this morph, move it forward to this position 58227 morphList.insertBeforeMorph(foundMorph, currentMorph); 58228 } else { 58229 // Otherwise, move the pointer forward to the existing morph for this key 58230 advanceToKey(key); 58231 } 58232 58233 handledMorphs[foundMorph.key] = foundMorph; 58234 yieldTemplate(template, env, parentScope, foundMorph, renderState, visitor)(blockArguments, self); 58235 } else { 58236 var childMorph = _htmlbarsRuntimeRender.createChildMorph(env.dom, morph); 58237 childMorph.key = key; 58238 morphMap[key] = handledMorphs[key] = childMorph; 58239 morphList.insertBeforeMorph(childMorph, currentMorph); 58240 yieldTemplate(template, env, parentScope, childMorph, renderState, visitor)(blockArguments, self); 58241 } 58242 58243 renderState.morphListToPrune = morphList; 58244 morph.childNodes = null; 58245 }; 58246 } 58247 58248 function isStableTemplate(template, lastYielded) { 58249 return !lastYielded.shadowTemplate && template === lastYielded.template; 58250 } 58251 function optionsFor(template, inverse, env, scope, morph, visitor) { 58252 // If there was a template yielded last time, set morphToClear so it will be cleared 58253 // if no template is yielded on this render. 58254 var morphToClear = morph.lastResult ? morph : null; 58255 var renderState = new _htmlbarsUtilTemplateUtils.RenderState(morphToClear, morph.morphList || null); 58256 58257 return { 58258 templates: { 58259 template: wrapForHelper(template, env, scope, morph, renderState, visitor), 58260 inverse: wrapForHelper(inverse, env, scope, morph, renderState, visitor) 58261 }, 58262 renderState: renderState 58263 }; 58264 } 58265 58266 function thisFor(options) { 58267 return { 58268 arity: options.template.arity, 58269 'yield': options.template.yield, // quoted since it's a reserved word, see issue #420 58270 yieldItem: options.template.yieldItem, 58271 yieldIn: options.template.yieldIn 58272 }; 58273 } 58274 58275 /** 58276 Host Hook: createScope 58277 58278 @param {Scope?} parentScope 58279 @return Scope 58280 58281 Corresponds to entering a new HTMLBars block. 58282 58283 This hook is invoked when a block is entered with 58284 a new `self` or additional local variables. 58285 58286 When invoked for a top-level template, the 58287 `parentScope` is `null`, and this hook should return 58288 a fresh Scope. 58289 58290 When invoked for a child template, the `parentScope` 58291 is the scope for the parent environment. 58292 58293 Note that the `Scope` is an opaque value that is 58294 passed to other host hooks. For example, the `get` 58295 hook uses the scope to retrieve a value for a given 58296 scope and variable name. 58297 */ 58298 58299 function createScope(env, parentScope) { 58300 if (parentScope) { 58301 return env.hooks.createChildScope(parentScope); 58302 } else { 58303 return env.hooks.createFreshScope(); 58304 } 58305 } 58306 58307 function createFreshScope() { 58308 // because `in` checks have unpredictable performance, keep a 58309 // separate dictionary to track whether a local was bound. 58310 // See `bindLocal` for more information. 58311 return { self: null, blocks: {}, locals: {}, localPresent: {} }; 58312 } 58313 58314 /** 58315 Host Hook: bindShadowScope 58316 58317 @param {Scope?} parentScope 58318 @return Scope 58319 58320 Corresponds to rendering a new template into an existing 58321 render tree, but with a new top-level lexical scope. This 58322 template is called the "shadow root". 58323 58324 If a shadow template invokes `{{yield}}`, it will render 58325 the block provided to the shadow root in the original 58326 lexical scope. 58327 58328 ```hbs 58329 {{!-- post template --}} 58330 <p>{{props.title}}</p> 58331 {{yield}} 58332
58333 {{!-- blog template --}} 58334 {{#post title="Hello world"}} 58335 <p>by {{byline}}</p> 58336 <article>This is my first post</article> 58337 {{/post}} 58338 58339 {{#post title="Goodbye world"}} 58340 <p>by {{byline}}</p> 58341 <article>This is my last post</article> 58342 {{/post}} 58343 ``` 58344 58345 ```js 58346 helpers.post = function(params, hash, options) { 58347 options.template.yieldIn(postTemplate, { props: hash }); 58348 }; 58349 58350 blog.render({ byline: "Yehuda Katz" }); 58351 ``` 58352 58353 Produces: 58354 58355 ```html 58356 <p>Hello world</p> 58357 <p>by Yehuda Katz</p> 58358 <article>This is my first post</article> 58359 58360 <p>Goodbye world</p> 58361 <p>by Yehuda Katz</p> 58362 <article>This is my last post</article> 58363 ``` 58364 58365 In short, `yieldIn` creates a new top-level scope for the 58366 provided template and renders it, making the original block 58367 available to `{{yield}}` in that template. 58368 */ 58369 58370 function bindShadowScope(env /*, parentScope, shadowScope */) { 58371 return env.hooks.createFreshScope(); 58372 } 58373 58374 function createChildScope(parent) { 58375 var scope = Object.create(parent); 58376 scope.locals = Object.create(parent.locals); 58377 scope.localPresent = Object.create(parent.localPresent); 58378 scope.blocks = Object.create(parent.blocks); 58379 return scope; 58380 } 58381 58382 /** 58383 Host Hook: bindSelf 58384 58385 @param {Scope} scope 58386 @param {any} self 58387 58388 Corresponds to entering a template. 58389 58390 This hook is invoked when the `self` value for a scope is ready to be bound. 58391 58392 The host must ensure that child scopes reflect the change to the `self` in 58393 future calls to the `get` hook. 58394 */ 58395 58396 function bindSelf(env, scope, self) { 58397 scope.self = self; 58398 } 58399 58400 function updateSelf(env, scope, self) { 58401 env.hooks.bindSelf(env, scope, self); 58402 } 58403 58404 /** 58405 Host Hook: bindLocal 58406 58407 @param {Environment} env 58408 @param {Scope} scope 58409 @param {String} name 58410 @param {any} value 58411 58412 Corresponds to entering a template with block arguments. 58413 58414 This hook is invoked when a local variable for a scope has been provided. 58415 58416 The host must ensure that child scopes reflect the change in future calls 58417 to the `get` hook. 58418 */ 58419 58420 function bindLocal(env, scope, name, value) { 58421 scope.localPresent[name] = true; 58422 scope.locals[name] = value; 58423 } 58424 58425 function updateLocal(env, scope, name, value) { 58426 env.hooks.bindLocal(env, scope, name, value); 58427 } 58428 58429 /** 58430 Host Hook: bindBlock 58431 58432 @param {Environment} env 58433 @param {Scope} scope 58434 @param {Function} block 58435 58436 Corresponds to entering a shadow template that was invoked by a block helper with 58437 `yieldIn`. 58438 58439 This hook is invoked with an opaque block that will be passed along 58440 to the shadow template, and inserted into the shadow template when 58441 `{{yield}}` is used. Optionally provide a non-default block name 58442 that can be targeted by `{{yield to=blockName}}`. 58443 */ 58444 58445 function bindBlock(env, scope, block) { 58446 var name = arguments.length <= 3 || arguments[3] === undefined ? 'default' : arguments[3]; 58447 58448 scope.blocks[name] = block; 58449 } 58450 58451 /** 58452 Host Hook: block 58453
58454 @param {RenderNode} renderNode 58455 @param {Environment} env 58456 @param {Scope} scope 58457 @param {String} path 58458 @param {Array} params 58459 @param {Object} hash 58460 @param {Block} block 58461 @param {Block} elseBlock 58462 58463 Corresponds to: 58464 58465 ```hbs 58466 {{#helper param1 param2 key1=val1 key2=val2}} 58467 {{!-- child template --}} 58468 {{/helper}} 58469 ``` 58470 58471 This host hook is a workhorse of the system. It is invoked 58472 whenever a block is encountered, and is responsible for 58473 resolving the helper to call, and then invoke it. 58474 58475 The helper should be invoked with: 58476 58477 - `{Array} params`: the parameters passed to the helper 58478 in the template. 58479 - `{Object} hash`: an object containing the keys and values passed 58480 in the hash position in the template. 58481 58482 The values in `params` and `hash` will already be resolved 58483 through a previous call to the `get` host hook. 58484 58485 The helper should be invoked with a `this` value that is 58486 an object with one field: 58487 58488 `{Function} yield`: when invoked, this function executes the 58489 block with the current scope. It takes an optional array of 58490 block parameters. If block parameters are supplied, HTMLBars 58491 will invoke the `bindLocal` host hook to bind the supplied 58492 values to the block arguments provided by the template. 58493 58494 In general, the default implementation of `block` should work 58495 for most host environments. It delegates to other host hooks 58496 where appropriate, and properly invokes the helper with the 58497 appropriate arguments. 58498 */ 58499 58500 function block(morph, env, scope, path, params, hash, template, inverse, visitor) { 58501 if (handleRedirect(morph, env, scope, path, params, hash, template, inverse, visitor)) { 58502 return; 58503 } 58504 58505 continueBlock(morph, env, scope, path, params, hash, template, inverse, visitor); 58506 } 58507 58508 function continueBlock(morph, env, scope, path, params, hash, template, inverse, visitor) { 58509 hostBlock(morph, env, scope, template, inverse, null, visitor, function (options) { 58510 var helper = env.hooks.lookupHelper(env, scope, path); 58511 return env.hooks.invokeHelper(morph, env, scope, visitor, params, hash, helper, options.templates, thisFor(options.templates)); 58512 }); 58513 } 58514 58515 function hostBlock(morph, env, scope, template, inverse, shadowOptions, visitor, callback) { 58516 var options = optionsFor(template, inverse, env, scope, morph, visitor); 58517 _htmlbarsUtilTemplateUtils.renderAndCleanup(morph, env, options, shadowOptions, callback); 58518 } 58519 58520 function handleRedirect(morph, env, scope, path, params, hash, template, inverse, visitor) { 58521 if (!path) { 58522 return false; 58523 } 58524 58525 var redirect = env.hooks.classify(env, scope, path); 58526 if (redirect) { 58527 switch (redirect) { 58528 case 'component': 58529 env.hooks.component(morph, env, scope, path, params, hash, { default: template, inverse: inverse }, visitor);break; 58530 case 'inline': 58531 env.hooks.inline(morph, env, scope, path, params, hash, visitor);break; 58532 case 'block': 58533 env.hooks.block(morph, env, scope, path, params, hash, template, inverse, visitor);break; 58534 default: 58535 throw new Error("Internal HTMLBars redirection to " + redirect + " not supported"); 58536 } 58537 return true; 58538 } 58539 58540 if (handleKeyword(path, morph, env, scope, params, hash, template, inverse, visitor)) { 58541 return true; 58542 } 58543 58544 return false; 58545 } 58546 58547 function handleKeyword(path, morph, env, scope, params, hash, template, inverse, visitor) { 58548 var keyword = env.hooks.keywords[path]; 58549 if (!keyword) { 58550 return false; 58551 } 58552 58553 if (typeof keyword === 'function') { 58554 return keyword(morph, env, scope, params, hash, template, inverse, visitor); 58555 } 58556 58557 if (keyword.willRender) { 58558 keyword.willRender(morph, env); 58559 } 58560 58561 var lastState, newState; 58562 if (keyword.setupState) { 58563 lastState = _htmlbarsUtilObjectUtils.shallowCopy(morph.getState()); 58564 newState = morph.setState(keyword.setupState(lastState, env, scope, params, hash)); 58565 } 58566 58567 if (keyword.childEnv) { 58568 // Build the child environment... 58569 env = keyword.childEnv(morph.getState(), env); 58570 58571 // ..then save off the child env builder on the render node. If the render 58572 // node tree is re-rendered and this node is not dirty, the child env 58573 // builder will still be invoked so that child dirty render nodes still get 58574 // the correct child env. 58575 morph.buildChildEnv = keyword.childEnv; 58576 } 58577 58578 var firstTime = !morph.rendered; 58579 58580 if (keyword.isEmpty) { 58581 var isEmpty = keyword.isEmpty(morph.getState(), env, scope, params, hash); 58582 58583 if (isEmpty) { 58584 if (!firstTime) { 58585 _htmlbarsUtilTemplateUtils.clearMorph(morph, env, false); 58586 } 58587 return true; 58588 } 58589 } 58590 58591 if (firstTime) { 58592 if (keyword.render) { 58593 keyword.render(morph, env, scope, params, hash, template, inverse, visitor); 58594 } 58595 morph.rendered = true; 58596 return true; 58597 } 58598 58599 var isStable; 58600 if (keyword.isStable) {
58601 isStable = keyword.isStable(lastState, newState); 58602 } else { 58603 isStable = stableState(lastState, newState); 58604 } 58605 58606 if (isStable) { 58607 if (keyword.rerender) { 58608 var newEnv = keyword.rerender(morph, env, scope, params, hash, template, inverse, visitor); 58609 env = newEnv || env; 58610 } 58611 _htmlbarsUtilMorphUtils.validateChildMorphs(env, morph, visitor); 58612 return true; 58613 } else { 58614 _htmlbarsUtilTemplateUtils.clearMorph(morph, env, false); 58615 } 58616 58617 // If the node is unstable, re-render from scratch 58618 if (keyword.render) { 58619 keyword.render(morph, env, scope, params, hash, template, inverse, visitor); 58620 morph.rendered = true; 58621 return true; 58622 } 58623 } 58624 58625 function stableState(oldState, newState) { 58626 if (_htmlbarsUtilObjectUtils.keyLength(oldState) !== _htmlbarsUtilObjectUtils.keyLength(newState)) { 58627 return false; 58628 } 58629 58630 for (var prop in oldState) { 58631 if (oldState[prop] !== newState[prop]) { 58632 return false; 58633 } 58634 } 58635 58636 return true; 58637 } 58638 58639 function linkRenderNode() /* morph, env, scope, params, hash */{ 58640 return; 58641 } 58642 58643 /** 58644 Host Hook: inline 58645
58646 @param {RenderNode} renderNode 58647 @param {Environment} env 58648 @param {Scope} scope 58649 @param {String} path 58650 @param {Array} params 58651 @param {Hash} hash 58652 58653 Corresponds to: 58654 58655 ```hbs 58656 {{helper param1 param2 key1=val1 key2=val2}} 58657 ``` 58658 58659 This host hook is similar to the `block` host hook, but it 58660 invokes helpers that do not supply an attached block. 58661 58662 Like the `block` hook, the helper should be invoked with: 58663 58664 - `{Array} params`: the parameters passed to the helper 58665 in the template. 58666 - `{Object} hash`: an object containing the keys and values passed 58667 in the hash position in the template. 58668 58669 The values in `params` and `hash` will already be resolved 58670 through a previous call to the `get` host hook. 58671 58672 In general, the default implementation of `inline` should work 58673 for most host environments. It delegates to other host hooks 58674 where appropriate, and properly invokes the helper with the 58675 appropriate arguments. 58676 58677 The default implementation of `inline` also makes `partial` 58678 a keyword. Instead of invoking a helper named `partial`, 58679 it invokes the `partial` host hook. 58680 */ 58681 58682 function inline(morph, env, scope, path, params, hash, visitor) { 58683 if (handleRedirect(morph, env, scope, path, params, hash, null, null, visitor)) { 58684 return; 58685 } 58686 58687 var value = undefined, 58688 hasValue = undefined; 58689 if (morph.linkedResult) { 58690 value = env.hooks.getValue(morph.linkedResult); 58691 hasValue = true; 58692 } else { 58693 var options = optionsFor(null, null, env, scope, morph); 58694 58695 var helper = env.hooks.lookupHelper(env, scope, path); 58696 var result = env.hooks.invokeHelper(morph, env, scope, visitor, params, hash, helper, options.templates, thisFor(options.templates)); 58697 58698 if (result && result.link) { 58699 morph.linkedResult = result.value; 58700 _htmlbarsUtilMorphUtils.linkParams(env, scope, morph, '@content-helper', [morph.linkedResult], null); 58701 } 58702 58703 if (result && 'value' in result) { 58704 value = env.hooks.getValue(result.value); 58705 hasValue = true; 58706 } 58707 } 58708 58709 if (hasValue) { 58710 if (morph.lastValue !== value) { 58711 morph.setContent(value); 58712 } 58713 morph.lastValue = value; 58714 } 58715 } 58716 58717 function keyword(path, morph, env, scope, params, hash, template, inverse, visitor) { 58718 handleKeyword(path, morph, env, scope, params, hash, template, inverse, visitor); 58719 } 58720 58721 function invokeHelper(morph, env, scope, visitor, _params, _hash, helper, templates, context) { 58722 var params = normalizeArray(env, _params); 58723 var hash = normalizeObject(env, _hash); 58724 return { value: helper.call(context, params, hash, templates) }; 58725 } 58726 58727 function normalizeArray(env, array) { 58728 var out = new Array(array.length); 58729 58730 for (var i = 0, l = array.length; i < l; i++) { 58731 out[i] = env.hooks.getCellOrValue(array[i]); 58732 } 58733 58734 return out; 58735 } 58736 58737 function normalizeObject(env, object) { 58738 var out = {}; 58739 58740 for (var prop in object) { 58741 out[prop] = env.hooks.getCellOrValue(object[prop]); 58742 } 58743 58744 return out; 58745 } 58746 58747 function classify() /* env, scope, path */{ 58748 return null; 58749 } 58750 58751 var keywords = { 58752 partial: function (morph, env, scope, params) { 58753 var value = env.hooks.partial(morph, env, scope, params[0]); 58754 morph.setContent(value); 58755 return true; 58756 }, 58757 58758 // quoted since it's a reserved word, see issue #420 58759 'yield': function (morph, env, scope, params, hash, template, inverse, visitor) { 58760 // the current scope is provided purely for the creation of shadow 58761 // scopes; it should not be provided to user code. 58762 58763 var to = env.hooks.getValue(hash.to) || 'default'; 58764 var block = env.hooks.getBlock(scope, to); 58765 58766 if (block) { 58767 block.invoke(env, params, hash.self, morph, scope, visitor); 58768 } 58769 return true; 58770 }, 58771 58772 hasBlock: function (morph, env, scope, params) { 58773 var name = env.hooks.getValue(params[0]) || 'default'; 58774 return !!env.hooks.getBlock(scope, name); 58775 }, 58776 58777 hasBlockParams: function (morph, env, scope, params) { 58778 var name = env.hooks.getValue(params[0]) || 'default'; 58779 var block = env.hooks.getBlock(scope, name); 58780 return !!(block && block.arity); 58781 } 58782 58783 }; 58784 58785 exports.keywords = keywords; 58786 /** 58787 Host Hook: partial 58788
58789 @param {RenderNode} renderNode 58790 @param {Environment} env 58791 @param {Scope} scope 58792 @param {String} path 58793 58794 Corresponds to: 58795 58796 ```hbs 58797 {{partial "location"}} 58798 ``` 58799 58800 This host hook is invoked by the default implementation of 58801 the `inline` hook. This makes `partial` a keyword in an 58802 HTMLBars environment using the default `inline` host hook. 58803 58804 It is implemented as a host hook so that it can retrieve 58805 the named partial out of the `Environment`. Helpers, in 58806 contrast, only have access to the values passed in to them, 58807 and not to the ambient lexical environment. 58808 58809 The host hook should invoke the referenced partial with 58810 the ambient `self`. 58811 */ 58812 58813 function partial(renderNode, env, scope, path) { 58814 var template = env.partials[path]; 58815 return template.render(scope.self, env, {}).fragment; 58816 } 58817 58818 /** 58819 Host hook: range 58820 58821 @param {RenderNode} renderNode 58822 @param {Environment} env 58823 @param {Scope} scope 58824 @param {any} value 58825 58826 Corresponds to: 58827 58828 ```hbs 58829 {{content}} 58830 {{{unescaped}}} 58831 ``` 58832 58833 This hook is responsible for updating a render node 58834 that represents a range of content with a value. 58835 */ 58836 58837 function range(morph, env, scope, path, value, visitor) { 58838 if (handleRedirect(morph, env, scope, path, [], {}, null, null, visitor)) { 58839 return; 58840 } 58841 58842 value = env.hooks.getValue(value); 58843 58844 if (morph.lastValue !== value) { 58845 morph.setContent(value); 58846 } 58847 58848 morph.lastValue = value; 58849 } 58850 58851 /** 58852 Host hook: element 58853
58854 @param {RenderNode} renderNode 58855 @param {Environment} env 58856 @param {Scope} scope 58857 @param {String} path 58858 @param {Array} params 58859 @param {Hash} hash 58860 58861 Corresponds to: 58862 58863 ```hbs 58864 <div {{bind-attr foo=bar}}></div> 58865 ``` 58866 58867 This hook is responsible for invoking a helper that 58868 modifies an element. 58869 58870 Its purpose is largely legacy support for awkward 58871 idioms that became common when using the string-based 58872 Handlebars engine. 58873 58874 Most of the uses of the `element` hook are expected 58875 to be superseded by component syntax and the 58876 `attribute` hook. 58877 */ 58878 58879 function element(morph, env, scope, path, params, hash, visitor) { 58880 if (handleRedirect(morph, env, scope, path, params, hash, null, null, visitor)) { 58881 return; 58882 } 58883 58884 var helper = env.hooks.lookupHelper(env, scope, path); 58885 if (helper) { 58886 env.hooks.invokeHelper(null, env, scope, null, params, hash, helper, { element: morph.element }); 58887 } 58888 } 58889 58890 /** 58891 Host hook: attribute 58892 58893 @param {RenderNode} renderNode 58894 @param {Environment} env 58895 @param {String} name 58896 @param {any} value 58897 58898 Corresponds to: 58899 58900 ```hbs 58901 <div foo={{bar}}></div> 58902 ``` 58903 58904 This hook is responsible for updating a render node 58905 that represents an element's attribute with a value. 58906 58907 It receives the name of the attribute as well as an 58908 already-resolved value, and should update the render 58909 node with the value if appropriate. 58910 */ 58911 58912 function attribute(morph, env, scope, name, value) { 58913 value = env.hooks.getValue(value); 58914 58915 if (morph.lastValue !== value) { 58916 morph.setContent(value); 58917 } 58918 58919 morph.lastValue = value; 58920 } 58921 58922 function subexpr(env, scope, helperName, params, hash) { 58923 var helper = env.hooks.lookupHelper(env, scope, helperName); 58924 var result = env.hooks.invokeHelper(null, env, scope, null, params, hash, helper, {}); 58925 if (result && 'value' in result) { 58926 return env.hooks.getValue(result.value); 58927 } 58928 } 58929 58930 /** 58931 Host Hook: get 58932 58933 @param {Environment} env 58934 @param {Scope} scope 58935 @param {String} path 58936 58937 Corresponds to: 58938 58939 ```hbs 58940 {{foo.bar}} 58941 ^ 58942 58943 {{helper foo.bar key=value}} 58944 ^ ^ 58945 ``` 58946 58947 This hook is the "leaf" hook of the system. It is used to 58948 resolve a path relative to the current scope. 58949 */ 58950 58951 function get(env, scope, path) { 58952 if (path === '') { 58953 return scope.self; 58954 } 58955 58956 var keys = path.split('.'); 58957 var value = env.hooks.getRoot(scope, keys[0])[0]; 58958 58959 for (var i = 1; i < keys.length; i++) { 58960 if (value) { 58961 value = env.hooks.getChild(value, keys[i]); 58962 } else { 58963 break; 58964 } 58965 } 58966 58967 return value; 58968 } 58969 58970 function getRoot(scope, key) { 58971 if (scope.localPresent[key]) { 58972 return [scope.locals[key]]; 58973 } else if (scope.self) { 58974 return [scope.self[key]]; 58975 } else { 58976 return [undefined]; 58977 } 58978 } 58979 58980 function getBlock(scope, key) { 58981 return scope.blocks[key]; 58982 } 58983 58984 function getChild(value, key) { 58985 return value[key]; 58986 } 58987 58988 function getValue(reference) { 58989 return reference; 58990 } 58991 58992 function getCellOrValue(reference) { 58993 return reference; 58994 } 58995 58996 function component(morph, env, scope, tagName, params, attrs, templates, visitor) { 58997 if (env.hooks.hasHelper(env, scope, tagName)) { 58998 return env.hooks.block(morph, env, scope, tagName, params, attrs, templates.default, templates.inverse, visitor); 58999 } 59000 59001 componentFallback(morph, env, scope, tagName, attrs, templates.default); 59002 } 59003 59004 function concat(env, params) { 59005 var value = ""; 59006 for (var i = 0, l = params.length; i < l; i++) { 59007 value += env.hooks.getValue(params[i]); 59008 } 59009 return value; 59010 } 59011 59012 function componentFallback(morph, env, scope, tagName, attrs, template) { 59013 var element = env.dom.createElement(tagName); 59014 for (var name in attrs) { 59015 element.setAttribute(name, env.hooks.getValue(attrs[name])); 59016 } 59017 var fragment = _htmlbarsRuntimeRender.default(template, env, scope, {}).fragment; 59018 element.appendChild(fragment); 59019 morph.setNode(element); 59020 } 59021 59022 function hasHelper(env, scope, helperName) { 59023 return env.helpers[helperName] !== undefined; 59024 } 59025 59026 function lookupHelper(env, scope, helperName) { 59027 return env.helpers[helperName]; 59028 } 59029 59030 function bindScope() /* env, scope */{ 59031 // this function is used to handle host-specified extensions to scope 59032 // other than `self`, `locals` and `block`. 59033 } 59034 59035 function updateScope(env, scope) { 59036 env.hooks.bindScope(env, scope); 59037 } 59038 59039 exports.default = { 59040 // fundamental hooks that you will likely want to override 59041 bindLocal: bindLocal, 59042 bindSelf: bindSelf, 59043 bindScope: bindScope, 59044 classify: classify, 59045 component: component, 59046 concat: concat, 59047 createFreshScope: createFreshScope, 59048 getChild: getChild, 59049 getRoot: getRoot, 59050 getBlock: getBlock, 59051 getValue: getValue, 59052 getCellOrValue: getCellOrValue, 59053 keywords: keywords, 59054 linkRenderNode: linkRenderNode, 59055 partial: partial, 59056 subexpr: subexpr, 59057 59058 // fundamental hooks with good default behavior 59059 bindBlock: bindBlock, 59060 bindShadowScope: bindShadowScope, 59061 updateLocal: updateLocal, 59062 updateSelf: updateSelf, 59063 updateScope: updateScope, 59064 createChildScope: createChildScope, 59065 hasHelper: hasHelper, 59066 lookupHelper: lookupHelper, 59067 invokeHelper: invokeHelper, 59068 cleanupRenderNode: null, 59069 destroyRenderNode: null, 59070 willCleanupTree: null, 59071 didCleanupTree: null, 59072 willRenderNode: null, 59073 didRenderNode: null, 59074 59075 // derived hooks 59076 attribute: attribute, 59077 block: block, 59078 createScope: createScope, 59079 element: element, 59080 get: get, 59081 inline: inline, 59082 range: range, 59083 keyword: keyword 59084 }; 59085}); 59086enifed("htmlbars-runtime/morph", ["exports", "morph-range"], function (exports, _morphRange) { 59087 "use strict"; 59088 59089 var guid = 1; 59090 59091 function HTMLBarsMorph(domHelper, contextualElement) { 59092 this.super$constructor(domHelper, contextualElement); 59093 59094 this._state = undefined; 59095 this.ownerNode = null; 59096 this.isDirty = false;
59097 this.isSubtreeDirty = false; 59098 this.lastYielded = null; 59099 this.lastResult = null; 59100 this.lastValue = null; 59101 this.buildChildEnv = null; 59102 this.morphList = null; 59103 this.morphMap = null; 59104 this.key = null; 59105 this.linkedParams = null; 59106 this.linkedResult = null; 59107 this.childNodes = null; 59108 this.rendered = false; 59109 this.guid = "range" + guid++; 59110 this.seen = false; 59111 } 59112 59113 HTMLBarsMorph.empty = function (domHelper, contextualElement) { 59114 var morph = new HTMLBarsMorph(domHelper, contextualElement); 59115 morph.clear(); 59116 return morph; 59117 }; 59118 59119 HTMLBarsMorph.create = function (domHelper, contextualElement, node) { 59120 var morph = new HTMLBarsMorph(domHelper, contextualElement); 59121 morph.setNode(node); 59122 return morph; 59123 }; 59124 59125 HTMLBarsMorph.attach = function (domHelper, contextualElement, firstNode, lastNode) { 59126 var morph = new HTMLBarsMorph(domHelper, contextualElement); 59127 morph.setRange(firstNode, lastNode); 59128 return morph; 59129 }; 59130 59131 var prototype = HTMLBarsMorph.prototype = Object.create(_morphRange.default.prototype); 59132 prototype.constructor = HTMLBarsMorph; 59133 prototype.super$constructor = _morphRange.default; 59134 59135 prototype.getState = function () { 59136 if (!this._state) { 59137 this._state = {}; 59138 } 59139 59140 return this._state; 59141 }; 59142 59143 prototype.setState = function (newState) { 59144 /*jshint -W093 */ 59145 59146 return this._state = newState; 59147 }; 59148 59149 exports.default = HTMLBarsMorph; 59150}); 59151enifed("htmlbars-runtime/node-visitor", ["exports", "htmlbars-util/morph-utils", "htmlbars-runtime/expression-visitor"], function (exports, _htmlbarsUtilMorphUtils, _htmlbarsRuntimeExpressionVisitor) { 59152 "use strict"; 59153 59154 /** 59155 Node classification: 59156 59157 # Primary Statement Nodes: 59158 59159 These nodes are responsible for a render node that represents a morph-range. 59160 59161 * block 59162 * inline 59163 * content 59164 * element 59165 * component 59166 59167 # Leaf Statement Nodes: 59168 59169 This node is responsible for a render node that represents a morph-attr. 59170 59171 * attribute 59172 */ 59173 59174 function linkParamsAndHash(env, scope, morph, path, params, hash) { 59175 if (morph.linkedParams) { 59176 params = morph.linkedParams.params; 59177 hash = morph.linkedParams.hash; 59178 } else { 59179 params = params && _htmlbarsRuntimeExpressionVisitor.acceptParams(params, env, scope); 59180 hash = hash && _htmlbarsRuntimeExpressionVisitor.acceptHash(hash, env, scope); 59181 } 59182 59183 _htmlbarsUtilMorphUtils.linkParams(env, scope, morph, path, params, hash); 59184 return [params, hash]; 59185 } 59186 59187 var AlwaysDirtyVisitor = { 59188 59189 block: function (node, morph, env, scope, template, visitor) { 59190 var path = node[1]; 59191 var params = node[2]; 59192 var hash = node[3]; 59193 var templateId = node[4]; 59194 var inverseId = node[5]; 59195 59196 var paramsAndHash = linkParamsAndHash(env, scope, morph, path, params, hash); 59197 59198 morph.isDirty = morph.isSubtreeDirty = false; 59199 env.hooks.block(morph, env, scope, path, paramsAndHash[0], paramsAndHash[1], templateId === null ? null : template.templates[templateId], inverseId === null ? null : template.templates[inverseId], visitor); 59200 }, 59201 59202 inline: function (node, morph, env, scope, visitor) { 59203 var path = node[1]; 59204 var params = node[2]; 59205 var hash = node[3]; 59206 59207 var paramsAndHash = linkParamsAndHash(env, scope, morph, path, params, hash); 59208 59209 morph.isDirty = morph.isSubtreeDirty = false; 59210 env.hooks.inline(morph, env, scope, path, paramsAndHash[0], paramsAndHash[1], visitor); 59211 }, 59212 59213 content: function (node, morph, env, scope, visitor) { 59214 var path = node[1]; 59215 59216 morph.isDirty = morph.isSubtreeDirty = false; 59217 59218 if (isHelper(env, scope, path)) { 59219 env.hooks.inline(morph, env, scope, path, [], {}, visitor); 59220 if (morph.linkedResult) { 59221 _htmlbarsUtilMorphUtils.linkParams(env, scope, morph, '@content-helper', [morph.linkedResult], null); 59222 } 59223 return; 59224 } 59225 59226 var params = undefined; 59227 if (morph.linkedParams) { 59228 params = morph.linkedParams.params; 59229 } else { 59230 params = [env.hooks.get(env, scope, path)]; 59231 } 59232 59233 _htmlbarsUtilMorphUtils.linkParams(env, scope, morph, '@range', params, null); 59234 env.hooks.range(morph, env, scope, path, params[0], visitor); 59235 }, 59236 59237 element: function (node, morph, env, scope, visitor) { 59238 var path = node[1]; 59239 var params = node[2]; 59240 var hash = node[3]; 59241 59242 var paramsAndHash = linkParamsAndHash(env, scope, morph, path, params, hash); 59243 59244 morph.isDirty = morph.isSubtreeDirty = false;
59245 env.hooks.element(morph, env, scope, path, paramsAndHash[0], paramsAndHash[1], visitor); 59246 }, 59247 59248 attribute: function (node, morph, env, scope) { 59249 var name = node[1]; 59250 var value = node[2]; 59251 59252 var paramsAndHash = linkParamsAndHash(env, scope, morph, '@attribute', [value], null); 59253 59254 morph.isDirty = morph.isSubtreeDirty = false; 59255 env.hooks.attribute(morph, env, scope, name, paramsAndHash[0][0]); 59256 }, 59257 59258 component: function (node, morph, env, scope, template, visitor) { 59259 var path = node[1]; 59260 var attrs = node[2]; 59261 var templateId = node[3]; 59262 var inverseId = node[4]; 59263 59264 var paramsAndHash = linkParamsAndHash(env, scope, morph, path, [], attrs); 59265 var templates = { 59266 default: template.templates[templateId], 59267 inverse: template.templates[inverseId] 59268 }; 59269 59270 morph.isDirty = morph.isSubtreeDirty = false; 59271 env.hooks.component(morph, env, scope, path, paramsAndHash[0], paramsAndHash[1], templates, visitor); 59272 }, 59273 59274 attributes: function (node, morph, env, scope, parentMorph, visitor) { 59275 var template = node[1]; 59276 59277 env.hooks.attributes(morph, env, scope, template, parentMorph, visitor); 59278 } 59279 59280 }; 59281 59282 exports.AlwaysDirtyVisitor = AlwaysDirtyVisitor; 59283 exports.default = { 59284 block: function (node, morph, env, scope, template, visitor) { 59285 dirtyCheck(env, morph, visitor, function (visitor) { 59286 AlwaysDirtyVisitor.block(node, morph, env, scope, template, visitor); 59287 }); 59288 }, 59289 59290 inline: function (node, morph, env, scope, visitor) { 59291 dirtyCheck(env, morph, visitor, function (visitor) { 59292 AlwaysDirtyVisitor.inline(node, morph, env, scope, visitor); 59293 }); 59294 }, 59295 59296 content: function (node, morph, env, scope, visitor) { 59297 dirtyCheck(env, morph, visitor, function (visitor) { 59298 AlwaysDirtyVisitor.content(node, morph, env, scope, visitor); 59299 }); 59300 }, 59301 59302 element: function (node, morph, env, scope, template, visitor) { 59303 dirtyCheck(env, morph, visitor, function (visitor) { 59304 AlwaysDirtyVisitor.element(node, morph, env, scope, template, visitor); 59305 }); 59306 }, 59307 59308 attribute: function (node, morph, env, scope, template) { 59309 dirtyCheck(env, morph, null, function () { 59310 AlwaysDirtyVisitor.attribute(node, morph, env, scope, template); 59311 }); 59312 }, 59313 59314 component: function (node, morph, env, scope, template, visitor) { 59315 dirtyCheck(env, morph, visitor, function (visitor) { 59316 AlwaysDirtyVisitor.component(node, morph, env, scope, template, visitor); 59317 }); 59318 }, 59319 59320 attributes: function (node, morph, env, scope, parentMorph, visitor) { 59321 AlwaysDirtyVisitor.attributes(node, morph, env, scope, parentMorph, visitor); 59322 } 59323 }; 59324 59325 function dirtyCheck(_env, morph, visitor, callback) { 59326 var isDirty = morph.isDirty; 59327 var isSubtreeDirty = morph.isSubtreeDirty; 59328 var env = _env; 59329 59330 if (isSubtreeDirty) { 59331 visitor = AlwaysDirtyVisitor; 59332 } 59333 59334 if (isDirty || isSubtreeDirty) { 59335 callback(visitor); 59336 } else { 59337 if (morph.buildChildEnv) { 59338 env = morph.buildChildEnv(morph.getState(), env); 59339 } 59340 _htmlbarsUtilMorphUtils.validateChildMorphs(env, morph, visitor); 59341 } 59342 } 59343 59344 function isHelper(env, scope, path) { 59345 return env.hooks.keywords[path] !== undefined || env.hooks.hasHelper(env, scope, path); 59346 } 59347}); 59348enifed("htmlbars-runtime/render", ["exports", "htmlbars-util/morph-utils", "htmlbars-runtime/node-visitor", "htmlbars-runtime/morph", "htmlbars-util/template-utils", "htmlbars-util/void-tag-names"], function (exports, _htmlbarsUtilMorphUtils, _htmlbarsRuntimeNodeVisitor, _htmlbarsRuntimeMorph, _htmlbarsUtilTemplateUtils, _htmlbarsUtilVoidTagNames) { 59349 "use strict"; 59350 59351 exports.default = render; 59352 exports.RenderOptions = RenderOptions; 59353 exports.manualElement = manualElement; 59354 exports.attachAttributes = attachAttributes; 59355 exports.createChildMorph = createChildMorph; 59356 exports.getCachedFragment = getCachedFragment; 59357 59358 var svgNamespace = "http://www.w3.org/2000/svg"; 59359 59360 function render(template, env, scope, options) { 59361 var dom = env.dom; 59362 var contextualElement; 59363 59364 if (options) { 59365 if (options.renderNode) { 59366 contextualElement = options.renderNode.contextualElement; 59367 } else if (options.contextualElement) { 59368 contextualElement = options.contextualElement; 59369 } 59370 } 59371 59372 dom.detectNamespace(contextualElement); 59373 59374 var renderResult = RenderResult.build(env, scope, template, options, contextualElement); 59375 renderResult.render(); 59376 59377 return renderResult; 59378 } 59379
59380 function RenderOptions(renderNode, self, blockArguments, contextualElement) { 59381 this.renderNode = renderNode || null; 59382 this.self = self; 59383 this.blockArguments = blockArguments || null; 59384 this.contextualElement = contextualElement || null; 59385 } 59386 59387 function RenderResult(env, scope, options, rootNode, ownerNode, nodes, fragment, template, shouldSetContent) { 59388 this.root = rootNode; 59389 this.fragment = fragment; 59390 59391 this.nodes = nodes; 59392 this.template = template; 59393 this.statements = template.statements.slice(); 59394 this.env = env; 59395 this.scope = scope; 59396 this.shouldSetContent = shouldSetContent; 59397 59398 if (options.self !== undefined) { 59399 this.bindSelf(options.self); 59400 } 59401 if (options.blockArguments !== undefined) { 59402 this.bindLocals(options.blockArguments); 59403 } 59404 59405 this.initializeNodes(ownerNode); 59406 } 59407 59408 RenderResult.build = function (env, scope, template, options, contextualElement) { 59409 var dom = env.dom; 59410 var fragment = getCachedFragment(template, env); 59411 var nodes = template.buildRenderNodes(dom, fragment, contextualElement); 59412 59413 var rootNode, ownerNode, shouldSetContent; 59414 59415 if (options && options.renderNode) { 59416 rootNode = options.renderNode; 59417 ownerNode = rootNode.ownerNode; 59418 shouldSetContent = true; 59419 } else { 59420 rootNode = dom.createMorph(null, fragment.firstChild, fragment.lastChild, contextualElement); 59421 ownerNode = rootNode; 59422 rootNode.ownerNode = ownerNode; 59423 shouldSetContent = false; 59424 } 59425 59426 if (rootNode.childNodes) { 59427 _htmlbarsUtilMorphUtils.visitChildren(rootNode.childNodes, function (node) { 59428 _htmlbarsUtilTemplateUtils.clearMorph(node, env, true); 59429 }); 59430 } 59431 59432 rootNode.childNodes = nodes; 59433 return new RenderResult(env, scope, options, rootNode, ownerNode, nodes, fragment, template, shouldSetContent); 59434 }; 59435 59436 function manualElement(tagName, attributes, _isEmpty) { 59437 var statements = []; 59438 59439 for (var key in attributes) { 59440 if (typeof attributes[key] === 'string') { 59441 continue; 59442 } 59443 statements.push(["attribute", key, attributes[key]]); 59444 } 59445 59446 var isEmpty = _isEmpty || _htmlbarsUtilVoidTagNames.default[tagName]; 59447 59448 if (!isEmpty) { 59449 statements.push(['content', 'yield']); 59450 } 59451 59452 var template = { 59453 arity: 0, 59454 cachedFragment: null, 59455 hasRendered: false, 59456 buildFragment: function buildFragment(dom) { 59457 var el0 = dom.createDocumentFragment(); 59458 if (tagName === 'svg') { 59459 dom.setNamespace(svgNamespace); 59460 } 59461 var el1 = dom.createElement(tagName); 59462 59463 for (var key in attributes) { 59464 if (typeof attributes[key] !== 'string') { 59465 continue; 59466 } 59467 dom.setAttribute(el1, key, attributes[key]); 59468 } 59469 59470 if (!isEmpty) { 59471 var el2 = dom.createComment(""); 59472 dom.appendChild(el1, el2); 59473 } 59474 59475 dom.appendChild(el0, el1); 59476 59477 return el0; 59478 }, 59479 buildRenderNodes: function buildRenderNodes(dom, fragment) { 59480 var element = dom.childAt(fragment, [0]); 59481 var morphs = []; 59482 59483 for (var key in attributes) { 59484 if (typeof attributes[key] === 'string') { 59485 continue; 59486 } 59487 morphs.push(dom.createAttrMorph(element, key)); 59488 } 59489 59490 if (!isEmpty) { 59491 morphs.push(dom.createMorphAt(element, 0, 0)); 59492 } 59493 59494 return morphs; 59495 }, 59496 statements: statements, 59497 locals: [], 59498 templates: [] 59499 }; 59500 59501 return template; 59502 } 59503 59504 function attachAttributes(attributes) { 59505 var statements = []; 59506 59507 for (var key in attributes) { 59508 if (typeof attributes[key] === 'string') { 59509 continue; 59510 } 59511 statements.push(["attribute", key, attributes[key]]); 59512 } 59513 59514 var template = { 59515 arity: 0, 59516 cachedFragment: null, 59517 hasRendered: false, 59518 buildFragment: function buildFragment(dom) { 59519 var el0 = this.element; 59520 if (el0.namespaceURI === "http://www.w3.org/2000/svg") { 59521 dom.setNamespace(svgNamespace); 59522 } 59523 for (var key in attributes) { 59524 if (typeof attributes[key] !== 'string') { 59525 continue; 59526 } 59527 dom.setAttribute(el0, key, attributes[key]); 59528 } 59529 59530 return el0; 59531 }, 59532 buildRenderNodes: function buildRenderNodes(dom) { 59533 var element = this.element; 59534 var morphs = []; 59535 59536 for (var key in attributes) { 59537 if (typeof attributes[key] === 'string') { 59538 continue; 59539 } 59540 morphs.push(dom.createAttrMorph(element, key)); 59541 } 59542 59543 return morphs; 59544 }, 59545 statements: statements, 59546 locals: [], 59547 templates: [], 59548 element: null 59549 }; 59550 59551 return template; 59552 } 59553 59554 RenderResult.prototype.initializeNodes = function (ownerNode) { 59555 var childNodes = this.root.childNodes; 59556 59557 for (var i = 0, l = childNodes.length; i < l; i++) { 59558 childNodes[i].ownerNode = ownerNode; 59559 } 59560 }; 59561 59562 RenderResult.prototype.render = function () { 59563 this.root.lastResult = this; 59564 this.root.rendered = true; 59565 this.populateNodes(_htmlbarsRuntimeNodeVisitor.AlwaysDirtyVisitor); 59566 59567 if (this.shouldSetContent && this.root.setContent) { 59568 this.root.setContent(this.fragment); 59569 } 59570 }; 59571 59572 RenderResult.prototype.dirty = function () {
59573 _htmlbarsUtilMorphUtils.visitChildren([this.root], function (node) { 59574 node.isDirty = true; 59575 }); 59576 }; 59577 59578 RenderResult.prototype.revalidate = function (env, self, blockArguments, scope) { 59579 this.revalidateWith(env, scope, self, blockArguments, _htmlbarsRuntimeNodeVisitor.default); 59580 }; 59581 59582 RenderResult.prototype.rerender = function (env, self, blockArguments, scope) { 59583 this.revalidateWith(env, scope, self, blockArguments, _htmlbarsRuntimeNodeVisitor.AlwaysDirtyVisitor); 59584 }; 59585 59586 RenderResult.prototype.revalidateWith = function (env, scope, self, blockArguments, visitor) { 59587 if (env !== undefined) { 59588 this.env = env; 59589 } 59590 if (scope !== undefined) { 59591 this.scope = scope; 59592 } 59593 this.updateScope(); 59594 59595 if (self !== undefined) { 59596 this.updateSelf(self); 59597 } 59598 if (blockArguments !== undefined) { 59599 this.updateLocals(blockArguments); 59600 } 59601 59602 this.populateNodes(visitor); 59603 }; 59604 59605 RenderResult.prototype.destroy = function () { 59606 var rootNode = this.root; 59607 _htmlbarsUtilTemplateUtils.clearMorph(rootNode, this.env, true); 59608 }; 59609 59610 RenderResult.prototype.populateNodes = function (visitor) { 59611 var env = this.env; 59612 var scope = this.scope; 59613 var template = this.template; 59614 var nodes = this.nodes; 59615 var statements = this.statements; 59616 var i, l; 59617 59618 for (i = 0, l = statements.length; i < l; i++) { 59619 var statement = statements[i]; 59620 var morph = nodes[i]; 59621 59622 if (env.hooks.willRenderNode) { 59623 env.hooks.willRenderNode(morph, env, scope); 59624 } 59625 59626 switch (statement[0]) { 59627 case 'block': 59628 visitor.block(statement, morph, env, scope, template, visitor);break; 59629 case 'inline': 59630 visitor.inline(statement, morph, env, scope, visitor);break; 59631 case 'content': 59632 visitor.content(statement, morph, env, scope, visitor);break; 59633 case 'element': 59634 visitor.element(statement, morph, env, scope, template, visitor);break; 59635 case 'attribute': 59636 visitor.attribute(statement, morph, env, scope);break; 59637 case 'component': 59638 visitor.component(statement, morph, env, scope, template, visitor);break; 59639 } 59640 59641 if (env.hooks.didRenderNode) { 59642 env.hooks.didRenderNode(morph, env, scope); 59643 } 59644 } 59645 }; 59646 59647 RenderResult.prototype.bindScope = function () { 59648 this.env.hooks.bindScope(this.env, this.scope); 59649 }; 59650 59651 RenderResult.prototype.updateScope = function () { 59652 this.env.hooks.updateScope(this.env, this.scope); 59653 }; 59654 59655 RenderResult.prototype.bindSelf = function (self) { 59656 this.env.hooks.bindSelf(this.env, this.scope, self); 59657 }; 59658 59659 RenderResult.prototype.updateSelf = function (self) { 59660 this.env.hooks.updateSelf(this.env, this.scope, self); 59661 }; 59662 59663 RenderResult.prototype.bindLocals = function (blockArguments) { 59664 var localNames = this.template.locals; 59665 59666 for (var i = 0, l = localNames.length; i < l; i++) { 59667 this.env.hooks.bindLocal(this.env, this.scope, localNames[i], blockArguments[i]); 59668 } 59669 }; 59670 59671 RenderResult.prototype.updateLocals = function (blockArguments) { 59672 var localNames = this.template.locals; 59673 59674 for (var i = 0, l = localNames.length; i < l; i++) { 59675 this.env.hooks.updateLocal(this.env, this.scope, localNames[i], blockArguments[i]); 59676 } 59677 }; 59678 59679 function initializeNode(node, owner) { 59680 node.ownerNode = owner; 59681 } 59682 59683 function createChildMorph(dom, parentMorph, contextualElement) { 59684 var morph = _htmlbarsRuntimeMorph.default.empty(dom, contextualElement || parentMorph.contextualElement); 59685 initializeNode(morph, parentMorph.ownerNode); 59686 return morph; 59687 } 59688 59689 function getCachedFragment(template, env) { 59690 var dom = env.dom, 59691 fragment; 59692 if (env.useFragmentCache && dom.canClone) { 59693 if (template.cachedFragment === null) { 59694 fragment = template.buildFragment(dom); 59695 if (template.hasRendered) { 59696 template.cachedFragment = fragment; 59697 } else { 59698 template.hasRendered = true; 59699 } 59700 } 59701 if (template.cachedFragment) { 59702 fragment = dom.cloneNode(template.cachedFragment, true); 59703 } 59704 } else if (!fragment) { 59705 fragment = template.buildFragment(dom); 59706 } 59707 59708 return fragment; 59709 } 59710}); 59711enifed('htmlbars-runtime', ['exports', 'htmlbars-runtime/hooks', 'htmlbars-runtime/render', 'htmlbars-util/morph-utils', 'htmlbars-util/template-utils'], function (exports, _htmlbarsRuntimeHooks, _htmlbarsRuntimeRender, _htmlbarsUtilMorphUtils, _htmlbarsUtilTemplateUtils) { 59712 'use strict'; 59713 59714 var internal = { 59715 blockFor: _htmlbarsUtilTemplateUtils.blockFor, 59716 manualElement: _htmlbarsRuntimeRender.manualElement, 59717 hostBlock: _htmlbarsRuntimeHooks.hostBlock, 59718 continueBlock: _htmlbarsRuntimeHooks.continueBlock, 59719 hostYieldWithShadowTemplate: _htmlbarsRuntimeHooks.hostYieldWithShadowTemplate,
59720 visitChildren: _htmlbarsUtilMorphUtils.visitChildren, 59721 validateChildMorphs: _htmlbarsUtilMorphUtils.validateChildMorphs, 59722 clearMorph: _htmlbarsUtilTemplateUtils.clearMorph 59723 }; 59724 59725 exports.hooks = _htmlbarsRuntimeHooks.default; 59726 exports.render = _htmlbarsRuntimeRender.default; 59727 exports.internal = internal; 59728}); 59729enifed('htmlbars-util/array-utils', ['exports'], function (exports) { 59730 'use strict'; 59731 59732 exports.forEach = forEach; 59733 exports.map = map; 59734 59735 function forEach(array, callback, binding) { 59736 var i, l; 59737 if (binding === undefined) { 59738 for (i = 0, l = array.length; i < l; i++) { 59739 callback(array[i], i, array); 59740 } 59741 } else { 59742 for (i = 0, l = array.length; i < l; i++) { 59743 callback.call(binding, array[i], i, array); 59744 } 59745 } 59746 } 59747 59748 function map(array, callback) { 59749 var output = []; 59750 var i, l; 59751 59752 for (i = 0, l = array.length; i < l; i++) { 59753 output.push(callback(array[i], i, array)); 59754 } 59755 59756 return output; 59757 } 59758 59759 var getIdx; 59760 if (Array.prototype.indexOf) { 59761 getIdx = function (array, obj, from) { 59762 return array.indexOf(obj, from); 59763 }; 59764 } else { 59765 getIdx = function (array, obj, from) { 59766 if (from === undefined || from === null) { 59767 from = 0; 59768 } else if (from < 0) { 59769 from = Math.max(0, array.length + from); 59770 } 59771 for (var i = from, l = array.length; i < l; i++) { 59772 if (array[i] === obj) { 59773 return i; 59774 } 59775 } 59776 return -1; 59777 }; 59778 } 59779 59780 var isArray = Array.isArray || function (array) { 59781 return Object.prototype.toString.call(array) === '[object Array]'; 59782 }; 59783 59784 exports.isArray = isArray; 59785 var indexOfArray = getIdx; 59786 exports.indexOfArray = indexOfArray; 59787}); 59788enifed('htmlbars-util/handlebars/safe-string', ['exports'], function (exports) { 59789 // Build out our basic SafeString type 59790 'use strict'; 59791 59792 function SafeString(string) { 59793 this.string = string; 59794 } 59795 59796 SafeString.prototype.toString = SafeString.prototype.toHTML = function () { 59797 return '' + this.string; 59798 }; 59799 59800 exports.default = SafeString; 59801}); 59802enifed('htmlbars-util/handlebars/utils', ['exports'], function (exports) { 59803 'use strict'; 59804 59805 exports.extend = extend; 59806 exports.indexOf = indexOf; 59807 exports.escapeExpression = escapeExpression; 59808 exports.isEmpty = isEmpty; 59809 exports.blockParams = blockParams; 59810 exports.appendContextPath = appendContextPath; 59811 var escape = { 59812 '&': '&', 59813 '<': '<', 59814 '>': '>', 59815 '"': '"', 59816 "'": ''', 59817 '`': '`' 59818 }; 59819 59820 var badChars = /[&<>"'`]/g, 59821 possible = /[&<>"'`]/; 59822 59823 function escapeChar(chr) { 59824 return escape[chr]; 59825 } 59826 59827 function extend(obj /* , ...source */) { 59828 for (var i = 1; i < arguments.length; i++) { 59829 for (var key in arguments[i]) { 59830 if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { 59831 obj[key] = arguments[i][key]; 59832 } 59833 } 59834 } 59835 59836 return obj; 59837 } 59838 59839 var toString = Object.prototype.toString; 59840 59841 exports.toString = toString; 59842 // Sourced from lodash 59843 // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt 59844 /*eslint-disable func-style, no-var */ 59845 var isFunction = function (value) { 59846 return typeof value === 'function'; 59847 }; 59848 // fallback for older versions of Chrome and Safari 59849 /* istanbul ignore next */ 59850 if (isFunction(/x/)) { 59851 exports.isFunction = isFunction = function (value) { 59852 return typeof value === 'function' && toString.call(value) === '[object Function]'; 59853 }; 59854 } 59855 var isFunction; 59856 exports.isFunction = isFunction; 59857 /*eslint-enable func-style, no-var */ 59858 59859 /* istanbul ignore next */ 59860 var isArray = Array.isArray || function (value) { 59861 return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; 59862 }; 59863 59864 exports.isArray = isArray; 59865 // Older IE versions do not directly support indexOf so we must implement our own, sadly. 59866 59867 function indexOf(array, value) { 59868 for (var i = 0, len = array.length; i < len; i++) { 59869 if (array[i] === value) { 59870 return i; 59871 } 59872 } 59873 return -1; 59874 } 59875 59876 function escapeExpression(string) { 59877 if (typeof string !== 'string') { 59878 // don't escape SafeStrings, since they're already safe 59879 if (string && string.toHTML) { 59880 return string.toHTML(); 59881 } else if (string == null) { 59882 return ''; 59883 } else if (!string) { 59884 return string + ''; 59885 } 59886 59887 // Force a string conversion as this will be done by the append regardless and 59888 // the regex test will do this transparently behind the scenes, causing issues if 59889 // an object's to string has escaped characters in it.
59890 string = '' + string; 59891 } 59892 59893 if (!possible.test(string)) { 59894 return string; 59895 } 59896 return string.replace(badChars, escapeChar); 59897 } 59898 59899 function isEmpty(value) { 59900 if (!value && value !== 0) { 59901 return true; 59902 } else if (isArray(value) && value.length === 0) { 59903 return true; 59904 } else { 59905 return false; 59906 } 59907 } 59908 59909 function blockParams(params, ids) { 59910 params.path = ids; 59911 return params; 59912 } 59913 59914 function appendContextPath(contextPath, id) { 59915 return (contextPath ? contextPath + '.' : '') + id; 59916 } 59917}); 59918enifed("htmlbars-util/morph-utils", ["exports"], function (exports) { 59919 /*globals console*/ 59920 59921 "use strict"; 59922 59923 exports.visitChildren = visitChildren; 59924 exports.validateChildMorphs = validateChildMorphs; 59925 exports.linkParams = linkParams; 59926 exports.dump = dump; 59927 59928 function visitChildren(nodes, callback) { 59929 if (!nodes || nodes.length === 0) { 59930 return; 59931 } 59932 59933 nodes = nodes.slice(); 59934 59935 while (nodes.length) { 59936 var node = nodes.pop(); 59937 callback(node); 59938 59939 if (node.childNodes) { 59940 nodes.push.apply(nodes, node.childNodes); 59941 } else if (node.firstChildMorph) { 59942 var current = node.firstChildMorph; 59943 59944 while (current) { 59945 nodes.push(current); 59946 current = current.nextMorph; 59947 } 59948 } else if (node.morphList) { 59949 var current = node.morphList.firstChildMorph; 59950 59951 while (current) { 59952 nodes.push(current); 59953 current = current.nextMorph; 59954 } 59955 } 59956 } 59957 } 59958 59959 function validateChildMorphs(env, morph, visitor) { 59960 var morphList = morph.morphList; 59961 if (morph.morphList) { 59962 var current = morphList.firstChildMorph; 59963 59964 while (current) { 59965 var next = current.nextMorph; 59966 validateChildMorphs(env, current, visitor); 59967 current = next; 59968 } 59969 } else if (morph.lastResult) { 59970 morph.lastResult.revalidateWith(env, undefined, undefined, undefined, visitor); 59971 } else if (morph.childNodes) { 59972 // This means that the childNodes were wired up manually 59973 for (var i = 0, l = morph.childNodes.length; i < l; i++) { 59974 validateChildMorphs(env, morph.childNodes[i], visitor); 59975 } 59976 } 59977 } 59978 59979 function linkParams(env, scope, morph, path, params, hash) { 59980 if (morph.linkedParams) { 59981 return; 59982 } 59983 59984 if (env.hooks.linkRenderNode(morph, env, scope, path, params, hash)) { 59985 morph.linkedParams = { params: params, hash: hash }; 59986 } 59987 } 59988 59989 function dump(node) { 59990 console.group(node, node.isDirty); 59991 59992 if (node.childNodes) { 59993 map(node.childNodes, dump); 59994 } else if (node.firstChildMorph) { 59995 var current = node.firstChildMorph; 59996 59997 while (current) { 59998 dump(current); 59999 current = current.nextMorph; 60000 } 60001 } else if (node.morphList) { 60002 dump(node.morphList); 60003 } 60004 60005 console.groupEnd(); 60006 } 60007 60008 function map(nodes, cb) { 60009 for (var i = 0, l = nodes.length; i < l; i++) { 60010 cb(nodes[i]); 60011 } 60012 } 60013}); 60014enifed('htmlbars-util/namespaces', ['exports'], function (exports) { 60015 // ref http://dev.w3.org/html5/spec-LC/namespaces.html 60016 'use strict'; 60017 60018 exports.getAttrNamespace = getAttrNamespace; 60019 var defaultNamespaces = { 60020 html: 'http://www.w3.org/1999/xhtml', 60021 mathml: 'http://www.w3.org/1998/Math/MathML', 60022 svg: 'http://www.w3.org/2000/svg', 60023 xlink: 'http://www.w3.org/1999/xlink', 60024 xml: 'http://www.w3.org/XML/1998/namespace' 60025 }; 60026 60027 function getAttrNamespace(attrName, detectedNamespace) { 60028 if (detectedNamespace) { 60029 return detectedNamespace; 60030 } 60031 60032 var namespace; 60033 60034 var colonIndex = attrName.indexOf(':'); 60035 if (colonIndex !== -1) { 60036 var prefix = attrName.slice(0, colonIndex); 60037 namespace = defaultNamespaces[prefix]; 60038 } 60039 60040 return namespace || null; 60041 } 60042}); 60043enifed("htmlbars-util/object-utils", ["exports"], function (exports) { 60044 "use strict"; 60045 60046 exports.merge = merge; 60047 exports.shallowCopy = shallowCopy; 60048 exports.keySet = keySet; 60049 exports.keyLength = keyLength; 60050 60051 function merge(options, defaults) { 60052 for (var prop in defaults) { 60053 if (options.hasOwnProperty(prop)) { 60054 continue; 60055 } 60056 options[prop] = defaults[prop]; 60057 } 60058 return options; 60059 } 60060 60061 function shallowCopy(obj) { 60062 return merge({}, obj); 60063 } 60064 60065 function keySet(obj) { 60066 var set = {}; 60067 60068 for (var prop in obj) { 60069 if (obj.hasOwnProperty(prop)) { 60070 set[prop] = true; 60071 } 60072 } 60073 60074 return set; 60075 } 60076 60077 function keyLength(obj) { 60078 var count = 0; 60079 60080 for (var prop in obj) { 60081 if (obj.hasOwnProperty(prop)) { 60082 count++; 60083 } 60084 } 60085 60086 return count; 60087 } 60088}); 60089enifed("htmlbars-util/quoting", ["exports"], function (exports) { 60090 "use strict"; 60091 60092 exports.hash = hash; 60093 exports.repeat = repeat; 60094 function escapeString(str) { 60095 str = str.replace(/\\/g, "\\\\"); 60096 str = str.replace(/"/g, '\\"'); 60097 str = str.replace(/\n/g, "\\n"); 60098 return str; 60099 } 60100 60101 exports.escapeString = escapeString; 60102 60103 function string(str) { 60104 return '"' + escapeString(str) + '"'; 60105 } 60106 60107 exports.string = string; 60108 60109 function array(a) { 60110 return "[" + a + "]"; 60111 } 60112 60113 exports.array = array; 60114 60115 function hash(pairs) { 60116 return "{" + pairs.join(", ") + "}"; 60117 } 60118 60119 function repeat(chars, times) { 60120 var str = ""; 60121 while (times--) { 60122 str += chars; 60123 } 60124 return str; 60125 } 60126}); 60127enifed('htmlbars-util/safe-string', ['exports', 'htmlbars-util/handlebars/safe-string'], function (exports, _htmlbarsUtilHandlebarsSafeString) { 60128 'use strict'; 60129 60130 exports.default = _htmlbarsUtilHandlebarsSafeString.default; 60131}); 60132enifed("htmlbars-util/template-utils", ["exports", "htmlbars-util/morph-utils", "htmlbars-runtime/render"], function (exports, _htmlbarsUtilMorphUtils, _htmlbarsRuntimeRender) { 60133 "use strict"; 60134 60135 exports.RenderState = RenderState; 60136 exports.blockFor = blockFor; 60137 exports.renderAndCleanup = renderAndCleanup; 60138 exports.clearMorph = clearMorph; 60139 exports.clearMorphList = clearMorphList; 60140
60141 function RenderState(renderNode, morphList) { 60142 // The morph list that is no longer needed and can be 60143 // destroyed. 60144 this.morphListToClear = morphList; 60145 60146 // The morph list that needs to be pruned of any items 60147 // that were not yielded on a subsequent render. 60148 this.morphListToPrune = null; 60149 60150 // A map of morphs for each item yielded in during this 60151 // rendering pass. Any morphs in the DOM but not in this map 60152 // will be pruned during cleanup. 60153 this.handledMorphs = {}; 60154 this.collisions = undefined; 60155 60156 // The morph to clear once rendering is complete. By 60157 // default, we set this to the previous morph (to catch 60158 // the case where nothing is yielded; in that case, we 60159 // should just clear the morph). Otherwise this gets set 60160 // to null if anything is rendered. 60161 this.morphToClear = renderNode; 60162 60163 this.shadowOptions = null; 60164 } 60165 60166 function Block(render, template, blockOptions) { 60167 this.render = render; 60168 this.template = template; 60169 this.blockOptions = blockOptions; 60170 this.arity = template.arity; 60171 } 60172 60173 Block.prototype.invoke = function (env, blockArguments, _self, renderNode, parentScope, visitor) { 60174 if (renderNode.lastResult) { 60175 renderNode.lastResult.revalidateWith(env, undefined, _self, blockArguments, visitor); 60176 } else { 60177 this._firstRender(env, blockArguments, _self, renderNode, parentScope); 60178 } 60179 }; 60180 60181 Block.prototype._firstRender = function (env, blockArguments, _self, renderNode, parentScope) { 60182 var options = { renderState: new RenderState(renderNode) }; 60183 var render = this.render; 60184 var template = this.template; 60185 var scope = this.blockOptions.scope; 60186 60187 var shadowScope = scope ? env.hooks.createChildScope(scope) : env.hooks.createFreshScope(); 60188 60189 env.hooks.bindShadowScope(env, parentScope, shadowScope, this.blockOptions.options); 60190 60191 if (_self !== undefined) { 60192 env.hooks.bindSelf(env, shadowScope, _self); 60193 } else if (this.blockOptions.self !== undefined) { 60194 env.hooks.bindSelf(env, shadowScope, this.blockOptions.self); 60195 } 60196 60197 bindBlocks(env, shadowScope, this.blockOptions.yieldTo); 60198 60199 renderAndCleanup(renderNode, env, options, null, function () { 60200 options.renderState.morphToClear = null; 60201 var renderOptions = new _htmlbarsRuntimeRender.RenderOptions(renderNode, undefined, blockArguments); 60202 render(template, env, shadowScope, renderOptions); 60203 }); 60204 }; 60205 60206 function blockFor(render, template, blockOptions) { 60207 return new Block(render, template, blockOptions); 60208 } 60209 60210 function bindBlocks(env, shadowScope, blocks) { 60211 if (!blocks) { 60212 return; 60213 } 60214 if (blocks instanceof Block) { 60215 env.hooks.bindBlock(env, shadowScope, blocks); 60216 } else { 60217 for (var name in blocks) { 60218 if (blocks.hasOwnProperty(name)) { 60219 env.hooks.bindBlock(env, shadowScope, blocks[name], name); 60220 } 60221 } 60222 } 60223 } 60224 60225 function renderAndCleanup(morph, env, options, shadowOptions, callback) { 60226 // The RenderState object is used to collect information about what the 60227 // helper or hook being invoked has yielded. Once it has finished either 60228 // yielding multiple items (via yieldItem) or a single template (via 60229 // yieldTemplate), we detect what was rendered and how it differs from 60230 // the previous render, cleaning up old state in DOM as appropriate. 60231 var renderState = options.renderState; 60232 renderState.collisions = undefined; 60233 renderState.shadowOptions = shadowOptions; 60234 60235 // Invoke the callback, instructing it to save information about what it 60236 // renders into RenderState. 60237 var result = callback(options); 60238 60239 // The hook can opt-out of cleanup if it handled cleanup itself. 60240 if (result && result.handled) { 60241 return; 60242 } 60243 60244 var morphMap = morph.morphMap; 60245 60246 // Walk the morph list, clearing any items that were yielded in a previous 60247 // render but were not yielded during this render. 60248 var morphList = renderState.morphListToPrune; 60249 if (morphList) { 60250 var handledMorphs = renderState.handledMorphs; 60251 var item = morphList.firstChildMorph; 60252 60253 while (item) { 60254 var next = item.nextMorph; 60255 60256 // If we don't see the key in handledMorphs, it wasn't 60257 // yielded in and we can safely remove it from DOM. 60258 if (!(item.key in handledMorphs)) { 60259 morphMap[item.key] = undefined; 60260 clearMorph(item, env, true); 60261 item.destroy(); 60262 } 60263 60264 item = next; 60265 } 60266 } 60267 60268 morphList = renderState.morphListToClear; 60269 if (morphList) { 60270 clearMorphList(morphList, morph, env); 60271 } 60272 60273 var toClear = renderState.morphToClear; 60274 if (toClear) { 60275 clearMorph(toClear, env); 60276 } 60277 } 60278 60279 function clearMorph(morph, env, destroySelf) { 60280 var cleanup = env.hooks.cleanupRenderNode;
60281 var destroy = env.hooks.destroyRenderNode; 60282 var willCleanup = env.hooks.willCleanupTree; 60283 var didCleanup = env.hooks.didCleanupTree; 60284 60285 function destroyNode(node) { 60286 if (cleanup) { 60287 cleanup(node); 60288 } 60289 if (destroy) { 60290 destroy(node); 60291 } 60292 } 60293 60294 if (willCleanup) { 60295 willCleanup(env, morph, destroySelf); 60296 } 60297 if (cleanup) { 60298 cleanup(morph); 60299 } 60300 if (destroySelf && destroy) { 60301 destroy(morph); 60302 } 60303 60304 _htmlbarsUtilMorphUtils.visitChildren(morph.childNodes, destroyNode); 60305 60306 // TODO: Deal with logical children that are not in the DOM tree 60307 morph.clear(); 60308 if (didCleanup) { 60309 didCleanup(env, morph, destroySelf); 60310 } 60311 60312 morph.lastResult = null; 60313 morph.lastYielded = null; 60314 morph.childNodes = null; 60315 } 60316 60317 function clearMorphList(morphList, morph, env) { 60318 var item = morphList.firstChildMorph; 60319 60320 while (item) { 60321 var next = item.nextMorph; 60322 morph.morphMap[item.key] = undefined; 60323 clearMorph(item, env, true); 60324 item.destroy(); 60325 60326 item = next; 60327 } 60328 60329 // Remove the MorphList from the morph. 60330 morphList.clear(); 60331 morph.morphList = null; 60332 } 60333}); 60334enifed("htmlbars-util/void-tag-names", ["exports", "htmlbars-util/array-utils"], function (exports, _htmlbarsUtilArrayUtils) { 60335 "use strict"; 60336 60337 // The HTML elements in this list are speced by 60338 // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements, 60339 // and will be forced to close regardless of if they have a 60340 // self-closing /> at the end. 60341 var voidTagNames = "area base br col command embed hr img input keygen link meta param source track wbr"; 60342 var voidMap = {}; 60343 60344 _htmlbarsUtilArrayUtils.forEach(voidTagNames.split(" "), function (tagName) { 60345 voidMap[tagName] = true; 60346 }); 60347 60348 exports.default = voidMap; 60349}); 60350enifed('htmlbars-util', ['exports', 'htmlbars-util/safe-string', 'htmlbars-util/handlebars/utils', 'htmlbars-util/namespaces', 'htmlbars-util/morph-utils'], function (exports, _htmlbarsUtilSafeString, _htmlbarsUtilHandlebarsUtils, _htmlbarsUtilNamespaces, _htmlbarsUtilMorphUtils) { 60351 'use strict'; 60352 60353 exports.SafeString = _htmlbarsUtilSafeString.default; 60354 exports.escapeExpression = _htmlbarsUtilHandlebarsUtils.escapeExpression; 60355 exports.getAttrNamespace = _htmlbarsUtilNamespaces.getAttrNamespace; 60356 exports.validateChildMorphs = _htmlbarsUtilMorphUtils.validateChildMorphs; 60357 exports.linkParams = _htmlbarsUtilMorphUtils.linkParams; 60358 exports.dump = _htmlbarsUtilMorphUtils.dump; 60359}); 60360enifed('morph-attr/sanitize-attribute-value', ['exports'], function (exports) { 60361 /* jshint scripturl:true */ 60362 60363 'use strict'; 60364 60365 exports.sanitizeAttributeValue = sanitizeAttributeValue; 60366 var badProtocols = { 60367 'javascript:': true, 60368 'vbscript:': true 60369 }; 60370 60371 var badTags = { 60372 'A': true, 60373 'BODY': true, 60374 'LINK': true, 60375 'IMG': true, 60376 'IFRAME': true, 60377 'BASE': true, 60378 'FORM': true 60379 }; 60380 60381 var badTagsForDataURI = { 60382 'EMBED': true 60383 }; 60384 60385 var badAttributes = { 60386 'href': true, 60387 'src': true, 60388 'background': true, 60389 'action': true 60390 }; 60391 60392 exports.badAttributes = badAttributes; 60393 var badAttributesForDataURI = { 60394 'src': true 60395 }; 60396 60397 function sanitizeAttributeValue(dom, element, attribute, value) { 60398 var tagName; 60399 60400 if (!element) { 60401 tagName = null; 60402 } else { 60403 tagName = element.tagName.toUpperCase(); 60404 } 60405 60406 if (value && value.toHTML) { 60407 return value.toHTML(); 60408 } 60409 60410 if ((tagName === null || badTags[tagName]) && badAttributes[attribute]) { 60411 var protocol = dom.protocolForURL(value); 60412 if (badProtocols[protocol] === true) { 60413 return 'unsafe:' + value; 60414 } 60415 } 60416 60417 if (badTagsForDataURI[tagName] && badAttributesForDataURI[attribute]) { 60418 return 'unsafe:' + value; 60419 } 60420 60421 return value; 60422 } 60423}); 60424enifed("morph-attr", ["exports", "morph-attr/sanitize-attribute-value", "dom-helper/prop", "dom-helper/build-html-dom", "htmlbars-util"], function (exports, _morphAttrSanitizeAttributeValue, _domHelperProp, _domHelperBuildHtmlDom, _htmlbarsUtil) { 60425 "use strict"; 60426 60427 function getProperty() { 60428 return this.domHelper.getPropertyStrict(this.element, this.attrName); 60429 } 60430 60431 function updateProperty(value) { 60432 if (this._renderedInitially === true || !_domHelperProp.isAttrRemovalValue(value)) { 60433 var element = this.element; 60434 var attrName = this.attrName; 60435 60436 if (attrName === 'value' && element.tagName === 'INPUT' && element.value === value) {
60437 // Do nothing. Attempts to avoid accidently changing the input cursor location. 60438 // See https://github.com/tildeio/htmlbars/pull/447 for more details. 60439 } else { 60440 // do not render if initial value is undefined or null 60441 this.domHelper.setPropertyStrict(element, attrName, value); 60442 } 60443 } 60444 60445 this._renderedInitially = true; 60446 } 60447 60448 function getAttribute() { 60449 return this.domHelper.getAttribute(this.element, this.attrName); 60450 } 60451 60452 function updateAttribute(value) { 60453 if (_domHelperProp.isAttrRemovalValue(value)) { 60454 this.domHelper.removeAttribute(this.element, this.attrName); 60455 } else { 60456 this.domHelper.setAttribute(this.element, this.attrName, value); 60457 } 60458 } 60459 60460 function getAttributeNS() { 60461 return this.domHelper.getAttributeNS(this.element, this.namespace, this.attrName); 60462 } 60463 60464 function updateAttributeNS(value) { 60465 if (_domHelperProp.isAttrRemovalValue(value)) { 60466 this.domHelper.removeAttribute(this.element, this.attrName); 60467 } else { 60468 this.domHelper.setAttributeNS(this.element, this.namespace, this.attrName, value); 60469 } 60470 } 60471 60472 var UNSET = { unset: true }; 60473 60474 var guid = 1; 60475 60476 AttrMorph.create = function (element, attrName, domHelper, namespace) { 60477 var ns = _htmlbarsUtil.getAttrNamespace(attrName, namespace); 60478 60479 if (ns) { 60480 return new AttributeNSAttrMorph(element, attrName, domHelper, ns); 60481 } else { 60482 return createNonNamespacedAttrMorph(element, attrName, domHelper); 60483 } 60484 }; 60485 60486 function createNonNamespacedAttrMorph(element, attrName, domHelper) { 60487 var _normalizeProperty = _domHelperProp.normalizeProperty(element, attrName); 60488 60489 var normalized = _normalizeProperty.normalized; 60490 var type = _normalizeProperty.type; 60491 60492 if (element.namespaceURI === _domHelperBuildHtmlDom.svgNamespace || attrName === 'style' || type === 'attr') { 60493 return new AttributeAttrMorph(element, normalized, domHelper); 60494 } else { 60495 return new PropertyAttrMorph(element, normalized, domHelper); 60496 } 60497 } 60498 60499 function AttrMorph(element, attrName, domHelper) { 60500 this.element = element; 60501 this.domHelper = domHelper; 60502 this.attrName = attrName; 60503 this._state = undefined; 60504 this.isDirty = false; 60505 this.isSubtreeDirty = false; 60506 this.escaped = true; 60507 this.lastValue = UNSET; 60508 this.lastResult = null; 60509 this.lastYielded = null; 60510 this.childNodes = null; 60511 this.linkedParams = null; 60512 this.linkedResult = null; 60513 this.guid = "attr" + guid++; 60514 this.seen = false; 60515 this.ownerNode = null; 60516 this.rendered = false; 60517 this._renderedInitially = false; 60518 this.namespace = undefined; 60519 this.didInit(); 60520 } 60521 60522 AttrMorph.prototype.getState = function () { 60523 if (!this._state) { 60524 this._state = {}; 60525 } 60526 60527 return this._state; 60528 }; 60529 60530 AttrMorph.prototype.setState = function (newState) { 60531 /*jshint -W093 */ 60532 60533 return this._state = newState; 60534 }; 60535 60536 AttrMorph.prototype.didInit = function () {}; 60537 AttrMorph.prototype.willSetContent = function () {}; 60538 60539 AttrMorph.prototype.setContent = function (value) { 60540 this.willSetContent(value); 60541 60542 if (this.lastValue === value) { 60543 return; 60544 } 60545 this.lastValue = value; 60546 60547 if (this.escaped) { 60548 var sanitized = _morphAttrSanitizeAttributeValue.sanitizeAttributeValue(this.domHelper, this.element, this.attrName, value); 60549 this._update(sanitized, this.namespace); 60550 } else { 60551 this._update(value, this.namespace); 60552 } 60553 }; 60554 60555 AttrMorph.prototype.getContent = function () { 60556 var value = this.lastValue = this._get(); 60557 return value; 60558 }; 60559 60560 // renderAndCleanup calls `clear` on all items in the morph map 60561 // just before calling `destroy` on the morph. 60562 // 60563 // As a future refactor this could be changed to set the property 60564 // back to its original/default value. 60565 AttrMorph.prototype.clear = function () {}; 60566 60567 AttrMorph.prototype.destroy = function () { 60568 this.element = null; 60569 this.domHelper = null; 60570 }; 60571 60572 AttrMorph.prototype._$superAttrMorph = AttrMorph; 60573 60574 function PropertyAttrMorph(element, attrName, domHelper) { 60575 this._$superAttrMorph(element, attrName, domHelper); 60576 } 60577 60578 PropertyAttrMorph.prototype = Object.create(AttrMorph.prototype); 60579 PropertyAttrMorph.prototype._update = updateProperty; 60580 PropertyAttrMorph.prototype._get = getProperty; 60581 60582 function AttributeNSAttrMorph(element, attrName, domHelper, namespace) { 60583 this._$superAttrMorph(element, attrName, domHelper); 60584 this.namespace = namespace; 60585 } 60586 60587 AttributeNSAttrMorph.prototype = Object.create(AttrMorph.prototype); 60588 AttributeNSAttrMorph.prototype._update = updateAttributeNS; 60589 AttributeNSAttrMorph.prototype._get = getAttributeNS; 60590 60591 function AttributeAttrMorph(element, attrName, domHelper) { 60592 this._$superAttrMorph(element, attrName, domHelper); 60593 } 60594 60595 AttributeAttrMorph.prototype = Object.create(AttrMorph.prototype); 60596 AttributeAttrMorph.prototype._update = updateAttribute; 60597 AttributeAttrMorph.prototype._get = getAttribute; 60598 60599 exports.default = AttrMorph; 60600 exports.sanitizeAttributeValue = _morphAttrSanitizeAttributeValue.sanitizeAttributeValue; 60601}); 60602enifed('morph-range/morph-list', ['exports', 'morph-range/utils'], function (exports, _morphRangeUtils) { 60603 'use strict'; 60604
60605 function MorphList() { 60606 // morph graph 60607 this.firstChildMorph = null; 60608 this.lastChildMorph = null; 60609 60610 this.mountedMorph = null; 60611 } 60612 60613 var prototype = MorphList.prototype; 60614 60615 prototype.clear = function MorphList$clear() { 60616 var current = this.firstChildMorph; 60617 60618 while (current) { 60619 var next = current.nextMorph; 60620 current.previousMorph = null; 60621 current.nextMorph = null; 60622 current.parentMorphList = null; 60623 current = next; 60624 } 60625 60626 this.firstChildMorph = this.lastChildMorph = null; 60627 }; 60628 60629 prototype.destroy = function MorphList$destroy() {}; 60630 60631 prototype.appendMorph = function MorphList$appendMorph(morph) { 60632 this.insertBeforeMorph(morph, null); 60633 }; 60634 60635 prototype.insertBeforeMorph = function MorphList$insertBeforeMorph(morph, referenceMorph) { 60636 if (morph.parentMorphList !== null) { 60637 morph.unlink(); 60638 } 60639 if (referenceMorph && referenceMorph.parentMorphList !== this) { 60640 throw new Error('The morph before which the new morph is to be inserted is not a child of this morph.'); 60641 } 60642 60643 var mountedMorph = this.mountedMorph; 60644 60645 if (mountedMorph) { 60646 60647 var parentNode = mountedMorph.firstNode.parentNode; 60648 var referenceNode = referenceMorph ? referenceMorph.firstNode : mountedMorph.lastNode.nextSibling; 60649 60650 _morphRangeUtils.insertBefore(parentNode, morph.firstNode, morph.lastNode, referenceNode); 60651 60652 // was not in list mode replace current content 60653 if (!this.firstChildMorph) { 60654 _morphRangeUtils.clear(this.mountedMorph.firstNode.parentNode, this.mountedMorph.firstNode, this.mountedMorph.lastNode); 60655 } 60656 } 60657 60658 morph.parentMorphList = this; 60659 60660 var previousMorph = referenceMorph ? referenceMorph.previousMorph : this.lastChildMorph; 60661 if (previousMorph) { 60662 previousMorph.nextMorph = morph; 60663 morph.previousMorph = previousMorph; 60664 } else { 60665 this.firstChildMorph = morph; 60666 } 60667 60668 if (referenceMorph) { 60669 referenceMorph.previousMorph = morph; 60670 morph.nextMorph = referenceMorph; 60671 } else { 60672 this.lastChildMorph = morph; 60673 } 60674 60675 this.firstChildMorph._syncFirstNode(); 60676 this.lastChildMorph._syncLastNode(); 60677 }; 60678 60679 prototype.removeChildMorph = function MorphList$removeChildMorph(morph) { 60680 if (morph.parentMorphList !== this) { 60681 throw new Error("Cannot remove a morph from a parent it is not inside of"); 60682 } 60683 60684 morph.destroy(); 60685 }; 60686 60687 exports.default = MorphList; 60688}); 60689enifed('morph-range/morph-list.umd', ['exports', 'morph-range/morph-list'], function (exports, _morphRangeMorphList) { 60690 'use strict'; 60691 60692 (function (root, factory) { 60693 if (typeof define === 'function' && define.amd) { 60694 define([], factory); 60695 } else if (typeof exports === 'object') { 60696 module.exports = factory(); 60697 } else { 60698 root.MorphList = factory(); 60699 } 60700 })(undefined, function () { 60701 return _morphRangeMorphList.default; 60702 }); 60703}); 60704enifed("morph-range/utils", ["exports"], function (exports) { 60705 // inclusive of both nodes 60706 "use strict"; 60707 60708 exports.clear = clear; 60709 exports.insertBefore = insertBefore; 60710 60711 function clear(parentNode, firstNode, lastNode) { 60712 if (!parentNode) { 60713 return; 60714 } 60715 60716 var node = firstNode; 60717 var nextNode; 60718 do { 60719 nextNode = node.nextSibling; 60720 parentNode.removeChild(node); 60721 if (node === lastNode) { 60722 break; 60723 } 60724 node = nextNode; 60725 } while (node); 60726 } 60727 60728 function insertBefore(parentNode, firstNode, lastNode, refNode) { 60729 var node = firstNode; 60730 var nextNode; 60731 do { 60732 nextNode = node.nextSibling; 60733 parentNode.insertBefore(node, refNode); 60734 if (node === lastNode) { 60735 break; 60736 } 60737 node = nextNode; 60738 } while (node); 60739 } 60740}); 60741enifed('morph-range', ['exports', 'morph-range/utils'], function (exports, _morphRangeUtils) { 60742 'use strict'; 60743 60744 // constructor just initializes the fields 60745 // use one of the static initializers to create a valid morph. 60746 function Morph(domHelper, contextualElement) { 60747 this.domHelper = domHelper; 60748 // context if content if current content is detached 60749 this.contextualElement = contextualElement; 60750 // inclusive range of morph 60751 // these should be nodeType 1, 3, or 8 60752 this.firstNode = null; 60753 this.lastNode = null; 60754 60755 // flag to force text to setContent to be treated as html 60756 this.parseTextAsHTML = false;
60757 60758 // morph list graph 60759 this.parentMorphList = null; 60760 this.previousMorph = null; 60761 this.nextMorph = null; 60762 } 60763 60764 Morph.empty = function (domHelper, contextualElement) { 60765 var morph = new Morph(domHelper, contextualElement); 60766 morph.clear(); 60767 return morph; 60768 }; 60769 60770 Morph.create = function (domHelper, contextualElement, node) { 60771 var morph = new Morph(domHelper, contextualElement); 60772 morph.setNode(node); 60773 return morph; 60774 }; 60775 60776 Morph.attach = function (domHelper, contextualElement, firstNode, lastNode) { 60777 var morph = new Morph(domHelper, contextualElement); 60778 morph.setRange(firstNode, lastNode); 60779 return morph; 60780 }; 60781 60782 Morph.prototype.setContent = function Morph$setContent(content) { 60783 if (content === null || content === undefined) { 60784 return this.clear(); 60785 } 60786 60787 var type = typeof content; 60788 switch (type) { 60789 case 'string': 60790 if (this.parseTextAsHTML) { 60791 return this.domHelper.setMorphHTML(this, content); 60792 } 60793 return this.setText(content); 60794 case 'object': 60795 if (typeof content.nodeType === 'number') { 60796 return this.setNode(content); 60797 } 60798 /* Handlebars.SafeString */ 60799 if (typeof content.toHTML === 'function') { 60800 return this.setHTML(content.toHTML()); 60801 } 60802 if (this.parseTextAsHTML) { 60803 return this.setHTML(content.toString()); 60804 } 60805 /* falls through */ 60806 case 'boolean': 60807 case 'number': 60808 return this.setText(content.toString()); 60809 case 'function': 60810 raiseCannotBindToFunction(content); 60811 default: 60812 throw new TypeError('unsupported content'); 60813 } 60814 }; 60815 60816 function raiseCannotBindToFunction(content) { 60817 var functionName = content.name; 60818 var message; 60819 60820 if (functionName) { 60821 message = 'Unsupported Content: Cannot bind to function `' + functionName + '`'; 60822 } else { 60823 message = 'Unsupported Content: Cannot bind to function'; 60824 } 60825 60826 throw new TypeError(message); 60827 } 60828 60829 Morph.prototype.clear = function Morph$clear() { 60830 var node = this.setNode(this.domHelper.createComment('')); 60831 return node; 60832 }; 60833 60834 Morph.prototype.setText = function Morph$setText(text) { 60835 var firstNode = this.firstNode; 60836 var lastNode = this.lastNode; 60837 60838 if (firstNode && lastNode === firstNode && firstNode.nodeType === 3) { 60839 firstNode.nodeValue = text; 60840 return firstNode; 60841 } 60842 60843 return this.setNode(text ? this.domHelper.createTextNode(text) : this.domHelper.createComment('')); 60844 }; 60845 60846 Morph.prototype.setNode = function Morph$setNode(newNode) { 60847 var firstNode, lastNode; 60848 switch (newNode.nodeType) { 60849 case 3: 60850 firstNode = newNode; 60851 lastNode = newNode; 60852 break; 60853 case 11: 60854 firstNode = newNode.firstChild; 60855 lastNode = newNode.lastChild; 60856 if (firstNode === null) { 60857 firstNode = this.domHelper.createComment(''); 60858 newNode.appendChild(firstNode); 60859 lastNode = firstNode; 60860 } 60861 break; 60862 default: 60863 firstNode = newNode; 60864 lastNode = newNode; 60865 break; 60866 } 60867 60868 this.setRange(firstNode, lastNode); 60869 60870 return newNode; 60871 }; 60872 60873 Morph.prototype.setRange = function (firstNode, lastNode) { 60874 var previousFirstNode = this.firstNode; 60875 if (previousFirstNode !== null) { 60876 60877 var parentNode = previousFirstNode.parentNode; 60878 if (parentNode !== null) { 60879 _morphRangeUtils.insertBefore(parentNode, firstNode, lastNode, previousFirstNode); 60880 _morphRangeUtils.clear(parentNode, previousFirstNode, this.lastNode); 60881 } 60882 } 60883 60884 this.firstNode = firstNode; 60885 this.lastNode = lastNode; 60886 60887 if (this.parentMorphList) { 60888 this._syncFirstNode(); 60889 this._syncLastNode(); 60890 } 60891 }; 60892 60893 Morph.prototype.destroy = function Morph$destroy() { 60894 this.unlink(); 60895 60896 var firstNode = this.firstNode; 60897 var lastNode = this.lastNode; 60898 var parentNode = firstNode && firstNode.parentNode; 60899 60900 this.firstNode = null; 60901 this.lastNode = null; 60902 60903 _morphRangeUtils.clear(parentNode, firstNode, lastNode); 60904 }; 60905
60906 Morph.prototype.unlink = function Morph$unlink() { 60907 var parentMorphList = this.parentMorphList; 60908 var previousMorph = this.previousMorph; 60909 var nextMorph = this.nextMorph; 60910 60911 if (previousMorph) { 60912 if (nextMorph) { 60913 previousMorph.nextMorph = nextMorph; 60914 nextMorph.previousMorph = previousMorph; 60915 } else { 60916 previousMorph.nextMorph = null; 60917 parentMorphList.lastChildMorph = previousMorph; 60918 } 60919 } else { 60920 if (nextMorph) { 60921 nextMorph.previousMorph = null; 60922 parentMorphList.firstChildMorph = nextMorph; 60923 } else if (parentMorphList) { 60924 parentMorphList.lastChildMorph = parentMorphList.firstChildMorph = null; 60925 } 60926 } 60927 60928 this.parentMorphList = null; 60929 this.nextMorph = null; 60930 this.previousMorph = null; 60931 60932 if (parentMorphList && parentMorphList.mountedMorph) { 60933 if (!parentMorphList.firstChildMorph) { 60934 // list is empty 60935 parentMorphList.mountedMorph.clear(); 60936 return; 60937 } else { 60938 parentMorphList.firstChildMorph._syncFirstNode(); 60939 parentMorphList.lastChildMorph._syncLastNode(); 60940 } 60941 } 60942 }; 60943 60944 Morph.prototype.setHTML = function (text) { 60945 var fragment = this.domHelper.parseHTML(text, this.contextualElement); 60946 return this.setNode(fragment); 60947 }; 60948 60949 Morph.prototype.setMorphList = function Morph$appendMorphList(morphList) { 60950 morphList.mountedMorph = this; 60951 this.clear(); 60952 60953 var originalFirstNode = this.firstNode; 60954 60955 if (morphList.firstChildMorph) { 60956 this.firstNode = morphList.firstChildMorph.firstNode; 60957 this.lastNode = morphList.lastChildMorph.lastNode; 60958 60959 var current = morphList.firstChildMorph; 60960 60961 while (current) { 60962 var next = current.nextMorph; 60963 current.insertBeforeNode(originalFirstNode, null); 60964 current = next; 60965 } 60966 originalFirstNode.parentNode.removeChild(originalFirstNode); 60967 } 60968 }; 60969 60970 Morph.prototype._syncFirstNode = function Morph$syncFirstNode() { 60971 var morph = this; 60972 var parentMorphList; 60973 while (parentMorphList = morph.parentMorphList) { 60974 if (parentMorphList.mountedMorph === null) { 60975 break; 60976 } 60977 if (morph !== parentMorphList.firstChildMorph) { 60978 break; 60979 } 60980 if (morph.firstNode === parentMorphList.mountedMorph.firstNode) { 60981 break; 60982 } 60983 60984 parentMorphList.mountedMorph.firstNode = morph.firstNode; 60985 60986 morph = parentMorphList.mountedMorph; 60987 } 60988 }; 60989 60990 Morph.prototype._syncLastNode = function Morph$syncLastNode() { 60991 var morph = this; 60992 var parentMorphList; 60993 while (parentMorphList = morph.parentMorphList) { 60994 if (parentMorphList.mountedMorph === null) { 60995 break; 60996 } 60997 if (morph !== parentMorphList.lastChildMorph) { 60998 break; 60999 } 61000 if (morph.lastNode === parentMorphList.mountedMorph.lastNode) { 61001 break; 61002 } 61003 61004 parentMorphList.mountedMorph.lastNode = morph.lastNode; 61005 61006 morph = parentMorphList.mountedMorph; 61007 } 61008 }; 61009 61010 Morph.prototype.insertBeforeNode = function Morph$insertBeforeNode(parentNode, refNode) { 61011 _morphRangeUtils.insertBefore(parentNode, this.firstNode, this.lastNode, refNode); 61012 }; 61013 61014 Morph.prototype.appendToNode = function Morph$appendToNode(parentNode) { 61015 _morphRangeUtils.insertBefore(parentNode, this.firstNode, this.lastNode, null); 61016 }; 61017 61018 exports.default = Morph; 61019}); 61020enifed("route-recognizer/dsl", ["exports"], function (exports) { 61021 "use strict"; 61022 61023 function Target(path, matcher, delegate) { 61024 this.path = path; 61025 this.matcher = matcher; 61026 this.delegate = delegate; 61027 } 61028 61029 Target.prototype = { 61030 to: function (target, callback) { 61031 var delegate = this.delegate; 61032 61033 if (delegate && delegate.willAddRoute) { 61034 target = delegate.willAddRoute(this.matcher.target, target); 61035 } 61036 61037 this.matcher.add(this.path, target); 61038 61039 if (callback) { 61040 if (callback.length === 0) { 61041 throw new Error("You must have an argument in the function passed to `to`"); 61042 } 61043 this.matcher.addChild(this.path, target, callback, this.delegate); 61044 } 61045 return this; 61046 } 61047 }; 61048 61049 function Matcher(target) { 61050 this.routes = {}; 61051 this.children = {}; 61052 this.target = target; 61053 } 61054 61055 Matcher.prototype = { 61056 add: function (path, handler) { 61057 this.routes[path] = handler; 61058 }, 61059 61060 addChild: function (path, target, callback, delegate) { 61061 var matcher = new Matcher(target); 61062 this.children[path] = matcher; 61063 61064 var match = generateMatch(path, matcher, delegate); 61065 61066 if (delegate && delegate.contextEntered) { 61067 delegate.contextEntered(target, match); 61068 } 61069 61070 callback(match); 61071 } 61072 }; 61073 61074 function generateMatch(startingPath, matcher, delegate) { 61075 return function (path, nestedCallback) { 61076 var fullPath = startingPath + path; 61077 61078 if (nestedCallback) { 61079 nestedCallback(generateMatch(fullPath, matcher, delegate)); 61080 } else { 61081 return new Target(startingPath + path, matcher, delegate); 61082 } 61083 }; 61084 } 61085 61086 function addRoute(routeArray, path, handler) { 61087 var len = 0; 61088 for (var i = 0, l = routeArray.length; i < l; i++) { 61089 len += routeArray[i].path.length; 61090 } 61091 61092 path = path.substr(len); 61093 var route = { path: path, handler: handler }; 61094 routeArray.push(route); 61095 } 61096 61097 function eachRoute(baseRoute, matcher, callback, binding) { 61098 var routes = matcher.routes; 61099 61100 for (var path in routes) { 61101 if (routes.hasOwnProperty(path)) { 61102 var routeArray = baseRoute.slice(); 61103 addRoute(routeArray, path, routes[path]); 61104 61105 if (matcher.children[path]) { 61106 eachRoute(routeArray, matcher.children[path], callback, binding); 61107 } else { 61108 callback.call(binding, routeArray); 61109 } 61110 } 61111 } 61112 } 61113 61114 exports.default = function (callback, addRouteCallback) { 61115 var matcher = new Matcher(); 61116 61117 callback(generateMatch("", matcher, this.delegate)); 61118 61119 eachRoute([], matcher, function (route) { 61120 if (addRouteCallback) { 61121 addRouteCallback(this, route); 61122 } else { 61123 this.add(route); 61124 } 61125 }, this); 61126 }; 61127}); 61128enifed('route-recognizer', ['exports', 'route-recognizer/dsl'], function (exports, _routeRecognizerDsl) { 61129 'use strict'; 61130 61131 var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; 61132 61133 var escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); 61134 61135 function isArray(test) { 61136 return Object.prototype.toString.call(test) === "[object Array]"; 61137 } 61138 61139 // A Segment represents a segment in the original route description. 61140 // Each Segment type provides an `eachChar` and `regex` method. 61141 // 61142 // The `eachChar` method invokes the callback with one or more character 61143 // specifications. A character specification consumes one or more input 61144 // characters. 61145 // 61146 // The `regex` method returns a regex fragment for the segment. If the 61147 // segment is a dynamic of star segment, the regex fragment also includes 61148 // a capture. 61149 // 61150 // A character specification contains: 61151 // 61152 // * `validChars`: a String with a list of all valid characters, or 61153 // * `invalidChars`: a String with a list of all invalid characters 61154 // * `repeat`: true if the character specification can repeat 61155 61156 function StaticSegment(string) { 61157 this.string = string; 61158 } 61159 StaticSegment.prototype = { 61160 eachChar: function (callback) { 61161 var string = this.string, 61162 ch; 61163 61164 for (var i = 0, l = string.length; i < l; i++) { 61165 ch = string.charAt(i); 61166 callback({ validChars: ch }); 61167 } 61168 }, 61169 61170 regex: function () { 61171 return this.string.replace(escapeRegex, '\\$1'); 61172 }, 61173 61174 generate: function () { 61175 return this.string; 61176 } 61177 }; 61178 61179 function DynamicSegment(name) { 61180 this.name = name; 61181 } 61182 DynamicSegment.prototype = { 61183 eachChar: function (callback) { 61184 callback({ invalidChars: "/", repeat: true }); 61185 }, 61186 61187 regex: function () { 61188 return "([^/]+)"; 61189 }, 61190 61191 generate: function (params) { 61192 return params[this.name]; 61193 } 61194 }; 61195 61196 function StarSegment(name) { 61197 this.name = name; 61198 } 61199 StarSegment.prototype = { 61200 eachChar: function (callback) { 61201 callback({ invalidChars: "", repeat: true }); 61202 }, 61203 61204 regex: function () { 61205 return "(.+)"; 61206 }, 61207 61208 generate: function (params) { 61209 return params[this.name]; 61210 } 61211 }; 61212 61213 function EpsilonSegment() {} 61214 EpsilonSegment.prototype = { 61215 eachChar: function () {}, 61216 regex: function () { 61217 return ""; 61218 }, 61219 generate: function () { 61220 return ""; 61221 } 61222 }; 61223 61224 function parse(route, names, types) { 61225 // normalize route as not starting with a "/". Recognition will 61226 // also normalize. 61227 if (route.charAt(0) === "/") { 61228 route = route.substr(1); 61229 } 61230 61231 var segments = route.split("/"), 61232 results = []; 61233 61234 for (var i = 0, l = segments.length; i < l; i++) { 61235 var segment = segments[i], 61236 match; 61237 61238 if (match = segment.match(/^:([^\/]+)$/)) { 61239 results.push(new DynamicSegment(match[1])); 61240 names.push(match[1]); 61241 types.dynamics++; 61242 } else if (match = segment.match(/^\*([^\/]+)$/)) { 61243 results.push(new StarSegment(match[1])); 61244 names.push(match[1]); 61245 types.stars++; 61246 } else if (segment === "") { 61247 results.push(new EpsilonSegment()); 61248 } else { 61249 results.push(new StaticSegment(segment)); 61250 types.statics++; 61251 } 61252 } 61253 61254 return results; 61255 } 61256 61257 // A State has a character specification and (`charSpec`) and a list of possible 61258 // subsequent states (`nextStates`). 61259 // 61260 // If a State is an accepting state, it will also have several additional 61261 // properties: 61262 // 61263 // * `regex`: A regular expression that is used to extract parameters from paths 61264 // that reached this accepting state. 61265 // * `handlers`: Information on how to convert the list of captures into calls 61266 // to registered handlers with the specified parameters 61267 // * `types`: How many static, dynamic or star segments in this route. Used to 61268 // decide which route to use if multiple registered routes match a path. 61269 // 61270 // Currently, State is implemented naively by looping over `nextStates` and 61271 // comparing a character specification against a character. A more efficient 61272 // implementation would use a hash of keys pointing at one or more next states. 61273 61274 function State(charSpec) { 61275 this.charSpec = charSpec; 61276 this.nextStates = []; 61277 } 61278 61279 State.prototype = { 61280 get: function (charSpec) { 61281 var nextStates = this.nextStates; 61282 61283 for (var i = 0, l = nextStates.length; i < l; i++) { 61284 var child = nextStates[i]; 61285 61286 var isEqual = child.charSpec.validChars === charSpec.validChars; 61287 isEqual = isEqual && child.charSpec.invalidChars === charSpec.invalidChars; 61288 61289 if (isEqual) { 61290 return child; 61291 } 61292 } 61293 }, 61294 61295 put: function (charSpec) { 61296 var state; 61297 61298 // If the character specification already exists in a child of the current 61299 // state, just return that state. 61300 if (state = this.get(charSpec)) { 61301 return state; 61302 } 61303 61304 // Make a new state for the character spec 61305 state = new State(charSpec); 61306 61307 // Insert the new state as a child of the current state 61308 this.nextStates.push(state); 61309 61310 // If this character specification repeats, insert the new state as a child 61311 // of itself. Note that this will not trigger an infinite loop because each 61312 // transition during recognition consumes a character. 61313 if (charSpec.repeat) { 61314 state.nextStates.push(state); 61315 } 61316 61317 // Return the new state 61318 return state; 61319 }, 61320 61321 // Find a list of child states matching the next character 61322 match: function (ch) { 61323 // DEBUG "Processing `" + ch + "`:" 61324 var nextStates = this.nextStates, 61325 child, 61326 charSpec, 61327 chars; 61328 61329 // DEBUG " " + debugState(this) 61330 var returned = []; 61331 61332 for (var i = 0, l = nextStates.length; i < l; i++) { 61333 child = nextStates[i]; 61334 61335 charSpec = child.charSpec; 61336 61337 if (typeof (chars = charSpec.validChars) !== 'undefined') { 61338 if (chars.indexOf(ch) !== -1) { 61339 returned.push(child); 61340 } 61341 } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') { 61342 if (chars.indexOf(ch) === -1) { 61343 returned.push(child); 61344 } 61345 } 61346 } 61347 61348 return returned; 61349 } 61350 61351 /** IF DEBUG 61352 , debug: function() { 61353 var charSpec = this.charSpec, 61354 debug = "[", 61355 chars = charSpec.validChars || charSpec.invalidChars; 61356 if (charSpec.invalidChars) { debug += "^"; } 61357 debug += chars; 61358 debug += "]"; 61359 if (charSpec.repeat) { debug += "+"; } 61360 return debug; 61361 } 61362 END IF **/ 61363 }; 61364 61365 /** IF DEBUG 61366 function debug(log) { 61367 console.log(log); 61368 } 61369 61370 function debugState(state) { 61371 return state.nextStates.map(function(n) { 61372 if (n.nextStates.length === 0) { return "( " + n.debug() + " [accepting] )"; } 61373 return "( " + n.debug() + " <then> " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; 61374 }).join(", ") 61375 } 61376 END IF **/ 61377 61378 // This is a somewhat naive strategy, but should work in a lot of cases 61379 // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id. 61380 // 61381 // This strategy generally prefers more static and less dynamic matching. 61382 // Specifically, it 61383 // 61384 // * prefers fewer stars to more, then 61385 // * prefers using stars for less of the match to more, then 61386 // * prefers fewer dynamic segments to more, then 61387 // * prefers more static segments to more 61388 function sortSolutions(states) { 61389 return states.sort(function (a, b) { 61390 if (a.types.stars !== b.types.stars) { 61391 return a.types.stars - b.types.stars; 61392 } 61393 61394 if (a.types.stars) { 61395 if (a.types.statics !== b.types.statics) { 61396 return b.types.statics - a.types.statics; 61397 } 61398 if (a.types.dynamics !== b.types.dynamics) { 61399 return b.types.dynamics - a.types.dynamics; 61400 } 61401 } 61402 61403 if (a.types.dynamics !== b.types.dynamics) { 61404 return a.types.dynamics - b.types.dynamics; 61405 } 61406 if (a.types.statics !== b.types.statics) { 61407 return b.types.statics - a.types.statics; 61408 } 61409 61410 return 0; 61411 }); 61412 } 61413 61414 function recognizeChar(states, ch) { 61415 var nextStates = []; 61416 61417 for (var i = 0, l = states.length; i < l; i++) { 61418 var state = states[i]; 61419 61420 nextStates = nextStates.concat(state.match(ch)); 61421 } 61422 61423 return nextStates; 61424 } 61425 61426 var oCreate = Object.create || function (proto) { 61427 function F() {} 61428 F.prototype = proto; 61429 return new F(); 61430 }; 61431 61432 function RecognizeResults(queryParams) { 61433 this.queryParams = queryParams || {}; 61434 } 61435 RecognizeResults.prototype = oCreate({ 61436 splice: Array.prototype.splice, 61437 slice: Array.prototype.slice, 61438 push: Array.prototype.push, 61439 length: 0, 61440 queryParams: null 61441 }); 61442 61443 function findHandler(state, path, queryParams) { 61444 var handlers = state.handlers, 61445 regex = state.regex; 61446 var captures = path.match(regex), 61447 currentCapture = 1; 61448 var result = new RecognizeResults(queryParams); 61449 61450 for (var i = 0, l = handlers.length; i < l; i++) { 61451 var handler = handlers[i], 61452 names = handler.names, 61453 params = {}; 61454 61455 for (var j = 0, m = names.length; j < m; j++) { 61456 params[names[j]] = captures[currentCapture++]; 61457 } 61458 61459 result.push({ handler: handler.handler, params: params, isDynamic: !!names.length }); 61460 } 61461 61462 return result; 61463 } 61464 61465 function addSegment(currentState, segment) { 61466 segment.eachChar(function (ch) { 61467 var state; 61468 61469 currentState = currentState.put(ch); 61470 }); 61471 61472 return currentState; 61473 } 61474 61475 function decodeQueryParamPart(part) { 61476 // http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 61477 part = part.replace(/\+/gm, '%20'); 61478 return decodeURIComponent(part); 61479 } 61480 61481 // The main interface 61482 61483 var RouteRecognizer = function () { 61484 this.rootState = new State(); 61485 this.names = {}; 61486 }; 61487 61488 RouteRecognizer.prototype = { 61489 add: function (routes, options) { 61490 var currentState = this.rootState, 61491 regex = "^", 61492 types = { statics: 0, dynamics: 0, stars: 0 }, 61493 handlers = [], 61494 allSegments = [], 61495 name; 61496 61497 var isEmpty = true; 61498 61499 for (var i = 0, l = routes.length; i < l; i++) { 61500
vendor: 4,272 bytes, lines 61500-61666
61500 var route = routes[i], 61501 names = []; 61502 61503 var segments = parse(route.path, names, types); 61504 61505 allSegments = allSegments.concat(segments); 61506 61507 for (var j = 0, m = segments.length; j < m; j++) { 61508 var segment = segments[j]; 61509 61510 if (segment instanceof EpsilonSegment) { 61511 continue; 61512 } 61513 61514 isEmpty = false; 61515 61516 // Add a "/" for the new segment 61517 currentState = currentState.put({ validChars: "/" }); 61518 regex += "/"; 61519 61520 // Add a representation of the segment to the NFA and regex 61521 currentState = addSegment(currentState, segment); 61522 regex += segment.regex(); 61523 } 61524 61525 var handler = { handler: route.handler, names: names }; 61526 handlers.push(handler); 61527 } 61528 61529 if (isEmpty) { 61530 currentState = currentState.put({ validChars: "/" }); 61531 regex += "/"; 61532 } 61533 61534 currentState.handlers = handlers; 61535 currentState.regex = new RegExp(regex + "$"); 61536 currentState.types = types; 61537 61538 if (name = options && options.as) { 61539 this.names[name] = { 61540 segments: allSegments, 61541 handlers: handlers 61542 }; 61543 } 61544 }, 61545 61546 handlersFor: function (name) { 61547 var route = this.names[name], 61548 result = []; 61549 if (!route) { 61550 throw new Error("There is no route named " + name); 61551 } 61552 61553 for (var i = 0, l = route.handlers.length; i < l; i++) { 61554 result.push(route.handlers[i]); 61555 } 61556 61557 return result; 61558 }, 61559 61560 hasRoute: function (name) { 61561 return !!this.names[name]; 61562 }, 61563 61564 generate: function (name, params) { 61565 var route = this.names[name], 61566 output = ""; 61567 if (!route) { 61568 throw new Error("There is no route named " + name); 61569 } 61570 61571 var segments = route.segments; 61572 61573 for (var i = 0, l = segments.length; i < l; i++) { 61574 var segment = segments[i]; 61575 61576 if (segment instanceof EpsilonSegment) { 61577 continue; 61578 } 61579 61580 output += "/"; 61581 output += segment.generate(params); 61582 } 61583 61584 if (output.charAt(0) !== '/') { 61585 output = '/' + output; 61586 } 61587 61588 if (params && params.queryParams) { 61589 output += this.generateQueryString(params.queryParams, route.handlers); 61590 } 61591 61592 return output; 61593 }, 61594 61595 generateQueryString: function (params, handlers) { 61596 var pairs = []; 61597 var keys = []; 61598 for (var key in params) { 61599 if (params.hasOwnProperty(key)) { 61600 keys.push(key); 61601 } 61602 } 61603 keys.sort(); 61604 for (var i = 0, len = keys.length; i < len; i++) { 61605 key = keys[i]; 61606 var value = params[key]; 61607 if (value == null) { 61608 continue; 61609 } 61610 var pair = encodeURIComponent(key); 61611 if (isArray(value)) { 61612 for (var j = 0, l = value.length; j < l; j++) { 61613 var arrayPair = key + '[]' + '=' + encodeURIComponent(value[j]); 61614 pairs.push(arrayPair); 61615 } 61616 } else { 61617 pair += "=" + encodeURIComponent(value); 61618 pairs.push(pair); 61619 } 61620 } 61621 61622 if (pairs.length === 0) { 61623 return ''; 61624 } 61625 61626 return "?" + pairs.join("&"); 61627 }, 61628 61629 parseQueryString: function (queryString) { 61630 var pairs = queryString.split("&"), 61631 queryParams = {}; 61632 for (var i = 0; i < pairs.length; i++) { 61633 var pair = pairs[i].split('='), 61634 key = decodeQueryParamPart(pair[0]), 61635 keyLength = key.length, 61636 isArray = false, 61637 value; 61638 if (pair.length === 1) { 61639 value = 'true'; 61640 } else { 61641 //Handle arrays 61642 if (keyLength > 2 && key.slice(keyLength - 2) === '[]') { 61643 isArray = true; 61644 key = key.slice(0, keyLength - 2); 61645 if (!queryParams[key]) { 61646 queryParams[key] = []; 61647 } 61648 } 61649 value = pair[1] ? decodeQueryParamPart(pair[1]) : ''; 61650 } 61651 if (isArray) { 61652 queryParams[key].push(value); 61653 } else { 61654 queryParams[key] = value; 61655 } 61656 } 61657 return queryParams; 61658 }, 61659 61660 recognize: function (path) { 61661 var states = [this.rootState], 61662 pathLen, 61663 i, 61664 l, 61665 queryStart, 61666 queryParams = {},
61667 isSlashDropped = false; 61668 61669 queryStart = path.indexOf('?'); 61670 if (queryStart !== -1) { 61671 var queryString = path.substr(queryStart + 1, path.length); 61672 path = path.substr(0, queryStart); 61673 queryParams = this.parseQueryString(queryString); 61674 } 61675 61676 path = decodeURI(path); 61677 61678 // DEBUG GROUP path 61679 61680 if (path.charAt(0) !== "/") { 61681 path = "/" + path; 61682 } 61683 61684 pathLen = path.length; 61685 if (pathLen > 1 && path.charAt(pathLen - 1) === "/") { 61686 path = path.substr(0, pathLen - 1); 61687 isSlashDropped = true; 61688 } 61689 61690 for (i = 0, l = path.length; i < l; i++) { 61691 states = recognizeChar(states, path.charAt(i)); 61692 if (!states.length) { 61693 break; 61694 } 61695 } 61696 61697 // END DEBUG GROUP 61698 61699 var solutions = []; 61700 for (i = 0, l = states.length; i < l; i++) { 61701 if (states[i].handlers) { 61702 solutions.push(states[i]); 61703 } 61704 } 61705 61706 states = sortSolutions(solutions); 61707 61708 var state = solutions[0]; 61709 61710 if (state && state.handlers) { 61711 // if a trailing slash was dropped and a star segment is the last segment 61712 // specified, put the trailing slash back 61713 if (isSlashDropped && state.regex.source.slice(-5) === "(.+)$") { 61714 path = path + "/"; 61715 } 61716 return findHandler(state, path, queryParams); 61717 } 61718 } 61719 }; 61720 61721 RouteRecognizer.prototype.map = _routeRecognizerDsl.default; 61722 61723 RouteRecognizer.VERSION = '0.1.5'; 61724 61725 exports.default = RouteRecognizer; 61726}); 61727enifed('router/handler-info/factory', ['exports', 'router/handler-info/resolved-handler-info', 'router/handler-info/unresolved-handler-info-by-object', 'router/handler-info/unresolved-handler-info-by-param'], function (exports, _routerHandlerInfoResolvedHandlerInfo, _routerHandlerInfoUnresolvedHandlerInfoByObject, _routerHandlerInfoUnresolvedHandlerInfoByParam) { 61728 'use strict'; 61729 61730 handlerInfoFactory.klasses = { 61731 resolved: _routerHandlerInfoResolvedHandlerInfo.default, 61732 param: _routerHandlerInfoUnresolvedHandlerInfoByParam.default, 61733 object: _routerHandlerInfoUnresolvedHandlerInfoByObject.default 61734 }; 61735 61736 function handlerInfoFactory(name, props) { 61737 var Ctor = handlerInfoFactory.klasses[name], 61738 handlerInfo = new Ctor(props || {}); 61739 handlerInfo.factory = handlerInfoFactory; 61740 return handlerInfo; 61741 } 61742 61743 exports.default = handlerInfoFactory; 61744}); 61745enifed('router/handler-info/resolved-handler-info', ['exports', 'router/handler-info', 'router/utils', 'rsvp/promise'], function (exports, _routerHandlerInfo, _routerUtils, _rsvpPromise) { 61746 'use strict'; 61747 61748 var ResolvedHandlerInfo = _routerUtils.subclass(_routerHandlerInfo.default, { 61749 resolve: function (shouldContinue, payload) { 61750 // A ResolvedHandlerInfo just resolved with itself. 61751 if (payload && payload.resolvedModels) { 61752 payload.resolvedModels[this.name] = this.context; 61753 } 61754 return _rsvpPromise.default.resolve(this, this.promiseLabel("Resolve")); 61755 }, 61756 61757 getUnresolved: function () { 61758 return this.factory('param', { 61759 name: this.name, 61760 handler: this.handler, 61761 params: this.params 61762 }); 61763 }, 61764 61765 isResolved: true 61766 }); 61767 61768 exports.default = ResolvedHandlerInfo; 61769}); 61770enifed('router/handler-info/unresolved-handler-info-by-object', ['exports', 'router/handler-info', 'router/utils', 'rsvp/promise'], function (exports, _routerHandlerInfo, _routerUtils, _rsvpPromise) { 61771 'use strict'; 61772 61773 var UnresolvedHandlerInfoByObject = _routerUtils.subclass(_routerHandlerInfo.default, { 61774 getModel: function (payload) { 61775 this.log(payload, this.name + ": resolving provided model"); 61776 return _rsvpPromise.default.resolve(this.context); 61777 }, 61778 61779 initialize: function (props) { 61780 this.names = props.names || []; 61781 this.context = props.context; 61782 }, 61783 61784 /** 61785 @private 61786 Serializes a handler using its custom `serialize` method or 61787 by a default that looks up the expected property name from 61788 the dynamic segment. 61789 @param {Object} model the model to be serialized for this handler 61790 */ 61791 serialize: function (_model) { 61792 var model = _model || this.context, 61793 names = this.names, 61794 handler = this.handler; 61795 61796 var object = {}; 61797 if (_routerUtils.isParam(model)) { 61798 object[names[0]] = model; 61799 return object; 61800 } 61801
61802 // Use custom serialize if it exists. 61803 if (handler.serialize) { 61804 return handler.serialize(model, names); 61805 } 61806 61807 if (names.length !== 1) { 61808 return; 61809 } 61810 61811 var name = names[0]; 61812 61813 if (/_id$/.test(name)) { 61814 object[name] = model.id; 61815 } else { 61816 object[name] = model; 61817 } 61818 return object; 61819 } 61820 }); 61821 61822 exports.default = UnresolvedHandlerInfoByObject; 61823}); 61824enifed('router/handler-info/unresolved-handler-info-by-param', ['exports', 'router/handler-info', 'router/utils'], function (exports, _routerHandlerInfo, _routerUtils) { 61825 'use strict'; 61826 61827 // Generated by URL transitions and non-dynamic route segments in named Transitions. 61828 var UnresolvedHandlerInfoByParam = _routerUtils.subclass(_routerHandlerInfo.default, { 61829 initialize: function (props) { 61830 this.params = props.params || {}; 61831 }, 61832 61833 getModel: function (payload) { 61834 var fullParams = this.params; 61835 if (payload && payload.queryParams) { 61836 fullParams = {}; 61837 _routerUtils.merge(fullParams, this.params); 61838 fullParams.queryParams = payload.queryParams; 61839 } 61840 61841 var handler = this.handler; 61842 var hookName = _routerUtils.resolveHook(handler, 'deserialize') || _routerUtils.resolveHook(handler, 'model'); 61843 61844 return this.runSharedModelHook(payload, hookName, [fullParams]); 61845 } 61846 }); 61847 61848 exports.default = UnresolvedHandlerInfoByParam; 61849}); 61850enifed('router/handler-info', ['exports', 'router/utils', 'rsvp/promise'], function (exports, _routerUtils, _rsvpPromise) { 61851 'use strict'; 61852 61853 function HandlerInfo(_props) { 61854 var props = _props || {}; 61855 _routerUtils.merge(this, props); 61856 this.initialize(props); 61857 } 61858 61859 HandlerInfo.prototype = { 61860 name: null, 61861 handler: null, 61862 params: null, 61863 context: null, 61864 61865 // Injected by the handler info factory. 61866 factory: null, 61867 61868 initialize: function () {}, 61869 61870 log: function (payload, message) { 61871 if (payload.log) { 61872 payload.log(this.name + ': ' + message); 61873 } 61874 }, 61875 61876 promiseLabel: function (label) { 61877 return _routerUtils.promiseLabel("'" + this.name + "' " + label); 61878 }, 61879 61880 getUnresolved: function () { 61881 return this; 61882 }, 61883 61884 serialize: function () { 61885 return this.params || {}; 61886 }, 61887 61888 resolve: function (shouldContinue, payload) { 61889 var checkForAbort = _routerUtils.bind(this, this.checkForAbort, shouldContinue), 61890 beforeModel = _routerUtils.bind(this, this.runBeforeModelHook, payload), 61891 model = _routerUtils.bind(this, this.getModel, payload), 61892 afterModel = _routerUtils.bind(this, this.runAfterModelHook, payload), 61893 becomeResolved = _routerUtils.bind(this, this.becomeResolved, payload); 61894 61895 return _rsvpPromise.default.resolve(undefined, this.promiseLabel("Start handler")).then(checkForAbort, null, this.promiseLabel("Check for abort")).then(beforeModel, null, this.promiseLabel("Before model")).then(checkForAbort, null, this.promiseLabel("Check if aborted during 'beforeModel' hook")).then(model, null, this.promiseLabel("Model")).then(checkForAbort, null, this.promiseLabel("Check if aborted in 'model' hook")).then(afterModel, null, this.promiseLabel("After model")).then(checkForAbort, null, this.promiseLabel("Check if aborted in 'afterModel' hook")).then(becomeResolved, null, this.promiseLabel("Become resolved")); 61896 }, 61897 61898 runBeforeModelHook: function (payload) { 61899 if (payload.trigger) { 61900 payload.trigger(true, 'willResolveModel', payload, this.handler); 61901 } 61902 return this.runSharedModelHook(payload, 'beforeModel', []); 61903 }, 61904 61905 runAfterModelHook: function (payload, resolvedModel) { 61906 // Stash the resolved model on the payload. 61907 // This makes it possible for users to swap out 61908 // the resolved model in afterModel. 61909 var name = this.name; 61910 this.stashResolvedModel(payload, resolvedModel); 61911 61912 return this.runSharedModelHook(payload, 'afterModel', [resolvedModel]).then(function () { 61913 // Ignore the fulfilled value returned from afterModel. 61914 // Return the value stashed in resolvedModels, which 61915 // might have been swapped out in afterModel. 61916 return payload.resolvedModels[name]; 61917 }, null, this.promiseLabel("Ignore fulfillment value and return model value")); 61918 }, 61919
61920 runSharedModelHook: function (payload, hookName, args) { 61921 this.log(payload, "calling " + hookName + " hook"); 61922 61923 if (this.queryParams) { 61924 args.push(this.queryParams); 61925 } 61926 args.push(payload); 61927 61928 var result = _routerUtils.applyHook(this.handler, hookName, args); 61929 61930 if (result && result.isTransition) { 61931 result = null; 61932 } 61933 61934 return _rsvpPromise.default.resolve(result, this.promiseLabel("Resolve value returned from one of the model hooks")); 61935 }, 61936 61937 // overridden by subclasses 61938 getModel: null, 61939 61940 checkForAbort: function (shouldContinue, promiseValue) { 61941 return _rsvpPromise.default.resolve(shouldContinue(), this.promiseLabel("Check for abort")).then(function () { 61942 // We don't care about shouldContinue's resolve value; 61943 // pass along the original value passed to this fn. 61944 return promiseValue; 61945 }, null, this.promiseLabel("Ignore fulfillment value and continue")); 61946 }, 61947 61948 stashResolvedModel: function (payload, resolvedModel) { 61949 payload.resolvedModels = payload.resolvedModels || {}; 61950 payload.resolvedModels[this.name] = resolvedModel; 61951 }, 61952 61953 becomeResolved: function (payload, resolvedContext) { 61954 var params = this.serialize(resolvedContext); 61955 61956 if (payload) { 61957 this.stashResolvedModel(payload, resolvedContext); 61958 payload.params = payload.params || {}; 61959 payload.params[this.name] = params; 61960 } 61961 61962 return this.factory('resolved', { 61963 context: resolvedContext, 61964 name: this.name, 61965 handler: this.handler, 61966 params: params 61967 }); 61968 }, 61969 61970 shouldSupercede: function (other) { 61971 // Prefer this newer handlerInfo over `other` if: 61972 // 1) The other one doesn't exist 61973 // 2) The names don't match 61974 // 3) This handler has a context that doesn't match 61975 // the other one (or the other one doesn't have one). 61976 // 4) This handler has parameters that don't match the other. 61977 if (!other) { 61978 return true; 61979 } 61980 61981 var contextsMatch = other.context === this.context; 61982 return other.name !== this.name || this.hasOwnProperty('context') && !contextsMatch || this.hasOwnProperty('params') && !paramsMatch(this.params, other.params); 61983 } 61984 }; 61985 61986 function paramsMatch(a, b) { 61987 if (!a ^ !b) { 61988 // Only one is null. 61989 return false; 61990 } 61991 61992 if (!a) { 61993 // Both must be null. 61994 return true; 61995 } 61996 61997 // Note: this assumes that both params have the same 61998 // number of keys, but since we're comparing the 61999 // same handlers, they should. 62000 for (var k in a) { 62001 if (a.hasOwnProperty(k) && a[k] !== b[k]) { 62002 return false; 62003 } 62004 } 62005 return true; 62006 } 62007 62008 exports.default = HandlerInfo; 62009}); 62010enifed('router/router', ['exports', 'route-recognizer', 'rsvp/promise', 'router/utils', 'router/transition-state', 'router/transition', 'router/transition-intent/named-transition-intent', 'router/transition-intent/url-transition-intent', 'router/handler-info'], function (exports, _routeRecognizer, _rsvpPromise, _routerUtils, _routerTransitionState, _routerTransition, _routerTransitionIntentNamedTransitionIntent, _routerTransitionIntentUrlTransitionIntent, _routerHandlerInfo) { 62011 'use strict'; 62012 62013 var pop = Array.prototype.pop; 62014 62015 function Router(_options) { 62016 var options = _options || {}; 62017 this.getHandler = options.getHandler || this.getHandler; 62018 this.updateURL = options.updateURL || this.updateURL; 62019 this.replaceURL = options.replaceURL || this.replaceURL; 62020 this.didTransition = options.didTransition || this.didTransition; 62021 this.willTransition = options.willTransition || this.willTransition; 62022 this.delegate = options.delegate || this.delegate; 62023 this.triggerEvent = options.triggerEvent || this.triggerEvent; 62024 this.log = options.log || this.log; 62025 62026 this.recognizer = new _routeRecognizer.default(); 62027 this.reset(); 62028 } 62029 62030 function getTransitionByIntent(intent, isIntermediate) { 62031 var wasTransitioning = !!this.activeTransition; 62032 var oldState = wasTransitioning ? this.activeTransition.state : this.state; 62033 var newTransition; 62034 62035 var newState = intent.applyToState(oldState, this.recognizer, this.getHandler, isIntermediate); 62036 var queryParamChangelist = _routerUtils.getChangelist(oldState.queryParams, newState.queryParams); 62037 62038 if (handlerInfosEqual(newState.handlerInfos, oldState.handlerInfos)) { 62039 62040 // This is a no-op transition. See if query params changed. 62041 if (queryParamChangelist) { 62042 newTransition = this.queryParamsTransition(queryParamChangelist, wasTransitioning, oldState, newState); 62043 if (newTransition) { 62044 return newTransition; 62045 } 62046 } 62047 62048 // No-op. No need to create a new transition. 62049 return this.activeTransition || new _routerTransition.Transition(this); 62050 } 62051 62052 if (isIntermediate) { 62053 setupContexts(this, newState); 62054 return; 62055 } 62056 62057 // Create a new transition to the destination route. 62058 newTransition = new _routerTransition.Transition(this, intent, newState); 62059 62060 // Abort and usurp any previously active transition. 62061 if (this.activeTransition) { 62062 this.activeTransition.abort(); 62063 } 62064 this.activeTransition = newTransition; 62065 62066 // Transition promises by default resolve with resolved state. 62067 // For our purposes, swap out the promise to resolve 62068 // after the transition has been finalized. 62069 newTransition.promise = newTransition.promise.then(function (result) { 62070 return finalizeTransition(newTransition, result.state); 62071 }, null, _routerUtils.promiseLabel("Settle transition promise when transition is finalized")); 62072 62073 if (!wasTransitioning) { 62074 notifyExistingHandlers(this, newState, newTransition); 62075 } 62076 62077 fireQueryParamDidChange(this, newState, queryParamChangelist); 62078 62079 return newTransition; 62080 } 62081 62082 Router.prototype = { 62083 62084 /** 62085 The main entry point into the router. The API is essentially 62086 the same as the `map` method in `route-recognizer`. 62087 This method extracts the String handler at the last `.to()` 62088 call and uses it as the name of the whole route. 62089 @param {Function} callback 62090 */ 62091 map: function (callback) { 62092 this.recognizer.delegate = this.delegate; 62093 62094 this.recognizer.map(callback, function (recognizer, routes) { 62095 for (var i = routes.length - 1, proceed = true; i >= 0 && proceed; --i) { 62096 var route = routes[i]; 62097 recognizer.add(routes, { as: route.handler }); 62098 proceed = route.path === '/' || route.path === '' || route.handler.slice(-6) === '.index'; 62099 } 62100 }); 62101 }, 62102 62103 hasRoute: function (route) { 62104 return this.recognizer.hasRoute(route); 62105 }, 62106 62107 getHandler: function () {}, 62108 62109 queryParamsTransition: function (changelist, wasTransitioning, oldState, newState) { 62110 var router = this; 62111 62112 fireQueryParamDidChange(this, newState, changelist); 62113 62114 if (!wasTransitioning && this.activeTransition) { 62115 // One of the handlers in queryParamsDidChange 62116 // caused a transition. Just return that transition. 62117 return this.activeTransition; 62118 } else { 62119 // Running queryParamsDidChange didn't change anything. 62120 // Just update query params and be on our way. 62121 62122 // We have to return a noop transition that will 62123 // perform a URL update at the end. This gives 62124 // the user the ability to set the url update 62125 // method (default is replaceState). 62126 var newTransition = new _routerTransition.Transition(this); 62127 newTransition.queryParamsOnly = true; 62128 62129 oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams, newTransition); 62130 62131 newTransition.promise = newTransition.promise.then(function (result) { 62132 updateURL(newTransition, oldState, true); 62133 if (router.didTransition) { 62134 router.didTransition(router.currentHandlerInfos); 62135 } 62136 return result; 62137 }, null, _routerUtils.promiseLabel("Transition complete")); 62138 return newTransition; 62139 } 62140 }, 62141 62142 // NOTE: this doesn't really belong here, but here
62143 // it shall remain until our ES6 transpiler can 62144 // handle cyclical deps. 62145 transitionByIntent: function (intent, isIntermediate) { 62146 try { 62147 return getTransitionByIntent.apply(this, arguments); 62148 } catch (e) { 62149 return new _routerTransition.Transition(this, intent, null, e); 62150 } 62151 }, 62152 62153 /** 62154 Clears the current and target route handlers and triggers exit 62155 on each of them starting at the leaf and traversing up through 62156 its ancestors. 62157 */ 62158 reset: function () { 62159 if (this.state) { 62160 _routerUtils.forEach(this.state.handlerInfos.slice().reverse(), function (handlerInfo) { 62161 var handler = handlerInfo.handler; 62162 _routerUtils.callHook(handler, 'exit'); 62163 }); 62164 } 62165 62166 this.state = new _routerTransitionState.default(); 62167 this.currentHandlerInfos = null; 62168 }, 62169 62170 activeTransition: null, 62171 62172 /** 62173 var handler = handlerInfo.handler; 62174 The entry point for handling a change to the URL (usually 62175 via the back and forward button). 62176 Returns an Array of handlers and the parameters associated 62177 with those parameters. 62178 @param {String} url a URL to process 62179 @return {Array} an Array of `[handler, parameter]` tuples 62180 */ 62181 handleURL: function (url) { 62182 // Perform a URL-based transition, but don't change 62183 // the URL afterward, since it already happened. 62184 var args = _routerUtils.slice.call(arguments); 62185 if (url.charAt(0) !== '/') { 62186 args[0] = '/' + url; 62187 } 62188 62189 return doTransition(this, args).method(null); 62190 }, 62191 62192 /** 62193 Hook point for updating the URL. 62194 @param {String} url a URL to update to 62195 */ 62196 updateURL: function () { 62197 throw new Error("updateURL is not implemented"); 62198 }, 62199 62200 /** 62201 Hook point for replacing the current URL, i.e. with replaceState 62202 By default this behaves the same as `updateURL` 62203 @param {String} url a URL to update to 62204 */ 62205 replaceURL: function (url) { 62206 this.updateURL(url); 62207 }, 62208 62209 /** 62210 Transition into the specified named route. 62211 If necessary, trigger the exit callback on any handlers 62212 that are no longer represented by the target route. 62213 @param {String} name the name of the route 62214 */ 62215 transitionTo: function (name) { 62216 return doTransition(this, arguments); 62217 }, 62218 62219 intermediateTransitionTo: function (name) { 62220 return doTransition(this, arguments, true); 62221 }, 62222 62223 refresh: function (pivotHandler) { 62224 var state = this.activeTransition ? this.activeTransition.state : this.state; 62225 var handlerInfos = state.handlerInfos; 62226 var params = {}; 62227 for (var i = 0, len = handlerInfos.length; i < len; ++i) { 62228 var handlerInfo = handlerInfos[i]; 62229 params[handlerInfo.name] = handlerInfo.params || {}; 62230 } 62231 62232 _routerUtils.log(this, "Starting a refresh transition"); 62233 var intent = new _routerTransitionIntentNamedTransitionIntent.default({ 62234 name: handlerInfos[handlerInfos.length - 1].name, 62235 pivotHandler: pivotHandler || handlerInfos[0].handler, 62236 contexts: [], // TODO collect contexts...? 62237 queryParams: this._changedQueryParams || state.queryParams || {} 62238 }); 62239 62240 return this.transitionByIntent(intent, false); 62241 }, 62242 62243 /** 62244 Identical to `transitionTo` except that the current URL will be replaced 62245 if possible. 62246 This method is intended primarily for use with `replaceState`. 62247 @param {String} name the name of the route 62248 */ 62249 replaceWith: function (name) { 62250 return doTransition(this, arguments).method('replace'); 62251 }, 62252 62253 /** 62254 Take a named route and context objects and generate a 62255 URL. 62256 @param {String} name the name of the route to generate 62257 a URL for 62258 @param {...Object} objects a list of objects to serialize 62259 @return {String} a URL 62260 */ 62261 generate: function (handlerName) { 62262 62263 var partitionedArgs = _routerUtils.extractQueryParams(_routerUtils.slice.call(arguments, 1)), 62264 suppliedParams = partitionedArgs[0], 62265 queryParams = partitionedArgs[1]; 62266 62267 // Construct a TransitionIntent with the provided params 62268 // and apply it to the present state of the router. 62269 var intent = new _routerTransitionIntentNamedTransitionIntent.default({ name: handlerName, contexts: suppliedParams }); 62270 var state = intent.applyToState(this.state, this.recognizer, this.getHandler); 62271 var params = {}; 62272 62273 for (var i = 0, len = state.handlerInfos.length; i < len; ++i) { 62274 var handlerInfo = state.handlerInfos[i]; 62275 var handlerParams = handlerInfo.serialize(); 62276 _routerUtils.merge(params, handlerParams); 62277 } 62278 params.queryParams = queryParams; 62279 62280 return this.recognizer.generate(handlerName, params); 62281 }, 62282 62283 applyIntent: function (handlerName, contexts) { 62284 var intent = new _routerTransitionIntentNamedTransitionIntent.default({ 62285 name: handlerName, 62286 contexts: contexts 62287 }); 62288 62289 var state = this.activeTransition && this.activeTransition.state || this.state; 62290 return intent.applyToState(state, this.recognizer, this.getHandler); 62291 }, 62292 62293 isActiveIntent: function (handlerName, contexts, queryParams, _state) { 62294 var state = _state || this.state, 62295 targetHandlerInfos = state.handlerInfos, 62296 found = false, 62297 names, 62298 object, 62299 handlerInfo, 62300 handlerObj, 62301 i, 62302 len; 62303 62304 if (!targetHandlerInfos.length) { 62305 return false;
62306 } 62307 62308 var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name; 62309 var recogHandlers = this.recognizer.handlersFor(targetHandler); 62310 62311 var index = 0; 62312 for (len = recogHandlers.length; index < len; ++index) { 62313 handlerInfo = targetHandlerInfos[index]; 62314 if (handlerInfo.name === handlerName) { 62315 break; 62316 } 62317 } 62318 62319 if (index === recogHandlers.length) { 62320 // The provided route name isn't even in the route hierarchy. 62321 return false; 62322 } 62323 62324 var testState = new _routerTransitionState.default(); 62325 testState.handlerInfos = targetHandlerInfos.slice(0, index + 1); 62326 recogHandlers = recogHandlers.slice(0, index + 1); 62327 62328 var intent = new _routerTransitionIntentNamedTransitionIntent.default({ 62329 name: targetHandler, 62330 contexts: contexts 62331 }); 62332 62333 var newState = intent.applyToHandlers(testState, recogHandlers, this.getHandler, targetHandler, true, true); 62334 62335 var handlersEqual = handlerInfosEqual(newState.handlerInfos, testState.handlerInfos); 62336 if (!queryParams || !handlersEqual) { 62337 return handlersEqual; 62338 } 62339 62340 // Get a hash of QPs that will still be active on new route 62341 var activeQPsOnNewHandler = {}; 62342 _routerUtils.merge(activeQPsOnNewHandler, queryParams); 62343 62344 var activeQueryParams = state.queryParams; 62345 for (var key in activeQueryParams) { 62346 if (activeQueryParams.hasOwnProperty(key) && activeQPsOnNewHandler.hasOwnProperty(key)) { 62347 activeQPsOnNewHandler[key] = activeQueryParams[key]; 62348 } 62349 } 62350 62351 return handlersEqual && !_routerUtils.getChangelist(activeQPsOnNewHandler, queryParams); 62352 }, 62353 62354 isActive: function (handlerName) { 62355 var partitionedArgs = _routerUtils.extractQueryParams(_routerUtils.slice.call(arguments, 1)); 62356 return this.isActiveIntent(handlerName, partitionedArgs[0], partitionedArgs[1]); 62357 }, 62358 62359 trigger: function (name) { 62360 var args = _routerUtils.slice.call(arguments); 62361 _routerUtils.trigger(this, this.currentHandlerInfos, false, args); 62362 }, 62363 62364 /** 62365 Hook point for logging transition status updates. 62366 @param {String} message The message to log. 62367 */ 62368 log: null 62369 }; 62370 62371 /** 62372 @private 62373 62374 Fires queryParamsDidChange event 62375 */ 62376 function fireQueryParamDidChange(router, newState, queryParamChangelist) { 62377 // If queryParams changed trigger event 62378 if (queryParamChangelist) { 62379 62380 // This is a little hacky but we need some way of storing 62381 // changed query params given that no activeTransition 62382 // is guaranteed to have occurred. 62383 router._changedQueryParams = queryParamChangelist.all; 62384 _routerUtils.trigger(router, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]); 62385 router._changedQueryParams = null; 62386 } 62387 } 62388 62389 /** 62390 @private 62391 62392 Takes an Array of `HandlerInfo`s, figures out which ones are 62393 exiting, entering, or changing contexts, and calls the 62394 proper handler hooks. 62395 62396 For example, consider the following tree of handlers. Each handler is 62397 followed by the URL segment it handles. 62398 62399 ``` 62400 |~index ("/") 62401 | |~posts ("/posts") 62402 | | |-showPost ("/:id") 62403 | | |-newPost ("/new") 62404 | | |-editPost ("/edit") 62405 | |~about ("/about/:id") 62406 ``` 62407 62408 Consider the following transitions: 62409 62410 1. A URL transition to `/posts/1`. 62411 1. Triggers the `*model` callbacks on the 62412 `index`, `posts`, and `showPost` handlers 62413 2. Triggers the `enter` callback on the same 62414 3. Triggers the `setup` callback on the same 62415 2. A direct transition to `newPost` 62416 1. Triggers the `exit` callback on `showPost` 62417 2. Triggers the `enter` callback on `newPost` 62418 3. Triggers the `setup` callback on `newPost` 62419 3. A direct transition to `about` with a specified 62420 context object 62421 1. Triggers the `exit` callback on `newPost` 62422 and `posts` 62423 2. Triggers the `serialize` callback on `about` 62424 3. Triggers the `enter` callback on `about` 62425 4. Triggers the `setup` callback on `about` 62426 62427 @param {Router} transition 62428 @param {TransitionState} newState 62429 */ 62430 function setupContexts(router, newState, transition) { 62431 var partition = partitionHandlers(router.state, newState); 62432 var i, l, handler; 62433 62434 for (i = 0, l = partition.exited.length; i < l; i++) { 62435 handler = partition.exited[i].handler; 62436 delete handler.context; 62437 62438 _routerUtils.callHook(handler, 'reset', true, transition); 62439 _routerUtils.callHook(handler, 'exit', transition); 62440 } 62441 62442 var oldState = router.oldState = router.state; 62443 router.state = newState; 62444 var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice(); 62445 62446 try { 62447 for (i = 0, l = partition.reset.length; i < l; i++) { 62448 handler = partition.reset[i].handler; 62449 _routerUtils.callHook(handler, 'reset', false, transition); 62450 } 62451 62452 for (i = 0, l = partition.updatedContext.length; i < l; i++) { 62453 handlerEnteredOrUpdated(currentHandlerInfos, partition.updatedContext[i], false, transition); 62454 } 62455 62456 for (i = 0, l = partition.entered.length; i < l; i++) { 62457 handlerEnteredOrUpdated(currentHandlerInfos, partition.entered[i], true, transition); 62458 } 62459 } catch (e) { 62460 router.state = oldState; 62461 router.currentHandlerInfos = oldState.handlerInfos; 62462 throw e; 62463 } 62464 62465 router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams, transition); 62466 } 62467 62468 /** 62469 @private 62470 62471 Helper method used by setupContexts. Handles errors or redirects 62472 that may happen in enter/setup. 62473 */ 62474 function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) { 62475 62476 var handler = handlerInfo.handler, 62477 context = handlerInfo.context; 62478 62479 if (enter) { 62480 _routerUtils.callHook(handler, 'enter', transition); 62481 } 62482 if (transition && transition.isAborted) { 62483 throw new _routerTransition.TransitionAborted(); 62484 } 62485 62486 handler.context = context; 62487 _routerUtils.callHook(handler, 'contextDidChange'); 62488 62489 _routerUtils.callHook(handler, 'setup', context, transition); 62490 if (transition && transition.isAborted) { 62491 throw new _routerTransition.TransitionAborted(); 62492 } 62493 62494 currentHandlerInfos.push(handlerInfo); 62495 62496 return true; 62497 } 62498 62499 /** 62500 @private 62501 62502 This function is called when transitioning from one URL to 62503 another to determine which handlers are no longer active, 62504 which handlers are newly active, and which handlers remain 62505 active but have their context changed. 62506
62507 Take a list of old handlers and new handlers and partition 62508 them into four buckets: 62509 62510 * unchanged: the handler was active in both the old and 62511 new URL, and its context remains the same 62512 * updated context: the handler was active in both the 62513 old and new URL, but its context changed. The handler's 62514 `setup` method, if any, will be called with the new 62515 context. 62516 * exited: the handler was active in the old URL, but is 62517 no longer active. 62518 * entered: the handler was not active in the old URL, but 62519 is now active. 62520 62521 The PartitionedHandlers structure has four fields: 62522 62523 * `updatedContext`: a list of `HandlerInfo` objects that 62524 represent handlers that remain active but have a changed 62525 context 62526 * `entered`: a list of `HandlerInfo` objects that represent 62527 handlers that are newly active 62528 * `exited`: a list of `HandlerInfo` objects that are no 62529 longer active. 62530 * `unchanged`: a list of `HanderInfo` objects that remain active. 62531 62532 @param {Array[HandlerInfo]} oldHandlers a list of the handler 62533 information for the previous URL (or `[]` if this is the 62534 first handled transition) 62535 @param {Array[HandlerInfo]} newHandlers a list of the handler 62536 information for the new URL 62537 62538 @return {Partition} 62539 */ 62540 function partitionHandlers(oldState, newState) { 62541 var oldHandlers = oldState.handlerInfos; 62542 var newHandlers = newState.handlerInfos; 62543 62544 var handlers = { 62545 updatedContext: [], 62546 exited: [], 62547 entered: [], 62548 unchanged: [] 62549 }; 62550 62551 var handlerChanged, 62552 contextChanged = false, 62553 i, 62554 l; 62555 62556 for (i = 0, l = newHandlers.length; i < l; i++) { 62557 var oldHandler = oldHandlers[i], 62558 newHandler = newHandlers[i]; 62559 62560 if (!oldHandler || oldHandler.handler !== newHandler.handler) { 62561 handlerChanged = true; 62562 } 62563 62564 if (handlerChanged) { 62565 handlers.entered.push(newHandler); 62566 if (oldHandler) { 62567 handlers.exited.unshift(oldHandler); 62568 } 62569 } else if (contextChanged || oldHandler.context !== newHandler.context) { 62570 contextChanged = true; 62571 handlers.updatedContext.push(newHandler); 62572 } else { 62573 handlers.unchanged.push(oldHandler); 62574 } 62575 } 62576 62577 for (i = newHandlers.length, l = oldHandlers.length; i < l; i++) { 62578 handlers.exited.unshift(oldHandlers[i]); 62579 } 62580 62581 handlers.reset = handlers.updatedContext.slice(); 62582 handlers.reset.reverse(); 62583 62584 return handlers; 62585 } 62586 62587 function updateURL(transition, state, inputUrl) { 62588 var urlMethod = transition.urlMethod; 62589 62590 if (!urlMethod) { 62591 return; 62592 } 62593 62594 var router = transition.router, 62595 handlerInfos = state.handlerInfos, 62596 handlerName = handlerInfos[handlerInfos.length - 1].name, 62597 params = {}; 62598 62599 for (var i = handlerInfos.length - 1; i >= 0; --i) { 62600 var handlerInfo = handlerInfos[i]; 62601 _routerUtils.merge(params, handlerInfo.params); 62602 if (handlerInfo.handler.inaccessibleByURL) { 62603 urlMethod = null; 62604 } 62605 } 62606 62607 if (urlMethod) { 62608 params.queryParams = transition._visibleQueryParams || state.queryParams; 62609 var url = router.recognizer.generate(handlerName, params); 62610 62611 if (urlMethod === 'replace') { 62612 router.replaceURL(url); 62613 } else { 62614 router.updateURL(url); 62615 } 62616 } 62617 } 62618 62619 /** 62620 @private 62621 62622 Updates the URL (if necessary) and calls `setupContexts` 62623 to update the router's array of `currentHandlerInfos`. 62624 */ 62625 function finalizeTransition(transition, newState) { 62626 62627 try { 62628 _routerUtils.log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition."); 62629 62630 var router = transition.router, 62631 handlerInfos = newState.handlerInfos, 62632 seq = transition.sequence; 62633 62634 // Run all the necessary enter/setup/exit hooks 62635 setupContexts(router, newState, transition); 62636 62637 // Check if a redirect occurred in enter/setup 62638 if (transition.isAborted) { 62639 // TODO: cleaner way? distinguish b/w targetHandlerInfos? 62640 router.state.handlerInfos = router.currentHandlerInfos; 62641 return _rsvpPromise.default.reject(_routerTransition.logAbort(transition)); 62642 } 62643 62644 updateURL(transition, newState, transition.intent.url); 62645 62646 transition.isActive = false;
62647 router.activeTransition = null; 62648 62649 _routerUtils.trigger(router, router.currentHandlerInfos, true, ['didTransition']); 62650 62651 if (router.didTransition) { 62652 router.didTransition(router.currentHandlerInfos); 62653 } 62654 62655 _routerUtils.log(router, transition.sequence, "TRANSITION COMPLETE."); 62656 62657 // Resolve with the final handler. 62658 return handlerInfos[handlerInfos.length - 1].handler; 62659 } catch (e) { 62660 if (!(e instanceof _routerTransition.TransitionAborted)) { 62661 //var erroneousHandler = handlerInfos.pop(); 62662 var infos = transition.state.handlerInfos; 62663 transition.trigger(true, 'error', e, transition, infos[infos.length - 1].handler); 62664 transition.abort(); 62665 } 62666 62667 throw e; 62668 } 62669 } 62670 62671 /** 62672 @private 62673 62674 Begins and returns a Transition based on the provided 62675 arguments. Accepts arguments in the form of both URL 62676 transitions and named transitions. 62677 62678 @param {Router} router 62679 @param {Array[Object]} args arguments passed to transitionTo, 62680 replaceWith, or handleURL 62681 */ 62682 function doTransition(router, args, isIntermediate) { 62683 // Normalize blank transitions to root URL transitions. 62684 var name = args[0] || '/'; 62685 62686 var lastArg = args[args.length - 1]; 62687 var queryParams = {}; 62688 if (lastArg && lastArg.hasOwnProperty('queryParams')) { 62689 queryParams = pop.call(args).queryParams; 62690 } 62691 62692 var intent; 62693 if (args.length === 0) { 62694 62695 _routerUtils.log(router, "Updating query params"); 62696 62697 // A query param update is really just a transition 62698 // into the route you're already on. 62699 var handlerInfos = router.state.handlerInfos; 62700 intent = new _routerTransitionIntentNamedTransitionIntent.default({ 62701 name: handlerInfos[handlerInfos.length - 1].name, 62702 contexts: [], 62703 queryParams: queryParams 62704 }); 62705 } else if (name.charAt(0) === '/') { 62706 62707 _routerUtils.log(router, "Attempting URL transition to " + name); 62708 intent = new _routerTransitionIntentUrlTransitionIntent.default({ url: name }); 62709 } else { 62710 62711 _routerUtils.log(router, "Attempting transition to " + name); 62712 intent = new _routerTransitionIntentNamedTransitionIntent.default({ 62713 name: args[0], 62714 contexts: _routerUtils.slice.call(args, 1), 62715 queryParams: queryParams 62716 }); 62717 } 62718 62719 return router.transitionByIntent(intent, isIntermediate); 62720 } 62721 62722 function handlerInfosEqual(handlerInfos, otherHandlerInfos) { 62723 if (handlerInfos.length !== otherHandlerInfos.length) { 62724 return false; 62725 } 62726 62727 for (var i = 0, len = handlerInfos.length; i < len; ++i) { 62728 if (handlerInfos[i] !== otherHandlerInfos[i]) { 62729 return false; 62730 } 62731 } 62732 return true; 62733 } 62734 62735 function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams, transition) { 62736 // We fire a finalizeQueryParamChange event which 62737 // gives the new route hierarchy a chance to tell 62738 // us which query params it's consuming and what 62739 // their final values are. If a query param is 62740 // no longer consumed in the final route hierarchy, 62741 // its serialized segment will be removed 62742 // from the URL. 62743 62744 for (var k in newQueryParams) { 62745 if (newQueryParams.hasOwnProperty(k) && newQueryParams[k] === null) { 62746 delete newQueryParams[k]; 62747 } 62748 } 62749 62750 var finalQueryParamsArray = []; 62751 _routerUtils.trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray, transition]); 62752 62753 if (transition) { 62754 transition._visibleQueryParams = {}; 62755 } 62756 62757 var finalQueryParams = {}; 62758 for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) { 62759 var qp = finalQueryParamsArray[i]; 62760 finalQueryParams[qp.key] = qp.value; 62761 if (transition && qp.visible !== false) { 62762 transition._visibleQueryParams[qp.key] = qp.value; 62763 } 62764 } 62765 return finalQueryParams; 62766 } 62767 62768 function notifyExistingHandlers(router, newState, newTransition) { 62769 var oldHandlers = router.state.handlerInfos, 62770 changing = [], 62771 leavingIndex = null, 62772 leaving, 62773 leavingChecker, 62774 i, 62775 oldHandlerLen, 62776 oldHandler, 62777 newHandler; 62778 62779 oldHandlerLen = oldHandlers.length; 62780 for (i = 0; i < oldHandlerLen; i++) { 62781 oldHandler = oldHandlers[i]; 62782 newHandler = newState.handlerInfos[i]; 62783 62784 if (!newHandler || oldHandler.name !== newHandler.name) { 62785 leavingIndex = i; 62786 break; 62787 } 62788 62789 if (!newHandler.isResolved) { 62790 changing.push(oldHandler); 62791 } 62792 } 62793 62794 if (leavingIndex !== null) { 62795 leaving = oldHandlers.slice(leavingIndex, oldHandlerLen); 62796 leavingChecker = function (name) { 62797 for (var h = 0, len = leaving.length; h < len; h++) { 62798 if (leaving[h].name === name) { 62799 return true; 62800 } 62801 } 62802 return false;
62803 }; 62804 } 62805 62806 _routerUtils.trigger(router, oldHandlers, true, ['willTransition', newTransition]); 62807 62808 if (router.willTransition) { 62809 router.willTransition(oldHandlers, newState.handlerInfos, newTransition); 62810 } 62811 } 62812 62813 exports.default = Router; 62814}); 62815enifed('router/transition-intent/named-transition-intent', ['exports', 'router/transition-intent', 'router/transition-state', 'router/handler-info/factory', 'router/utils'], function (exports, _routerTransitionIntent, _routerTransitionState, _routerHandlerInfoFactory, _routerUtils) { 62816 'use strict'; 62817 62818 exports.default = _routerUtils.subclass(_routerTransitionIntent.default, { 62819 name: null, 62820 pivotHandler: null, 62821 contexts: null, 62822 queryParams: null, 62823 62824 initialize: function (props) { 62825 this.name = props.name; 62826 this.pivotHandler = props.pivotHandler; 62827 this.contexts = props.contexts || []; 62828 this.queryParams = props.queryParams; 62829 }, 62830 62831 applyToState: function (oldState, recognizer, getHandler, isIntermediate) { 62832 62833 var partitionedArgs = _routerUtils.extractQueryParams([this.name].concat(this.contexts)), 62834 pureArgs = partitionedArgs[0], 62835 queryParams = partitionedArgs[1], 62836 handlers = recognizer.handlersFor(pureArgs[0]); 62837 62838 var targetRouteName = handlers[handlers.length - 1].handler; 62839 62840 return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate); 62841 }, 62842 62843 applyToHandlers: function (oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) { 62844 62845 var i, len; 62846 var newState = new _routerTransitionState.default(); 62847 var objects = this.contexts.slice(0); 62848 62849 var invalidateIndex = handlers.length; 62850 62851 // Pivot handlers are provided for refresh transitions 62852 if (this.pivotHandler) { 62853 for (i = 0, len = handlers.length; i < len; ++i) { 62854 if (getHandler(handlers[i].handler) === this.pivotHandler) { 62855 invalidateIndex = i; 62856 break; 62857 } 62858 } 62859 } 62860 62861 var pivotHandlerFound = !this.pivotHandler; 62862 62863 for (i = handlers.length - 1; i >= 0; --i) { 62864 var result = handlers[i]; 62865 var name = result.handler; 62866 var handler = getHandler(name); 62867 62868 var oldHandlerInfo = oldState.handlerInfos[i]; 62869 var newHandlerInfo = null; 62870 62871 if (result.names.length > 0) { 62872 if (i >= invalidateIndex) { 62873 newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); 62874 } else { 62875 newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName, i); 62876 } 62877 } else { 62878 // This route has no dynamic segment. 62879 // Therefore treat as a param-based handlerInfo 62880 // with empty params. This will cause the `model` 62881 // hook to be called with empty params, which is desirable. 62882 newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); 62883 } 62884 62885 if (checkingIfActive) { 62886 // If we're performing an isActive check, we want to 62887 // serialize URL params with the provided context, but 62888 // ignore mismatches between old and new context. 62889 newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context); 62890 var oldContext = oldHandlerInfo && oldHandlerInfo.context; 62891 if (result.names.length > 0 && newHandlerInfo.context === oldContext) { 62892 // If contexts match in isActive test, assume params also match. 62893 // This allows for flexibility in not requiring that every last 62894 // handler provide a `serialize` method 62895 newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params; 62896 } 62897 newHandlerInfo.context = oldContext; 62898 } 62899 62900 var handlerToUse = oldHandlerInfo; 62901 if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { 62902 invalidateIndex = Math.min(i, invalidateIndex); 62903 handlerToUse = newHandlerInfo; 62904 } 62905 62906 if (isIntermediate && !checkingIfActive) { 62907 handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context); 62908 } 62909 62910 newState.handlerInfos.unshift(handlerToUse); 62911 } 62912 62913 if (objects.length > 0) { 62914 throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName); 62915 } 62916 62917 if (!isIntermediate) { 62918 this.invalidateChildren(newState.handlerInfos, invalidateIndex); 62919 } 62920 62921 _routerUtils.merge(newState.queryParams, this.queryParams || {}); 62922 62923 return newState; 62924 }, 62925 62926 invalidateChildren: function (handlerInfos, invalidateIndex) { 62927 for (var i = invalidateIndex, l = handlerInfos.length; i < l; ++i) { 62928 var handlerInfo = handlerInfos[i]; 62929 handlerInfos[i] = handlerInfos[i].getUnresolved(); 62930 } 62931 }, 62932 62933 getHandlerInfoForDynamicSegment: function (name, handler, names, objects, oldHandlerInfo, targetRouteName, i) { 62934 62935 var numNames = names.length; 62936 var objectToUse; 62937 if (objects.length > 0) { 62938 62939 // Use the objects provided for this transition. 62940 objectToUse = objects[objects.length - 1]; 62941 if (_routerUtils.isParam(objectToUse)) { 62942 return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo); 62943 } else { 62944 objects.pop(); 62945 } 62946 } else if (oldHandlerInfo && oldHandlerInfo.name === name) { 62947 // Reuse the matching oldHandlerInfo 62948 return oldHandlerInfo; 62949 } else { 62950 if (this.preTransitionState) { 62951 var preTransitionHandlerInfo = this.preTransitionState.handlerInfos[i]; 62952 objectToUse = preTransitionHandlerInfo && preTransitionHandlerInfo.context; 62953 } else { 62954 // Ideally we should throw this error to provide maximal 62955 // information to the user that not enough context objects 62956 // were provided, but this proves too cumbersome in Ember 62957 // in cases where inner template helpers are evaluated 62958 // before parent helpers un-render, in which cases this 62959 // error somewhat prematurely fires. 62960 //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]"); 62961 return oldHandlerInfo; 62962 } 62963 } 62964 62965 return _routerHandlerInfoFactory.default('object', { 62966 name: name, 62967 handler: handler, 62968 context: objectToUse, 62969 names: names 62970 }); 62971 }, 62972 62973 createParamHandlerInfo: function (name, handler, names, objects, oldHandlerInfo) { 62974 var params = {}; 62975 62976 // Soak up all the provided string/numbers 62977 var numNames = names.length; 62978 while (numNames--) { 62979 62980 // Only use old params if the names match with the new handler 62981 var oldParams = oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params || {}; 62982 62983 var peek = objects[objects.length - 1]; 62984 var paramName = names[numNames]; 62985 if (_routerUtils.isParam(peek)) { 62986 params[paramName] = "" + objects.pop(); 62987 } else { 62988 // If we're here, this means only some of the params 62989 // were string/number params, so try and use a param 62990 // value from a previous handler. 62991 if (oldParams.hasOwnProperty(paramName)) { 62992 params[paramName] = oldParams[paramName]; 62993 } else { 62994 throw new Error("You didn't provide enough string/numeric parameters to
62994satisfy all of the dynamic segments for route " + name); 62995 } 62996 } 62997 } 62998 62999 return _routerHandlerInfoFactory.default('param', { 63000 name: name, 63001 handler: handler, 63002 params: params 63003 }); 63004 } 63005 }); 63006}); 63007enifed('router/transition-intent/url-transition-intent', ['exports', 'router/transition-intent', 'router/transition-state', 'router/handler-info/factory', 'router/utils', 'router/unrecognized-url-error'], function (exports, _routerTransitionIntent, _routerTransitionState, _routerHandlerInfoFactory, _routerUtils, _routerUnrecognizedUrlError) { 63008 'use strict'; 63009 63010 exports.default = _routerUtils.subclass(_routerTransitionIntent.default, { 63011 url: null, 63012 63013 initialize: function (props) { 63014 this.url = props.url; 63015 }, 63016 63017 applyToState: function (oldState, recognizer, getHandler) { 63018 var newState = new _routerTransitionState.default(); 63019 63020 var results = recognizer.recognize(this.url), 63021 queryParams = {}, 63022 i, 63023 len; 63024 63025 if (!results) { 63026 throw new _routerUnrecognizedUrlError.default(this.url); 63027 } 63028 63029 var statesDiffer = false; 63030 63031 for (i = 0, len = results.length; i < len; ++i) { 63032 var result = results[i]; 63033 var name = result.handler; 63034 var handler = getHandler(name); 63035 63036 if (handler.inaccessibleByURL) { 63037 throw new _routerUnrecognizedUrlError.default(this.url); 63038 } 63039 63040 var newHandlerInfo = _routerHandlerInfoFactory.default('param', { 63041 name: name, 63042 handler: handler, 63043 params: result.params 63044 }); 63045 63046 var oldHandlerInfo = oldState.handlerInfos[i]; 63047 if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { 63048 statesDiffer = true; 63049 newState.handlerInfos[i] = newHandlerInfo; 63050 } else { 63051 newState.handlerInfos[i] = oldHandlerInfo; 63052 } 63053 } 63054 63055 _routerUtils.merge(newState.queryParams, results.queryParams); 63056 63057 return newState; 63058 } 63059 }); 63060}); 63061enifed('router/transition-intent', ['exports', 'router/utils'], function (exports, _routerUtils) { 63062 'use strict'; 63063 63064 function TransitionIntent(props) { 63065 this.initialize(props); 63066 63067 // TODO: wat 63068 this.data = this.data || {}; 63069 } 63070 63071 TransitionIntent.prototype = { 63072 initialize: null, 63073 applyToState: null 63074 }; 63075 63076 exports.default = TransitionIntent; 63077}); 63078enifed('router/transition-state', ['exports', 'router/handler-info', 'router/utils', 'rsvp/promise'], function (exports, _routerHandlerInfo, _routerUtils, _rsvpPromise) { 63079 'use strict'; 63080 63081 function TransitionState(other) { 63082 this.handlerInfos = []; 63083 this.queryParams = {}; 63084 this.params = {}; 63085 } 63086 63087 TransitionState.prototype = { 63088 handlerInfos: null, 63089 queryParams: null, 63090 params: null, 63091 63092 promiseLabel: function (label) { 63093 var targetName = ''; 63094 _routerUtils.forEach(this.handlerInfos, function (handlerInfo) { 63095 if (targetName !== '') { 63096 targetName += '.'; 63097 } 63098 targetName += handlerInfo.name; 63099 }); 63100 return _routerUtils.promiseLabel("'" + targetName + "': " + label); 63101 }, 63102 63103 resolve: function (shouldContinue, payload) { 63104 var self = this; 63105 // First, calculate params for this state. This is useful 63106 // information to provide to the various route hooks. 63107 var params = this.params; 63108 _routerUtils.forEach(this.handlerInfos, function (handlerInfo) { 63109 params[handlerInfo.name] = handlerInfo.params || {}; 63110 }); 63111 63112 payload = payload || {}; 63113 payload.resolveIndex = 0; 63114 63115 var currentState = this; 63116 var wasAborted = false; 63117 63118 // The prelude RSVP.resolve() asyncs us into the promise land. 63119 return _rsvpPromise.default.resolve(null, this.promiseLabel("Start transition")).then(resolveOneHandlerInfo, null, this.promiseLabel('Resolve handler'))['catch'](handleError, this.promiseLabel('Handle error')); 63120 63121 function innerShouldContinue() { 63122 return _rsvpPromise.default.resolve(shouldContinue(), currentState.promiseLabel("Check if should continue"))['catch'](function (reason) { 63123 // We distinguish between errors that occurred 63124 // during resolution (e.g. beforeModel/model/afterModel), 63125 // and aborts due to a rejecting promise from shouldContinue(). 63126 wasAborted = true; 63127 return _rsvpPromise.default.reject(reason); 63128 }, currentState.promiseLabel("Handle abort")); 63129 } 63130 63131 function handleError(error) { 63132 // This is the only possible 63133 // reject value of TransitionState#resolve 63134 var handlerInfos = currentState.handlerInfos; 63135 var errorHandlerIndex = payload.resolveIndex >= handlerInfos.length ? handlerInfos.length - 1 : payload.resolveIndex; 63136 return _rsvpPromise.default.reject({ 63137 error: error, 63138 handlerWithError: currentState.handlerInfos[errorHandlerIndex].handler, 63139 wasAborted: wasAborted, 63140 state: currentState 63141 }); 63142 } 63143 63144 function proceed(resolvedHandlerInfo) { 63145 var wasAlreadyResolved = currentState.handlerInfos[payload.resolveIndex].isResolved; 63146 63147 // Swap the previously unresolved handlerInfo with 63148 // the resolved handlerInfo 63149 currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo; 63150 63151 if (!wasAlreadyResolved) {
63152 // Call the redirect hook. The reason we call it here 63153 // vs. afterModel is so that redirects into child 63154 // routes don't re-run the model hooks for this 63155 // already-resolved route. 63156 var handler = resolvedHandlerInfo.handler; 63157 _routerUtils.callHook(handler, 'redirect', resolvedHandlerInfo.context, payload); 63158 } 63159 63160 // Proceed after ensuring that the redirect hook 63161 // didn't abort this transition by transitioning elsewhere. 63162 return innerShouldContinue().then(resolveOneHandlerInfo, null, currentState.promiseLabel('Resolve handler')); 63163 } 63164 63165 function resolveOneHandlerInfo() { 63166 if (payload.resolveIndex === currentState.handlerInfos.length) { 63167 // This is is the only possible 63168 // fulfill value of TransitionState#resolve 63169 return { 63170 error: null, 63171 state: currentState 63172 }; 63173 } 63174 63175 var handlerInfo = currentState.handlerInfos[payload.resolveIndex]; 63176 63177 return handlerInfo.resolve(innerShouldContinue, payload).then(proceed, null, currentState.promiseLabel('Proceed')); 63178 } 63179 } 63180 }; 63181 63182 exports.default = TransitionState; 63183}); 63184enifed('router/transition', ['exports', 'rsvp/promise', 'router/handler-info', 'router/utils'], function (exports, _rsvpPromise, _routerHandlerInfo, _routerUtils) { 63185 'use strict'; 63186 63187 /** 63188 @private 63189 63190 A Transition is a thennable (a promise-like object) that represents 63191 an attempt to transition to another route. It can be aborted, either 63192 explicitly via `abort` or by attempting another transition while a 63193 previous one is still underway. An aborted transition can also 63194 be `retry()`d later. 63195 */ 63196 function Transition(router, intent, state, error) { 63197 var transition = this; 63198 this.state = state || router.state; 63199 this.intent = intent; 63200 this.router = router; 63201 this.data = this.intent && this.intent.data || {}; 63202 this.resolvedModels = {}; 63203 this.queryParams = {}; 63204 63205 if (error) { 63206 this.promise = _rsvpPromise.default.reject(error); 63207 this.error = error; 63208 return; 63209 } 63210 63211 if (state) { 63212 this.params = state.params; 63213 this.queryParams = state.queryParams; 63214 this.handlerInfos = state.handlerInfos; 63215 63216 var len = state.handlerInfos.length; 63217 if (len) { 63218 this.targetName = state.handlerInfos[len - 1].name; 63219 } 63220 63221 for (var i = 0; i < len; ++i) { 63222 var handlerInfo = state.handlerInfos[i]; 63223 63224 // TODO: this all seems hacky 63225 if (!handlerInfo.isResolved) { 63226 break; 63227 } 63228 this.pivotHandler = handlerInfo.handler; 63229 } 63230 63231 this.sequence = Transition.currentSequence++; 63232 this.promise = state.resolve(checkForAbort, this)['catch'](function (result) { 63233 if (result.wasAborted || transition.isAborted) { 63234 return _rsvpPromise.default.reject(logAbort(transition)); 63235 } else { 63236 transition.trigger('error', result.error, transition, result.handlerWithError); 63237 transition.abort(); 63238 return _rsvpPromise.default.reject(result.error); 63239 } 63240 }, _routerUtils.promiseLabel('Handle Abort')); 63241 } else { 63242 this.promise = _rsvpPromise.default.resolve(this.state); 63243 this.params = {}; 63244 } 63245 63246 function checkForAbort() { 63247 if (transition.isAborted) { 63248 return _rsvpPromise.default.reject(undefined, _routerUtils.promiseLabel("Transition aborted - reject")); 63249 } 63250 } 63251 } 63252 63253 Transition.currentSequence = 0; 63254 63255 Transition.prototype = { 63256 targetName: null, 63257 urlMethod: 'update', 63258 intent: null, 63259 params: null, 63260 pivotHandler: null, 63261 resolveIndex: 0, 63262 handlerInfos: null, 63263 resolvedModels: null, 63264 isActive: true, 63265 state: null, 63266 queryParamsOnly: false, 63267 63268 isTransition: true, 63269 63270 isExiting: function (handler) { 63271 var handlerInfos = this.handlerInfos; 63272 for (var i = 0, len = handlerInfos.length; i < len; ++i) { 63273 var handlerInfo = handlerInfos[i]; 63274 if (handlerInfo.name === handler || handlerInfo.handler === handler) { 63275 return false; 63276 } 63277 } 63278 return true; 63279 }, 63280 63281 /** 63282 @public 63283 The Transition's internal promise. Calling `.then` on this property 63284 is that same as calling `.then` on the Transition object itself, but 63285 this property is exposed for when you want to pass around a 63286 Transition's promise, but not the Transition object itself, since 63287 Transition object can be externally `abort`ed, while the promise 63288 cannot. 63289 */ 63290 promise: null, 63291 63292 /** 63293 @public 63294 Custom state can be stored on a Transition's `data` object. 63295 This can be useful for decorating a Transition within an earlier 63296 hook and shared with a later hook. Properties set on `data` will 63297 be copied to new transitions generated by calling `retry` on this 63298 transition. 63299 */ 63300 data: null, 63301 63302 /** 63303 @public 63304 A standard promise hook that resolves if the transition
63305 succeeds and rejects if it fails/redirects/aborts. 63306 Forwards to the internal `promise` property which you can 63307 use in situations where you want to pass around a thennable, 63308 but not the Transition itself. 63309 @param {Function} onFulfilled 63310 @param {Function} onRejected 63311 @param {String} label optional string for labeling the promise. 63312 Useful for tooling. 63313 @return {Promise} 63314 */ 63315 then: function (onFulfilled, onRejected, label) { 63316 return this.promise.then(onFulfilled, onRejected, label); 63317 }, 63318 63319 /** 63320 @public 63321 Forwards to the internal `promise` property which you can 63322 use in situations where you want to pass around a thennable, 63323 but not the Transition itself. 63324 @method catch 63325 @param {Function} onRejection 63326 @param {String} label optional string for labeling the promise. 63327 Useful for tooling. 63328 @return {Promise} 63329 */ 63330 catch: function (onRejection, label) { 63331 return this.promise.catch(onRejection, label); 63332 }, 63333 63334 /** 63335 @public 63336 Forwards to the internal `promise` property which you can 63337 use in situations where you want to pass around a thennable, 63338 but not the Transition itself. 63339 @method finally 63340 @param {Function} callback 63341 @param {String} label optional string for labeling the promise. 63342 Useful for tooling. 63343 @return {Promise} 63344 */ 63345 finally: function (callback, label) { 63346 return this.promise.finally(callback, label); 63347 }, 63348 63349 /** 63350 @public 63351 Aborts the Transition. Note you can also implicitly abort a transition 63352 by initiating another transition while a previous one is underway. 63353 */ 63354 abort: function () { 63355 if (this.isAborted) { 63356 return this; 63357 } 63358 _routerUtils.log(this.router, this.sequence, this.targetName + ": transition was aborted"); 63359 this.intent.preTransitionState = this.router.state; 63360 this.isAborted = true; 63361 this.isActive = false; 63362 this.router.activeTransition = null; 63363 return this; 63364 }, 63365 63366 /** 63367 @public 63368 Retries a previously-aborted transition (making sure to abort the 63369 transition if it's still active). Returns a new transition that 63370 represents the new attempt to transition. 63371 */ 63372 retry: function () { 63373 // TODO: add tests for merged state retry()s 63374 this.abort(); 63375 return this.router.transitionByIntent(this.intent, false); 63376 }, 63377 63378 /** 63379 @public 63380 Sets the URL-changing method to be employed at the end of a 63381 successful transition. By default, a new Transition will just 63382 use `updateURL`, but passing 'replace' to this method will 63383 cause the URL to update using 'replaceWith' instead. Omitting 63384 a parameter will disable the URL change, allowing for transitions 63385 that don't update the URL at completion (this is also used for 63386 handleURL, since the URL has already changed before the 63387 transition took place). 63388 @param {String} method the type of URL-changing method to use 63389 at the end of a transition. Accepted values are 'replace', 63390 falsy values, or any other non-falsy value (which is 63391 interpreted as an updateURL transition). 63392 @return {Transition} this transition 63393 */ 63394 method: function (method) { 63395 this.urlMethod = method; 63396 return this; 63397 }, 63398 63399 /** 63400 @public 63401 Fires an event on the current list of resolved/resolving 63402 handlers within this transition. Useful for firing events 63403 on route hierarchies that haven't fully been entered yet. 63404 Note: This method is also aliased as `send` 63405 @param {Boolean} [ignoreFailure=false] a boolean specifying whether unhandled events throw an error 63406 @param {String} name the name of the event to fire 63407 */ 63408 trigger: function (ignoreFailure) { 63409 var args = _routerUtils.slice.call(arguments); 63410 if (typeof ignoreFailure === 'boolean') { 63411 args.shift(); 63412 } else { 63413 // Throw errors on unhandled trigger events by default 63414 ignoreFailure = false; 63415 } 63416 _routerUtils.trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); 63417 }, 63418 63419 /** 63420 @public 63421 Transitions are aborted and their promises rejected 63422 when redirects occur; this method returns a promise 63423 that will follow any redirects that occur and fulfill 63424 with the value fulfilled by any redirecting transitions 63425 that occur. 63426 @return {Promise} a promise that fulfills with the same 63427 value that the final redirecting transition fulfills with 63428 */ 63429 followRedirects: function () { 63430 var router = this.router; 63431 return this.promise['catch'](function (reason) { 63432 if (router.activeTransition) { 63433 return router.activeTransition.followRedirects(); 63434 } 63435 return _rsvpPromise.default.reject(reason); 63436 }); 63437 }, 63438 63439 toString: function () { 63440 return "Transition (sequence " + this.sequence + ")"; 63441 }, 63442 63443 /** 63444 @private 63445 */ 63446 log: function (message) { 63447 _routerUtils.log(this.router, this.sequence, message); 63448 } 63449 }; 63450 63451 // Alias 'trigger' as 'send' 63452 Transition.prototype.send = Transition.prototype.trigger; 63453 63454 /** 63455 @private 63456 63457 Logs and returns a TransitionAborted error. 63458 */ 63459 function logAbort(transition) { 63460 _routerUtils.log(transition.router, transition.sequence, "detected abort."); 63461 return new TransitionAborted(); 63462 } 63463 63464 function TransitionAborted(message) { 63465 this.message = message || "TransitionAborted"; 63466 this.name = "TransitionAborted"; 63467 } 63468 63469 exports.Transition = Transition; 63470 exports.logAbort = logAbort; 63471 exports.TransitionAborted = TransitionAborted; 63472}); 63473enifed("router/unrecognized-url-error", ["exports", "router/utils"], function (exports, _routerUtils) { 63474 "use strict"; 63475 63476 /** 63477 Promise reject reasons passed to promise rejection 63478 handlers for failed transitions. 63479 */ 63480 function UnrecognizedURLError(message) { 63481 this.message = message || "UnrecognizedURLError"; 63482 this.name = "UnrecognizedURLError"; 63483 Error.call(this); 63484 } 63485 63486 UnrecognizedURLError.prototype = _routerUtils.oCreate(Error.prototype); 63487 63488 exports.default = UnrecognizedURLError; 63489}); 63490enifed('router/utils', ['exports'], function (exports) { 63491 'use strict'; 63492 63493 exports.extractQueryParams = extractQueryParams; 63494 exports.log = log; 63495 exports.bind = bind;
63496 exports.forEach = forEach; 63497 exports.trigger = trigger; 63498 exports.getChangelist = getChangelist; 63499 exports.promiseLabel = promiseLabel; 63500 exports.subclass = subclass; 63501 var slice = Array.prototype.slice; 63502 63503 var _isArray; 63504 if (!Array.isArray) { 63505 _isArray = function (x) { 63506 return Object.prototype.toString.call(x) === "[object Array]"; 63507 }; 63508 } else { 63509 _isArray = Array.isArray; 63510 } 63511 63512 var isArray = _isArray; 63513 63514 exports.isArray = isArray; 63515 function merge(hash, other) { 63516 for (var prop in other) { 63517 if (other.hasOwnProperty(prop)) { 63518 hash[prop] = other[prop]; 63519 } 63520 } 63521 } 63522 63523 var oCreate = Object.create || function (proto) { 63524 function F() {} 63525 F.prototype = proto; 63526 return new F(); 63527 }; 63528 63529 exports.oCreate = oCreate; 63530 /** 63531 @private 63532 63533 Extracts query params from the end of an array 63534 **/ 63535 63536 function extractQueryParams(array) { 63537 var len = array && array.length, 63538 head, 63539 queryParams; 63540 63541 if (len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { 63542 queryParams = array[len - 1].queryParams; 63543 head = slice.call(array, 0, len - 1); 63544 return [head, queryParams]; 63545 } else { 63546 return [array, null]; 63547 } 63548 } 63549 63550 /** 63551 @private 63552 63553 Coerces query param properties and array elements into strings. 63554 **/ 63555 function coerceQueryParamsToString(queryParams) { 63556 for (var key in queryParams) { 63557 if (typeof queryParams[key] === 'number') { 63558 queryParams[key] = '' + queryParams[key]; 63559 } else if (isArray(queryParams[key])) { 63560 for (var i = 0, l = queryParams[key].length; i < l; i++) { 63561 queryParams[key][i] = '' + queryParams[key][i]; 63562 } 63563 } 63564 } 63565 } 63566 /** 63567 @private 63568 */ 63569 63570 function log(router, sequence, msg) { 63571 if (!router.log) { 63572 return; 63573 } 63574 63575 if (arguments.length === 3) { 63576 router.log("Transition #" + sequence + ": " + msg); 63577 } else { 63578 msg = sequence; 63579 router.log(msg); 63580 } 63581 } 63582 63583 function bind(context, fn) { 63584 var boundArgs = arguments; 63585 return function (value) { 63586 var args = slice.call(boundArgs, 2); 63587 args.push(value); 63588 return fn.apply(context, args); 63589 }; 63590 } 63591 63592 function isParam(object) { 63593 return typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number; 63594 } 63595 63596 function forEach(array, callback) { 63597 for (var i = 0, l = array.length; i < l && false !== callback(array[i]); i++) {} 63598 } 63599 63600 function trigger(router, handlerInfos, ignoreFailure, args) { 63601 if (router.triggerEvent) { 63602 router.triggerEvent(handlerInfos, ignoreFailure, args); 63603 return; 63604 } 63605 63606 var name = args.shift(); 63607 63608 if (!handlerInfos) { 63609 if (ignoreFailure) { 63610 return; 63611 } 63612 throw new Error("Could not trigger event '" + name + "'. There are no active handlers"); 63613 } 63614 63615 var eventWasHandled = false; 63616 63617 for (var i = handlerInfos.length - 1; i >= 0; i--) { 63618 var handlerInfo = handlerInfos[i], 63619 handler = handlerInfo.handler; 63620 63621 if (handler.events && handler.events[name]) { 63622 if (handler.events[name].apply(handler, args) === true) { 63623 eventWasHandled = true; 63624 } else { 63625 return; 63626 } 63627 } 63628 } 63629 63630 if (!eventWasHandled && !ignoreFailure) { 63631 throw new Error("Nothing handled the event '" + name + "'."); 63632 } 63633 } 63634 63635 function getChangelist(oldObject, newObject) { 63636 var key; 63637 var results = { 63638 all: {}, 63639 changed: {}, 63640 removed: {} 63641 }; 63642 63643 merge(results.all, newObject); 63644 63645 var didChange = false; 63646 coerceQueryParamsToString(oldObject); 63647 coerceQueryParamsToString(newObject); 63648 63649 // Calculate removals 63650 for (key in oldObject) { 63651 if (oldObject.hasOwnProperty(key)) { 63652 if (!newObject.hasOwnProperty(key)) { 63653 didChange = true; 63654 results.removed[key] = oldObject[key]; 63655 } 63656 } 63657 } 63658 63659 // Calculate changes 63660 for (key in newObject) { 63661 if (newObject.hasOwnProperty(key)) {
63662 if (isArray(oldObject[key]) && isArray(newObject[key])) { 63663 if (oldObject[key].length !== newObject[key].length) { 63664 results.changed[key] = newObject[key]; 63665 didChange = true; 63666 } else { 63667 for (var i = 0, l = oldObject[key].length; i < l; i++) { 63668 if (oldObject[key][i] !== newObject[key][i]) { 63669 results.changed[key] = newObject[key]; 63670 didChange = true; 63671 } 63672 } 63673 } 63674 } else { 63675 if (oldObject[key] !== newObject[key]) { 63676 results.changed[key] = newObject[key]; 63677 didChange = true; 63678 } 63679 } 63680 } 63681 } 63682 63683 return didChange && results; 63684 } 63685 63686 function promiseLabel(label) { 63687 return 'Router: ' + label; 63688 } 63689 63690 function subclass(parentConstructor, proto) { 63691 function C(props) { 63692 parentConstructor.call(this, props || {}); 63693 } 63694 C.prototype = oCreate(parentConstructor.prototype); 63695 merge(C.prototype, proto); 63696 return C; 63697 } 63698 63699 function resolveHook(obj, hookName) { 63700 if (!obj) { 63701 return; 63702 } 63703 var underscored = "_" + hookName; 63704 return obj[underscored] && underscored || obj[hookName] && hookName; 63705 } 63706 63707 function callHook(obj, _hookName, arg1, arg2) { 63708 var hookName = resolveHook(obj, _hookName); 63709 return hookName && obj[hookName].call(obj, arg1, arg2); 63710 } 63711 63712 function applyHook(obj, _hookName, args) { 63713 var hookName = resolveHook(obj, _hookName); 63714 if (hookName) { 63715 if (args.length === 0) { 63716 return obj[hookName].call(obj); 63717 } else if (args.length === 1) { 63718 return obj[hookName].call(obj, args[0]); 63719 } else if (args.length === 2) { 63720 return obj[hookName].call(obj, args[0], args[1]); 63721 } else { 63722 return obj[hookName].apply(obj, args); 63723 } 63724 } 63725 } 63726 63727 exports.merge = merge; 63728 exports.slice = slice; 63729 exports.isParam = isParam; 63730 exports.coerceQueryParamsToString = coerceQueryParamsToString; 63731 exports.callHook = callHook; 63732 exports.resolveHook = resolveHook; 63733 exports.applyHook = applyHook; 63734}); 63735enifed('router', ['exports', 'router/router'], function (exports, _routerRouter) { 63736 'use strict'; 63737 63738 exports.default = _routerRouter.default; 63739}); 63740enifed('rsvp/-internal', ['exports', 'rsvp/utils', 'rsvp/instrument', 'rsvp/config'], function (exports, _rsvpUtils, _rsvpInstrument, _rsvpConfig) { 63741 'use strict'; 63742 63743 function withOwnPromise() { 63744 return new TypeError('A promises callback cannot return that same promise.'); 63745 } 63746 63747 function noop() {} 63748 63749 var PENDING = void 0; 63750 var FULFILLED = 1; 63751 var REJECTED = 2; 63752 63753 var GET_THEN_ERROR = new ErrorObject(); 63754 63755 function getThen(promise) { 63756 try { 63757 return promise.then; 63758 } catch (error) { 63759 GET_THEN_ERROR.error = error; 63760 return GET_THEN_ERROR; 63761 } 63762 } 63763 63764 function tryThen(then, value, fulfillmentHandler, rejectionHandler) { 63765 try { 63766 then.call(value, fulfillmentHandler, rejectionHandler); 63767 } catch (e) { 63768 return e; 63769 } 63770 } 63771 63772 function handleForeignThenable(promise, thenable, then) { 63773 _rsvpConfig.config.async(function (promise) { 63774 var sealed = false; 63775 var error = tryThen(then, thenable, function (value) { 63776 if (sealed) { 63777 return; 63778 } 63779 sealed = true; 63780 if (thenable !== value) { 63781 resolve(promise, value); 63782 } else { 63783 fulfill(promise, value); 63784 } 63785 }, function (reason) { 63786 if (sealed) { 63787 return; 63788 } 63789 sealed = true; 63790 63791 reject(promise, reason); 63792 }, 'Settle: ' + (promise._label || ' unknown promise')); 63793 63794 if (!sealed && error) { 63795 sealed = true; 63796 reject(promise, error); 63797 } 63798 }, promise); 63799 } 63800 63801 function handleOwnThenable(promise, thenable) { 63802 if (thenable._state === FULFILLED) { 63803 fulfill(promise, thenable._result); 63804 } else if (thenable._state === REJECTED) { 63805 thenable._onError = null; 63806 reject(promise, thenable._result); 63807 } else { 63808 subscribe(thenable, undefined, function (value) { 63809 if (thenable !== value) { 63810 resolve(promise, value); 63811 } else { 63812 fulfill(promise, value); 63813 } 63814 }, function (reason) { 63815 reject(promise, reason); 63816 }); 63817 } 63818 } 63819 63820 function handleMaybeThenable(promise, maybeThenable) { 63821 if (maybeThenable.constructor === promise.constructor) { 63822 handleOwnThenable(promise, maybeThenable); 63823 } else { 63824 var then = getThen(maybeThenable); 63825 63826 if (then === GET_THEN_ERROR) { 63827 reject(promise, GET_THEN_ERROR.error); 63828 } else if (then === undefined) { 63829 fulfill(promise, maybeThenable); 63830 } else if (_rsvpUtils.isFunction(then)) { 63831 handleForeignThenable(promise, maybeThenable, then); 63832 } else { 63833 fulfill(promise, maybeThenable); 63834 } 63835 } 63836 } 63837 63838 function resolve(promise, value) { 63839 if (promise === value) { 63840 fulfill(promise, value); 63841 } else if (_rsvpUtils.objectOrFunction(value)) { 63842 handleMaybeThenable(promise, value); 63843 } else { 63844 fulfill(promise, value); 63845 } 63846 } 63847 63848 function publishRejection(promise) { 63849 if (promise._onError) { 63850 promise._onError(promise._result); 63851 } 63852 63853 publish(promise); 63854 } 63855 63856 function fulfill(promise, value) { 63857 if (promise._state !== PENDING) { 63858 return; 63859 } 63860 63861 promise._result = value; 63862 promise._state = FULFILLED; 63863 63864 if (promise._subscribers.length === 0) { 63865 if (_rsvpConfig.config.instrument) { 63866 _rsvpInstrument.default('fulfilled', promise); 63867 } 63868 } else { 63869 _rsvpConfig.config.async(publish, promise); 63870 } 63871 } 63872 63873 function reject(promise, reason) { 63874 if (promise._state !== PENDING) { 63875 return; 63876 } 63877 promise._state = REJECTED; 63878 promise._result = reason; 63879 _rsvpConfig.config.async(publishRejection, promise); 63880 } 63881 63882 function subscribe(parent, child, onFulfillment, onRejection) { 63883 var subscribers = parent._subscribers; 63884 var length = subscribers.length; 63885 63886 parent._onError = null; 63887 63888 subscribers[length] = child; 63889 subscribers[length + FULFILLED] = onFulfillment; 63890 subscribers[length + REJECTED] = onRejection; 63891 63892 if (length === 0 && parent._state) { 63893 _rsvpConfig.config.async(publish, parent); 63894 } 63895 } 63896 63897 function publish(promise) { 63898 var subscribers = promise._subscribers; 63899 var settled = promise._state; 63900 63901 if (_rsvpConfig.config.instrument) { 63902 _rsvpInstrument.default(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); 63903 } 63904 63905 if (subscribers.length === 0) { 63906 return; 63907 } 63908 63909 var child, 63910 callback, 63911 detail = promise._result; 63912 63913 for (var i = 0; i < subscribers.length; i += 3) { 63914 child = subscribers[i]; 63915 callback = subscribers[i + settled]; 63916 63917 if (child) { 63918 invokeCallback(settled, child, callback, detail); 63919 } else { 63920 callback(detail); 63921 } 63922 } 63923 63924 promise._subscribers.length = 0; 63925 } 63926 63927 function ErrorObject() { 63928 this.error = null; 63929 } 63930 63931 var TRY_CATCH_ERROR = new ErrorObject(); 63932 63933 function tryCatch(callback, detail) { 63934 try { 63935 return callback(detail); 63936 } catch (e) { 63937 TRY_CATCH_ERROR.error = e; 63938 return TRY_CATCH_ERROR; 63939 } 63940 } 63941
63942 function invokeCallback(settled, promise, callback, detail) { 63943 var hasCallback = _rsvpUtils.isFunction(callback), 63944 value, 63945 error, 63946 succeeded, 63947 failed; 63948 63949 if (hasCallback) { 63950 value = tryCatch(callback, detail); 63951 63952 if (value === TRY_CATCH_ERROR) { 63953 failed = true; 63954 error = value.error; 63955 value = null; 63956 } else { 63957 succeeded = true; 63958 } 63959 63960 if (promise === value) { 63961 reject(promise, withOwnPromise()); 63962 return; 63963 } 63964 } else { 63965 value = detail; 63966 succeeded = true; 63967 } 63968 63969 if (promise._state !== PENDING) { 63970 // noop 63971 } else if (hasCallback && succeeded) { 63972 resolve(promise, value); 63973 } else if (failed) { 63974 reject(promise, error); 63975 } else if (settled === FULFILLED) { 63976 fulfill(promise, value); 63977 } else if (settled === REJECTED) { 63978 reject(promise, value); 63979 } 63980 } 63981 63982 function initializePromise(promise, resolver) { 63983 var resolved = false; 63984 try { 63985 resolver(function resolvePromise(value) { 63986 if (resolved) { 63987 return; 63988 } 63989 resolved = true; 63990 resolve(promise, value); 63991 }, function rejectPromise(reason) { 63992 if (resolved) { 63993 return; 63994 } 63995 resolved = true; 63996 reject(promise, reason); 63997 }); 63998 } catch (e) { 63999 reject(promise, e); 64000 } 64001 } 64002 64003 exports.noop = noop; 64004 exports.resolve = resolve; 64005 exports.reject = reject; 64006 exports.fulfill = fulfill; 64007 exports.subscribe = subscribe; 64008 exports.publish = publish; 64009 exports.publishRejection = publishRejection; 64010 exports.initializePromise = initializePromise; 64011 exports.invokeCallback = invokeCallback; 64012 exports.FULFILLED = FULFILLED; 64013 exports.REJECTED = REJECTED; 64014 exports.PENDING = PENDING; 64015}); 64016enifed('rsvp/all-settled', ['exports', 'rsvp/enumerator', 'rsvp/promise', 'rsvp/utils'], function (exports, _rsvpEnumerator, _rsvpPromise, _rsvpUtils) { 64017 'use strict'; 64018 64019 exports.default = allSettled; 64020 64021 function AllSettled(Constructor, entries, label) { 64022 this._superConstructor(Constructor, entries, false, /* don't abort on reject */label); 64023 } 64024 64025 AllSettled.prototype = _rsvpUtils.o_create(_rsvpEnumerator.default.prototype); 64026 AllSettled.prototype._superConstructor = _rsvpEnumerator.default; 64027 AllSettled.prototype._makeResult = _rsvpEnumerator.makeSettledResult; 64028 AllSettled.prototype._validationError = function () { 64029 return new Error('allSettled must be called with an array'); 64030 }; 64031 64032 /** 64033 `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing 64034 a fail-fast method, it waits until all the promises have returned and 64035 shows you all the results. This is useful if you want to handle multiple 64036 promises' failure states together as a set. 64037 64038 Returns a promise that is fulfilled when all the given promises have been 64039 settled. The return promise is fulfilled with an array of the states of 64040 the promises passed into the `promises` array argument. 64041 64042 Each state object will either indicate fulfillment or rejection, and 64043 provide the corresponding value or reason. The states will take one of 64044 the following formats: 64045 64046 ```javascript 64047 { state: 'fulfilled', value: value } 64048 or 64049 { state: 'rejected', reason: reason } 64050 ``` 64051 64052 Example: 64053 64054 ```javascript 64055 var promise1 = RSVP.Promise.resolve(1); 64056 var promise2 = RSVP.Promise.reject(new Error('2')); 64057 var promise3 = RSVP.Promise.reject(new Error('3')); 64058 var promises = [ promise1, promise2, promise3 ]; 64059 64060 RSVP.allSettled(promises).then(function(array){ 64061 // array == [ 64062 // { state: 'fulfilled', value: 1 }, 64063 // { state: 'rejected', reason: Error }, 64064 // { state: 'rejected', reason: Error } 64065 // ] 64066 // Note that for the second item, reason.message will be '2', and for the 64067 // third item, reason.message will be '3'. 64068 }, function(error) { 64069 // Not run. (This block would only be called if allSettled had failed, 64070 // for instance if passed an incorrect argument type.) 64071 }); 64072 ``` 64073 64074 @method allSettled 64075 @static 64076 @for RSVP 64077 @param {Array} entries 64078 @param {String} label - optional string that describes the promise. 64079 Useful for tooling. 64080 @return {Promise} promise that is fulfilled with an array of the settled 64081 states of the constituent promises. 64082 */ 64083 64084 function allSettled(entries, label) { 64085 return new AllSettled(_rsvpPromise.default, entries, label).promise; 64086 } 64087}); 64088enifed("rsvp/all", ["exports", "rsvp/promise"], function (exports, _rsvpPromise) { 64089 "use strict"; 64090 64091 exports.default = all; 64092 64093 /** 64094 This is a convenient alias for `RSVP.Promise.all`. 64095 64096 @method all 64097 @static 64098 @for RSVP 64099 @param {Array} array Array of promises. 64100 @param {String} label An optional label. This is useful 64101 for tooling. 64102 */ 64103 64104 function all(array, label) { 64105 return _rsvpPromise.default.all(array, label); 64106 } 64107}); 64108enifed('rsvp/asap', ['exports'], function (exports) { 64109 'use strict'; 64110 64111 exports.default = asap; 64112 var len = 0; 64113 var toString = ({}).toString; 64114 var vertxNext; 64115 64116 function asap(callback, arg) { 64117 queue[len] = callback; 64118 queue[len + 1] = arg;
64119 len += 2; 64120 if (len === 2) { 64121 // If len is 1, that means that we need to schedule an async flush. 64122 // If additional callbacks are queued before the queue is flushed, they 64123 // will be processed by this flush that we are scheduling. 64124 scheduleFlush(); 64125 } 64126 } 64127 64128 var browserWindow = typeof window !== 'undefined' ? window : undefined; 64129 var browserGlobal = browserWindow || {}; 64130 var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; 64131 var isNode = typeof window === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]'; 64132 64133 // test for web worker but not in IE10 64134 var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; 64135 64136 // node 64137 function useNextTick() { 64138 var nextTick = process.nextTick; 64139 // node version 0.10.x displays a deprecation warning when nextTick is used recursively 64140 // setImmediate should be used instead instead 64141 var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/); 64142 if (Array.isArray(version) && version[1] === '0' && version[2] === '10') { 64143 nextTick = setImmediate; 64144 } 64145 return function () { 64146 nextTick(flush); 64147 }; 64148 } 64149 64150 // vertx 64151 function useVertxTimer() { 64152 return function () { 64153 vertxNext(flush); 64154 }; 64155 } 64156 64157 function useMutationObserver() { 64158 var iterations = 0; 64159 var observer = new BrowserMutationObserver(flush); 64160 var node = document.createTextNode(''); 64161 observer.observe(node, { characterData: true }); 64162 64163 return function () { 64164 node.data = iterations = ++iterations % 2; 64165 }; 64166 } 64167 64168 // web worker 64169 function useMessageChannel() { 64170 var channel = new MessageChannel(); 64171 channel.port1.onmessage = flush; 64172 return function () { 64173 channel.port2.postMessage(0); 64174 }; 64175 } 64176 64177 function useSetTimeout() { 64178 return function () { 64179 setTimeout(flush, 1); 64180 }; 64181 } 64182 64183 var queue = new Array(1000); 64184 function flush() { 64185 for (var i = 0; i < len; i += 2) { 64186 var callback = queue[i]; 64187 var arg = queue[i + 1]; 64188 64189 callback(arg); 64190 64191 queue[i] = undefined; 64192 queue[i + 1] = undefined; 64193 } 64194 64195 len = 0; 64196 } 64197 64198 function attemptVertex() { 64199 try { 64200 var r = require; 64201 var vertx = r('vertx'); 64202 vertxNext = vertx.runOnLoop || vertx.runOnContext; 64203 return useVertxTimer(); 64204 } catch (e) { 64205 return useSetTimeout(); 64206 } 64207 } 64208 64209 var scheduleFlush; 64210 // Decide what async method to use to triggering processing of queued callbacks: 64211 if (isNode) { 64212 scheduleFlush = useNextTick(); 64213 } else if (BrowserMutationObserver) { 64214 scheduleFlush = useMutationObserver(); 64215 } else if (isWorker) { 64216 scheduleFlush = useMessageChannel(); 64217 } else if (browserWindow === undefined && typeof require === 'function') { 64218 scheduleFlush = attemptVertex(); 64219 } else { 64220 scheduleFlush = useSetTimeout(); 64221 } 64222}); 64223enifed('rsvp/config', ['exports', 'rsvp/events'], function (exports, _rsvpEvents) { 64224 'use strict'; 64225 64226 var config = { 64227 instrument: false 64228 }; 64229 64230 _rsvpEvents.default['mixin'](config); 64231 64232 function configure(name, value) { 64233 if (name === 'onerror') { 64234 // handle for legacy users that expect the actual 64235 // error to be passed to their function added via 64236 // `RSVP.configure('onerror', someFunctionHere);` 64237 config['on']('error', value); 64238 return; 64239 } 64240 64241 if (arguments.length === 2) { 64242 config[name] = value; 64243 } else { 64244 return config[name]; 64245 } 64246 } 64247 64248 exports.config = config; 64249 exports.configure = configure; 64250}); 64251enifed('rsvp/defer', ['exports', 'rsvp/promise'], function (exports, _rsvpPromise) { 64252 'use strict'; 64253 64254 exports.default = defer; 64255 64256 /** 64257 `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. 64258 `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s 64259 interface. New code should use the `RSVP.Promise` constructor instead. 64260 64261 The object returned from `RSVP.defer` is a plain object with three properties: 64262 64263 * promise - an `RSVP.Promise`. 64264 * reject - a function that causes the `promise` property on this object to 64265 become rejected 64266 * resolve - a function that causes the `promise` property on this object to 64267 become fulfilled. 64268 64269 Example: 64270 64271 ```javascript 64272 var deferred = RSVP.defer(); 64273 64274 deferred.resolve("Success!"); 64275 64276 deferred.promise.then(function(value){ 64277 // value here is "Success!" 64278 }); 64279 ``` 64280 64281 @method defer 64282 @static 64283 @for RSVP 64284 @param {String} label optional string for labeling the promise. 64285 Useful for tooling. 64286 @return {Object} 64287 */ 64288 64289 function defer(label) { 64290 var deferred = {}; 64291 64292 deferred['promise'] = new _rsvpPromise.default(function (resolve, reject) { 64293 deferred['resolve'] = resolve; 64294 deferred['reject'] = reject; 64295 }, label); 64296 64297 return deferred; 64298 } 64299}); 64300enifed('rsvp/enumerator', ['exports', 'rsvp/utils', 'rsvp/-internal'], function (exports, _rsvpUtils, _rsvpInternal) { 64301 'use strict'; 64302 64303 exports.makeSettledResult = makeSettledResult; 64304 64305 function makeSettledResult(state, position, value) { 64306 if (state === _rsvpInternal.FULFILLED) { 64307 return { 64308 state: 'fulfilled', 64309 value: value 64310 }; 64311 } else { 64312 return { 64313 state: 'rejected', 64314 reason: value 64315 }; 64316 } 64317 } 64318 64319 function Enumerator(Constructor, input, abortOnReject, label) { 64320 var enumerator = this; 64321 64322 enumerator._instanceConstructor = Constructor; 64323 enumerator.promise = new Constructor(_rsvpInternal.noop, label); 64324 enumerator._abortOnReject = abortOnReject; 64325 64326 if (enumerator._validateInput(input)) { 64327 enumerator._input = input; 64328 enumerator.length = input.length; 64329 enumerator._remaining = input.length; 64330 64331 enumerator._init(); 64332 64333 if (enumerator.length === 0) { 64334 _rsvpInternal.fulfill(enumerator.promise, enumerator._result); 64335 } else { 64336 enumerator.length = enumerator.length || 0; 64337 enumerator._enumerate(); 64338 if (enumerator._remaining === 0) { 64339 _rsvpInternal.fulfill(enumerator.promise, enumerator._result); 64340 } 64341 } 64342 } else { 64343 _rsvpInternal.reject(enumerator.promise, enumerator._validationError()); 64344 } 64345 } 64346 64347 exports.default = Enumerator; 64348 64349 Enumerator.prototype._validateInput = function (input) { 64350 return _rsvpUtils.isArray(input); 64351 }; 64352 64353 Enumerator.prototype._validationError = function () { 64354 return new Error('Array Methods must be provided an Array'); 64355 }; 64356 64357 Enumerator.prototype._init = function () { 64358 this._result = new Array(this.length); 64359 }; 64360 64361 Enumerator.prototype._enumerate = function () { 64362 var enumerator = this; 64363 var length = enumerator.length; 64364 var promise = enumerator.promise; 64365 var input = enumerator._input; 64366 64367 for (var i = 0; promise._state === _rsvpInternal.PENDING && i < length; i++) { 64368 enumerator._eachEntry(input[i], i); 64369 } 64370 }; 64371 64372 Enumerator.prototype._eachEntry = function (entry, i) { 64373 var enumerator = this; 64374 var c = enumerator._instanceConstructor; 64375 if (_rsvpUtils.isMaybeThenable(entry)) { 64376 if (entry.constructor === c && entry._state !== _rsvpInternal.PENDING) { 64377 entry._onError = null; 64378 enumerator._settledAt(entry._state, i, entry._result); 64379 } else { 64380 enumerator._willSettleAt(c.resolve(entry), i); 64381 } 64382 } else { 64383 enumerator._remaining--; 64384 enumerator._result[i] = enumerator._makeResult(_rsvpInternal.FULFILLED, i, entry); 64385 } 64386 }; 64387 64388 Enumerator.prototype._settledAt = function (state, i, value) { 64389 var enumerator = this; 64390 var promise = enumerator.promise; 64391 64392 if (promise._state === _rsvpInternal.PENDING) { 64393 enumerator._remaining--; 64394 64395 if (enumerator._abortOnReject && state === _rsvpInternal.REJECTED) { 64396 _rsvpInternal.reject(promise, value); 64397 } else { 64398 enumerator._result[i] = enumerator._makeResult(state, i, value); 64399 } 64400 } 64401 64402 if (enumerator._remaining === 0) { 64403 _rsvpInternal.fulfill(promise, enumerator._result); 64404 } 64405 }; 64406 64407 Enumerator.prototype._makeResult = function (state, i, value) { 64408 return value; 64409 }; 64410 64411 Enumerator.prototype._willSettleAt = function (promise, i) { 64412 var enumerator = this; 64413 64414 _rsvpInternal.subscribe(promise, undefined, function (value) { 64415 enumerator._settledAt(_rsvpInternal.FULFILLED, i, value); 64416 }, function (reason) { 64417 enumerator._settledAt(_rsvpInternal.REJECTED, i, reason); 64418 }); 64419 }; 64420}); 64421enifed('rsvp/events', ['exports'], function (exports) { 64422 'use strict'; 64423 64424 function indexOf(callbacks, callback) { 64425 for (var i = 0, l = callbacks.length; i < l; i++) { 64426 if (callbacks[i] === callback) { 64427 return i; 64428 } 64429 } 64430 64431 return -1; 64432 } 64433 64434 function callbacksFor(object) { 64435 var callbacks = object._promiseCallbacks; 64436 64437 if (!callbacks) { 64438 callbacks = object._promiseCallbacks = {}; 64439 } 64440 64441 return callbacks; 64442 } 64443 64444 /** 64445 @class RSVP.EventTarget 64446 */ 64447 exports.default = { 64448 64449 /** 64450 `RSVP.EventTarget.mixin` extends an object with EventTarget methods. For 64451 Example: 64452 ```javascript 64453 var object = {}; 64454 RSVP.EventTarget.mixin(object); 64455 object.on('finished', function(event) { 64456 // handle event 64457 }); 64458 object.trigger('finished', { detail: value }); 64459 ``` 64460 `EventTarget.mixin` also works with prototypes: 64461 ```javascript 64462 var Person = function() {}; 64463 RSVP.EventTarget.mixin(Person.prototype); 64464 var yehuda = new Person(); 64465 var tom = new Person(); 64466 yehuda.on('poke', function(event) { 64467 console.log('Yehuda says OW'); 64468 }); 64469 tom.on('poke', function(event) { 64470 console.log('Tom says OW'); 64471 }); 64472 yehuda.trigger('poke'); 64473 tom.trigger('poke'); 64474 ``` 64475 @method mixin 64476 @for RSVP.EventTarget 64477 @private 64478 @param {Object} object object to extend with EventTarget methods 64479 */ 64480 'mixin': function (object) { 64481 object['on'] = this['on']; 64482 object['off'] = this['off']; 64483 object['trigger'] = this['trigger']; 64484 object._promiseCallbacks = undefined; 64485 return object; 64486 }, 64487 64488 /** 64489 Registers a callback to be executed when `eventName` is triggered 64490 ```javascript 64491 object.on('event', function(eventInfo){ 64492 // handle the event 64493 }); 64494 object.trigger('event'); 64495 ``` 64496 @method on 64497 @for RSVP.EventTarget 64498 @private 64499 @param {String} eventName name of the event to listen for 64500 @param {Function} callback function to be called when the event is triggered. 64501 */ 64502 'on': function (eventName, callback) { 64503 if (typeof callback !== 'function') { 64504 throw new TypeError('Callback must be a function'); 64505 } 64506 64507 var allCallbacks = callbacksFor(this), 64508 callbacks; 64509 64510 callbacks = allCallbacks[eventName]; 64511 64512 if (!callbacks) { 64513 callbacks = allCallbacks[eventName] = []; 64514 } 64515 64516 if (indexOf(callbacks, callback) === -1) { 64517 callbacks.push(callback); 64518 } 64519 }, 64520 64521 /** 64522 You can use `off` to stop firing a particular callback for an event: 64523 ```javascript 64524 function doStuff() { // do stuff! } 64525 object.on('stuff', doStuff); 64526 object.trigger('stuff'); // doStuff will be called 64527 // Unregister ONLY the doStuff callback 64528 object.off('stuff', doStuff); 64529 object.trigger('stuff'); // doStuff will NOT be called 64530 ``` 64531 If you don't pass a `callback` argument to `off`, ALL callbacks for the 64532 event will not be executed when the event fires. For example: 64533 ```javascript 64534 var callback1 = function(){}; 64535 var callback2 = function(){}; 64536 object.on('stuff', callback1); 64537 object.on('stuff', callback2); 64538 object.trigger('stuff'); // callback1 and callback2 will be executed. 64539 object.off('stuff'); 64540 object.trigger('stuff'); // callback1 and callback2 will not be executed! 64541 ``` 64542 @method off 64543 @for RSVP.EventTarget 64544 @private 64545 @param {String} eventName event to stop listening to 64546 @param {Function} callback optional argument. If given, only the function 64547 given will be removed from the event's callback queue. If no `callback` 64548 argument is given, all callbacks will be removed from the event's callback 64549 queue. 64550 */ 64551 'off': function (eventName, callback) { 64552 var allCallbacks = callbacksFor(this), 64553 callbacks, 64554 index; 64555 64556 if (!callback) { 64557 allCallbacks[eventName] = []; 64558 return; 64559 } 64560 64561 callbacks = allCallbacks[eventName]; 64562 64563 index = indexOf(callbacks, callback); 64564 64565 if (index !== -1) { 64566 callbacks.splice(index, 1); 64567 } 64568 }, 64569 64570 /** 64571 Use `trigger` to fire custom events. For example: 64572 ```javascript 64573 object.on('foo', function(){ 64574 console.log('foo event happened!'); 64575 }); 64576 object.trigger('foo'); 64577 // 'foo event happened!' logged to the console 64578 ``` 64579 You can also pass a value as a second argument to `trigger` that will be 64580 passed as an argument to all event listeners for the event: 64581 ```javascript 64582 object.on('foo', function(value){ 64583 console.log(value.name); 64584 }); 64585 object.trigger('foo', { name: 'bar' }); 64586 // 'bar' logged to the console 64587 ``` 64588 @method trigger 64589 @for RSVP.EventTarget 64590 @private 64591 @param {String} eventName name of the event to be triggered 64592 @param {*} options optional value to be passed to any event handlers for 64593 the given `eventName` 64594 */ 64595 'trigger': function (eventName, options) { 64596 var allCallbacks = callbacksFor(this), 64597 callbacks, 64598 callback; 64599 64600 if (callbacks = allCallbacks[eventName]) { 64601 // Don't cache the callbacks.length since it may grow 64602 for (var i = 0; i < callbacks.length; i++) { 64603 callback = callbacks[i]; 64604 64605 callback(options); 64606 } 64607 } 64608 } 64609 }; 64610}); 64611enifed('rsvp/filter', ['exports', 'rsvp/promise', 'rsvp/utils'], function (exports, _rsvpPromise, _rsvpUtils) { 64612 'use strict'; 64613 64614 exports.default = filter; 64615 64616 /** 64617 `RSVP.filter` is similar to JavaScript's native `filter` method, except that it 64618 waits for all promises to become fulfilled before running the `filterFn` on 64619 each item in given to `promises`. `RSVP.filter` returns a promise that will 64620 become fulfilled with the result of running `filterFn` on the values the 64621 promises become fulfilled with. 64622 64623 For example: 64624 64625 ```javascript 64626 64627 var promise1 = RSVP.resolve(1); 64628 var promise2 = RSVP.resolve(2); 64629 var promise3 = RSVP.resolve(3); 64630 64631 var promises = [promise1, promise2, promise3]; 64632 64633 var filterFn = function(item){ 64634 return item > 1; 64635 }; 64636 64637 RSVP.filter(promises, filterFn).then(function(result){ 64638 // result is [ 2, 3 ] 64639 }); 64640 ``` 64641 64642 If any of the `promises` given to `RSVP.filter` are rejected, the first promise 64643 that is rejected will be given as an argument to the returned promise's 64644 rejection handler. For example: 64645 64646 ```javascript 64647 var promise1 = RSVP.resolve(1); 64648 var promise2 = RSVP.reject(new Error('2')); 64649 var promise3 = RSVP.reject(new Error('3')); 64650 var promises = [ promise1, promise2, promise3 ]; 64651 64652 var filterFn = function(item){ 64653 return item > 1; 64654 }; 64655 64656 RSVP.filter(promises, filterFn).then(function(array){ 64657 // Code here never runs because there are rejected promises! 64658 }, function(reason) { 64659 // reason.message === '2' 64660 }); 64661 ``` 64662 64663 `RSVP.filter` will also wait for any promises returned from `filterFn`. 64664 For instance, you may want to fetch a list of users then return a subset 64665 of those users based on some asynchronous operation: 64666 64667 ```javascript 64668 64669 var alice = { name: 'alice' }; 64670 var bob = { name: 'bob' }; 64671 var users = [ alice, bob ]; 64672 64673 var promises = users.map(function(user){ 64674 return RSVP.resolve(user); 64675 }); 64676 64677 var filterFn = function(user){ 64678 // Here, Alice has permissions to create a blog post, but Bob does not. 64679 return getPrivilegesForUser(user).then(function(privs){ 64680 return privs.can_create_blog_post === true; 64681 }); 64682 }; 64683 RSVP.filter(promises, filterFn).then(function(users){ 64684 // true, because the server told us only Alice can create a blog post. 64685 users.length
64685 === 1; 64686 // false, because Alice is the only user present in `users` 64687 users[0] === bob; 64688 }); 64689 ``` 64690 64691 @method filter 64692 @static 64693 @for RSVP 64694 @param {Array} promises 64695 @param {Function} filterFn - function to be called on each resolved value to 64696 filter the final results. 64697 @param {String} label optional string describing the promise. Useful for 64698 tooling. 64699 @return {Promise} 64700 */ 64701 64702 function filter(promises, filterFn, label) { 64703 return _rsvpPromise.default.all(promises, label).then(function (values) { 64704 if (!_rsvpUtils.isFunction(filterFn)) { 64705 throw new TypeError("You must pass a function as filter's second argument."); 64706 } 64707 64708 var length = values.length; 64709 var filtered = new Array(length); 64710 64711 for (var i = 0; i < length; i++) { 64712 filtered[i] = filterFn(values[i]); 64713 } 64714 64715 return _rsvpPromise.default.all(filtered, label).then(function (filtered) { 64716 var results = new Array(length); 64717 var newLength = 0; 64718 64719 for (var i = 0; i < length; i++) { 64720 if (filtered[i]) { 64721 results[newLength] = values[i]; 64722 newLength++; 64723 } 64724 } 64725 64726 results.length = newLength; 64727 64728 return results; 64729 }); 64730 }); 64731 } 64732}); 64733enifed('rsvp/hash-settled', ['exports', 'rsvp/promise', 'rsvp/enumerator', 'rsvp/promise-hash', 'rsvp/utils'], function (exports, _rsvpPromise, _rsvpEnumerator, _rsvpPromiseHash, _rsvpUtils) { 64734 'use strict'; 64735 64736 exports.default = hashSettled; 64737 64738 function HashSettled(Constructor, object, label) { 64739 this._superConstructor(Constructor, object, false, label); 64740 } 64741 64742 HashSettled.prototype = _rsvpUtils.o_create(_rsvpPromiseHash.default.prototype); 64743 HashSettled.prototype._superConstructor = _rsvpEnumerator.default; 64744 HashSettled.prototype._makeResult = _rsvpEnumerator.makeSettledResult; 64745 64746 HashSettled.prototype._validationError = function () { 64747 return new Error('hashSettled must be called with an object'); 64748 }; 64749 64750 /** 64751 `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object 64752 instead of an array for its `promises` argument. 64753 64754 Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, 64755 but like `RSVP.allSettled`, `hashSettled` waits until all the 64756 constituent promises have returned and then shows you all the results 64757 with their states and values/reasons. This is useful if you want to 64758 handle multiple promises' failure states together as a set. 64759 64760 Returns a promise that is fulfilled when all the given promises have been 64761 settled, or rejected if the passed parameters are invalid. 64762 64763 The returned promise is fulfilled with a hash that has the same key names as 64764 the `promises` object argument. If any of the values in the object are not 64765 promises, they will be copied over to the fulfilled object and marked with state 64766 'fulfilled'. 64767 64768 Example: 64769 64770 ```javascript 64771 var promises = { 64772 myPromise: RSVP.Promise.resolve(1), 64773 yourPromise: RSVP.Promise.resolve(2), 64774 theirPromise: RSVP.Promise.resolve(3), 64775 notAPromise: 4 64776 }; 64777 64778 RSVP.hashSettled(promises).then(function(hash){ 64779 // hash here is an object that looks like: 64780 // { 64781 // myPromise: { state: 'fulfilled', value: 1 }, 64782 // yourPromise: { state: 'fulfilled', value: 2 }, 64783 // theirPromise: { state: 'fulfilled', value: 3 }, 64784 // notAPromise: { state: 'fulfilled', value: 4 } 64785 // } 64786 }); 64787 ``` 64788 64789 If any of the `promises` given to `RSVP.hash` are rejected, the state will 64790 be set to 'rejected' and the reason for rejection provided. 64791 64792 Example: 64793 64794 ```javascript 64795 var promises = { 64796 myPromise: RSVP.Promise.resolve(1), 64797 rejectedPromise: RSVP.Promise.reject(new Error('rejection')), 64798 anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), 64799 }; 64800 64801 RSVP.hashSettled(promises).then(function(hash){ 64802 // hash here is an object that looks like: 64803 // { 64804 // myPromise: { state: 'fulfilled', value: 1 }, 64805 // rejectedPromise: { state: 'rejected', reason: Error }, 64806 // anotherRejectedPromise: { state: 'rejected', reason: Error }, 64807 // } 64808 // Note that for rejectedPromise, reason.message == 'rejection', 64809 // and for anotherRejectedPromise, reason.message == 'more rejection'. 64810 }); 64811 ``` 64812 64813 An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that 64814 are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype 64815 chains. 64816 64817 Example: 64818 64819 ```javascript 64820 function MyConstructor(){ 64821 this.example = RSVP.Promise.resolve('Example'); 64822 } 64823 64824 MyConstructor.prototype = { 64825 protoProperty: RSVP.Promise.resolve('Proto Property') 64826 }; 64827 64828 var myObject = new MyConstructor(); 64829 64830 RSVP.hashSettled(myObject).then(function(hash){ 64831 // protoProperty will not be present, instead you will just have an 64832 // object that looks like: 64833 // {
64834 // example: { state: 'fulfilled', value: 'Example' } 64835 // } 64836 // 64837 // hash.hasOwnProperty('protoProperty'); // false 64838 // 'undefined' === typeof hash.protoProperty 64839 }); 64840 ``` 64841 64842 @method hashSettled 64843 @for RSVP 64844 @param {Object} object 64845 @param {String} label optional string that describes the promise. 64846 Useful for tooling. 64847 @return {Promise} promise that is fulfilled when when all properties of `promises` 64848 have been settled. 64849 @static 64850 */ 64851 64852 function hashSettled(object, label) { 64853 return new HashSettled(_rsvpPromise.default, object, label).promise; 64854 } 64855}); 64856enifed('rsvp/hash', ['exports', 'rsvp/promise', 'rsvp/promise-hash'], function (exports, _rsvpPromise, _rsvpPromiseHash) { 64857 'use strict'; 64858 64859 exports.default = hash; 64860 64861 /** 64862 `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array 64863 for its `promises` argument. 64864 64865 Returns a promise that is fulfilled when all the given promises have been 64866 fulfilled, or rejected if any of them become rejected. The returned promise 64867 is fulfilled with a hash that has the same key names as the `promises` object 64868 argument. If any of the values in the object are not promises, they will 64869 simply be copied over to the fulfilled object. 64870 64871 Example: 64872 64873 ```javascript 64874 var promises = { 64875 myPromise: RSVP.resolve(1), 64876 yourPromise: RSVP.resolve(2), 64877 theirPromise: RSVP.resolve(3), 64878 notAPromise: 4 64879 }; 64880 64881 RSVP.hash(promises).then(function(hash){ 64882 // hash here is an object that looks like: 64883 // { 64884 // myPromise: 1, 64885 // yourPromise: 2, 64886 // theirPromise: 3, 64887 // notAPromise: 4 64888 // } 64889 }); 64890 ```` 64891 64892 If any of the `promises` given to `RSVP.hash` are rejected, the first promise 64893 that is rejected will be given as the reason to the rejection handler. 64894 64895 Example: 64896 64897 ```javascript 64898 var promises = { 64899 myPromise: RSVP.resolve(1), 64900 rejectedPromise: RSVP.reject(new Error('rejectedPromise')), 64901 anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), 64902 }; 64903 64904 RSVP.hash(promises).then(function(hash){ 64905 // Code here never runs because there are rejected promises! 64906 }, function(reason) { 64907 // reason.message === 'rejectedPromise' 64908 }); 64909 ``` 64910 64911 An important note: `RSVP.hash` is intended for plain JavaScript objects that 64912 are just a set of keys and values. `RSVP.hash` will NOT preserve prototype 64913 chains. 64914 64915 Example: 64916 64917 ```javascript 64918 function MyConstructor(){ 64919 this.example = RSVP.resolve('Example'); 64920 } 64921 64922 MyConstructor.prototype = { 64923 protoProperty: RSVP.resolve('Proto Property') 64924 }; 64925 64926 var myObject = new MyConstructor(); 64927 64928 RSVP.hash(myObject).then(function(hash){ 64929 // protoProperty will not be present, instead you will just have an 64930 // object that looks like: 64931 // { 64932 // example: 'Example' 64933 // } 64934 // 64935 // hash.hasOwnProperty('protoProperty'); // false 64936 // 'undefined' === typeof hash.protoProperty 64937 }); 64938 ``` 64939 64940 @method hash 64941 @static 64942 @for RSVP 64943 @param {Object} object 64944 @param {String} label optional string that describes the promise. 64945 Useful for tooling. 64946 @return {Promise} promise that is fulfilled when all properties of `promises` 64947 have been fulfilled, or rejected if any of them become rejected. 64948 */ 64949 64950 function hash(object, label) { 64951 return new _rsvpPromiseHash.default(_rsvpPromise.default, object, label).promise; 64952 } 64953}); 64954enifed('rsvp/instrument', ['exports', 'rsvp/config', 'rsvp/utils'], function (exports, _rsvpConfig, _rsvpUtils) { 64955 'use strict'; 64956 64957 exports.default = instrument; 64958 64959 var queue = []; 64960 64961 function scheduleFlush() { 64962 setTimeout(function () { 64963 var entry; 64964 for (var i = 0; i < queue.length; i++) { 64965 entry = queue[i]; 64966 64967 var payload = entry.payload; 64968 64969 payload.guid = payload.key + payload.id; 64970 payload.childGuid = payload.key + payload.childId; 64971 if (payload.error) { 64972 payload.stack = payload.error.stack; 64973 } 64974 64975 _rsvpConfig.config['trigger'](entry.name, entry.payload); 64976 } 64977 queue.length = 0; 64978 }, 50); 64979 } 64980
64981 function instrument(eventName, promise, child) { 64982 if (1 === queue.push({ 64983 name: eventName, 64984 payload: { 64985 key: promise._guidKey, 64986 id: promise._id, 64987 eventName: eventName, 64988 detail: promise._result, 64989 childId: child && child._id, 64990 label: promise._label, 64991 timeStamp: _rsvpUtils.now(), 64992 error: _rsvpConfig.config["instrument-with-stack"] ? new Error(promise._label) : null 64993 } })) { 64994 scheduleFlush(); 64995 } 64996 } 64997}); 64998enifed('rsvp/map', ['exports', 'rsvp/promise', 'rsvp/utils'], function (exports, _rsvpPromise, _rsvpUtils) { 64999 'use strict'; 65000 65001 exports.default = map; 65002 65003 /** 65004 `RSVP.map` is similar to JavaScript's native `map` method, except that it 65005 waits for all promises to become fulfilled before running the `mapFn` on 65006 each item in given to `promises`. `RSVP.map` returns a promise that will 65007 become fulfilled with the result of running `mapFn` on the values the promises 65008 become fulfilled with. 65009 65010 For example: 65011 65012 ```javascript 65013 65014 var promise1 = RSVP.resolve(1); 65015 var promise2 = RSVP.resolve(2); 65016 var promise3 = RSVP.resolve(3); 65017 var promises = [ promise1, promise2, promise3 ]; 65018 65019 var mapFn = function(item){ 65020 return item + 1; 65021 }; 65022 65023 RSVP.map(promises, mapFn).then(function(result){ 65024 // result is [ 2, 3, 4 ] 65025 }); 65026 ``` 65027 65028 If any of the `promises` given to `RSVP.map` are rejected, the first promise 65029 that is rejected will be given as an argument to the returned promise's 65030 rejection handler. For example: 65031 65032 ```javascript 65033 var promise1 = RSVP.resolve(1); 65034 var promise2 = RSVP.reject(new Error('2')); 65035 var promise3 = RSVP.reject(new Error('3')); 65036 var promises = [ promise1, promise2, promise3 ]; 65037 65038 var mapFn = function(item){ 65039 return item + 1; 65040 }; 65041 65042 RSVP.map(promises, mapFn).then(function(array){ 65043 // Code here never runs because there are rejected promises! 65044 }, function(reason) { 65045 // reason.message === '2' 65046 }); 65047 ``` 65048 65049 `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, 65050 say you want to get all comments from a set of blog posts, but you need 65051 the blog posts first because they contain a url to those comments. 65052 65053 ```javscript 65054 65055 var mapFn = function(blogPost){ 65056 // getComments does some ajax and returns an RSVP.Promise that is fulfilled 65057 // with some comments data 65058 return getComments(blogPost.comments_url); 65059 }; 65060 65061 // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled 65062 // with some blog post data 65063 RSVP.map(getBlogPosts(), mapFn).then(function(comments){ 65064 // comments is the result of asking the server for the comments 65065 // of all blog posts returned from getBlogPosts() 65066 }); 65067 ``` 65068 65069 @method map 65070 @static 65071 @for RSVP 65072 @param {Array} promises 65073 @param {Function} mapFn function to be called on each fulfilled promise. 65074 @param {String} label optional string for labeling the promise. 65075 Useful for tooling. 65076 @return {Promise} promise that is fulfilled with the result of calling 65077 `mapFn` on each fulfilled promise or value when they become fulfilled. 65078 The promise will be rejected if any of the given `promises` become rejected. 65079 @static 65080 */ 65081 65082 function map(promises, mapFn, label) { 65083 return _rsvpPromise.default.all(promises, label).then(function (values) { 65084 if (!_rsvpUtils.isFunction(mapFn)) { 65085 throw new TypeError("You must pass a function as map's second argument."); 65086 } 65087 65088 var length = values.length; 65089 var results = new Array(length); 65090 65091 for (var i = 0; i < length; i++) { 65092 results[i] = mapFn(values[i]); 65093 } 65094 65095 return _rsvpPromise.default.all(results, label); 65096 }); 65097 } 65098}); 65099enifed('rsvp/node', ['exports', 'rsvp/promise', 'rsvp/-internal', 'rsvp/utils'], function (exports, _rsvpPromise, _rsvpInternal, _rsvpUtils) { 65100 'use strict'; 65101 65102 exports.default = denodeify; 65103 65104 function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Ob
65104ject.defineProperty(obj, key, value); } } return obj; } 65105 65106 function Result() { 65107 this.value = undefined; 65108 } 65109 65110 var ERROR = new Result(); 65111 var GET_THEN_ERROR = new Result(); 65112 65113 function getThen(obj) { 65114 try { 65115 return obj.then; 65116 } catch (error) { 65117 ERROR.value = error; 65118 return ERROR; 65119 } 65120 } 65121 65122 function tryApply(f, s, a) { 65123 try { 65124 f.apply(s, a); 65125 } catch (error) { 65126 ERROR.value = error; 65127 return ERROR; 65128 } 65129 } 65130 65131 function makeObject(_, argumentNames) { 65132 var obj = {}; 65133 var name; 65134 var i; 65135 var length = _.length; 65136 var args = new Array(length); 65137 65138 for (var x = 0; x < length; x++) { 65139 args[x] = _[x]; 65140 } 65141 65142 for (i = 0; i < argumentNames.length; i++) { 65143 name = argumentNames[i]; 65144 obj[name] = args[i + 1]; 65145 } 65146 65147 return obj; 65148 } 65149 65150 function arrayResult(_) { 65151 var length = _.length; 65152 var args = new Array(length - 1); 65153 65154 for (var i = 1; i < length; i++) { 65155 args[i - 1] = _[i]; 65156 } 65157 65158 return args; 65159 } 65160 65161 function wrapThenable(then, promise) { 65162 return { 65163 then: function (onFulFillment, onRejection) { 65164 return then.call(promise, onFulFillment, onRejection); 65165 } 65166 }; 65167 } 65168 65169 /** 65170 `RSVP.denodeify` takes a 'node-style' function and returns a function that 65171 will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the 65172 browser when you'd prefer to use promises over using callbacks. For example, 65173 `denodeify` transforms the following: 65174 65175 ```javascript 65176 var fs = require('fs'); 65177 65178 fs.readFile('myfile.txt', function(err, data){ 65179 if (err) return handleError(err); 65180 handleData(data); 65181 }); 65182 ``` 65183 65184 into: 65185 65186 ```javascript 65187 var fs = require('fs'); 65188 var readFile = RSVP.denodeify(fs.readFile); 65189
65190 readFile('myfile.txt').then(handleData, handleError); 65191 ``` 65192 65193 If the node function has multiple success parameters, then `denodeify` 65194 just returns the first one: 65195 65196 ```javascript 65197 var request = RSVP.denodeify(require('request')); 65198 65199 request('http://example.com').then(function(res) { 65200 // ... 65201 }); 65202 ``` 65203 65204 However, if you need all success parameters, setting `denodeify`'s 65205 second parameter to `true` causes it to return all success parameters 65206 as an array: 65207 65208 ```javascript 65209 var request = RSVP.denodeify(require('request'), true); 65210 65211 request('http://example.com').then(function(result) { 65212 // result[0] -> res 65213 // result[1] -> body 65214 }); 65215 ``` 65216 65217 Or if you pass it an array with names it returns the parameters as a hash: 65218 65219 ```javascript 65220 var request = RSVP.denodeify(require('request'), ['res', 'body']); 65221 65222 request('http://example.com').then(function(result) { 65223 // result.res 65224 // result.body 65225 }); 65226 ``` 65227 65228 Sometimes you need to retain the `this`: 65229 65230 ```javascript 65231 var app = require('express')(); 65232 var render = RSVP.denodeify(app.render.bind(app)); 65233 ``` 65234 65235 The denodified function inherits from the original function. It works in all 65236 environments, except IE 10 and below. Consequently all properties of the original 65237 function are available to you. However, any properties you change on the 65238 denodeified function won't be changed on the original function. Example: 65239 65240 ```javascript 65241 var request = RSVP.denodeify(require('request')), 65242 cookieJar = request.jar(); // <- Inheritance is used here 65243 65244 request('http://example.com', {jar: cookieJar}).then(function(res) { 65245 // cookieJar.cookies holds now the cookies returned by example.com 65246 }); 65247 ``` 65248 65249 Using `denodeify` makes it easier to compose asynchronous operations instead 65250 of using callbacks. For example, instead of: 65251 65252 ```javascript 65253 var fs = require('fs'); 65254 65255 fs.readFile('myfile.txt', function(err, data){ 65256 if (err) { ... } // Handle error 65257 fs.writeFile('myfile2.txt', data, function(err){ 65258 if (err) { ... } // Handle error 65259 console.log('done') 65260 }); 65261 }); 65262 ``` 65263 65264 you can chain the operations together using `then` from the returned promise: 65265 65266 ```javascript 65267 var fs = require('fs'); 65268 var readFile = RSVP.denodeify(fs.readFile); 65269 var writeFile = RSVP.denodeify(fs.writeFile); 65270 65271 readFile('myfile.txt').then(function(data){ 65272 return writeFile('myfile2.txt', data); 65273 }).then(function(){ 65274 console.log('done') 65275 }).catch(function(error){ 65276 // Handle error 65277 }); 65278 ``` 65279 65280 @method denodeify 65281 @static 65282 @for RSVP 65283 @param {Function} nodeFunc a 'node-style' function that takes a callback as 65284 its last argument. The callback expects an error to be passed as its first 65285 argument (if an error occurred, otherwise null), and the value from the 65286 operation as its second argument ('function(err, value){ }'). 65287 @param {Boolean|Array} [options] An optional paramter that if set 65288 to `true` causes the promise to fulfill with the callback's success arguments 65289 as an array. This is useful if the node function has multiple success 65290 paramters. If you set this paramter to an array with names, the promise will 65291 fulfill with a hash with these names as keys and the success parameters as 65292 values. 65293 @return {Function} a function that wraps `nodeFunc` to return an 65294 `RSVP.Promise` 65295 @static 65296 */ 65297 65298 function denodeify(nodeFunc, options) { 65299 var fn = function () { 65300 var self = this; 65301 var l = arguments.length; 65302 var args = new Array(l + 1); 65303 var arg; 65304 var promiseInput = false; 65305 65306 for (var i = 0; i < l; ++i) { 65307 arg = arguments[i]; 65308 65309 if (!promiseInput) { 65310 // TODO: clean this up 65311 promiseInput = needsPromiseInput(arg); 65312 if (promiseInput === GET_THEN_ERROR) { 65313 var p = new _rsvpPromise.default(_rsvpInternal.noop); 65314 _rsvpInternal.reject(p, GET_THEN_ERROR.value); 65315 return p; 65316 } else if (promiseInput && promiseInput !== true) { 65317 arg = wrapThenable(promiseInput, arg); 65318 } 65319 } 65320 args[i] = arg;
65321 } 65322 65323 var promise = new _rsvpPromise.default(_rsvpInternal.noop); 65324 65325 args[l] = function (err, val) { 65326 if (err) _rsvpInternal.reject(promise, err);else if (options === undefined) _rsvpInternal.resolve(promise, val);else if (options === true) _rsvpInternal.resolve(promise, arrayResult(arguments));else if (_rsvpUtils.isArray(options)) _rsvpInternal.resolve(promise, makeObject(arguments, options));else _rsvpInternal.resolve(promise, val); 65327 }; 65328 65329 if (promiseInput) { 65330 return handlePromiseInput(promise, args, nodeFunc, self); 65331 } else { 65332 return handleValueInput(promise, args, nodeFunc, self); 65333 } 65334 }; 65335 65336 _defaults(fn, nodeFunc); 65337 65338 return fn; 65339 } 65340 65341 function handleValueInput(promise, args, nodeFunc, self) { 65342 var result = tryApply(nodeFunc, self, args); 65343 if (result === ERROR) { 65344 _rsvpInternal.reject(promise, result.value); 65345 } 65346 return promise; 65347 } 65348 65349 function handlePromiseInput(promise, args, nodeFunc, self) { 65350 return _rsvpPromise.default.all(args).then(function (args) { 65351 var result = tryApply(nodeFunc, self, args); 65352 if (result === ERROR) { 65353 _rsvpInternal.reject(promise, result.value); 65354 } 65355 return promise; 65356 }); 65357 } 65358 65359 function needsPromiseInput(arg) { 65360 if (arg && typeof arg === 'object') { 65361 if (arg.constructor === _rsvpPromise.default) { 65362 return true; 65363 } else { 65364 return getThen(arg); 65365 } 65366 } else { 65367 return false; 65368 } 65369 } 65370}); 65371enifed('rsvp/platform', ['exports'], function (exports) { 65372 'use strict'; 65373 65374 var platform; 65375 65376 /* global self */ 65377 if (typeof self === 'object') { 65378 platform = self; 65379 65380 /* global global */ 65381 } else if (typeof global === 'object') { 65382 platform = global; 65383 } else { 65384 throw new Error('no global: `self` or `global` found'); 65385 } 65386 65387 exports.default = platform; 65388}); 65389enifed('rsvp/promise/all', ['exports', 'rsvp/enumerator'], function (exports, _rsvpEnumerator) { 65390 'use strict'; 65391 65392 exports.default = all; 65393 65394 /** 65395 `RSVP.Promise.all` accepts an array of promises, and returns a new promise which 65396 is fulfilled with an array of fulfillment values for the passed promises, or 65397 rejected with the reason of the first passed promise to be rejected. It casts all 65398 elements of the passed iterable to promises as it runs this algorithm. 65399 65400 Example: 65401 65402 ```javascript 65403 var promise1 = RSVP.resolve(1); 65404 var promise2 = RSVP.resolve(2); 65405 var promise3 = RSVP.resolve(3); 65406 var promises = [ promise1, promise2, promise3 ]; 65407 65408 RSVP.Promise.all(promises).then(function(array){ 65409 // The array here would be [ 1, 2, 3 ]; 65410 }); 65411 ``` 65412 65413 If any of the `promises` given to `RSVP.all` are rejected, the first promise 65414 that is rejected will be given as an argument to the returned promises's 65415 rejection handler. For example: 65416 65417 Example: 65418 65419 ```javascript 65420 var promise1 = RSVP.resolve(1); 65421 var promise2 = RSVP.reject(new Error("2")); 65422 var promise3 = RSVP.reject(new Error("3")); 65423 var promises = [ promise1, promise2, promise3 ]; 65424 65425 RSVP.Promise.all(promises).then(function(array){ 65426 // Code here never runs because there are rejected promises! 65427 }, function(error) { 65428 // error.message === "2" 65429 }); 65430 ``` 65431 65432 @method all 65433 @static 65434 @param {Array} entries array of promises 65435 @param {String} label optional string for labeling the promise. 65436 Useful for tooling. 65437 @return {Promise} promise that is fulfilled when all `promises` have been 65438 fulfilled, or rejected if any of them become rejected. 65439 @static 65440 */ 65441 65442 function all(entries, label) { 65443 return new _rsvpEnumerator.default(this, entries, true, /* abort on reject */label).promise; 65444 } 65445}); 65446enifed('rsvp/promise/race', ['exports', 'rsvp/utils', 'rsvp/-internal'], function (exports, _rsvpUtils, _rsvpInternal) { 65447 'use strict'; 65448 65449 exports.default = race; 65450 65451 /** 65452 `RSVP.Promise.race` returns a new promise which is settled in the same way as the 65453 first passed promise to settle. 65454 65455 Example: 65456 65457 ```javascript 65458 var promise1 = new RSVP.Promise(function(resolve, reject){ 65459 setTimeout(function(){ 65460 resolve('promise 1'); 65461 }, 200); 65462 }); 65463 65464 var promise2 = new RSVP.Promise(function(resolve, reject){ 65465 setTimeout(function(){ 65466 resolve('promise 2'); 65467 }, 100); 65468 }); 65469 65470 RSVP.Promise.race([promise1, promise2]).then(function(result){ 65471 // result === 'promise 2' because it was resolved before promise1 65472 // was resolved. 65473 }); 65474 ``` 65475 65476 `RSVP.Promise.race` is deterministic in that only the state of the first 65477 settled promise matters. For example, even if other promises given to the 65478 `promises` array argument are resolved, but the first settled promise has 65479 become rejected before the other promises became fulfilled, the returned 65480 promise will become rejected: 65481 65482 ```javascript 65483 var promise1 = new RSVP.Promise(function(resolve, reject){ 65484 setTimeout(function(){ 65485 resolve('promise 1'); 65486 }, 200); 65487 }); 65488 65489 var promise2 = new RSVP.Promise(function(resolve, reject){ 65490 setTimeout(function(){ 65491 reject(new Error('promise 2')); 65492 }, 100); 65493 }); 65494 65495 RSVP.Promise.race([promise1, promise2]).then(function(result){ 65496 // Code here never runs 65497 }, function(reason){
65498 // reason.message === 'promise 2' because promise 2 became rejected before 65499 // promise 1 became fulfilled 65500 }); 65501 ``` 65502 65503 An example real-world use case is implementing timeouts: 65504 65505 ```javascript 65506 RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) 65507 ``` 65508 65509 @method race 65510 @static 65511 @param {Array} entries array of promises to observe 65512 @param {String} label optional string for describing the promise returned. 65513 Useful for tooling. 65514 @return {Promise} a promise which settles in the same way as the first passed 65515 promise to settle. 65516 */ 65517 65518 function race(entries, label) { 65519 /*jshint validthis:true */ 65520 var Constructor = this; 65521 65522 var promise = new Constructor(_rsvpInternal.noop, label); 65523 65524 if (!_rsvpUtils.isArray(entries)) { 65525 _rsvpInternal.reject(promise, new TypeError('You must pass an array to race.')); 65526 return promise; 65527 } 65528 65529 var length = entries.length; 65530 65531 function onFulfillment(value) { 65532 _rsvpInternal.resolve(promise, value); 65533 } 65534 65535 function onRejection(reason) { 65536 _rsvpInternal.reject(promise, reason); 65537 } 65538 65539 for (var i = 0; promise._state === _rsvpInternal.PENDING && i < length; i++) { 65540 _rsvpInternal.subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); 65541 } 65542 65543 return promise; 65544 } 65545}); 65546enifed('rsvp/promise/reject', ['exports', 'rsvp/-internal'], function (exports, _rsvpInternal) { 65547 'use strict'; 65548 65549 exports.default = reject; 65550 65551 /** 65552 `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. 65553 It is shorthand for the following: 65554 65555 ```javascript 65556 var promise = new RSVP.Promise(function(resolve, reject){ 65557 reject(new Error('WHOOPS')); 65558 }); 65559 65560 promise.then(function(value){ 65561 // Code here doesn't run because the promise is rejected! 65562 }, function(reason){ 65563 // reason.message === 'WHOOPS' 65564 }); 65565 ``` 65566 65567 Instead of writing the above, your code now simply becomes the following: 65568 65569 ```javascript 65570 var promise = RSVP.Promise.reject(new Error('WHOOPS')); 65571 65572 promise.then(function(value){ 65573 // Code here doesn't run because the promise is rejected! 65574 }, function(reason){ 65575 // reason.message === 'WHOOPS' 65576 }); 65577 ``` 65578 65579 @method reject 65580 @static 65581 @param {*} reason value that the returned promise will be rejected with. 65582 @param {String} label optional string for identifying the returned promise. 65583 Useful for tooling. 65584 @return {Promise} a promise rejected with the given `reason`. 65585 */ 65586 65587 function reject(reason, label) { 65588 /*jshint validthis:true */ 65589 var Constructor = this; 65590 var promise = new Constructor(_rsvpInternal.noop, label); 65591 _rsvpInternal.reject(promise, reason); 65592 return promise; 65593 } 65594}); 65595enifed('rsvp/promise/resolve', ['exports', 'rsvp/-internal'], function (exports, _rsvpInternal) { 65596 'use strict'; 65597 65598 exports.default = resolve; 65599 65600 /** 65601 `RSVP.Promise.resolve` returns a promise that will become resolved with the 65602 passed `value`. It is shorthand for the following: 65603 65604 ```javascript 65605 var promise = new RSVP.Promise(function(resolve, reject){ 65606 resolve(1); 65607 }); 65608 65609 promise.then(function(value){ 65610 // value === 1 65611 }); 65612 ``` 65613 65614 Instead of writing the above, your code now simply becomes the following: 65615 65616 ```javascript 65617 var promise = RSVP.Promise.resolve(1); 65618 65619 promise.then(function(value){ 65620 // value === 1 65621 }); 65622 ``` 65623 65624 @method resolve 65625 @static 65626 @param {*} object value that the returned promise will be resolved with 65627 @param {String} label optional string for identifying the returned promise. 65628 Useful for tooling. 65629 @return {Promise} a promise that will become fulfilled with the given 65630 `value` 65631 */ 65632 65633 function resolve(object, label) { 65634 /*jshint validthis:true */ 65635 var Constructor = this; 65636 65637 if (object && typeof object === 'object' && object.constructor === Constructor) { 65638 return object; 65639 } 65640 65641 var promise = new Constructor(_rsvpInternal.noop, label); 65642 _rsvpInternal.resolve(promise, object); 65643 return promise; 65644 } 65645}); 65646enifed('rsvp/promise-hash', ['exports', 'rsvp/enumerator', 'rsvp/-internal', 'rsvp/utils'], function (exports, _rsvpEnumerator, _rsvpInternal, _rsvpUtils) { 65647 'use strict'; 65648 65649 function PromiseHash(Constructor, object, label) { 65650 this._superConstructor(Constructor, object, true, label); 65651 } 65652 65653 exports.default = PromiseHash; 65654 65655 PromiseHash.prototype = _rsvpUtils.o_create(_rsvpEnumerator.default.prototype); 65656 PromiseHash.prototype._superConstructor = _rsvpEnumerator.default; 65657 PromiseHash.prototype._init = function () { 65658 this._result = {}; 65659 }; 65660 65661 PromiseHash.prototype._validateInput = function (input) { 65662 return input && typeof input === 'object'; 65663 }; 65664 65665 PromiseHash.prototype._validationError = function () { 65666 return new Error('Promise.hash must be called with an object'); 65667 }; 65668 65669 PromiseHash.prototype._enumerate = function () { 65670 var enumerator = this; 65671 var promise = enumerator.promise; 65672 var input = enumerator._input; 65673 var results = []; 65674 65675 for (var key in input) { 65676 if (promise._state === _rsvpInternal.PENDING && Object.prototype.hasOwnProperty.call(input, key)) { 65677 results.push({ 65678 position: key, 65679 entry: input[key] 65680 }); 65681 } 65682 } 65683 65684 var length = results.length; 65685 enumerator._remaining = length; 65686 var result; 65687 65688 for (var i = 0; promise._state === _rsvpInternal.PENDING && i < length; i++) { 65689 result = results[i]; 65690 enumerator._eachEntry(result.entry, result.position); 65691 } 65692 }; 65693}); 65694enifed('rsvp/promise', ['exports', 'rsvp/config', 'rsvp/instrument', 'rsvp/utils', 'rsvp/-internal', 'rsvp/promise/all', 'rsvp/promise/race', 'rsvp/promise/resolve', 'rsvp/promise/reject'], function (exports, _rsvpConfig, _r
65694svpInstrument, _rsvpUtils, _rsvpInternal, _rsvpPromiseAll, _rsvpPromiseRace, _rsvpPromiseResolve, _rsvpPromiseReject) { 65695 'use strict'; 65696 65697 exports.default = Promise; 65698 65699 var guidKey = 'rsvp_' + _rsvpUtils.now() + '-'; 65700 var counter = 0; 65701 65702 function needsResolver() { 65703 throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); 65704 } 65705 65706 function needsNew() { 65707 throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); 65708 } 65709 65710 /** 65711 Promise objects represent the eventual result of an asynchronous operation. The 65712 primary way of interacting with a promise is through its `then` method, which 65713 registers callbacks to receive either a promiseâs eventual value or the reason 65714 why the promise cannot be fulfilled. 65715 65716 Terminology 65717 ----------- 65718 65719 - `promise` is an object or function with a `then` method whose behavior conforms to this specification. 65720 - `thenable` is an object or function that defines a `then` method. 65721 - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). 65722 - `exception` is a value that is thrown using the throw statement. 65723 - `reason` is a value that indicates why a promise was rejected. 65724 - `settled` the final resting state of a promise, fulfilled or rejected. 65725 65726 A promise can be in one of three states: pending, fulfilled, or rejected. 65727 65728 Promises that are fulfilled have a fulfillment value and are in the fulfilled 65729 state. Promises that are rejected have a rejection reason and are in the 65730 rejected state. A fulfillment value is never a thenable. 65731 65732 Promises can also be said to *resolve* a value. If this value is also a 65733 promise, then the original promise's settled state will match the value's 65734 settled state. So a promise that *resolves* a promise that rejects will 65735 itself reject, and a promise that *resolves* a promise that fulfills will 65736 itself fulfill. 65737 65738 65739 Basic Usage: 65740 ------------ 65741 65742 ```js 65743 var promise = new Promise(function(resolve, reject) { 65744 // on success 65745 resolve(value); 65746 65747 // on failure 65748 reject(reason); 65749 }); 65750 65751 promise.then(function(value) { 65752 // on fulfillment 65753 }, function(reason) { 65754 // on rejection 65755 }); 65756 ``` 65757 65758 Advanced Usage: 65759 --------------- 65760 65761 Promises shine when abstracting away asynchronous interactions such as 65762 `XMLHttpRequest`s. 65763 65764 ```js 65765 function getJSON(url) { 65766 return new Promise(function(resolve, reject){ 65767 var xhr = new XMLHttpRequest(); 65768 65769 xhr.open('GET', url); 65770 xhr.onreadystatechange = handler; 65771 xhr.responseType = 'json'; 65772 xhr.setRequestHeader('Accept', 'application/json'); 65773 xhr.send(); 65774 65775 function handler() { 65776 if (this.readyState === this.DONE) { 65777 if (this.status === 200) { 65778 resolve(this.response); 65779 } else { 65780 reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); 65781 } 65782 } 65783 }; 65784 }); 65785 } 65786 65787 getJSON('/posts.json').then(function(json) { 65788 // on fulfillment 65789 }, function(reason) { 65790 // on rejection 65791 }); 65792 ``` 65793 65794 Unlike callbacks, promises are great composable primitives. 65795 65796 ```js 65797 Promise.all([ 65798 getJSON('/posts'), 65799 getJSON('/comments') 65800 ]).then(function(values){ 65801 values[0] // => postsJSON 65802 values[1] // => commentsJSON 65803 65804 return values; 65805 }); 65806 ``` 65807 65808 @class RSVP.Promise 65809 @param {function} resolver 65810 @param {String} label optional string for labeling the promise. 65811 Useful for tooling. 65812 @constructor 65813 */ 65814 65815 function Promise(resolver, label) { 65816 var promise = this; 65817 65818 promise._id = counter++; 65819 promise._label = label; 65820 promise._state = undefined; 65821 promise._result = undefined; 65822 promise._subscribers = []; 65823 65824 if (_rsvpConfig.config.instrument) { 65825 _rsvpInstrument.default('created', promise); 65826 } 65827 65828 if (_rsvpInternal.noop !== resolver) { 65829 if (!_rsvpUtils.isFunction(resolver)) { 65830 needsResolver(); 65831 } 65832 65833 if (!(promise instanceof Promise)) { 65834 needsNew(); 65835 } 65836 65837 _rsvpInternal.initializePromise(promise, resolver); 65838 } 65839 } 65840 65841 Promise.cast = _rsvpPromiseResolve.default; // deprecated 65842 Promise.all = _rsvpPromiseAll.default; 65843 Promise.race = _rsvpPromiseRace.default; 65844 Promise.resolve = _rsvpPromiseResolve.default; 65845 Promise.reject = _rsvpPromiseReject.default; 65846 65847 Promise.prototype = { 65848 constructor: Promise, 65849 65850 _guidKey: guidKey, 65851 65852 _onError: function (reason) { 65853 var promise = this; 65854 _rsvpConfig.config.after(function () { 65855 if (promise._onError) { 65856 _rsvpConfig.config['trigger']('error', reason); 65857 } 65858 }); 65859 }, 65860 65861 /** 65862 The primary way of interacting with a promise is through its `then` method, 65863 which registers callbacks to receive either a promise's eventual value or the 65864 reason why the promise cannot be fulfilled. 65865 65866 ```js 65867 findUser().then(function(user){ 65868 // user is available 65869 }, function(reason){ 65870 // user is unavailable, and you are given the reason why 65871 }); 65872 ``` 65873 65874 Chaining 65875 -------- 65876 65877 The return value of `then` is itself a promise. This second, 'downstream' 65878 promise is resolved with the return value of the first promise's fulfillment 65879 or rejection handler, or rejected if the handler throws an exception. 65880 65881 ```js 65882 findUser().then(function (user) { 65883 return user.name; 65884 }, function (reason) { 65885 return 'default name'; 65886 }).then(function (userName) { 65887 // If `findUser` fulfilled, `userName` will be the user's name, otherwise it 65888 // will be `'default name'` 65889 }); 65890 65891 findUser().then(function (user) { 65892 throw new Error('Found user, but still unhappy'); 65893 }, function (reason) { 65894 throw new Error('`findUser` rejected and we're unhappy'); 65895 }).then(function (value) { 65896 // never reached 65897 }, function (reason) { 65898 // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. 65899 // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. 65900 }); 65901 ``` 65902 If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. 65903 65904 ```js 65905 findUser().then(function (user) { 65906 throw new PedagogicalException('Upstream error'); 65907 }).then(function (value) { 65908 // never reached 65909 }).then(function (value) { 65910 // never reached 65911 }, function (reason) { 65912 // The `PedgagocialException` is propagated all the way down to here 65913 }); 65914 ``` 65915 65916 Assimilation 65917 ------------ 65918 65919 Sometimes the value you want to propagate to a downstream promise can only be 65920 retrieved asynchronously. This can be achieved by returning a promise in the 65921 fulfillment or rejection handler. The downstream promise will then be pending 65922 until the returned promise is settled. This is called *assimilation*. 65923 65924 ```js 65925 findUser().then(function (user) { 65926 return findCommentsByAuthor(user); 65927 }).then(function (comments) { 65928 // The user's comments are now available 65929 }); 65930 ``` 65931 65932 If the assimliated promise rejects, then the downstream promise will also reject. 65933 65934 ```js 65935 findUser().then(function (user) { 65936 return findCommentsByAuthor(user); 65937 }).then(function (comments) { 65938 // If `findCommentsByAuthor` fulfills, we'll have the value here 65939 }, function (reason) { 65940 // If `findCommentsByAuthor` rejects, we'll have the reason here 65941 }); 65942 ``` 65943
65944 Simple Example 65945 -------------- 65946 65947 Synchronous Example 65948 65949 ```javascript 65950 var result; 65951 65952 try { 65953 result = findResult(); 65954 // success 65955 } catch(reason) { 65956 // failure 65957 } 65958 ``` 65959 65960 Errback Example 65961 65962 ```js 65963 findResult(function(result, err){ 65964 if (err) { 65965 // failure 65966 } else { 65967 // success 65968 } 65969 }); 65970 ``` 65971 65972 Promise Example; 65973 65974 ```javascript 65975 findResult().then(function(result){ 65976 // success 65977 }, function(reason){ 65978 // failure 65979 }); 65980 ``` 65981 65982 Advanced Example 65983 -------------- 65984 65985 Synchronous Example 65986 65987 ```javascript 65988 var author, books; 65989 65990 try { 65991 author = findAuthor(); 65992 books = findBooksByAuthor(author); 65993 // success 65994 } catch(reason) { 65995 // failure 65996 } 65997 ``` 65998 65999 Errback Example 66000 66001 ```js 66002 66003 function foundBooks(books) { 66004 66005 } 66006 66007 function failure(reason) { 66008 66009 } 66010 66011 findAuthor(function(author, err){ 66012 if (err) { 66013 failure(err); 66014 // failure 66015 } else { 66016 try { 66017 findBoooksByAuthor(author, function(books, err) { 66018 if (err) { 66019 failure(err); 66020 } else { 66021 try { 66022 foundBooks(books); 66023 } catch(reason) { 66024 failure(reason); 66025 } 66026 } 66027 }); 66028 } catch(error) { 66029 failure(err); 66030 } 66031 // success 66032 } 66033 }); 66034 ``` 66035 66036 Promise Example; 66037 66038 ```javascript 66039 findAuthor(). 66040 then(findBooksByAuthor). 66041 then(function(books){ 66042 // found books 66043 }).catch(function(reason){ 66044 // something went wrong 66045 }); 66046 ``` 66047 66048 @method then 66049 @param {Function} onFulfillment 66050 @param {Function} onRejection 66051 @param {String} label optional string for labeling the promise. 66052 Useful for tooling. 66053 @return {Promise} 66054 */ 66055 then: function (onFulfillment, onRejection, label) { 66056 var parent = this; 66057 var state = parent._state; 66058 66059 if (state === _rsvpInternal.FULFILLED && !onFulfillment || state === _rsvpInternal.REJECTED && !onRejection) { 66060 if (_rsvpConfig.config.instrument) { 66061 _rsvpInstrument.default('chained', parent, parent); 66062 } 66063 return parent; 66064 } 66065 66066 parent._onError = null; 66067 66068 var child = new parent.constructor(_rsvpInternal.noop, label); 66069 var result = parent._result; 66070 66071 if (_rsvpConfig.config.instrument) { 66072 _rsvpInstrument.default('chained', parent, child); 66073 } 66074 66075 if (state) { 66076 var callback = arguments[state - 1]; 66077 _rsvpConfig.config.async(function () { 66078 _rsvpInternal.invokeCallback(state, child, callback, result); 66079 }); 66080 } else { 66081 _rsvpInternal.subscribe(parent, child, onFulfillment, onRejection); 66082 } 66083 66084 return child; 66085 }, 66086 66087 /** 66088 `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same 66089 as the catch block of a try/catch statement. 66090 66091 ```js 66092 function findAuthor(){ 66093 throw new Error('couldn't find that author'); 66094 } 66095 66096 // synchronous 66097 try { 66098 findAuthor(); 66099 } catch(reason) { 66100 // something went wrong 66101 } 66102 66103 // async with promises 66104 findAuthor().catch(function(reason){ 66105 // something went wrong 66106 }); 66107 ``` 66108 66109 @method catch 66110 @param {Function} onRejection 66111 @param {String} label optional string for labeling the promise. 66112 Useful for tooling. 66113 @return {Promise} 66114 */ 66115 'catch': function (onRejection, label) { 66116 return this.then(undefined, onRejection, label); 66117 }, 66118 66119 /** 66120 `finally` will be invoked regardless of the promise's fate just as native 66121 try/catch/finally behaves 66122 66123 Synchronous example: 66124 66125 ```js 66126 findAuthor() { 66127 if (Math.random() > 0.5) { 66128 throw new Error(); 66129 } 66130 return new Author(); 66131 } 66132
66133 try { 66134 return findAuthor(); // succeed or fail 66135 } catch(error) { 66136 return findOtherAuther(); 66137 } finally { 66138 // always runs 66139 // doesn't affect the return value 66140 } 66141 ``` 66142 66143 Asynchronous example: 66144 66145 ```js 66146 findAuthor().catch(function(reason){ 66147 return findOtherAuther(); 66148 }).finally(function(){ 66149 // author was either found, or not 66150 }); 66151 ``` 66152 66153 @method finally 66154 @param {Function} callback 66155 @param {String} label optional string for labeling the promise. 66156 Useful for tooling. 66157 @return {Promise} 66158 */ 66159 'finally': function (callback, label) { 66160 var promise = this; 66161 var constructor = promise.constructor; 66162 66163 return promise.then(function (value) { 66164 return constructor.resolve(callback()).then(function () { 66165 return value; 66166 }); 66167 }, function (reason) { 66168 return constructor.resolve(callback()).then(function () { 66169 throw reason; 66170 }); 66171 }, label); 66172 } 66173 }; 66174}); 66175enifed('rsvp/race', ['exports', 'rsvp/promise'], function (exports, _rsvpPromise) { 66176 'use strict'; 66177 66178 exports.default = race; 66179 66180 /** 66181 This is a convenient alias for `RSVP.Promise.race`. 66182 66183 @method race 66184 @static 66185 @for RSVP 66186 @param {Array} array Array of promises. 66187 @param {String} label An optional label. This is useful 66188 for tooling. 66189 */ 66190 66191 function race(array, label) { 66192 return _rsvpPromise.default.race(array, label); 66193 } 66194}); 66195enifed('rsvp/reject', ['exports', 'rsvp/promise'], function (exports, _rsvpPromise) { 66196 'use strict'; 66197 66198 exports.default = reject; 66199 66200 /** 66201 This is a convenient alias for `RSVP.Promise.reject`. 66202 66203 @method reject 66204 @static 66205 @for RSVP 66206 @param {*} reason value that the returned promise will be rejected with. 66207 @param {String} label optional string for identifying the returned promise. 66208 Useful for tooling. 66209 @return {Promise} a promise rejected with the given `reason`. 66210 */ 66211 66212 function reject(reason, label) { 66213 return _rsvpPromise.default.reject(reason, label); 66214 } 66215}); 66216enifed('rsvp/resolve', ['exports', 'rsvp/promise'], function (exports, _rsvpPromise) { 66217 'use strict'; 66218 66219 exports.default = resolve; 66220 66221 /** 66222 This is a convenient alias for `RSVP.Promise.resolve`. 66223 66224 @method resolve 66225 @static 66226 @for RSVP 66227 @param {*} value value that the returned promise will be resolved with 66228 @param {String} label optional string for identifying the returned promise. 66229 Useful for tooling. 66230 @return {Promise} a promise that will become fulfilled with the given 66231 `value` 66232 */ 66233 66234 function resolve(value, label) { 66235 return _rsvpPromise.default.resolve(value, label); 66236 } 66237}); 66238enifed("rsvp/rethrow", ["exports"], function (exports) { 66239 /** 66240 `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event 66241 loop in order to aid debugging. 66242 66243 Promises A+ specifies that any exceptions that occur with a promise must be 66244 caught by the promises implementation and bubbled to the last handler. For 66245 this reason, it is recommended that you always specify a second rejection 66246 handler function to `then`. However, `RSVP.rethrow` will throw the exception 66247 outside of the promise, so it bubbles up to your console if in the browser, 66248 or domain/cause uncaught exception in Node. `rethrow` will also throw the 66249 error again so the error can be handled by the promise per the spec. 66250 66251 ```javascript 66252 function throws(){ 66253 throw new Error('Whoops!'); 66254 } 66255 66256 var promise = new RSVP.Promise(function(resolve, reject){ 66257 throws(); 66258 }); 66259 66260 promise.catch(RSVP.rethrow).then(function(){ 66261 // Code here doesn't run because the promise became rejected due to an 66262 // error! 66263 }, function (err){ 66264 // handle the error here 66265 }); 66266 ``` 66267 66268 The 'Whoops' error will be thrown on the next turn of the event loop 66269 and you can watch for it in your console. You can also handle it using a 66270 rejection handler given to `.then` or `.catch` on the returned promise. 66271 66272 @method rethrow 66273 @static 66274 @for RSVP 66275 @param {Error} reason reason the promise became rejected. 66276 @throws Error 66277 @static 66278 */ 66279 "use strict"; 66280 66281 exports.default = rethrow; 66282 66283 function rethrow(reason) { 66284 setTimeout(function () { 66285 throw reason; 66286 }); 66287 throw reason; 66288 } 66289}); 66290enifed('rsvp/utils', ['exports'], function (exports) { 66291 'use strict'; 66292 66293 exports.objectOrFunction = objectOrFunction; 66294 exports.isFunction = isFunction; 66295 exports.isMaybeThenable = isMaybeThenable; 66296 66297 function objectOrFunction(x) { 66298 return typeof x === 'function' || typeof x === 'object' && x !== null; 66299 } 66300 66301 function isFunction(x) { 66302 return typeof x === 'function'; 66303 } 66304 66305 function isMaybeThenable(x) { 66306 return typeof x === 'object' && x !== null; 66307 } 66308 66309 var _isArray; 66310 if (!Array.isArray) { 66311 _isArray = function (x) { 66312 return Object.prototype.toString.call(x) === '[object Array]'; 66313 }; 66314 } else { 66315 _isArray = Array.isArray; 66316 } 66317 66318 var isArray = _isArray; 66319 66320 exports.isArray = isArray; 66321 // Date.now is not available in browsers < IE9 66322 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility 66323 var now = Date.now || function () { 66324 return new Date().getTime(); 66325 }; 66326 66327 exports.now = now; 66328 function F() {} 66329 66330 var o_create = Object.create || function (o) { 66331 if (arguments.length > 1) { 66332 throw new Error('Second argument not supported'); 66333 } 66334 if (typeof o !== 'object') { 66335 throw new TypeError('Argument must be an object'); 66336 } 66337 F.prototype = o; 66338 return new F(); 66339 }; 66340 exports.o_create = o_create; 66341}); 66342enifed('rsvp', ['exports', 'rsvp/promise', 'rsvp/events', 'rsvp/node', 'rsvp/all', 'rsvp/all-settled', 'rsvp/race', 'rsvp/hash', 'rsvp/hash-settled', 'rsvp/rethrow', 'rsvp/defer', 'rsvp/config', 'rsvp/map', 'rsvp/resolve', 'rsvp/reject', 'rsvp/filter', 'rsvp/asap'], function (exports, _rsvpPromise, _rsvpEvents, _rsvpNode, _rsvpAll, _rsvpAllSettled, _rsvpRace, _rsvpHash, _rsvpHashSettled, _rsvpRethrow, _rsvpDefer, _rsvpConfig, _r
66342svpMap, _rsvpResolve, _rsvpReject, _rsvpFilter, _rsvpAsap) { 66343 'use strict'; 66344 66345 // defaults 66346 _rsvpConfig.config.async = _rsvpAsap.default; 66347 _rsvpConfig.config.after = function (cb) { 66348 setTimeout(cb, 0); 66349 }; 66350 var cast = _rsvpResolve.default; 66351 function async(callback, arg) { 66352 _rsvpConfig.config.async(callback, arg); 66353 } 66354 66355 function on() { 66356 _rsvpConfig.config['on'].apply(_rsvpConfig.config, arguments); 66357 } 66358 66359 function off() { 66360 _rsvpConfig.config['off'].apply(_rsvpConfig.config, arguments); 66361 } 66362 66363 // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` 66364 if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { 66365 var callbacks = window['__PROMISE_INSTRUMENTATION__']; 66366 _rsvpConfig.configure('instrument', true); 66367 for (var eventName in callbacks) { 66368 if (callbacks.hasOwnProperty(eventName)) { 66369 on(eventName, callbacks[eventName]); 66370 } 66371 } 66372 } 66373 66374 exports.cast = cast; 66375 exports.Promise = _rsvpPromise.default; 66376 exports.EventTarget = _rsvpEvents.default; 66377 exports.all = _rsvpAll.default; 66378 exports.allSettled = _rsvpAllSettled.default; 66379 exports.race = _rsvpRace.default; 66380 exports.hash = _rsvpHash.default; 66381 exports.hashSettled = _rsvpHashSettled.default; 66382 exports.rethrow = _rsvpRethrow.default; 66383 exports.defer = _rsvpDefer.default; 66384 exports.denodeify = _rsvpNode.default; 66385 exports.configure = _rsvpConfig.configure; 66386 exports.on = on; 66387 exports.off = off; 66388 exports.resolve = _rsvpResolve.default; 66389 exports.reject = _rsvpReject.default; 66390 exports.async = async; 66391 exports.map = _rsvpMap.default; 66392 exports.filter = _rsvpFilter.default; 66393}); 66394enifed('rsvp.umd', ['exports', 'rsvp/platform', 'rsvp'], function (exports, _rsvpPlatform, _rsvp) { 66395 'use strict'; 66396 66397 var RSVP = { 66398 'race': _rsvp.race, 66399 'Promise': _rsvp.Promise, 66400 'allSettled': _rsvp.allSettled, 66401 'hash': _rsvp.hash, 66402 'hashSettled': _rsvp.hashSettled, 66403 'denodeify': _rsvp.denodeify, 66404 'on': _rsvp.on, 66405 'off': _rsvp.off, 66406 'map': _rsvp.map, 66407 'filter': _rsvp.filter, 66408 'resolve': _rsvp.resolve, 66409 'reject': _rsvp.reject, 66410 'all': _rsvp.all, 66411 'rethrow': _rsvp.rethrow, 66412 'defer': _rsvp.defer, 66413 'EventTarget': _rsvp.EventTarget, 66414 'configure': _rsvp.configure, 66415 'async': _rsvp.async 66416 }; 66417 66418 /* global define:true module:true window: true */ 66419 if (typeof define === 'function' && define['amd']) { 66420 define(function () { 66421 return RSVP; 66422 }); 66423 } else if (typeof module !== 'undefined' && module['exports']) { 66424 module['exports'] = RSVP; 66425 } else if (typeof _rsvpPlatform.default !== 'undefined') { 66426 _rsvpPlatform.default['RSVP'] = RSVP; 66427 } 66428}); 66429enifed("vertex", ["exports"], function (exports) { 66430 /** 66431 * DAG Vertex 66432 * 66433 * @class Vertex 66434 * @constructor 66435 */ 66436 66437 "use strict"; 66438 66439 exports.default = Vertex; 66440 66441 function Vertex(name) { 66442 this.name = name; 66443 this.incoming = {}; 66444 this.incomingNames = []; 66445 this.hasOutgoing = false; 66446 this.value = null; 66447 } 66448}); 66449enifed("visit", ["exports"], function (exports) { 66450 "use strict"; 66451 66452 exports.default = visit; 66453 66454 function visit(vertex, fn, visited, path) { 66455 var name = vertex.name; 66456 var vertices = vertex.incoming; 66457 var names = vertex.incomingNames; 66458 var len = names.length; 66459 var i; 66460 66461 if (!visited) { 66462 visited = {}; 66463 } 66464 if (!path) { 66465 path = []; 66466 } 66467 if (visited.hasOwnProperty(name)) { 66468 return; 66469 } 66470 path.push(name); 66471 visited[name] = true; 66472 for (i = 0; i < len; i++) { 66473 visit(vertices[names[i]], fn, visited, path); 66474 } 66475 fn(vertex, path); 66476 path.pop(); 66477 } 66478}); 66479requireModule("ember"); 66480 66481}()); 66482 66483;(function() { 66484/* globals define, Ember, jQuery */ 66485 66486 function processEmberShims() { 66487 var shims = { 66488 'ember': { 66489 'default': Ember 66490 }, 66491 'ember-application': { 66492 'default': Ember.Application 66493 }, 66494 'ember-array': { 66495 'default': Ember.Array 66496 }, 66497 'ember-array/mutable': { 66498 'default': Ember.MutableArray 66499 }, 66500 'ember-array/utils': { 66501 'A': Ember.A, 66502 'isEmberArray': Ember.isArray, 66503 'wrap': Ember.makeArray 66504 }, 66505 'ember-component': { 66506 'default': Ember.Component 66507 }, 66508 'ember-components/checkbox': { 66509 'default': Ember.Checkbox 66510 }, 66511 'ember-components/text-area': { 66512 'default': Ember.TextArea 66513 }, 66514 'ember-components/text-field': { 66515 'default': Ember.TextField 66516 }, 66517 'ember-controller': { 66518 'default': Ember.Controller 66519 }, 66520 'ember-controller/inject': { 66521 'default': Ember.inject.controller 66522 }, 66523 'ember-controller/proxy': { 66524 'default': Ember.ArrayProxy 66525 }, 66526 'ember-controllers/sortable': { 66527 'default': Ember.SortableMixin 66528 }, 66529 'ember-debug': { 66530 'log': Ember.debug, 66531 'inspect': Ember.inspect, 66532 'run': Ember.runInDebug, 66533 'warn': Ember.warn 66534 }, 66535 'ember-debug/container-debug-adapter': { 66536 'default': Ember.ContainerDebugAdapter 66537 }, 66538 'ember-debug/data-adapter': { 66539 'default': Ember.DataAdapter 66540 }, 66541 'ember-deprecations': { 66542 'deprecate': Ember.deprecate, 66543 'deprecateFunc': Ember.deprecateFunc 66544 }, 66545 'ember-enumerable': { 66546 'default': Ember.Enumerable 66547 }, 66548 'ember-evented': { 66549 'default': Ember.Evented 66550 }, 66551 'ember-evented/on': { 66552 'default': Ember.on 66553 }, 66554 'ember-globals-resolver': { 66555 'default': Ember.DefaultResolver 66556 }, 66557 'ember-helper': { 66558 'default': Ember.Helper, 66559 'helper': Ember.Helper && Ember.Helper.helper 66560 }, 66561 'ember-instrumentation': { 66562 'instrument': Ember.Instrumentation.instrument, 66563 'reset': Ember.Instrumentation.reset, 66564 'subscribe': Ember.Instrumentation.subscribe, 66565 'unsubscribe': Ember.Instrumentation.unsubscribe 66566 }, 66567 'ember-locations/hash': { 66568 'default': Ember.HashLocation 66569 }, 66570 'ember-locations/history': { 66571 'default': Ember.HistoryLocation 66572 }, 66573 'ember-locations/none': { 66574 'default': Ember.NoneLocation 66575 }, 66576 'ember-map': { 66577 'default': Ember.Map, 66578 'withDefault': Ember.MapWithDefault 66579 }, 66580 'ember-metal/destroy': { 66581 'default': Ember.destroy 66582 }, 66583 'ember-metal/events': { 66584 'addListener': Ember.addListener, 66585 'removeListener': Ember.removeListener, 66586 'send': Ember.sendEvent 66587 }, 66588 'ember-metal/get': { 66589 'default': Ember.get, 66590 'getProperties': Ember.getProperties 66591 }, 66592 'ember-metal/mixin': { 66593 'default': Ember.Mixin 66594 }, 66595 'ember-metal/observer': { 66596 'default': Ember.observer, 66597 'addObserver': Ember.addObserver, 66598 'removeObserver': Ember.removeObserver 66599 }, 66600 'ember-metal/on-load': { 66601 'default': Ember.onLoad,
66602 'run': Ember.runLoadHooks 66603 }, 66604 'ember-metal/set': { 66605 'default': Ember.set, 66606 'setProperties': Ember.setProperties, 66607 'trySet': Ember.trySet 66608 }, 66609 'ember-metal/utils': { 66610 'aliasMethod': Ember.aliasMethod, 66611 'assert': Ember.assert, 66612 'cacheFor': Ember.cacheFor, 66613 'copy': Ember.copy, 66614 'guidFor': Ember.guidFor 66615 }, 66616 'ember-object': { 66617 'default': Ember.Object 66618 }, 66619 'ember-platform': { 66620 'assign': Ember.merge, 66621 'create': Ember.create, 66622 'defineProperty': Ember.platform.defineProperty, 66623 'hasAccessors': Ember.platform.hasPropertyAccessors, 66624 'keys': Ember.keys 66625 }, 66626 'ember-route': { 66627 'default': Ember.Route 66628 }, 66629 'ember-router': { 66630 'default': Ember.Router 66631 }, 66632 'ember-runloop': { 66633 'default': Ember.run, 66634 'begin': Ember.run.begin, 66635 'bind': Ember.run.bind, 66636 'cancel': Ember.run.cancel, 66637 'debounce': Ember.run.debounce, 66638 'end': Ember.run.end, 66639 'join': Ember.run.join, 66640 'later': Ember.run.later, 66641 'next': Ember.run.next, 66642 'once': Ember.run.once, 66643 'schedule': Ember.run.schedule, 66644 'scheduleOnce': Ember.run.scheduleOnce, 66645 'throttle': Ember.run.throttle 66646 }, 66647 'ember-service': { 66648 'default': Ember.Service 66649 }, 66650 'ember-service/inject': { 66651 'default': Ember.inject.service 66652 }, 66653 'ember-set/ordered': { 66654 'default': Ember.OrderedSet 66655 }, 66656 'ember-string': { 66657 'camelize': Ember.String.camelize, 66658 'capitalize': Ember.String.capitalize, 66659 'classify': Ember.String.classify, 66660 'dasherize': Ember.String.dasherize, 66661 'decamelize': Ember.String.decamelize, 66662 'fmt': Ember.String.fmt, 66663 'htmlSafe': Ember.String.htmlSafe, 66664 'loc': Ember.String.loc, 66665 'underscore': Ember.String.underscore, 66666 'w': Ember.String.w 66667 }, 66668 'ember-utils': { 66669 'isBlank': Ember.isBlank, 66670 'isEmpty': Ember.isEmpty, 66671 'isNone': Ember.isNone, 66672 'isPresent': Ember.isPresent, 66673 'tryInvoke': Ember.tryInvoke, 66674 'typeOf': Ember.typeOf 66675 } 66676 }; 66677 66678 // populate `ember/computed` named exports 66679 shims['ember-computed'] = { 66680 'default': Ember.computed 66681 }; 66682 var computedMacros = [ 66683 "empty","notEmpty", "none", "not", "bool", "match", 66684 "equal", "gt", "gte", "lt", "lte", "alias", "oneWay", 66685 "reads", "readOnly", "deprecatingAlias", 66686 "and", "or", "collect", "sum", "min", "max", 66687 "map", "sort", "setDiff", "mapBy", "mapProperty", 66688 "filter", "filterBy", "filterProperty", "uniq", 66689 "union", "intersect" 66690 ]; 66691 for (var i = 0, l = computedMacros.length; i < l; i++) { 66692 var key = computedMacros[i]; 66693 shims['ember-computed'][key] = Ember.computed[key]; 66694 } 66695 66696 for (var moduleName in shims) { 66697 generateModule(moduleName, shims[moduleName]); 66698 } 66699 } 66700 66701 function processTestShims() { 66702 if (Ember.Test) { 66703 var testShims = { 66704 'ember-test': { 66705 'default': Ember.Test 66706 }, 66707 'ember-test/adapter': { 66708 'default': Ember.Test.Adapter 66709 }, 66710 'ember-test/qunit-adapter': { 66711 'default': Ember.Test.QUnitAdapter 66712 } 66713 }; 66714 66715 for (var moduleName in testShims) { 66716 generateModule(moduleName, testShims[moduleName]); 66717 } 66718 } 66719 } 66720 66721 function generateModule(name, values) { 66722 define(name, [], function() { 66723 'use strict'; 66724 66725 return values; 66726 }); 66727 } 66728 66729 processEmberShims(); 66730 processTestShims(); 66731 generateModule('jquery', { 'default': self.jQuery }); 66732 generateModule('rsvp', { 'default': Ember.RSVP }); 66733})(); 66734 66735;/* globals define */ 66736define('ember/load-initializers', ['exports', 'ember-load-initializers', 'ember'], function(exports, loadInitializer
66736s, Ember) { 66737 Ember['default'].deprecate( 66738 'Usage of `' + 'ember/load-initializers' + '` module is deprecated, please update to `ember-load-initializers`.', 66739 false, 66740 { id: 'ember-load-initializers.legacy-shims', until: '3.0.0' } 66741 ); 66742 66743 exports['default'] = loadInitializers['default']; 66744}); 66745 66746;/* globals define */ 66747 66748function createDeprecatedModule(moduleId) { 66749 define(moduleId, ['exports', 'ember-resolver/resolver', 'ember'], function(exports, Resolver, Ember) { 66750 Ember['default'].deprecate( 66751 'Usage of `' + moduleId + '` module is deprecated, please update to `ember-resolver`.', 66752 false, 66753 { id: 'ember-resolver.legacy-shims', until: '3.0.0' } 66754 ); 66755 66756 exports['default'] = Resolver['default']; 66757 }); 66758} 66759 66760createDeprecatedModule('ember/resolver'); 66761createDeprecatedModule('resolver'); 66762 66763;define('ember-ajax/errors', ['exports', 'ember'], function (exports, _ember) { 66764 'use strict'; 66765 66766 exports.AjaxError = AjaxError; 66767 exports.InvalidError = InvalidError; 66768 exports.UnauthorizedError = UnauthorizedError; 66769 exports.ForbiddenError = ForbiddenError; 66770 66771 var EmberError = _ember['default'].Error; 66772 66773 /** 66774 @class AjaxError 66775 @namespace DS 66776 */ 66777 66778 function AjaxError(errors) { 66779 var message = arguments.length <= 1 || arguments[1] === undefined ? 'Ajax operation failed' : arguments[1]; 66780 66781 EmberError.call(this, message); 66782 66783 this.errors = errors || [{ 66784 title: 'Ajax Error', 66785 detail: message 66786 }]; 66787 } 66788 66789 AjaxError.prototype = Object.create(EmberError.prototype); 66790 66791 function InvalidError(errors) { 66792 AjaxError.call(this, errors, 'Request was rejected because it was invali
66792d'); 66793 } 66794 66795 InvalidError.prototype = Object.create(AjaxError.prototype); 66796 66797 function UnauthorizedError(errors) { 66798 AjaxError.call(this, errors, 'Ajax authorization failed'); 66799 } 66800 66801 UnauthorizedError.prototype = Object.create(AjaxError.prototype); 66802 66803 function ForbiddenError(errors) { 66804 AjaxError.call(this, errors, 'Request was rejected because user is not permitted to perform this operation.'); 66805 } 66806 66807 ForbiddenError.prototype = Object.create(AjaxError.prototype); 66808}); 66809define('ember-ajax/index', ['exports', 'ember-ajax/request'], function (exports, _emberAjaxRequest) { 66810 'use strict'; 66811 66812 Object.defineProperty(exports, 'default', { 66813 enumerable: true, 66814 get: function get() { 66815 return _emberAjaxRequest['default']; 66816 } 66817 }); 66818}); 66819define('ember-ajax/make-promise', ['exports', 'ember'], function (exports, _ember) { 66820 'use strict'; 66821 66822 exports['default'] = makePromise; 66823 66824 var run = _ember['default'].run; 66825 var RSVP = _ember['default'].RSVP; 66826 66827 function makePromise(settings) { 66828 var type = settings.type || 'GET'; 66829 return new RSVP.Promise(function (resolve, reject) { 66830 settings.success = makeSuccess(resolve); 66831 settings.error = makeError(reject); 66832 _ember['default'].$.ajax(settings); 66833 }, 'ember-ajax: ' + type + ' to ' + settings.url); 66834 } 66835 66836 function makeSuccess(resolve) { 66837 return function success(response, textStatus, jqXHR) { 66838 run(null, resolve, { 66839 response: response, 66840 textStatus: textStatus, 66841 jqXHR: jqXHR 66842 }); 66843 }; 66844 } 66845 66846 function makeError(reject) { 66847 return function error(jqXHR, textStatus, errorThrown) { 66848 run(null, reject, { 66849 jqXHR: jqXHR, 66850 textStatus: textStatus, 66851 errorThrown: errorThrown 66852 }); 66853 }; 66854 } 66855}); 66856define('ember-ajax/raw', ['exports', 'ember-ajax/make-promise', 'ember-ajax/utils/parse-args', 'ember'], function (exports, _emberAjaxMakePromise, _emberAjaxUtilsParseArgs, _ember) { 66857 'use strict'; 66858 66859 var _slicedToArray = (function () { 66860 function sliceIterator(arr, i) { 66861 var _arr = [];var _n = true;var _d = false;var _e = undefined;try { 66862 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 66863 _arr.push(_s.value);if (i && _arr.length === i) break; 66864 } 66865 } catch (err) { 66866 _d = true;_e = err; 66867 } finally { 66868 try { 66869 if (!_n && _i['return']) _i['return'](); 66870 } finally { 66871 if (_d) throw _e; 66872 } 66873 }return _arr; 66874 }return function (arr, i) { 66875 if (Array.isArray(arr)) { 66876 return arr; 66877 } else if (Symbol.iterator in Object(arr)) { 66878 return sliceIterator(arr, i); 66879 } else { 66880 throw new TypeError('Invalid attempt to destructure non-iterable instance'); 66881 } 66882 }; 66883 })(); 66884 66885 exports['default'] = raw; 66886 66887 var deprecate = _ember['default'].deprecate; 66888 66889 /* 66890 * Same as `request` except it resolves an object with `{response, textStatus, 66891 * jqXHR}`, useful if you need access to the jqXHR object for headers, etc. 66892 */ 66893 function raw() { 66894 deprecate('ember-ajax/raw is deprecated and will be removed in [email protected]', false, { id: 'ember-ajax.raw' }); 66895 66896 var _parseArgs$apply = _emberAjaxUtilsParseArgs['default'].apply(null, arguments); 66897 66898 var _parseArgs$apply2 = _slicedToArray(_parseArgs$apply, 3); 66899 66900 var url = _parseArgs$apply2[0]; 66901 var type = _parseArgs$apply2[1]; 66902 var settings = _parseArgs$apply2[2]; 66903 66904 if (!settings) { 66905 settings = {}; 66906 } 66907 settings.url = url; 66908 settings.type = type; 66909 return (0, _emberAjaxMakePromise['default'])(settings); 66910 } 66911}); 66912define('ember-ajax/request', ['exports', 'ember-ajax/raw', 'ember'], function (exports, _emberAjaxRaw, _ember) { 66913 'use strict'; 66914 66915 exports['default'] = request; 66916 66917 var deprecate = _ember['default'].deprecate; 66918 66919 /* 66920 * jQuery.ajax wrapper, supports the same signature except providing 66921 * `success` and `error` handlers will throw an error (use promises instead) 66922 * and it resolves only the response (no access to jqXHR or textStatus). 66923 */ 66924 function request() { 66925 deprecate('ember-ajax/request is deprecated and will be removed in ember-
66925[email protected]', false, { id: 'ember-ajax.raw' }); 66926 return _emberAjaxRaw['default'].apply(undefined, arguments).then(function (result) { 66927 return result.response; 66928 }, null, 'ember-ajax: unwrap raw ajax response'); 66929 } 66930}); 66931define('ember-ajax/services/ajax', ['exports', 'ember', 'ember-ajax/errors', 'ember-ajax/utils/parse-response-headers'], function (exports, _ember, _emberAjaxErrors, _emberAjaxUtilsParseResponseHeaders) { 66932 'use strict'; 66933 66934 var deprecate = _ember['default'].deprecate; 66935 var get = _ember['default'].get; 66936 var isBlank = _ember['default'].isBlank; 66937 66938 /** 66939 ### Headers customization 66940 66941 Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary 66942 headers can be set as key/value pairs on the `RESTAdapter`'s `headers` 66943 object and Ember Data will send them along with each ajax request. 66944 66945 ```app/services/ajax 66946 import AjaxService from 'ember-ajax/services/ajax'; 66947 66948 export default AjaxService.extend({ 66949 headers: { 66950 "API_KEY": "secret key", 66951 "ANOTHER_HEADER": "Some header value" 66952 } 66953 }); 66954 ``` 66955 66956 `headers` can also be used as a computed property to support dynamic 66957 headers. 66958 66959 ```app/services/ajax.js 66960 import Ember from 'ember'; 66961 import AjaxService from 'ember-ajax/services/ajax'; 66962 66963 export default AjaxService.extend({ 66964 session: Ember.inject.service(), 66965 headers: Ember.computed("session.authToken", function() { 66966 return { 66967 "API_KEY": this.get("session.authToken"), 66968 "ANOTHER_HEADER": "Some header value" 66969 }; 66970 }) 66971 }); 66972 ``` 66973 66974 In some cases, your dynamic headers may require data from some 66975 object outside of Ember's observer system (for example 66976 `document.cookie`). You can use the 66977 [volatile](/api/classes/Ember.ComputedProperty.html#method_volatile) 66978 function to set the property into a non-cached mode causing the headers to 66979 be recomputed with every request. 66980 66981 ```app/services/ajax.js 66982 import Ember from 'ember'; 66983 import AjaxService from 'ember-ajax/services/ajax'; 66984 66985 export default AjaxService.extend({ 66986 session: Ember.inject.service(), 66987 headers: Ember.computed("session.authToken", function() { 66988 return { 66989 "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), 66990 "ANOTHER_HEADER": "Some header value" 66991 }; 66992 }).volatile() 66993 }); 66994 ``` 66995 66996 **/ 66997 exports['default'] = _ember['default'].Service.extend({ 66998 66999 request: function request(url, options) { 67000 var _this = this; 67001 67002 var opts; 67003 67004 if (arguments.length > 2 || typeof options === 'string') { 67005 deprecate('ember-ajax/ajax#request calling request with `type` is deprecated and will be removed in [email protected]. If you want to specify a type pass an object like {type: \'DELETE\'}', false, { id: 'ember-ajax.service.request' }); 67006 67007 if (arguments.length > 2) { 67008 opts = arguments[2]; 67009 opts.type = options; 67010 } else { 67011 opts = { type: options }; 67012 } 67013 } else { 67014 opts = options; 67015 } 67016 67017 var hash = this.options(url, opts); 67018 67019 return new _ember['default'].RSVP.Promise(function (resolve, reject) { 67020 67021 hash.success = function (payload, textStatus, jqXHR) { 67022 var response = _this.handleResponse(jqXHR.status, (0, _emberAjaxUtilsParseResponseHeaders['default'])(jqXHR.getAllResponseHeaders()), payload); 67023 67024 if (response instanceof _emberAjaxErrors.AjaxError) { 67025 reject(response); 67026 } else { 67027 resolve(response); 67028 } 67029 }; 67030 67031 hash.error = function (jqXHR, textStatus, errorThrown) { 67032 var error = undefined; 67033 67034 if (!(error instanceof Error)) { 67035 if (errorThrown instanceof Error) { 67036 error = errorThrown; 67037 } else { 67038 error = _this.handleResponse(jqXHR.status, (0, _emberAjaxUtilsParseResponseHeaders['default'])(jqXHR.getAllResponseHeaders()), _this.parseErrorResponse(jqXHR.responseText) || errorThrown); 67039 } 67040 } 67041 reject(error); 67042 }; 67043 67044 _ember['default'].$.ajax(hash); 67045 }, 'ember-ajax: ' + hash.type + ' to ' + url); 67046 }, 67047 67048 // calls `request()` but forces `options.type` to `POST` 67049 post: function post(url, options) { 67050 return this.request(url, this._addTypeToOptionsFor(options, 'POST')); 67051 }, 67052 67053 // calls `request()` but forces `options.type` to `PUT` 67054 put: function put(url, options) { 67055 return this.request(url, this._addTypeToOptionsFor(options, 'PUT')); 67056 }, 67057 67058 // calls `request()` but forces `options.type` to `PATCH` 67059 patch: function patch(url, options) { 67060 return this.request(url, this._addTypeToOptionsFor(options, 'PATCH')); 67061 }, 67062 67063 // calls `request()` but forces `options.type` to `DELETE` 67064 del: function del(url, options) { 67065 return this.request(url, this._addTypeToOptionsFor(options, 'DELETE')); 67066 }, 67067 67068 // forcibly manipulates the options hash to include the HTTP method on the type key
67069 _addTypeToOptionsFor: function _addTypeToOptionsFor(options, method) { 67070 options = options || {}; 67071 options.type = method; 67072 return options; 67073 }, 67074 67075 /** 67076 @method options 67077 @private 67078 @param {String} url 67079 @param {Object} options 67080 @return {Object} 67081 */ 67082 options: function options(url, _options) { 67083 var hash = _options || {}; 67084 hash.url = this._buildURL(url); 67085 hash.type = hash.type || 'GET'; 67086 hash.dataType = hash.dataType || 'json'; 67087 hash.context = this; 67088 67089 var headers = get(this, 'headers'); 67090 if (headers !== undefined) { 67091 hash.beforeSend = function (xhr) { 67092 Object.keys(headers).forEach(function (key) { 67093 return xhr.setRequestHeader(key, headers[key]); 67094 }); 67095 }; 67096 } 67097 67098 return hash; 67099 }, 67100 67101 _buildURL: function _buildURL(url) { 67102 var host = get(this, 'host'); 67103 if (isBlank(host)) { 67104 return url; 67105 } 67106 var startsWith = String.prototype.startsWith || function (searchString, position) { 67107 position = position || 0; 67108 return this.indexOf(searchString, position) === position; 67109 }; 67110 if (startsWith.call(url, '/')) { 67111 return '' + host + url; 67112 } else { 67113 return host + '/' + url; 67114 } 67115 }, 67116 67117 /** 67118 Takes an ajax response, and returns the json payload or an error. 67119 By default this hook just returns the json payload passed to it. 67120 You might want to override it in two cases: 67121 1. Your API might return useful results in the response headers. 67122 Response headers are passed in as the second argument. 67123 2. Your API might return errors as successful responses with status code 67124 200 and an Errors text or object. 67125 @method handleResponse 67126 @param {Number} status 67127 @param {Object} headers 67128 @param {Object} payload 67129 @return {Object | DS.AdapterError} response 67130 */ 67131 handleResponse: function handleResponse(status, headers, payload) { 67132 if (this.isSuccess(status, headers, payload)) { 67133 return payload; 67134 } else if (this.isUnauthorized(status, headers, payload)) { 67135 return new _emberAjaxErrors.UnauthorizedError(payload.errors); 67136 } else if (this.isForbidden(status, headers, payload)) { 67137 return new _emberAjaxErrors.ForbiddenError(payload.errors); 67138 } else if (this.isInvalid(status, headers, payload)) { 67139 return new _emberAjaxErrors.InvalidError(payload.errors); 67140 } 67141 67142 var errors = this.normalizeErrorResponse(status, headers, payload); 67143 67144 return new _emberAjaxErrors.AjaxError(errors); 67145 }, 67146 67147 /** 67148 Default `handleResponse` implementation uses this hook to decide if the 67149 response is a an authorized error. 67150 @method isUnauthorized 67151 @param {Number} status 67152 @param {Object} headers 67153 @param {Object} payload 67154 @return {Boolean} 67155 */ 67156 isUnauthorized: function isUnauthorized(status /*, headers, payload */) { 67157 return status === 401; 67158 }, 67159 67160 /** 67161 Default `handleResponse` implementation uses this hook to decide if the 67162 response is a forbidden error. 67163 @method isForbidden 67164 @param {Number} status 67165 @param {Object} headers 67166 @param {Object} payload 67167 @return {Boolean} 67168 */ 67169 isForbidden: function isForbidden(status /*, headers, payload */) { 67170 return status === 403; 67171 }, 67172 67173 /** 67174 Default `handleResponse` implementation uses this hook to decide if the 67175 response is a an invalid error. 67176 @method isInvalid 67177 @param {Number} status 67178 @param {Object} headers 67179 @param {Object} payload 67180 @return {Boolean} 67181 */ 67182 isInvalid: function isInvalid(status /*, headers, payload */) { 67183 return status === 422; 67184 }, 67185 67186 /** 67187 Default `handleResponse` implementation uses this hook to decide if the 67188 response is a success. 67189 @method isSuccess 67190 @param {Number} status 67191 @param {Object} headers 67192 @param {Object} payload 67193 @return {Boolean} 67194 */ 67195 isSuccess: function isSuccess(status /*, headers, payload */) { 67196 return status >= 200 && status < 300 || status === 304; 67197 }, 67198 67199 /** 67200 @method parseErrorResponse 67201 @private 67202 @param {String} responseText 67203 @return {Object} 67204 */ 67205 parseErrorResponse: function parseErrorResponse(responseText) { 67206 var json = responseText; 67207
67208 try { 67209 json = _ember['default'].$.parseJSON(responseText); 67210 } catch (e) {} 67211 67212 return json; 67213 }, 67214 67215 /** 67216 @method normalizeErrorResponse 67217 @private 67218 @param {Number} status 67219 @param {Object} headers 67220 @param {Object} payload 67221 @return {Object} errors payload 67222 */ 67223 normalizeErrorResponse: function normalizeErrorResponse(status, headers, payload) { 67224 if (payload && typeof payload === 'object' && payload.errors) { 67225 return payload.errors; 67226 } else { 67227 return [{ 67228 status: '' + status, 67229 title: "The backend responded with an error", 67230 detail: '' + payload 67231 }]; 67232 } 67233 } 67234 }); 67235}); 67236define("ember-ajax/utils/parse-args", ["exports"], function (exports) { 67237 "use strict"; 67238 67239 var _slicedToArray = (function () { 67240 function sliceIterator(arr, i) { 67241 var _arr = [];var _n = true;var _d = false;var _e = undefined;try { 67242 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 67243 _arr.push(_s.value);if (i && _arr.length === i) break; 67244 } 67245 } catch (err) { 67246 _d = true;_e = err; 67247 } finally { 67248 try { 67249 if (!_n && _i["return"]) _i["return"](); 67250 } finally { 67251 if (_d) throw _e; 67252 } 67253 }return _arr; 67254 }return function (arr, i) { 67255 if (Array.isArray(arr)) { 67256 return arr; 67257 } else if (Symbol.iterator in Object(arr)) { 67258 return sliceIterator(arr, i); 67259 } else { 67260 throw new TypeError("Invalid attempt to destructure non-iterable instance"); 67261 } 67262 }; 67263 })(); 67264 67265 exports["default"] = parseArgs; 67266 67267 function parseArgs() { 67268 var args = [].slice.apply(arguments); 67269 if (args.length === 1) { 67270 if (typeof args[0] === "string") { 67271 var _args = _slicedToArray(args, 1); 67272 67273 var url = _args[0]; 67274 67275 return [url]; 67276 } else { 67277 var _args2 = _slicedToArray(args, 1); 67278 67279 var options = _args2[0]; 67280 var url = options.url; 67281 67282 delete options.url; 67283 var type = options.type || options.method; 67284 delete options.type; 67285 delete options.method; 67286 return [url, type, options]; 67287 } 67288 } 67289 if (args.length === 2) { 67290 var _args3 = _slicedToArray(args, 1); 67291 67292 var url = _args3[0]; 67293 67294 if (typeof args[1] === 'object') { 67295 var options = args[1]; 67296 var type = options.type || options.method; 67297 delete options.type; 67298 delete options.method; 67299 return [url, type, options]; 67300 } else { 67301 var type = args[1]; 67302 return [url, type]; 67303 } 67304 } 67305 return args; 67306 } 67307}); 67308define('ember-ajax/utils/parse-response-headers', ['exports'], function (exports) { 67309 'use strict'; 67310 67311 exports['default'] = parseResponseHeaders; 67312 67313 function parseResponseHeaders(headerStr) { 67314 var headers = Object.create(null); 67315 if (!headerStr) { 67316 return headers; 67317 } 67318 67319 var headerPairs = headerStr.split('\r\n'); 67320 for (var i = 0; i < headerPairs.length; i++) { 67321 var headerPair = headerPairs[i]; 67322 // Can't use split() here because it does the wrong thing 67323 // if the header value has the string ": " in it. 67324 var index = headerPair.indexOf(': '); 67325 if (index > 0) { 67326 var key = headerPair.substring(0, index); 67327 var val = headerPair.substring(index + 2); 67328 headers[key] = val; 67329 } 67330 } 67331 67332 return headers; 67333 } 67334}); 67335define('ember-cli-app-version/initializer-factory', ['exports', 'ember'], function (exports, _ember) { 67336 'use strict'; 67337 67338 exports['default'] = initializerFactory; 67339 67340 var classify = _ember['default'].String.classify; 67341 var libraries = _ember['default'].libraries; 67342 67343 function initializerFactory(name, version) { 67344 var registered = false; 67345 67346 return function () { 67347 if (!registered && name && version) { 67348 var appName = classify(name); 67349 libraries.register(appName, version); 67350 registered = true; 67351 } 67352 }; 67353 } 67354}); 67355define("ember-data/-private/adapters", ["exports", "ember-data/adapters/json-api", "ember-data/adapters/rest"], function (exports, _emberDataAdaptersJsonApi, _emberDataAdaptersRest) { 67356 /** 67357 @module ember-data 67358 */ 67359 67360 "use strict"; 67361 67362 exports.JSONAPIAdapter = _emberDataAdaptersJsonApi["default"]; 67363 exports.RESTAdapter = _emberDataAdaptersRest["default"]; 67364}); 67365define('ember-data/-private/adapters/build-url-mixin', ['exports', 'ember'], function (exports, _ember) { 67366 'use strict'; 67367 67368 var get = _ember['default'].get; 67369 67370 /** 67371 67372 WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 67373 67374 ## Using BuildURLMixin 67375 67376 To use url building, include the mixin when extending an adapter, and call `buildURL` where needed. 67377 The default behaviour is designed for RESTAdapter. 67378 67379 ### Example 67380 67381 ```javascript 67382 export default DS.Adapter.extend(BuildURLMixin, {
67383 findRecord: function(store, type, id, snapshot) { 67384 var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); 67385 return this.ajax(url, 'GET'); 67386 } 67387 }); 67388 ``` 67389 67390 ### Attributes 67391 67392 The `host` and `namespace` attributes will be used if defined, and are optional. 67393 67394 @class BuildURLMixin 67395 @namespace DS 67396 */ 67397 exports['default'] = _ember['default'].Mixin.create({ 67398 /** 67399 Builds a URL for a given type and optional ID. 67400 By default, it pluralizes the type's name (for example, 'post' 67401 becomes 'posts' and 'person' becomes 'people'). To override the 67402 pluralization see [pathForType](#method_pathForType). 67403 If an ID is specified, it adds the ID to the path generated 67404 for the type, separated by a `/`. 67405 When called by RESTAdapter.findMany() the `id` and `snapshot` parameters 67406 will be arrays of ids and snapshots. 67407 @method buildURL 67408 @param {String} modelName 67409 @param {(String|Array|Object)} id single id or array of ids or query 67410 @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots 67411 @param {String} requestType 67412 @param {Object} query object of query parameters to send for query requests. 67413 @return {String} url 67414 */ 67415 buildURL: function buildURL(modelName, id, snapshot, requestType, query) { 67416 switch (requestType) { 67417 case 'findRecord': 67418 return this.urlForFindRecord(id, modelName, snapshot); 67419 case 'findAll': 67420 return this.urlForFindAll(modelName, snapshot); 67421 case 'query': 67422 return this.urlForQuery(query, modelName); 67423 case 'queryRecord': 67424 return this.urlForQueryRecord(query, modelName); 67425 case 'findMany': 67426 return this.urlForFindMany(id, modelName, snapshot); 67427 case 'findHasMany': 67428 return this.urlForFindHasMany(id, modelName, snapshot); 67429 case 'findBelongsTo': 67430 return this.urlForFindBelongsTo(id, modelName, snapshot); 67431 case 'createRecord': 67432 return this.urlForCreateRecord(modelName, snapshot); 67433 case 'updateRecord': 67434 return this.urlForUpdateRecord(id, modelName, snapshot); 67435 case 'deleteRecord': 67436 return this.urlForDeleteRecord(id, modelName, snapshot); 67437 default: 67438 return this._buildURL(modelName, id); 67439 } 67440 }, 67441 67442 /** 67443 @method _buildURL 67444 @private 67445 @param {String} modelName 67446 @param {String} id 67447 @return {String} url 67448 */ 67449 _buildURL: function _buildURL(modelName, id) { 67450 var url = []; 67451 var host = get(this, 'host'); 67452 var prefix = this.urlPrefix(); 67453 var path; 67454 67455 if (modelName) { 67456 path = this.pathForType(modelName); 67457 if (path) { 67458 url.push(path); 67459 } 67460 } 67461 67462 if (id) { 67463 url.push(encodeURIComponent(id)); 67464 } 67465 if (prefix) { 67466 url.unshift(prefix); 67467 } 67468 67469 url = url.join('/'); 67470 if (!host && url && url.charAt(0) !== '/') { 67471 url = '/' + url; 67472 } 67473 67474 return url; 67475 }, 67476 67477 /** 67478 * @method urlForFindRecord 67479 * @param {String} id 67480 * @param {String} modelName 67481 * @param {DS.Snapshot} snapshot 67482 * @return {String} url 67483 */ 67484 urlForFindRecord: function urlForFindRecord(id, modelName, snapshot) { 67485 return this._buildURL(modelName, id); 67486 }, 67487 67488 /** 67489 * @method urlForFindAll 67490 * @param {String} modelName 67491 * @param {DS.SnapshotRecordArray} snapshot 67492 * @return {String} url 67493 */ 67494 urlForFindAll: function urlForFindAll(modelName, snapshot) { 67495 return this._buildURL(modelName); 67496 }, 67497 67498 /** 67499 * @method urlForQuery 67500 * @param {Object} query 67501 * @param {String} modelName 67502 * @return {String} url 67503 */ 67504 urlForQuery: function urlForQuery(query, modelName) { 67505 return this._buildURL(modelName); 67506 }, 67507 67508 /** 67509 * @method urlForQueryRecord 67510 * @param {Object} query 67511 * @param {String} modelName 67512 * @return {String} url 67513 */ 67514 urlForQueryRecord: function urlForQueryRecord(query, modelName) { 67515 return this._buildURL(modelName); 67516 }, 67517 67518 /** 67519 * @method urlForFindMany 67520 * @param {Array} ids 67521 * @param {String} modelName 67522 * @param {Array} snapshots 67523 * @return {String} url 67524 */ 67525 urlForFindMany: function urlForFindMany(ids, modelName, snapshots) { 67526 return this._buildURL(modelName); 67527 }, 67528 67529 /** 67530 * @method urlForFindHasMany 67531 * @param {String} id 67532 * @param {String} modelName 67533 * @param {DS.Snapshot} snapshot 67534 * @return {String} url 67535 */ 67536 urlForFindHasMany: function urlForFindHasMany(id, modelName, snapshot) { 67537 return this._buildURL(modelName, id); 67538 }, 67539 67540 /** 67541 * @method urlForFindBelongsTo 67542 * @param {String} id 67543 * @param {String} modelName 67544 * @param {DS.Snapshot} snapshot 67545 * @return {String} url 67546 */ 67547 urlForFindBelongsTo: function urlForFindBelongsTo(id, modelName, snapshot) { 67548 return this._buildURL(modelName, id); 67549 }, 67550 67551 /** 67552 * @method urlForCreateRecord 67553 * @param {String} modelName 67554 * @param {DS.Snapshot} snapshot 67555 * @return {String} url 67556 */ 67557 urlForCreateRecord: function urlForCreateRecord(modelName, snapshot) { 67558 return this._buildURL(modelName); 67559 }, 67560 67561 /** 67562 * @method urlForUpdateRecord 67563 * @param {String} id 67564 * @param {String} modelName 67565 * @param {DS.Snapshot} snapshot 67566 * @return {String} url 67567 */ 67568 urlForUpdateRecord: function urlForUpdateRecord(id, modelName, snapshot) { 67569 return this._buildURL(modelName, id); 67570 }, 67571 67572 /** 67573 * @method urlForDeleteRecord 67574 * @param {String} id 67575 * @param {String} modelName 67576 * @param {DS.Snapshot} snapshot 67577 * @return {String} url 67578 */ 67579 urlForDeleteRecord: function urlForDeleteRecord(id, modelName, snapshot) { 67580 return this._buildURL(modelName, id); 67581 }, 67582 67583 /** 67584 @method urlPrefix 67585 @private 67586 @param {String} path 67587 @param {String} parentURL 67588 @return {String} urlPrefix 67589 */ 67590 urlPrefix: function urlPrefix(path, parentURL) { 67591 var host = get(this, 'host'); 67592 var namespace = get(this, 'namespace'); 67593 67594 if (!host || host === '/') { 67595 host = ''; 67596 } 67597 67598 if (path) { 67599 // Protocol relative url 67600 if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) {
67601 // Do nothing, the full host is already included. 67602 return path; 67603 67604 // Absolute path 67605 } else if (path.charAt(0) === '/') { 67606 return '' + host + path; 67607 // Relative path 67608 } else { 67609 return parentURL + '/' + path; 67610 } 67611 } 67612 67613 // No path provided 67614 var url = []; 67615 if (host) { 67616 url.push(host); 67617 } 67618 if (namespace) { 67619 url.push(namespace); 67620 } 67621 return url.join('/'); 67622 }, 67623 67624 /** 67625 Determines the pathname for a given type. 67626 By default, it pluralizes the type's name (for example, 67627 'post' becomes 'posts' and 'person' becomes 'people'). 67628 ### Pathname customization 67629 For example if you have an object LineItem with an 67630 endpoint of "/line_items/". 67631 ```app/adapters/application.js 67632 import DS from 'ember-data'; 67633 export default DS.RESTAdapter.extend({ 67634 pathForType: function(modelName) { 67635 var decamelized = Ember.String.decamelize(modelName); 67636 return Ember.String.pluralize(decamelized); 67637 } 67638 }); 67639 ``` 67640 @method pathForType 67641 @param {String} modelName 67642 @return {String} path 67643 **/ 67644 pathForType: function pathForType(modelName) { 67645 var camelized = _ember['default'].String.camelize(modelName); 67646 return _ember['default'].String.pluralize(camelized); 67647 } 67648 }); 67649}); 67650define('ember-data/-private/core', ['exports', 'ember', 'ember-data/version'], function (exports, _ember, _emberDataVersion) { 67651 'use strict'; 67652 67653 /** 67654 @module ember-data 67655 */ 67656 67657 /** 67658 All Ember Data methods and functions are defined inside of this namespace. 67659 67660 @class DS 67661 @static 67662 */ 67663 67664 /** 67665 @property VERSION 67666 @type String 67667 @static 67668 */ 67669 var DS = _ember['default'].Namespace.create({ 67670 VERSION: _emberDataVersion['default'], 67671 name: "DS" 67672 }); 67673 67674 if (_ember['default'].libraries) { 67675 _ember['default'].libraries.registerCoreLibrary('Ember Data', DS.VERSION); 67676 } 67677 67678 exports['default'] = DS; 67679}); 67680define('ember-data/-private/debug', ['exports', 'ember'], function (exports, _ember) { 67681 'use strict'; 67682 67683 exports.assert = assert; 67684 exports.debug = debug; 67685 exports.deprecate = deprecate; 67686 exports.info = info; 67687 exports.runInDebug = runInDebug; 67688 exports.warn = warn; 67689 exports.debugSeal = debugSeal; 67690 exports.assertPolymorphicType = assertPolymorphicType; 67691 67692 function assert() { 67693 return _ember['default'].assert.apply(_ember['default'], arguments); 67694 } 67695 67696 function debug() { 67697 return _ember['default'].debug.apply(_ember['default'], arguments); 67698 } 67699 67700 function deprecate() { 67701 return _ember['default'].deprecate.apply(_ember['default'], arguments); 67702 } 67703 67704 function info() { 67705 return _ember['default'].info.apply(_ember['default'], arguments); 67706 } 67707 67708 function runInDebug() { 67709 return _ember['default'].runInDebug.apply(_ember['default'], arguments); 67710 } 67711 67712 function warn() { 67713 return _ember['default'].warn.apply(_ember['default'], arguments); 67714 } 67715 67716 function debugSeal() { 67717 return _ember['default'].debugSeal.apply(_ember['default'], arguments); 67718 } 67719 67720 function checkPolymorphic(typeClass, addedRecord) { 67721 if (typeClass.__isMixin) { 67722 //TODO Need to do this in order to support mixins, should convert to public api 67723 //once it exists in Ember 67724 return typeClass.__mixin.detect(addedRecord.type.PrototypeMixin); 67725 } 67726 if (_ember['default'].MODEL_FACTORY_INJECTIONS) { 67727 typeClass = typeClass.superclass; 67728 } 67729 return typeClass.detect(addedRecord.type); 67730 } 67731 67732 /** 67733 Assert that `addedRecord` has a valid type so it can be added to the 67734 relationship of the `record`. 67735 67736 The assert basically checks if the `addedRecord` can be added to the 67737 relationship (specified via `relationshipMeta`) of the `record`. 67738 67739 This utility should only be used internally, as both record parameters must 67740 be an InternalModel and the `relationshipMeta` needs to be the meta 67741 information about the relationship, retrieved via 67742 `record.relationshipFor(key)`. 67743 67744 @method assertPolymorphicType 67745 @param {InternalModel} record 67746 @param {RelationshipMeta} relationshipMeta retrieved via 67747 `record.relationshipFor(key)` 67748 @param {InternalModel} addedRecord record which 67749 should be added/set for the relationship 67750 */ 67751 67752 function assertPolymorphicType(record, relationshipMeta, addedRecord) { 67753 var addedType = addedRecord.type.modelName; 67754 var recordType = record.type.modelName; 67755 var key = relationshipMeta.key; 67756 var typeClass = record.store.modelFor(relationshipMeta.type); 67757
67758 var assertionMessage = 'You cannot add a record of type \'' + addedType + '\' to the \'' + recordType + '.' + key + '\' relationship (only \'' + typeClass.modelName + '\' allowed)'; 67759 67760 assert(assertionMessage, checkPolymorphic(typeClass, addedRecord)); 67761 } 67762}); 67763define('ember-data/-private/ext/date', ['exports', 'ember', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateDebug) { 67764 /** 67765 @module ember-data 67766 */ 67767 67768 'use strict'; 67769 67770 _ember['default'].Date = _ember['default'].Date || {}; 67771 67772 var origParse = Date.parse; 67773 var numericKeys = [1, 4, 5, 6, 7, 10, 11]; 67774 67775 var parseDate = function parseDate(date) { 67776 var timestamp, struct; 67777 var minutesOffset = 0; 67778 67779 // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string 67780 // before falling back to any implementation-specific date parsing, so thatâs what we do, even if native 67781 // implementations could be faster 67782 // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm 67783 if (struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?:(\d{2}))?)?)?$/.exec(date)) { 67784 // avoid NaN timestamps caused by âundefinedâ values being passed to Date.UTC 67785 for (var i = 0, k; k = numericKeys[i]; ++i) { 67786 struct[k] = +struct[k] || 0; 67787 } 67788 67789 // allow undefined days and months 67790 struct[2] = (+struct[2] || 1) - 1; 67791 struct[3] = +struct[3] || 1; 67792 67793 if (struct[8] !== 'Z' && struct[9] !== undefined) { 67794 minutesOffset = struct[10] * 60 + struct[11]; 67795 67796 if (struct[9] === '+') { 67797 minutesOffset = 0 - minutesOffset; 67798 } 67799 } 67800 67801 timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); 67802 } else { 67803 timestamp = origParse ? origParse(date) : NaN; 67804 } 67805 67806 return timestamp; 67807 }; 67808 67809 exports.parseDate = parseDate; 67810 67811 _ember['default'].Date.parse = function (date) { 67812 // throw deprecation 67813 (0, _emberDataPrivateDebug.deprecate)('Ember.Date.parse is deprecated because Safari 5-, IE8-, and\n Firefox 3.6- are no longer supported (see\n https://github.com/csnover/js-iso8601 for the history of this issue).\n Please use Date.parse instead', false, { 67814 id: 'ds.ember.date.parse-deprecate', 67815 until: '3.0.0' 67816 }); 67817 67818 return parseDate(date); 67819 }; 67820 67821 if (_ember['default'].EXTEND_PROTOTYPES === true || _ember['default'].EXTEND_PROTOTYPES.Date) { 67822 (0, _emberDataPrivateDebug.deprecate)('Overriding Date.parse with Ember.Date.parse is deprecated. Please set ENV.EmberENV.EXTEND_PROTOTYPES.Date to false in config/environment.js\n\n\n// config/environment.js\nENV = {\n EmberENV: {\n EXTEND_PROTOTYPES: {\n Date: false,\n }\n }\n}\n', false, { 67823 id: 'ds.date.parse-deprecate', 67824 until: '3.0.0' 67825 }); 67826 Date.parse = parseDate; 67827 } 67828}); 67829define('ember-data/-private/features', ['exports', 'ember'], function (exports, _ember) { 67830 'use strict'; 67831 67832 exports['default'] = isEnabled; 67833 67834 function isEnabled() { 67835 var _Ember$FEATURES; 67836 67837 return (_Ember$FEATURES = _ember['default'].FEATURES).isEnabled.apply(_Ember$FEATURES, arguments); 67838 } 67839}); 67840define('ember-data/-private/global', ['exports'], function (exports) { 67841 /* globals global, window, self */ 67842 67843 // originally from https://github.com/emberjs/ember.js/blob/c0bd26639f50efd6a03ee5b87035fd200e313b8e/packages/ember-environment/lib/global.js 67844 67845 // from lodash to catch fake globals 67846 'use strict'; 67847 67848 function checkGlobal(value) { 67849 return value && value.Object === Object ? value : undefined; 67850 } 67851 67852 // element ids can ruin global miss checks 67853 function checkElementIdShadowing(value) { 67854 return value && value.nodeType === undefined ? value : undefined; 67855 } 67856 67857 // export real global 67858 exports['default'] = checkGlobal(checkElementIdShadowing(typeof global === 'object' && global)) || checkGlobal(typeof self === 'object' && self) || checkGlobal(typeof window === 'object' && window) || new Function('return this')(); 67859 // eval outside of strict mode 67860});
67861define("ember-data/-private/initializers/data-adapter", ["exports", "ember-data/-private/system/debug/debug-adapter"], function (exports, _emberDataPrivateSystemDebugDebugAdapter) { 67862 "use strict"; 67863 67864 exports["default"] = initializeDebugAdapter; 67865 67866 /** 67867 Configures a registry with injections on Ember applications 67868 for the Ember-Data store. Accepts an optional namespace argument. 67869 67870 @method initializeStoreInjections 67871 @param {Ember.Registry} registry 67872 */ 67873 function initializeDebugAdapter(registry) { 67874 registry.register('data-adapter:main', _emberDataPrivateSystemDebugDebugAdapter["default"]); 67875 } 67876}); 67877define('ember-data/-private/initializers/store-injections', ['exports'], function (exports) { 67878 'use strict'; 67879 67880 exports['default'] = initializeStoreInjections; 67881 67882 /** 67883 Configures a registry with injections on Ember applications 67884 for the Ember-Data store. Accepts an optional namespace argument. 67885 67886 @method initializeStoreInjections 67887 @param {Ember.Registry} registry 67888 */ 67889 function initializeStoreInjections(registry) { 67890 // registry.injection for Ember < 2.1.0 67891 // application.inject for Ember 2.1.0+ 67892 var inject = registry.inject || registry.injection; 67893 inject.call(registry, 'controller', 'store', 'service:store'); 67894 inject.call(registry, 'route', 'store', 'service:store'); 67895 inject.call(registry, 'data-adapter', 'store', 'service:store'); 67896 } 67897}); 67898define("ember-data/-private/initializers/store", ["exports", "ember-data/-private/system/store", "ember-data/-private/serializers", "ember-data/-private/adapters"], function (exports, _emberDataPrivateSystemStore, _emberDataPrivateSerializers, _emberDataPrivateAdapters) { 67899 "use strict"; 67900 67901 exports["default"] = initializeStore; 67902 67903 function has(applicationOrRegistry, fullName) { 67904 if (applicationOrRegistry.has) { 67905 // < 2.1.0 67906 return applicationOrRegistry.has(fullName); 67907 } else { 67908 // 2.1.0+ 67909 return applicationOrRegistry.hasRegistration(fullName); 67910 } 67911 } 67912 67913 /** 67914 Configures a registry for use with an Ember-Data 67915 store. Accepts an optional namespace argument. 67916 67917 @method initializeStore 67918 @param {Ember.Registry} registry 67919 */ 67920 function initializeStore(registry) { 67921 // registry.optionsForType for Ember < 2.1.0 67922 // application.registerOptionsForType for Ember 2.1.0+ 67923 var registerOptionsForType = registry.registerOptionsForType || registry.optionsForType; 67924 registerOptionsForType.call(registry, 'serializer', { singleton: false }); 67925 registerOptionsForType.call(registry, 'adapter', { singleton: false }); 67926 67927 registry.register('serializer:-default', _emberDataPrivateSerializers.JSONSerializer); 67928 registry.register('serializer:-rest', _emberDataPrivateSerializers.RESTSerializer); 67929 registry.register('adapter:-rest', _emberDataPrivateAdapters.RESTAdapter); 67930 67931 registry.register('adapter:-json-api', _emberDataPrivateAdapters.JSONAPIAdapter); 67932 registry.register('serializer:-json-api', _emberDataPrivateSerializers.JSONAPISerializer); 67933 67934 if (!has(registry, 'service:store')) { 67935 registry.register('service:store', _emberDataPrivateSystemStore["default"]); 67936 } 67937 } 67938}); 67939define('ember-data/-private/initializers/transforms', ['exports', 'ember-data/-private/transforms'], function (exports, _emberDataPrivateTransforms) { 67940 'use strict'; 67941 67942 exports['default'] = initializeTransforms; 67943 67944 /** 67945 Configures a registry for use with Ember-Data 67946 transforms. 67947 67948 @method initializeTransforms 67949 @param {Ember.Registry} registry 67950 */ 67951 function initializeTransforms(registry) { 67952 registry.register('transform:boolean', _emberDataPrivateTransforms.BooleanTransform); 67953 registry.register('transform:date', _emberDataPrivateTransforms.DateTransform); 67954 registry.register('transform:number', _emberDataPrivateTransforms.NumberTransform); 67955 registry.register('transform:string', _emberDataPrivateTransforms.StringTransform); 67956 } 67957}); 67958define('ember-data/-private/instance-initializers/initialize-store-service', ['exports'], function (exports) { 67959 'use strict'; 67960 67961 exports['default'] = initializeStoreService; 67962 67963 /** 67964 Configures a registry for use with an Ember-Data 67965 store. 67966 67967 @method initializeStore 67968 @param {Ember.ApplicationInstance} applicationOrRegistry 67969 */ 67970 function initializeStoreService(application) { 67971 var container = application.lookup ? application : application.container; 67972 // Eagerly generate the store so defaultStore is populated. 67973 container.lookup('service:store'); 67974 } 67975}); 67976define("ember-data/-private/serializers", ["exports", "ember-data/serializers/json-api", "ember-data/serializers/json", "ember-data/serializers/rest"], function (exports, _emberDataSerializersJsonApi, _emberDataSerializersJson, _emberDataSerializersRest) { 67977 /** 67978 @module ember-data 67979 */ 67980 67981 "use strict"; 67982 67983 exports.JSONAPISerializer = _emberDataSerializersJsonApi["default"]; 67984 exports.JSONSerializer = _emberDataSerializersJson["default"]; 67985 exports.RESTSerializer = _emberDataSerializersRest["default"]; 67986}); 67987define("ember-data/-private/system/clone-null", ["exports", "ember-data/-private/system/empty-object"], function (exports, _emberDataPrivateSystemEmptyObject) { 67988 "use strict"; 67989 67990 exports["default"] = cloneNull; 67991 67992 function cloneNull(source) { 67993 var clone = new _emberDataPrivateSystemEmptyObject["default"](); 67994 for (var key in source) { 67995 clone[key] = source[key]; 67996 } 67997 return clone; 67998 } 67999}); 68000define('ember-data/-private/system/coerce-id', ['exports'], function (exports) { 68001 'use strict'; 68002 68003 exports['default'] = coerceId; 68004 68005 // Used by the store to normalize IDs entering the store. Despite the fact 68006 // that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`), 68007 // it is important that internally we use strings, since IDs may be serialized 68008 // and lose type information. For example, Ember's router may put a record's 68009 // ID into the URL, and if we later try to deserialize that URL and find the 68010 // corresponding record, we will not know if it is a string or a number. 68011 68012 function coerceId(id) { 68013 return id === null || id === undefined || id === '' ? null : id + ''; 68014 } 68015}); 68016define('ember-data/-private/system/container-proxy', ['exports', 'ember-data/-private/debug'], function (exports, _emberDataPrivateDebug) { 68017 'use strict'; 68018 68019 exports['default'] = ContainerProxy; 68020 68021 /* 68022 This is used internally to enable deprecation of container paths and provide 68023 a decent message to the user indicating how to fix the issue. 68024 68025 @class ContainerProxy 68026 @namespace DS 68027 @private 68028 */ 68029 function ContainerProxy(container) { 68030 this.container = container; 68031 } 68032 68033 ContainerProxy.prototype.aliasedFactory = function (path, preLookup) { 68034 var _this = this; 68035 68036 return { 68037 create: function create() { 68038 if (preLookup) { 68039 preLookup(); 68040 } 68041 68042 return _this.container.lookup(path); 68043 } 68044 }; 68045 }; 68046 68047 ContainerProxy.prototype.registerAlias = function (source, dest, preLookup) { 68048 var factory = this.aliasedFactory(dest, preLookup); 68049 68050 return this.container.register(source, factory); 68051 }; 68052 68053 ContainerProxy.prototype.registerDeprecation = function (deprecated, val
68053id) { 68054 var preLookupCallback = function preLookupCallback() { 68055 (0, _emberDataPrivateDebug.deprecate)('You tried to look up \'' + deprecated + '\', but this has been deprecated in favor of \'' + valid + '\'.', false, { 68056 id: 'ds.store.deprecated-lookup', 68057 until: '2.0.0' 68058 }); 68059 }; 68060 68061 return this.registerAlias(deprecated, valid, preLookupCallback); 68062 }; 68063 68064 ContainerProxy.prototype.registerDeprecations = function (proxyPairs) { 68065 var i, proxyPair, deprecated, valid; 68066 68067 for (i = proxyPairs.length; i > 0; i--) { 68068 proxyPair = proxyPairs[i - 1]; 68069 deprecated = proxyPair['deprecated']; 68070 valid = proxyPair['valid']; 68071 68072 this.registerDeprecation(deprecated, valid); 68073 } 68074 }; 68075}); 68076define("ember-data/-private/system/debug", ["exports", "ember-data/-private/system/debug/debug-adapter"], function (exports, _emberDataPrivateSystemDebugDebugAdapter) { 68077 /** 68078 @module ember-data 68079 */ 68080 68081 "use strict"; 68082 68083 exports["default"] = _emberDataPrivateSystemDebugDebugAdapter["default"]; 68084}); 68085define('ember-data/-private/system/debug/debug-adapter', ['exports', 'ember', 'ember-data/model'], function (exports, _ember, _emberDataModel) { 68086 /** 68087 @module ember-data 68088 */ 68089 'use strict'; 68090 68091 var get = _ember['default'].get; 68092 var capitalize = _ember['default'].String.capitalize; 68093 var underscore = _ember['default'].String.underscore; 68094 var assert = _ember['default'].assert; 68095 68096 /* 68097 Extend `Ember.DataAdapter` with ED specific code. 68098 68099 @class DebugAdapter 68100 @namespace DS 68101 @extends Ember.DataAdapter 68102 @private 68103 */ 68104 exports['default'] = _ember['default'].DataAdapter.extend({ 68105 getFilters: function getFilters() { 68106 return [{ name: 'isNew', desc: 'New' }, { name: 'isModified', desc: 'Modified' }, { name: 'isClean', desc: 'Clean' }]; 68107 }, 68108 68109 detect: function detect(typeClass) { 68110 return typeClass !== _emberDataModel['default'] && _emberDataModel['default'].detect(typeClass); 68111 }, 68112 68113 columnsForType: function columnsForType(typeClass) { 68114 var columns = [{ 68115 name: 'id', 68116 desc: 'Id' 68117 }]; 68118 var count = 0; 68119 var self = this; 68120 get(typeClass, 'attributes').forEach(function (meta, name) { 68121 if (count++ > self.attributeLimit) { 68122 return false; 68123 } 68124 var desc = capitalize(underscore(name).replace('_', ' ')); 68125 columns.push({ name: name, desc: desc }); 68126 }); 68127 return columns; 68128 }, 68129 68130 getRecords: function getRecords(modelClass, modelName) { 68131 if (arguments.length < 2) { 68132 // Legacy Ember.js < 1.13 support 68133 var containerKey = modelClass._debugContainerKey; 68134 if (containerKey) { 68135 var match = containerKey.match(/model:(.*)/); 68136 if (match) { 68137 modelName = match[1]; 68138 } 68139 } 68140 } 68141 assert("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); 68142 return this.get('store').peekAll(modelName); 68143 }, 68144 68145 getRecordColumnValues: function getRecordColumnValues(record) { 68146 var _this = this; 68147 68148 var count = 0; 68149 var columnValues = { id: get(record, 'id') }; 68150 68151 record.eachAttribute(function (key) { 68152 if (count++ > _this.attributeLimit) { 68153 return false; 68154 } 68155 var value = get(record, key); 68156 columnValues[key] = value; 68157 }); 68158 return columnValues; 68159 }, 68160 68161 getRecordKeywords: function getRecordKeywords(record) { 68162 var keywords = []; 68163 var keys = _ember['default'].A(['id']); 68164 record.eachAttribute(function (key) { 68165 return keys.push(key); 68166 }); 68167 keys.forEach(function (key) { 68168 return keywords.push(get(record, key)); 68169 }); 68170 return keywords; 68171 }, 68172 68173 getRecordFilterValues: function getRecordFilterValues(record) { 68174 return { 68175 isNew: record.get('isNew'), 68176 isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), 68177 isClean: !record.get('hasDirtyAttributes') 68178 }; 68179 }, 68180 68181 getRecordColor: function getRecordColor(record) { 68182 var color = 'black'; 68183 if (record.get('isNew')) { 68184 color = 'green'; 68185 } else if (record.get('hasDirtyAttributes')) { 68186 color = 'blue'; 68187 } 68188 return color; 68189 }, 68190 68191 observeRecord: function observeRecord(record, recordUpdated) { 68192 var releaseMethods = _ember['default'].A(); 68193 var keysToObserve = _ember['default'].A(['id', 'isNew', 'hasDirtyAttributes']); 68194 68195 record.eachAttribute(function (key) { 68196 return keysToObserve.push(key); 68197 }); 68198 var adapter = this; 68199 68200 keysToObserve.forEach(function (key) { 68201 var handler = function handler() { 68202 recordUpdated(adapter.wrapRecord(record)); 68203 }; 68204 _ember['default'].addObserver(record, key, handler); 68205 releaseMethods.push(function () { 68206 _ember['default'].removeObserver(record, key, handler); 68207 }); 68208 }); 68209 68210 var release = function release() { 68211 releaseMethods.forEach(function (fn) { 68212 return fn(); 68213 }); 68214 }; 68215 68216 return release; 68217 } 68218 }); 68219}); 68220define('ember-data/-private/system/debug/debug-info', ['exports', 'ember'], function (exports, _ember) { 68221 'use strict'; 68222 68223 exports['default'] = _ember['default'].Mixin.create({ 68224 68225 /** 68226 Provides info about the model for debugging purposes 68227 by grouping the properties into more semantic groups. 68228 Meant to be used by debugging tools such as the Chrome Ember Extension. 68229 - Groups all attributes in "Attributes" group. 68230 - Groups all belongsTo relationships in "Belongs To" group. 68231 - Groups all hasMany relationships in "Has Many" group. 68232 - Groups all flags in "Flags" group. 68233 - Flags relationship CPs as expensive properties. 68234 @method _debugInfo 68235 @for DS.Model 68236 @private 68237 */ 68238 _debugInfo: function _debugInfo() { 68239 var attributes = ['id']; 68240 var relationships = { belongsTo: [], hasMany: [] }; 68241 var expensiveProperties = []; 68242 68243 this.eachAttribute(function (name, meta) { 68244 return attributes.push(name); 68245 }); 68246
68247 this.eachRelationship(function (name, relationship) { 68248 relationships[relationship.kind].push(name); 68249 expensiveProperties.push(name); 68250 }); 68251 68252 var groups = [{ 68253 name: 'Attributes', 68254 properties: attributes, 68255 expand: true 68256 }, { 68257 name: 'Belongs To', 68258 properties: relationships.belongsTo, 68259 expand: true 68260 }, { 68261 name: 'Has Many', 68262 properties: relationships.hasMany, 68263 expand: true 68264 }, { 68265 name: 'Flags', 68266 properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] 68267 }]; 68268 68269 return { 68270 propertyInfo: { 68271 // include all other mixins / properties (not just the grouped ones) 68272 includeOtherProperties: true, 68273 groups: groups, 68274 // don't pre-calculate unless cached 68275 expensiveProperties: expensiveProperties 68276 } 68277 }; 68278 } 68279 }); 68280}); 68281define("ember-data/-private/system/empty-object", ["exports"], function (exports) { 68282 "use strict"; 68283 68284 exports["default"] = EmptyObject; 68285 68286 // This exists because `Object.create(null)` is absurdly slow compared 68287 // to `new EmptyObject()`. In either case, you want a null prototype 68288 // when you're treating the object instances as arbitrary dictionaries 68289 // and don't want your keys colliding with build-in methods on the 68290 // default object prototype. 68291 var proto = Object.create(null, { 68292 // without this, we will always still end up with (new 68293 // EmptyObject()).constructor === Object 68294 constructor: { 68295 value: undefined, 68296 enumerable: false, 68297 writable: true 68298 } 68299 }); 68300 function EmptyObject() {} 68301 68302 EmptyObject.prototype = proto; 68303}); 68304define('ember-data/-private/system/is-array-like', ['exports', 'ember'], function (exports, _ember) { 68305 'use strict'; 68306 68307 exports['default'] = isArrayLike; 68308 68309 /* 68310 We're using this to detect arrays and "array-like" objects. 68311 68312 This is a copy of the `isArray` method found in `ember-runtime/utils` as we're 68313 currently unable to import non-exposed modules. 68314 68315 This method was previously exposed as `Ember.isArray` but since 68316 https://github.com/emberjs/ember.js/pull/11463 `Ember.isArray` is an alias of 68317 `Array.isArray` hence removing the "array-like" part. 68318 */ 68319 function isArrayLike(obj) { 68320 if (!obj || obj.setInterval) { 68321 return false; 68322 } 68323 if (Array.isArray(obj)) { 68324 return true; 68325 } 68326 if (_ember['default'].Array.detect(obj)) { 68327 return true; 68328 } 68329 68330 var type = _ember['default'].typeOf(obj); 68331 if ('array' === type) { 68332 return true; 68333 } 68334 if (obj.length !== undefined && 'object' === type) { 68335 return true; 68336 } 68337 return false; 68338 } 68339}); 68340define("ember-data/-private/system/many-array", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/store/common"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStoreCommon) { 68341 /** 68342 @module ember-data 68343 */ 68344 "use strict"; 68345 68346 var get = _ember["default"].get; 68347 var set = _ember["default"].set; 68348 68349 /** 68350 A `ManyArray` is a `MutableArray` that represents the contents of a has-many 68351 relationship. 68352 68353 The `ManyArray` is instantiated lazily the first time the relationship is 68354 requested. 68355 68356 ### Inverses 68357 68358 Often, the relationships in Ember Data applications will have 68359 an inverse. For example, imagine the following models are 68360 defined: 68361 68362 ```app/models/post.js 68363 import DS from 'ember-data'; 68364 68365 export default DS.Model.extend({ 68366 comments: DS.hasMany('comment') 68367 }); 68368 ``` 68369 68370 ```app/models/comment.js 68371 import DS from 'ember-data'; 68372 68373 export default DS.Model.extend({ 68374 post: DS.belongsTo('post') 68375 }); 68376 ``` 68377 68378 If you created a new instance of `App.Post` and added 68379 a `App.Comment` record to its `comments` has-many 68380 relationship, you would expect the comment's `post` 68381 property to be set to the post that contained 68382 the has-many. 68383 68384 We call the record to which a relationship belongs the 68385 relationship's _owner_. 68386 68387 @class ManyArray 68388 @namespace DS
68389 @extends Ember.Object 68390 @uses Ember.MutableArray, Ember.Evented 68391 */ 68392 exports["default"] = _ember["default"].Object.extend(_ember["default"].MutableArray, _ember["default"].Evented, { 68393 init: function init() { 68394 this._super.apply(this, arguments); 68395 this.currentState = _ember["default"].A([]); 68396 }, 68397 68398 record: null, 68399 68400 canonicalState: null, 68401 currentState: null, 68402 68403 length: 0, 68404 68405 objectAt: function objectAt(index) { 68406 //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses 68407 if (!this.currentState[index]) { 68408 return undefined; 68409 } 68410 return this.currentState[index].getRecord(); 68411 }, 68412 68413 flushCanonical: function flushCanonical() { 68414 //TODO make this smarter, currently its plenty stupid 68415 var toSet = this.canonicalState.filter(function (internalModel) { 68416 return !internalModel.isDeleted(); 68417 }); 68418 68419 //a hack for not removing new records 68420 //TODO remove once we have proper diffing 68421 var newRecords = this.currentState.filter( 68422 // only add new records which are not yet in the canonical state of this 68423 // relationship (a new record can be in the canonical state if it has 68424 function (internalModel) { 68425 return internalModel.isNew() && toSet.indexOf(internalModel) === -1; 68426 }); 68427 toSet = toSet.concat(newRecords); 68428 var oldLength = this.length; 68429 this.arrayContentWillChange(0, this.length, toSet.length); 68430 // Itâs possible the parent side of the relationship may have been unloaded by this point 68431 if ((0, _emberDataPrivateSystemStoreCommon._objectIsAlive)(this)) { 68432 this.set('length', toSet.length); 68433 } 68434 this.currentState = toSet; 68435 this.arrayContentDidChange(0, oldLength, this.length); 68436 //TODO Figure out to notify only on additions and maybe only if unloaded 68437 this.relationship.notifyHasManyChanged(); 68438 this.record.updateRecordArrays(); 68439 }, 68440 /** 68441 `true` if the relationship is polymorphic, `false` otherwise. 68442 @property {Boolean} isPolymorphic 68443 @private 68444 */ 68445 isPolymorphic: false, 68446 68447 /** 68448 The loading state of this array 68449 @property {Boolean} isLoaded 68450 */ 68451 isLoaded: false, 68452 68453 /** 68454 The relationship which manages this array. 68455 @property {ManyRelationship} relationship 68456 @private 68457 */ 68458 relationship: null, 68459 68460 /** 68461 Metadata associated with the request for async hasMany relationships. 68462 Example 68463 Given that the server returns the following JSON payload when fetching a 68464 hasMany relationship: 68465 ```js 68466 { 68467 "comments": [{ 68468 "id": 1, 68469 "comment": "This is the first comment", 68470 }, { 68471 // ... 68472 }], 68473 "meta": { 68474 "page": 1, 68475 "total": 5 68476 } 68477 } 68478 ``` 68479 You can then access the metadata via the `meta` property: 68480 ```js 68481 post.get('comments').then(function(comments) { 68482 var meta = comments.get('meta'); 68483 // meta.page => 1 68484 // meta.total => 5 68485 }); 68486 ``` 68487 @property {Object} meta 68488 @public 68489 */ 68490 meta: null, 68491 68492 internalReplace: function internalReplace(idx, amt, objects) { 68493 if (!objects) { 68494 objects = []; 68495 } 68496 this.arrayContentWillChange(idx, amt, objects.length); 68497 this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); 68498 this.set('length', this.currentState.length); 68499 this.arrayContentDidChange(idx, amt, objects.length); 68500 if (objects) { 68501 //TODO(Igor) probably needed only for unloaded records 68502 this.relationship.notifyHasManyChanged(); 68503 } 68504 this.record.updateRecordArrays(); 68505 }, 68506 68507 //TODO(Igor) optimize 68508 internalRemoveRecords: function internalRemoveRecords(records) { 68509 var index; 68510 for (var i = 0; i < records.length; i++) { 68511 index = this.currentState.indexOf(records[i]); 68512 this.internalReplace(index, 1); 68513 } 68514 }, 68515 68516 //TODO(Igor) optimize 68517 internalAddRecords: function internalAddRecords(records, idx) { 68518 if (idx === undefined) { 68519 idx = this.currentState.length; 68520 } 68521 this.internalReplace(idx, 0, records); 68522 }, 68523 68524 replace: function replace(idx, amt, objects) { 68525 var records; 68526 if (amt > 0) { 68527 records = this.currentState.slice(idx, idx + amt); 68528 this.get('relationship').removeRecords(records); 68529 } 68530 if (objects) { 68531 this.get('relationship').addRecords(objects.map(function (obj) { 68532 return obj._internalModel; 68533 }), idx); 68534 } 68535 }, 68536 /** 68537 Used for async `hasMany` arrays 68538 to keep track of when they will resolve. 68539 @property {Ember.RSVP.Promise} promise 68540 @private 68541 */ 68542 promise: null, 68543 68544 /** 68545 @method loadingRecordsCount 68546 @param {Number} count 68547 @private 68548 */ 68549 loadingRecordsCount: function loadingRecordsCount(count) { 68550 this.loadingRecordsCount = count; 68551 }, 68552 68553 /** 68554 @method loadedRecord 68555 @private 68556 */ 68557 loadedRecord: function loadedRecord() { 68558 this.loadingRecordsCount--; 68559 if (this.loadingRecordsCount === 0) { 68560 set(this, 'isLoaded', true); 68561 this.trigger('didLoad'); 68562 } 68563 }, 68564 68565 /** 68566 @method reload 68567 @public 68568 */ 68569 reload: function reload() { 68570 return this.relationship.reload(); 68571 }, 68572 68573 /** 68574 Saves all of the records in the `ManyArray`. 68575 Example 68576 ```javascript 68577 store.findRecord('inbox', 1).then(function(inbox) { 68578 inbox.get('messages').then(function(messages) {
68579 messages.forEach(function(message) { 68580 message.set('isRead', true); 68581 }); 68582 messages.save() 68583 }); 68584 }); 68585 ``` 68586 @method save 68587 @return {DS.PromiseArray} promise 68588 */ 68589 save: function save() { 68590 var manyArray = this; 68591 var promiseLabel = "DS: ManyArray#save " + get(this, 'type'); 68592 var promise = _ember["default"].RSVP.all(this.invoke("save"), promiseLabel).then(function (array) { 68593 return manyArray; 68594 }, null, "DS: ManyArray#save return ManyArray"); 68595 68596 return _emberDataPrivateSystemPromiseProxies.PromiseArray.create({ promise: promise }); 68597 }, 68598 68599 /** 68600 Create a child record within the owner 68601 @method createRecord 68602 @private 68603 @param {Object} hash 68604 @return {DS.Model} record 68605 */ 68606 createRecord: function createRecord(hash) { 68607 var store = get(this, 'store'); 68608 var type = get(this, 'type'); 68609 var record; 68610 68611 (0, _emberDataPrivateDebug.assert)("You cannot add '" + type.modelName + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic')); 68612 record = store.createRecord(type.modelName, hash); 68613 this.pushObject(record); 68614 68615 return record; 68616 } 68617 }); 68618}); 68619// been 'acknowleged' to be in the relationship via a store.push) 68620define("ember-data/-private/system/model", ["exports", "ember-data/-private/system/model/model", "ember-data/attr", "ember-data/-private/system/model/states", "ember-data/-private/system/model/errors"], function (exports, _emberDataPrivateSystemModelModel, _emberDataAttr, _emberDataPrivateSystemModelStates, _emberDataPrivateSystemModelErrors) { 68621 /** 68622 @module ember-data 68623 */ 68624 68625 "use strict"; 68626 68627 exports.RootState = _emberDataPrivateSystemModelStates["default"]; 68628 exports.attr = _emberDataAttr["default"]; 68629 exports.Errors = _emberDataPrivateSystemModelErrors["default"]; 68630 exports["default"] = _emberDataPrivateSystemModelModel["default"]; 68631}); 68632define("ember-data/-private/system/model/attr", ["exports", "ember", "ember-data/-private/debug"], function (exports, _ember, _emberDataPrivateDebug) { 68633 "use strict"; 68634 68635 var get = _ember["default"].get; 68636 var Map = _ember["default"].Map; 68637 68638 /** 68639 @module ember-data 68640 */ 68641 68642 /** 68643 @class Model 68644 @namespace DS 68645 */ 68646 68647 var AttrClassMethodsMixin = _ember["default"].Mixin.create({ 68648 /** 68649 A map whose keys are the attributes of the model (properties 68650 described by DS.attr) and whose values are the meta object for the 68651 property. 68652 Example 68653 ```app/models/person.js 68654 import DS from 'ember-data'; 68655 export default DS.Model.extend({ 68656 firstName: attr('string'), 68657 lastName: attr('string'), 68658 birthday: attr('date') 68659 }); 68660 ``` 68661 ```javascript 68662 import Ember from 'ember'; 68663 import Person from 'app/models/person'; 68664 var attributes = Ember.get(Person, 'attributes') 68665 attributes.forEach(function(meta, name) { 68666 console.log(name, meta); 68667 }); 68668 // prints: 68669 // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} 68670 // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} 68671 // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} 68672 ``` 68673 @property attributes 68674 @static 68675 @type {Ember.Map} 68676 @readOnly 68677 */ 68678 attributes: _ember["default"].computed(function () { 68679 var _this = this; 68680 68681 var map = Map.create(); 68682 68683 this.eachComputedProperty(function (name, meta) { 68684 if (meta.isAttribute) { 68685 (0, _emberDataPrivateDebug.assert)("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + _this.toString(), name !== 'id'); 68686 68687 meta.name = name; 68688 map.set(name, meta); 68689 } 68690 }); 68691 68692 return map; 68693 }).readOnly(), 68694 68695 /** 68696 A map whose keys are the attributes of the model (properties 68697 described by DS.attr) and whose values are type of transformation 68698 applied to each attribute. This map does not include any 68699 attributes that do not have an transformation type. 68700 Example 68701 ```app/models/person.js 68702 import DS from 'ember-data'; 68703 export default DS.Model.extend({ 68704 firstName: attr(), 68705 lastName: attr('string'), 68706 birthday: attr('date') 68707 }); 68708 ``` 68709 ```javascript 68710 import Ember from 'ember'; 68711 import Person from 'app/models/person'; 68712 var transformedAttributes = Ember.get(Person, 'transformedAttributes')
68713 transformedAttributes.forEach(function(field, type) { 68714 console.log(field, type); 68715 }); 68716 // prints: 68717 // lastName string 68718 // birthday date 68719 ``` 68720 @property transformedAttributes 68721 @static 68722 @type {Ember.Map} 68723 @readOnly 68724 */ 68725 transformedAttributes: _ember["default"].computed(function () { 68726 var map = Map.create(); 68727 68728 this.eachAttribute(function (key, meta) { 68729 if (meta.type) { 68730 map.set(key, meta.type); 68731 } 68732 }); 68733 68734 return map; 68735 }).readOnly(), 68736 68737 /** 68738 Iterates through the attributes of the model, calling the passed function on each 68739 attribute. 68740 The callback method you provide should have the following signature (all 68741 parameters are optional): 68742 ```javascript 68743 function(name, meta); 68744 ``` 68745 - `name` the name of the current property in the iteration 68746 - `meta` the meta object for the attribute property in the iteration 68747 Note that in addition to a callback, you can also pass an optional target 68748 object that will be set as `this` on the context. 68749 Example 68750 ```javascript 68751 import DS from 'ember-data'; 68752 var Person = DS.Model.extend({ 68753 firstName: attr('string'), 68754 lastName: attr('string'), 68755 birthday: attr('date') 68756 }); 68757 Person.eachAttribute(function(name, meta) { 68758 console.log(name, meta); 68759 }); 68760 // prints: 68761 // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} 68762 // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} 68763 // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} 68764 ``` 68765 @method eachAttribute 68766 @param {Function} callback The callback to execute 68767 @param {Object} [binding] the value to which the callback's `this` should be bound 68768 @static 68769 */ 68770 eachAttribute: function eachAttribute(callback, binding) { 68771 get(this, 'attributes').forEach(function (meta, name) { 68772 callback.call(binding, name, meta); 68773 }); 68774 }, 68775 68776 /** 68777 Iterates through the transformedAttributes of the model, calling 68778 the passed function on each attribute. Note the callback will not be 68779 called for any attributes that do not have an transformation type. 68780 The callback method you provide should have the following signature (all 68781 parameters are optional): 68782 ```javascript 68783 function(name, type); 68784 ``` 68785 - `name` the name of the current property in the iteration 68786 - `type` a string containing the name of the type of transformed 68787 applied to the attribute 68788 Note that in addition to a callback, you can also pass an optional target 68789 object that will be set as `this` on the context. 68790 Example 68791 ```javascript 68792 import DS from 'ember-data'; 68793 var Person = DS.Model.extend({ 68794 firstName: attr(), 68795 lastName: attr('string'), 68796 birthday: attr('date') 68797 }); 68798 Person.eachTransformedAttribute(function(name, type) { 68799 console.log(name, type); 68800 }); 68801 // prints: 68802 // lastName string 68803 // birthday date 68804 ``` 68805 @method eachTransformedAttribute 68806 @param {Function} callback The callback to execute 68807 @param {Object} [binding] the value to which the callback's `this` should be bound 68808 @static 68809 */ 68810 eachTransformedAttribute: function eachTransformedAttribute(callback, binding) { 68811 get(this, 'transformedAttributes').forEach(function (type, name) { 68812 callback.call(binding, name, type); 68813 }); 68814 } 68815 }); 68816 68817 exports.AttrClassMethodsMixin = AttrClassMethodsMixin; 68818 68819 var AttrInstanceMethodsMixin = _ember["default"].Mixin.create({ 68820 eachAttribute: function eachAttribute(callback, binding) { 68821 this.constructor.eachAttribute(callback, binding); 68822 } 68823 }); 68824 exports.AttrInstanceMethodsMixin = AttrInstanceMethodsMixin; 68825}); 68826define('ember-data/-private/system/model/errors', ['exports', 'ember', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateDebug) { 68827 'use strict'; 68828 68829 var get = _ember['default'].get; 68830 var set = _ember['default'].set; 68831 var isEmpty = _ember['default'].isEmpty; 68832 var makeArray = _ember['default'].makeArray; 68833 68834 var MapWithDefault = _ember['default'].MapWithDefault; 68835 68836 /** 68837 @module ember-data 68838 */ 68839 68840 /** 68841 Holds validation errors for a given record, organized by attribute names. 68842 68843 Every `DS.Model` has an `errors` property that is an instance of 68844 `DS.Errors`. This can be used to display validation error 68845 messages returned from the server when a `record.save()` rejects. 68846 68847 For Example, if you had a `User` model that looked like this: 68848 68849 ```app/models/user.js 68850 import DS from 'ember-data'; 68851 68852 export default DS.Model.extend({ 68853 username: attr('string'), 68854 email: attr('string') 68855 }); 68856 ```
68857 And you attempted to save a record that did not validate on the backend: 68858 68859 ```javascript 68860 var user = store.createRecord('user', { 68861 username: 'tomster', 68862 email: 'invalidEmail' 68863 }); 68864 user.save(); 68865 ``` 68866 68867 Your backend would be expected to return an error response that described 68868 the problem, so that error messages can be generated on the app. 68869 68870 API responses will be translated into instances of `DS.Errors` differently, 68871 depending on the specific combination of adapter and serializer used. You 68872 may want to check the documentation or the source code of the libraries 68873 that you are using, to know how they expect errors to be communicated. 68874 68875 Errors can be displayed to the user by accessing their property name 68876 to get an array of all the error objects for that property. Each 68877 error object is a JavaScript object with two keys: 68878 68879 - `message` A string containing the error message from the backend 68880 - `attribute` The name of the property associated with this error message 68881 68882 ```handlebars 68883 <label>Username: {{input value=username}} </label> 68884 {{#each model.errors.username as |error|}} 68885 <div class="error"> 68886 {{error.message}} 68887 </div> 68888 {{/each}} 68889 68890 <label>Email: {{input value=email}} </label> 68891 {{#each model.errors.email as |error|}} 68892 <div class="error"> 68893 {{error.message}} 68894 </div> 68895 {{/each}} 68896 ``` 68897 68898 You can also access the special `messages` property on the error 68899 object to get an array of all the error strings. 68900 68901 ```handlebars 68902 {{#each model.errors.messages as |message|}} 68903 <div class="error"> 68904 {{message}} 68905 </div> 68906 {{/each}} 68907 ``` 68908 68909 @class Errors 68910 @namespace DS 68911 @extends Ember.Object 68912 @uses Ember.Enumerable 68913 @uses Ember.Evented 68914 */ 68915 exports['default'] = _ember['default'].ArrayProxy.extend(_ember['default'].Evented, { 68916 /** 68917 Register with target handler 68918 @method registerHandlers 68919 @param {Object} target 68920 @param {Function} becameInvalid 68921 @param {Function} becameValid 68922 @deprecated 68923 */ 68924 registerHandlers: function registerHandlers(target, becameInvalid, becameValid) { 68925 (0, _emberDataPrivateDebug.deprecate)('Record errors will no longer be evented.', false, { 68926 id: 'ds.errors.registerHandlers', 68927 until: '3.0.0' 68928 }); 68929 68930 this._registerHandlers(target, becameInvalid, becameValid); 68931 }, 68932 68933 /** 68934 Register with target handler 68935 @method _registerHandlers 68936 @private 68937 */ 68938 _registerHandlers: function _registerHandlers(target, becameInvalid, becameValid) { 68939 this.on('becameInvalid', target, becameInvalid); 68940 this.on('becameValid', target, becameValid); 68941 }, 68942 68943 /** 68944 @property errorsByAttributeName 68945 @type {Ember.MapWithDefault} 68946 @private 68947 */ 68948 errorsByAttributeName: _ember['default'].computed(function () { 68949 return MapWithDefault.create({ 68950 defaultValue: function defaultValue() { 68951 return _ember['default'].A(); 68952 } 68953 }); 68954 }), 68955 68956 /** 68957 Returns errors for a given attribute 68958 ```javascript 68959 var user = store.createRecord('user', { 68960 username: 'tomster', 68961 email: 'invalidEmail' 68962 }); 68963 user.save().catch(function(){ 68964 user.get('errors').errorsFor('email'); // returns: 68965 // [{attribute: "email", message: "Doesn't look like a valid email."}] 68966 }); 68967 ``` 68968 @method errorsFor 68969 @param {String} attribute 68970 @return {Array} 68971 */ 68972 errorsFor: function errorsFor(attribute) { 68973 return get(this, 'errorsByAttributeName').get(attribute); 68974 }, 68975 68976 /** 68977 An array containing all of the error messages for this 68978 record. This is useful for displaying all errors to the user. 68979 ```handlebars 68980 {{#each model.errors.messages as |message|}} 68981 <div class="error"> 68982 {{message}} 68983 </div> 68984 {{/each}} 68985 ``` 68986 @property messages 68987 @type {Array} 68988 */ 68989 messages: _ember['default'].computed.mapBy('content', 'message'), 68990 68991 /** 68992 @property content 68993 @type {Array} 68994 @private 68995 */ 68996 content: _ember['default'].computed(function () { 68997 return _ember['default'].A(); 68998 }), 68999 69000 /** 69001 @method unknownProperty 69002 @private 69003 */ 69004 unknownProperty: function unknownProperty(attribute) { 69005 var errors = this.errorsFor(attribute); 69006 if (isEmpty(errors)) { 69007 return null; 69008 } 69009 return errors; 69010 }, 69011 69012 /** 69013 Total number of errors. 69014 @property length 69015 @type {Number} 69016 @readOnly 69017 */ 69018 69019 /** 69020 @property isEmpty 69021 @type {Boolean} 69022 @readOnly 69023 */ 69024 isEmpty: _ember['default'].computed.not('length').readOnly(), 69025 69026 /** 69027 Adds error messages to a given attribute and sends 69028 `becameInvalid` event to the record. 69029 Example: 69030 ```javascript 69031 if (!user.get('username') { 69032 user.get('errors').add('username', 'This field is required'); 69033 } 69034 ``` 69035 @method add 69036 @param {String} attribute 69037 @param {(Array|String)} messages 69038 @deprecated 69039 */ 69040 add: function add(attribute, messages) { 69041 (0, _emberDataPrivateDebug.warn)('Interacting with a record errors object will no longer change the record state.', false, { 69042 id: 'ds.errors.add' 69043 }); 69044 69045 var wasEmpty = get(this, 'isEmpty'); 69046 69047 this._add(attribute, messages); 69048 69049 if (wasEmpty && !get(this, 'isEmpty')) { 69050 this.trigger('becameInvalid'); 69051 } 69052 }, 69053 69054 /** 69055 Adds error messages to a given attribute without sending event. 69056 @method _add 69057 @private 69058 */ 69059 _add: function _add(attribute, messages) { 69060 messages = this._findOrCreateMessages(attribute, messages); 69061 this.addObjects(messages); 69062 get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); 69063 69064 this.notifyPropertyChange(attribute); 69065 }, 69066 69067 /** 69068 @method _findOrCreateMessages 69069 @private 69070 */ 69071 _findOrCreateMessages: function _findOrCreateMessages(attribute, messages) { 69072 var errors = this.errorsFor(attribute); 69073 var messagesArray = makeArray(messages); 69074 var _messages = new Array(messagesArray.length); 69075 69076 for (var i = 0; i < messagesArray.length; i++) { 69077 var message = messagesArray[i]; 69078 var err = errors.findBy('message', message); 69079 if (err) { 69080 _messages[i] = err; 69081 } else { 69082 _messages[i] = { 69083 attribute: attribute, 69084 message: message 69085 }; 69086 } 69087 } 69088 69089 return _messages; 69090 }, 69091 69092 /** 69093 Removes all error messages from the given attribute and sends
69094 `becameValid` event to the record if there no more errors left. 69095 Example: 69096 ```app/models/user.js 69097 import DS from 'ember-data'; 69098 export default DS.Model.extend({ 69099 email: DS.attr('string'), 69100 twoFactorAuth: DS.attr('boolean'), 69101 phone: DS.attr('string') 69102 }); 69103 ``` 69104 ```app/routes/user/edit.js 69105 import Ember from 'ember'; 69106 export default Ember.Route.extend({ 69107 actions: { 69108 save: function(user) { 69109 if (!user.get('twoFactorAuth')) { 69110 user.get('errors').remove('phone'); 69111 } 69112 user.save(); 69113 } 69114 } 69115 }); 69116 ``` 69117 @method remove 69118 @param {String} attribute 69119 @deprecated 69120 */ 69121 remove: function remove(attribute) { 69122 (0, _emberDataPrivateDebug.warn)('Interacting with a record errors object will no longer change the record state.', false, { 69123 id: 'ds.errors.remove' 69124 }); 69125 69126 if (get(this, 'isEmpty')) { 69127 return; 69128 } 69129 69130 this._remove(attribute); 69131 69132 if (get(this, 'isEmpty')) { 69133 this.trigger('becameValid'); 69134 } 69135 }, 69136 69137 /** 69138 Removes all error messages from the given attribute without sending event. 69139 @method _remove 69140 @private 69141 */ 69142 _remove: function _remove(attribute) { 69143 if (get(this, 'isEmpty')) { 69144 return; 69145 } 69146 69147 var content = this.rejectBy('attribute', attribute); 69148 set(this, 'content', content); 69149 get(this, 'errorsByAttributeName')['delete'](attribute); 69150 69151 this.notifyPropertyChange(attribute); 69152 }, 69153 69154 /** 69155 Removes all error messages and sends `becameValid` event 69156 to the record. 69157 Example: 69158 ```app/routes/user/edit.js 69159 import Ember from 'ember'; 69160 export default Ember.Route.extend({ 69161 actions: { 69162 retrySave: function(user) { 69163 user.get('errors').clear(); 69164 user.save(); 69165 } 69166 } 69167 }); 69168 ``` 69169 @method clear 69170 @deprecated 69171 */ 69172 clear: function clear() { 69173 (0, _emberDataPrivateDebug.warn)('Interacting with a record errors object will no longer change the record state.', false, { 69174 id: 'ds.errors.clear' 69175 }); 69176 69177 if (get(this, 'isEmpty')) { 69178 return; 69179 } 69180 69181 this._clear(); 69182 this.trigger('becameValid'); 69183 }, 69184 69185 /** 69186 Removes all error messages. 69187 to the record. 69188 @method _clear 69189 @private 69190 */ 69191 _clear: function _clear() { 69192 if (get(this, 'isEmpty')) { 69193 return; 69194 } 69195 69196 var errorsByAttributeName = get(this, 'errorsByAttributeName'); 69197 var attributes = _ember['default'].A(); 69198 69199 errorsByAttributeName.forEach(function (_, attribute) { 69200 attributes.push(attribute); 69201 }); 69202 69203 errorsByAttributeName.clear(); 69204 attributes.forEach(function (attribute) { 69205 this.notifyPropertyChange(attribute); 69206 }, this); 69207 69208 _ember['default'].ArrayProxy.prototype.clear.call(this); 69209 }, 69210 69211 /** 69212 Checks if there is error messages for the given attribute. 69213 ```app/routes/user/edit.js 69214 import Ember from 'ember'; 69215 export default Ember.Route.extend({ 69216 actions: { 69217 save: function(user) { 69218 if (user.get('errors').has('email')) { 69219 return alert('Please update your email before attempting to save.'); 69220 } 69221 user.save(); 69222 } 69223 } 69224 }); 69225 ``` 69226 @method has 69227 @param {String} attribute 69228 @return {Boolean} true if there some errors on given attribute 69229 */ 69230 has: function has(attribute) { 69231 return !isEmpty(this.errorsFor(attribute)); 69232 } 69233 }); 69234}); 69235define("ember-data/-private/system/model/internal-model", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/model/states", "ember-data/-private/system/relationships/state/create", "ember-data/-private/system/snapshot", "ember-data/-private/system/empty-object", "ember-data/-private/utils", "ember-data/-private/system/references"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemModelStates, _emberDataPrivateSystemRelationshipsStateCreate, _emberDataPrivateSystemSnapshot, _emberDataPrivateSystemEmptyObject, _emberDataPrivateUtils, _emberDataPrivateSystemReferences) { 69236 "use strict"; 69237 69238 var _slicedToArray = (function () { 69239 function sliceIterator(arr, i) { 69240 var _arr = [];var _n = true;var _d = false;var _e = undefined;try { 69241 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 69242 _arr.push(_s.value);if (i && _arr.length === i) break; 69243 } 69244 } catch (err) { 69245 _d = true;_e = err; 69246 } finally { 69247 try { 69248 if (!_n && _i["return"]) _i["return"](); 69249 } finally { 69250 if (_d) throw _e; 69251 } 69252 }return _arr; 69253 }return function (arr, i) { 69254 if (Array.isArray(arr)) { 69255 return arr; 69256 } else if (Symbol.iterator in Object(arr)) { 69257 return sliceIterator(arr, i); 69258 } else {
69259 throw new TypeError("Invalid attempt to destructure non-iterable instance"); 69260 } 69261 }; 69262 })(); 69263 69264 exports["default"] = InternalModel; 69265 69266 var Promise = _ember["default"].RSVP.Promise; 69267 var get = _ember["default"].get; 69268 var set = _ember["default"].set; 69269 var copy = _ember["default"].copy; 69270 var assign = _ember["default"].assign || _ember["default"].merge; 69271 69272 var _extractPivotNameCache = new _emberDataPrivateSystemEmptyObject["default"](); 69273 var _splitOnDotCache = new _emberDataPrivateSystemEmptyObject["default"](); 69274 69275 function splitOnDot(name) { 69276 return _splitOnDotCache[name] || (_splitOnDotCache[name] = name.split('.')); 69277 } 69278 69279 function extractPivotName(name) { 69280 return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]); 69281 } 69282 69283 function retrieveFromCurrentState(key) { 69284 return function () { 69285 return get(this.currentState, key); 69286 }; 69287 } 69288 69289 var guid = 0; 69290 /* 69291 `InternalModel` is the Model class that we use internally inside Ember Data to represent models. 69292 Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. 69293 69294 We expose `DS.Model` to application code, by materializing a `DS.Model` from `InternalModel` lazily, as 69295 a performance optimization. 69296 69297 `InternalModel` should never be exposed to application code. At the boundaries of the system, in places 69298 like `find`, `push`, etc. we convert between Models and InternalModels. 69299 69300 We need to make sure that the properties from `InternalModel` are correctly exposed/proxied on `Model` 69301 if they are needed. 69302 69303 @private 69304 @class InternalModel 69305 */ 69306 function InternalModel(type, id, store, _, data) { 69307 this.type = type; 69308 this.id = id; 69309 this.store = store; 69310 this._data = data || new _emberDataPrivateSystemEmptyObject["default"](); 69311 this.modelName = type.modelName; 69312 this.dataHasInitialized = false; 69313 //Look into making this lazy 69314 this._deferredTriggers = []; 69315 this._attributes = new _emberDataPrivateSystemEmptyObject["default"](); 69316 this._inFlightAttributes = new _emberDataPrivateSystemEmptyObject["default"](); 69317 this._relationships = new _emberDataPrivateSystemRelationshipsStateCreate["default"](this); 69318 this._recordArrays = undefined; 69319 this.currentState = _emberDataPrivateSystemModelStates["default"].empty; 69320 this.recordReference = new _emberDataPrivateSystemReferences.RecordReference(store, this); 69321 this.references = {}; 69322 this.isReloading = false; 69323 this.isError = false; 69324 this.error = null; 69325 this.__ember_meta__ = null; 69326 this[_ember["default"].GUID_KEY] = guid++ + 'internal-model'; 69327 /* 69328 implicit relationships are relationship which have not been declared but the inverse side exists on 69329 another record somewhere 69330 For example if there was 69331 ```app/models/comment.js 69332 import DS from 'ember-data'; 69333 export default DS.Model.extend({ 69334 name: DS.attr() 69335 }) 69336 ``` 69337 but there is also 69338 ```app/models/post.js 69339 import DS from 'ember-data'; 69340 export default DS.Model.extend({ 69341 name: DS.attr(), 69342 comments: DS.hasMany('comment') 69343 }) 69344 ``` 69345 would have a implicit post relationship in order to be do things like remove ourselves from the post 69346 when we are deleted 69347 */ 69348 this._implicitRelationships = new _emberDataPrivateSystemEmptyObject["default"](); 69349 } 69350 69351 InternalModel.prototype = { 69352 isEmpty: retrieveFromCurrentState('isEmpty'), 69353 isLoading: retrieveFromCurrentState('isLoading'), 69354 isLoaded: retrieveFromCurrentState('isLoaded'), 69355 hasDirtyAttributes: retrieveFromCurrentState('hasDirtyAttributes'), 69356 isSaving: retrieveFromCurrentState('isSaving'), 69357 isDeleted: retrieveFromCurrentState('isDeleted'), 69358 isNew: retrieveFromCurrentState('isNew'), 69359 isValid: retrieveFromCurrentState('isValid'), 69360 dirtyType: retrieveFromCurrentState('dirtyType'), 69361 69362 constructor: InternalModel, 69363 materializeRecord: function materializeRecord() { 69364 (0, _emberDataPrivateDebug.assert)("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); 69365 69366 // lookupFactory should really return an object that creates 69367 // instances with the injections applied 69368 var createOptions = { 69369 store: this.store, 69370 _internalModel: this, 69371 id: this.id, 69372 currentState: get(this, 'currentState'), 69373 isError: this.isError, 69374 adapterError: this.error 69375 }; 69376 69377 if (_ember["default"].setOwner) { 69378 // ensure that `Ember.getOwner(this)` works inside a model instance 69379 _ember["default"].setOwner(createOptions, (0, _emberDataPrivateUtils.getOwner)(this.store)); 69380 } else { 69381 createOptions.container = this.store.container; 69382 } 69383 69384 this.record = this.type._create(createOptions); 69385 69386 this._triggerDeferredTriggers(); 69387 }, 69388 69389 recordObjectWillDestroy: function recordObjectWillDestroy() { 69390 this.record = null; 69391 }, 69392 69393 deleteRecord: function deleteRecord() { 69394 this.send('deleteRecord'); 69395 }, 69396 69397 save: function save(options) { 69398 var promiseLabel = "DS: Model#save " + this; 69399 var resolver = _ember["default"].RSVP.defer(promiseLabel); 69400 69401 this.store.scheduleSave(this, resolver, options); 69402 return resolver.promise; 69403 }, 69404 69405 startedReloading: function startedReloading() { 69406 this.isReloading = true; 69407 if (this.record) { 69408 set(this.record, 'isReloading', true); 69409 } 69410 }, 69411 69412 finishedReloading: function finishedReloading() { 69413 this.isReloading = false;
69414 if (this.record) { 69415 set(this.record, 'isReloading', false); 69416 } 69417 }, 69418 69419 reload: function reload() { 69420 this.startedReloading(); 69421 var record = this; 69422 var promiseLabel = "DS: Model#reload of " + this; 69423 return new Promise(function (resolve) { 69424 record.send('reloadRecord', resolve); 69425 }, promiseLabel).then(function () { 69426 record.didCleanError(); 69427 return record; 69428 }, function (error) { 69429 record.didError(error); 69430 throw error; 69431 }, "DS: Model#reload complete, update flags")["finally"](function () { 69432 record.finishedReloading(); 69433 record.updateRecordArrays(); 69434 }); 69435 }, 69436 69437 getRecord: function getRecord() { 69438 if (!this.record) { 69439 this.materializeRecord(); 69440 } 69441 return this.record; 69442 }, 69443 69444 unloadRecord: function unloadRecord() { 69445 this.send('unloadRecord'); 69446 }, 69447 69448 eachRelationship: function eachRelationship(callback, binding) { 69449 return this.type.eachRelationship(callback, binding); 69450 }, 69451 69452 eachAttribute: function eachAttribute(callback, binding) { 69453 return this.type.eachAttribute(callback, binding); 69454 }, 69455 69456 inverseFor: function inverseFor(key) { 69457 return this.type.inverseFor(key); 69458 }, 69459 69460 setupData: function setupData(data) { 69461 var changedKeys = this._changedKeys(data.attributes); 69462 assign(this._data, data.attributes); 69463 this.pushedData(); 69464 if (this.record) { 69465 this.record._notifyProperties(changedKeys); 69466 } 69467 this.didInitalizeData(); 69468 }, 69469 69470 becameReady: function becameReady() { 69471 _ember["default"].run.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); 69472 }, 69473 69474 didInitalizeData: function didInitalizeData() { 69475 if (!this.dataHasInitialized) { 69476 this.becameReady(); 69477 this.dataHasInitialized = true; 69478 } 69479 }, 69480 69481 destroy: function destroy() { 69482 if (this.record) { 69483 return this.record.destroy(); 69484 } 69485 }, 69486 69487 /* 69488 @method createSnapshot 69489 @private 69490 */ 69491 createSnapshot: function createSnapshot(options) { 69492 return new _emberDataPrivateSystemSnapshot["default"](this, options); 69493 }, 69494 69495 /* 69496 @method loadingData 69497 @private 69498 @param {Promise} promise 69499 */ 69500 loadingData: function loadingData(promise) { 69501 this.send('loadingData', promise); 69502 }, 69503 69504 /* 69505 @method loadedData 69506 @private 69507 */ 69508 loadedData: function loadedData() { 69509 this.send('loadedData'); 69510 this.didInitalizeData(); 69511 }, 69512 69513 /* 69514 @method notFound 69515 @private 69516 */ 69517 notFound: function notFound() { 69518 this.send('notFound'); 69519 }, 69520 69521 /* 69522 @method pushedData 69523 @private 69524 */ 69525 pushedData: function pushedData() { 69526 this.send('pushedData'); 69527 }, 69528 69529 flushChangedAttributes: function flushChangedAttributes() { 69530 this._inFlightAttributes = this._attributes; 69531 this._attributes = new _emberDataPrivateSystemEmptyObject["default"](); 69532 }, 69533 69534 hasChangedAttributes: function hasChangedAttributes() { 69535 return Object.keys(this._attributes).length > 0; 69536 }, 69537 69538 /* 69539 Checks if the attributes which are considered as changed are still 69540 different to the state which is acknowledged by the server. 69541 This method is needed when data for the internal model is pushed and the 69542 pushed data might acknowledge dirty attributes as confirmed. 69543 @method updateChangedAttributes 69544 @private 69545 */ 69546 updateChangedAttributes: function updateChangedAttributes() { 69547 var changedAttributes = this.changedAttributes(); 69548 var changedAttributeNames = Object.keys(changedAttributes); 69549 69550 for (var i = 0, _length = changedAttributeNames.length; i < _length; i++) { 69551 var attribute = changedAttributeNames[i]; 69552 69553 var _changedAttributes$attribute = _slicedToArray(changedAttributes[attribute], 2); 69554 69555 var oldData = _changedAttributes$attribute[0]; 69556 var newData = _changedAttributes$attribute[1]; 69557 69558 if (oldData === newData) { 69559 delete this._attributes[attribute]; 69560 } 69561 } 69562 }, 69563 69564 /* 69565 Returns an object, whose keys are changed properties, and value is an 69566 [oldProp, newProp] array. 69567 @method changedAttributes 69568 @private 69569 */ 69570 changedAttributes: function changedAttributes() { 69571 var oldData = this._data; 69572 var currentData = this._attributes; 69573 var inFlightData = this._inFlightAttributes; 69574 var newData = assign(copy(inFlightData), currentData); 69575 var diffData = new _emberDataPrivateSystemEmptyObject["default"](); 69576 69577 var newDataKeys = Object.keys(newData); 69578 69579 for (var i = 0, _length2 = newDataKeys.length; i < _length2; i++) { 69580 var key = newDataKeys[i]; 69581 diffData[key] = [oldData[key], newData[key]]; 69582 } 69583 69584 return diffData; 69585 }, 69586 69587 /* 69588 @method adapterWillCommit 69589 @private 69590 */ 69591 adapterWillCommit: function adapterWillCommit() { 69592 this.send('willCommit'); 69593 }, 69594 69595 /* 69596 @method adapterDidDirty 69597 @private 69598 */ 69599 adapterDidDirty: function adapterDidDirty() { 69600 this.send('becomeDirty'); 69601 this.updateRecordArraysLater(); 69602 }, 69603 69604 /* 69605 @method send 69606 @private 69607 @param {String} name 69608 @param {Object} context 69609 */ 69610 send: function send(name, context) { 69611 var currentState = get(this, 'currentState'); 69612 69613 if (!currentState[name]) { 69614 this._unhandledEvent(currentState, name, context); 69615 } 69616 69617 return currentState[name](this, context); 69618 }, 69619 69620 notifyHasManyAdded: function notifyHasManyAdded(key, record, idx) { 69621 if (this.record) { 69622 this.record.notifyHasManyAdded(key, record, idx); 69623 } 69624 }, 69625 69626 notifyHasManyRemoved: function notifyHasManyRemoved(key, record, idx) { 69627 if (this.record) { 69628 this.record.notifyHasManyRemoved(key, record, idx); 69629 } 69630 }, 69631 69632 notifyBelongsToChanged: function notifyBelongsToChanged(key, record) { 69633 if (this.record) { 69634 this.record.notifyBelongsToChanged(key, record); 69635 } 69636 }, 69637
69638 notifyPropertyChange: function notifyPropertyChange(key) { 69639 if (this.record) { 69640 this.record.notifyPropertyChange(key); 69641 } 69642 }, 69643 69644 rollbackAttributes: function rollbackAttributes() { 69645 var dirtyKeys = Object.keys(this._attributes); 69646 69647 this._attributes = new _emberDataPrivateSystemEmptyObject["default"](); 69648 69649 if (get(this, 'isError')) { 69650 this._inFlightAttributes = new _emberDataPrivateSystemEmptyObject["default"](); 69651 this.didCleanError(); 69652 } 69653 69654 //Eventually rollback will always work for relationships 69655 //For now we support it only out of deleted state, because we 69656 //have an explicit way of knowing when the server acked the relationship change 69657 if (this.isDeleted()) { 69658 //TODO: Should probably move this to the state machine somehow 69659 this.becameReady(); 69660 } 69661 69662 if (this.isNew()) { 69663 this.clearRelationships(); 69664 } 69665 69666 if (this.isValid()) { 69667 this._inFlightAttributes = new _emberDataPrivateSystemEmptyObject["default"](); 69668 } 69669 69670 this.send('rolledBack'); 69671 69672 this.record._notifyProperties(dirtyKeys); 69673 }, 69674 /* 69675 @method transitionTo 69676 @private 69677 @param {String} name 69678 */ 69679 transitionTo: function transitionTo(name) { 69680 // POSSIBLE TODO: Remove this code and replace with 69681 // always having direct reference to state objects 69682 69683 var pivotName = extractPivotName(name); 69684 var currentState = get(this, 'currentState'); 69685 var state = currentState; 69686 69687 do { 69688 if (state.exit) { 69689 state.exit(this); 69690 } 69691 state = state.parentState; 69692 } while (!state.hasOwnProperty(pivotName)); 69693 69694 var path = splitOnDot(name); 69695 var setups = []; 69696 var enters = []; 69697 var i, l; 69698 69699 for (i = 0, l = path.length; i < l; i++) { 69700 state = state[path[i]]; 69701 69702 if (state.enter) { 69703 enters.push(state); 69704 } 69705 if (state.setup) { 69706 setups.push(state); 69707 } 69708 } 69709 69710 for (i = 0, l = enters.length; i < l; i++) { 69711 enters[i].enter(this); 69712 } 69713 69714 set(this, 'currentState', state); 69715 //TODO Consider whether this is the best approach for keeping these two in sync 69716 if (this.record) { 69717 set(this.record, 'currentState', state); 69718 } 69719 69720 for (i = 0, l = setups.length; i < l; i++) { 69721 setups[i].setup(this); 69722 } 69723 69724 this.updateRecordArraysLater(); 69725 }, 69726 69727 _unhandledEvent: function _unhandledEvent(state, name, context) { 69728 var errorMessage = "Attempted to handle event `" + name + "` "; 69729 errorMessage += "on " + String(this) + " while in state "; 69730 errorMessage += state.stateName + ". "; 69731 69732 if (context !== undefined) { 69733 errorMessage += "Called with " + _ember["default"].inspect(context) + "."; 69734 } 69735 69736 throw new _ember["default"].Error(errorMessage); 69737 }, 69738 69739 triggerLater: function triggerLater() { 69740 var length = arguments.length; 69741 var args = new Array(length); 69742 69743 for (var i = 0; i < length; i++) { 69744 args[i] = arguments[i]; 69745 } 69746 69747 if (this._deferredTriggers.push(args) !== 1) { 69748 return; 69749 } 69750 _ember["default"].run.scheduleOnce('actions', this, '_triggerDeferredTriggers'); 69751 }, 69752 69753 _triggerDeferredTriggers: function _triggerDeferredTriggers() { 69754 //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, 69755 //but for now, we queue up all the events triggered before the record was materialized, and flush 69756 //them once we have the record 69757 if (!this.record) { 69758 return; 69759 } 69760 for (var i = 0, l = this._deferredTriggers.length; i < l; i++) { 69761 this.record.trigger.apply(this.record, this._deferredTriggers[i]); 69762 } 69763 69764 this._deferredTriggers.length = 0; 69765 }, 69766 /* 69767 @method clearRelationships 69768 @private 69769 */ 69770 clearRelationships: function clearRelationships() { 69771 var _this = this; 69772 69773 this.eachRelationship(function (name, relationship) { 69774 if (_this._relationships.has(name)) { 69775 var rel = _this._relationships.get(name); 69776 rel.clear(); 69777 rel.destroy(); 69778 } 69779 });
69780 Object.keys(this._implicitRelationships).forEach(function (key) { 69781 _this._implicitRelationships[key].clear(); 69782 _this._implicitRelationships[key].destroy(); 69783 }); 69784 }, 69785 69786 /* 69787 When a find request is triggered on the store, the user can optionally pass in 69788 attributes and relationships to be preloaded. These are meant to behave as if they 69789 came back from the server, except the user obtained them out of band and is informing 69790 the store of their existence. The most common use case is for supporting client side 69791 nested URLs, such as `/posts/1/comments/2` so the user can do 69792 `store.findRecord('comment', 2, { preload: { post: 1 } })` without having to fetch the post. 69793 Preloaded data can be attributes and relationships passed in either as IDs or as actual 69794 models. 69795 @method _preloadData 69796 @private 69797 @param {Object} preload 69798 */ 69799 _preloadData: function _preloadData(preload) { 69800 var _this2 = this; 69801 69802 //TODO(Igor) consider the polymorphic case 69803 Object.keys(preload).forEach(function (key) { 69804 var preloadValue = get(preload, key); 69805 var relationshipMeta = _this2.type.metaForProperty(key); 69806 if (relationshipMeta.isRelationship) { 69807 _this2._preloadRelationship(key, preloadValue); 69808 } else { 69809 _this2._data[key] = preloadValue; 69810 } 69811 }); 69812 }, 69813 69814 _preloadRelationship: function _preloadRelationship(key, preloadValue) { 69815 var relationshipMeta = this.type.metaForProperty(key); 69816 var type = relationshipMeta.type; 69817 if (relationshipMeta.kind === 'hasMany') { 69818 this._preloadHasMany(key, preloadValue, type); 69819 } else { 69820 this._preloadBelongsTo(key, preloadValue, type); 69821 } 69822 }, 69823 69824 _preloadHasMany: function _preloadHasMany(key, preloadValue, type) { 69825 (0, _emberDataPrivateDebug.assert)("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); 69826 var recordsToSet = new Array(preloadValue.length); 69827 69828 for (var i = 0; i < preloadValue.length; i++) { 69829 var recordToPush = preloadValue[i]; 69830 recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, type); 69831 } 69832 69833 //We use the pathway of setting the hasMany as if it came from the adapter 69834 //because the user told us that they know this relationships exists already 69835 this._relationships.get(key).updateRecordsFromAdapter(recordsToSet); 69836 }, 69837 69838 _preloadBelongsTo: function _preloadBelongsTo(key, preloadValue, type) { 69839 var recordToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, type); 69840 69841 //We use the pathway of setting the hasMany as if it came from the adapter 69842 //because the user told us that they know this relationships exists already 69843 this._relationships.get(key).setRecord(recordToSet); 69844 }, 69845 69846 _convertStringOrNumberIntoInternalModel: function _convertStringOrNumberIntoInternalModel(value, type) { 69847 if (typeof value === 'string' || typeof value === 'number') { 69848 return this.store._internalModelForId(type, value); 69849 } 69850 if (value._internalModel) { 69851 return value._internalModel; 69852 } 69853 return value; 69854 }, 69855 69856 /* 69857 @method updateRecordArrays 69858 @private 69859 */ 69860 updateRecordArrays: function updateRecordArrays() { 69861 this._updatingRecordArraysLater = false; 69862 this.store.dataWasUpdated(this.type, this); 69863 }, 69864 69865 setId: function setId(id) { 69866 (0, _emberDataPrivateDebug.assert)('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); 69867 this.id = id; 69868 if (this.record.get('id') !== id) { 69869 this.record.set('id', id); 69870 } 69871 }, 69872 69873 didError: function didError(error) { 69874 this.error = error; 69875 this.isError = true; 69876 69877 if (this.record) { 69878 this.record.setProperties({ 69879 isError: true, 69880 adapterError: error 69881 }); 69882 } 69883 }, 69884 69885 didCleanError: function didCleanError() { 69886 this.error = null; 69887 this.isError = false;
69888 69889 if (this.record) { 69890 this.record.setProperties({ 69891 isError: false, 69892 adapterError: null 69893 }); 69894 } 69895 }, 69896 /* 69897 If the adapter did not return a hash in response to a commit, 69898 merge the changed attributes and relationships into the existing 69899 saved data. 69900 @method adapterDidCommit 69901 */ 69902 adapterDidCommit: function adapterDidCommit(data) { 69903 if (data) { 69904 data = data.attributes; 69905 } 69906 69907 this.didCleanError(); 69908 var changedKeys = this._changedKeys(data); 69909 69910 assign(this._data, this._inFlightAttributes); 69911 if (data) { 69912 assign(this._data, data); 69913 } 69914 69915 this._inFlightAttributes = new _emberDataPrivateSystemEmptyObject["default"](); 69916 69917 this.send('didCommit'); 69918 this.updateRecordArraysLater(); 69919 69920 if (!data) { 69921 return; 69922 } 69923 69924 this.record._notifyProperties(changedKeys); 69925 }, 69926 69927 /* 69928 @method updateRecordArraysLater 69929 @private 69930 */ 69931 updateRecordArraysLater: function updateRecordArraysLater() { 69932 // quick hack (something like this could be pushed into run.once 69933 if (this._updatingRecordArraysLater) { 69934 return; 69935 } 69936 this._updatingRecordArraysLater = true; 69937 _ember["default"].run.schedule('actions', this, this.updateRecordArrays); 69938 }, 69939 69940 addErrorMessageToAttribute: function addErrorMessageToAttribute(attribute, message) { 69941 var record = this.getRecord(); 69942 get(record, 'errors')._add(attribute, message); 69943 }, 69944 69945 removeErrorMessageFromAttribute: function removeErrorMessageFromAttribute(attribute) { 69946 var record = this.getRecord(); 69947 get(record, 'errors')._remove(attribute); 69948 }, 69949 69950 clearErrorMessages: function clearErrorMessages() { 69951 var record = this.getRecord(); 69952 get(record, 'errors')._clear(); 69953 }, 69954 69955 hasErrors: function hasErrors() { 69956 var record = this.getRecord(); 69957 var errors = get(record, 'errors'); 69958 69959 return !_ember["default"].isEmpty(errors); 69960 }, 69961 69962 // FOR USE DURING COMMIT PROCESS 69963 69964 /* 69965 @method adapterDidInvalidate 69966 @private 69967 */ 69968 adapterDidInvalidate: function adapterDidInvalidate(errors) { 69969 var attribute; 69970 69971 for (attribute in errors) { 69972 if (errors.hasOwnProperty(attribute)) { 69973 this.addErrorMessageToAttribute(attribute, errors[attribute]); 69974 } 69975 } 69976 69977 this.send('becameInvalid'); 69978 69979 this._saveWasRejected(); 69980 }, 69981 69982 /* 69983 @method adapterDidError 69984 @private 69985 */ 69986 adapterDidError: function adapterDidError(error) { 69987 this.send('becameError'); 69988 this.didError(error); 69989 this._saveWasRejected(); 69990 }, 69991 69992 _saveWasRejected: function _saveWasRejected() { 69993 var keys = Object.keys(this._inFlightAttributes); 69994 for (var i = 0; i < keys.length; i++) { 69995 if (this._attributes[keys[i]] === undefined) { 69996 this._attributes[keys[i]] = this._inFlightAttributes[keys[i]]; 69997 } 69998 } 69999 this._inFlightAttributes = new _emberDataPrivateSystemEmptyObject["default"](); 70000 }, 70001 70002 /* 70003 Ember Data has 3 buckets for storing the value of an attribute on an internalModel. 70004 `_data` holds all of the attributes that have been acknowledged by 70005 a backend via the adapter. When rollbackAttributes is called on a model all 70006 attributes will revert to the record's state in `_data`. 70007 `_attributes` holds any change the user has made to an attribute 70008 that has not been acknowledged by the adapter. Any values in 70009 `_attributes` are have priority over values in `_data`. 70010 `_inFlightAttributes`. When a record is being synced with the 70011 backend the values in `_attributes` are copied to 70012 `_inFlightAttributes`. This way if the backend acknowledges the 70013 save but does not return the new state Ember Data can copy the 70014 values from `_inFlightAttributes` to `_data`. Without having to 70015 worry about changes made to `_attributes` while the save was 70016 happenign. 70017 Changed keys builds a list of all of the values that may have been 70018 changed by the backend after a successful save. 70019 It does this by iterating over each key, value pair in the payload 70020 returned from the server after a save. If the `key` is found in 70021 `_attributes` then the user has a local changed to the attribute 70022 that has not been synced with the server and the key is not 70023 included in the list of changed keys. 70024 70025 If the value, for a key differs from the value in what Ember Data 70026 believes to be the truth about the backend state (A merger of the 70027 `_data` and `_inFlightAttributes` objects where 70028 `_inFlightAttributes` has priority) then that means the backend 70029 has updated the value and the key is added to the list of changed 70030 keys.
70031 @method _changedKeys 70032 @private 70033 */ 70034 _changedKeys: function _changedKeys(updates) { 70035 var changedKeys = []; 70036 70037 if (updates) { 70038 var original, i, value, key; 70039 var keys = Object.keys(updates); 70040 var length = keys.length; 70041 70042 original = assign(new _emberDataPrivateSystemEmptyObject["default"](), this._data); 70043 original = assign(original, this._inFlightAttributes); 70044 70045 for (i = 0; i < length; i++) { 70046 key = keys[i]; 70047 value = updates[key]; 70048 70049 // A value in _attributes means the user has a local change to 70050 // this attributes. We never override this value when merging 70051 // updates from the backend so we should not sent a change 70052 // notification if the server value differs from the original. 70053 if (this._attributes[key] !== undefined) { 70054 continue; 70055 } 70056 70057 if (!_ember["default"].isEqual(original[key], value)) { 70058 changedKeys.push(key); 70059 } 70060 } 70061 } 70062 70063 return changedKeys; 70064 }, 70065 70066 toString: function toString() { 70067 if (this.record) { 70068 return this.record.toString(); 70069 } else { 70070 return "<" + this.modelName + ":" + this.id + ">"; 70071 } 70072 }, 70073 70074 referenceFor: function referenceFor(type, name) { 70075 var reference = this.references[name]; 70076 70077 if (!reference) { 70078 var relationship = this._relationships.get(name); 70079 70080 if (type === "belongsTo") { 70081 reference = new _emberDataPrivateSystemReferences.BelongsToReference(this.store, this, relationship); 70082 } else if (type === "hasMany") { 70083 reference = new _emberDataPrivateSystemReferences.HasManyReference(this.store, this, relationship); 70084 } 70085 70086 this.references[name] = reference; 70087 } 70088 70089 return reference; 70090 } 70091 }; 70092}); 70093define("ember-data/-private/system/model/model", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/model/errors", "ember-data/-private/system/debug/debug-info", "ember-data/-private/system/relationships/belongs-to", "ember-data/-private/system/relationships/has-many", "ember-data/-private/system/relationships/ext", "ember-data/-private/system/model/attr"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemModelErrors, _emberDataPrivateSystemDebugDebugInfo, _emberDataPrivateSystemRelationshipsBelongsTo, _emberDataPrivateSystemRelationshipsHasMany, _emberDataPrivateSystemRelationshipsExt, _emberDataPrivateSystemModelAttr) { 70094 "use strict"; 70095 70096 /** 70097 @module ember-data 70098 */ 70099 70100 var get = _ember["default"].get; 70101 70102 function intersection(array1, array2) { 70103 var result = []; 70104 array1.forEach(function (element) { 70105 if (array2.indexOf(element) >= 0) { 70106 result.push(element); 70107 } 70108 }); 70109 70110 return result; 70111 } 70112 70113 var RESERVED_MODEL_PROPS = ['currentState', 'data', 'store']; 70114 70115 var retrieveFromCurrentState = _ember["default"].computed('currentState', function (key) { 70116 return get(this._internalModel.currentState, key); 70117 }).readOnly(); 70118 70119 /** 70120 70121 The model class that all Ember Data records descend from. 70122 This is the public API of Ember Data models. If you are using Ember Data 70123 in your application, this is the class you should use. 70124 If you are working on Ember Data internals, you most likely want to be dealing 70125 with `InternalModel` 70126 70127 @class Model 70128 @namespace DS 70129 @extends Ember.Object 70130 @uses Ember.Evented 70131 */ 70132 var Model = _ember["default"].Object.extend(_ember["default"].Evented, { 70133 _internalModel: null, 70134 store: null, 70135 70136 /** 70137 If this property is `true` the record is in the `empty` 70138 state. Empty is the first state all records enter after they have 70139 been created. Most records created by the store will quickly 70140 transition to the `loading` state if data needs to be fetched from 70141 the server or the `created` state if the record is created on the 70142 client. A record can also enter the empty state if the adapter is 70143 unable to locate the record. 70144 @property isEmpty 70145 @type {Boolean} 70146 @readOnly 70147 */ 70148 isEmpty: retrieveFromCurrentState, 70149 /**
70150 If this property is `true` the record is in the `loading` state. A 70151 record enters this state when the store asks the adapter for its 70152 data. It remains in this state until the adapter provides the 70153 requested data. 70154 @property isLoading 70155 @type {Boolean} 70156 @readOnly 70157 */ 70158 isLoading: retrieveFromCurrentState, 70159 /** 70160 If this property is `true` the record is in the `loaded` state. A 70161 record enters this state when its data is populated. Most of a 70162 record's lifecycle is spent inside substates of the `loaded` 70163 state. 70164 Example 70165 ```javascript 70166 var record = store.createRecord('model'); 70167 record.get('isLoaded'); // true 70168 store.findRecord('model', 1).then(function(model) { 70169 model.get('isLoaded'); // true 70170 }); 70171 ``` 70172 @property isLoaded 70173 @type {Boolean} 70174 @readOnly 70175 */ 70176 isLoaded: retrieveFromCurrentState, 70177 /** 70178 If this property is `true` the record is in the `dirty` state. The 70179 record has local changes that have not yet been saved by the 70180 adapter. This includes records that have been created (but not yet 70181 saved) or deleted. 70182 Example 70183 ```javascript 70184 var record = store.createRecord('model'); 70185 record.get('hasDirtyAttributes'); // true 70186 store.findRecord('model', 1).then(function(model) { 70187 model.get('hasDirtyAttributes'); // false 70188 model.set('foo', 'some value'); 70189 model.get('hasDirtyAttributes'); // true 70190 }); 70191 ``` 70192 @since 1.13.0 70193 @property hasDirtyAttributes 70194 @type {Boolean} 70195 @readOnly 70196 */ 70197 hasDirtyAttributes: _ember["default"].computed('currentState.isDirty', function () { 70198 return this.get('currentState.isDirty'); 70199 }), 70200 /** 70201 If this property is `true` the record is in the `saving` state. A 70202 record enters the saving state when `save` is called, but the 70203 adapter has not yet acknowledged that the changes have been 70204 persisted to the backend. 70205 Example 70206 ```javascript 70207 var record = store.createRecord('model'); 70208 record.get('isSaving'); // false 70209 var promise = record.save(); 70210 record.get('isSaving'); // true 70211 promise.then(function() { 70212 record.get('isSaving'); // false 70213 }); 70214 ``` 70215 @property isSaving 70216 @type {Boolean} 70217 @readOnly 70218 */ 70219 isSaving: retrieveFromCurrentState, 70220 /** 70221 If this property is `true` the record is in the `deleted` state 70222 and has been marked for deletion. When `isDeleted` is true and 70223 `hasDirtyAttributes` is true, the record is deleted locally but the deletion 70224 was not yet persisted. When `isSaving` is true, the change is 70225 in-flight. When both `hasDirtyAttributes` and `isSaving` are false, the 70226 change has persisted. 70227 Example 70228 ```javascript 70229 var record = store.createRecord('model'); 70230 record.get('isDeleted'); // false 70231 record.deleteRecord(); 70232 // Locally deleted 70233 record.get('isDeleted'); // true 70234 record.get('hasDirtyAttributes'); // true 70235 record.get('isSaving'); // false 70236 // Persisting the deletion 70237 var promise = record.save(); 70238 record.get('isDeleted'); // true 70239 record.get('isSaving'); // true 70240 // Deletion Persisted 70241 promise.then(function() { 70242 record.get('isDeleted'); // true 70243 record.get('isSaving'); // false 70244 record.get('hasDirtyAttributes'); // false 70245 }); 70246 ``` 70247 @property isDeleted 70248 @type {Boolean} 70249 @readOnly 70250 */ 70251 isDeleted: retrieveFromCurrentState, 70252 /** 70253 If this property is `true` the record is in the `new` state. A 70254 record will be in the `new` state when it has been created on the 70255 client and the adapter has not yet report that it was successfully 70256 saved. 70257 Example 70258 ```javascript 70259 var record = store.createRecord('model'); 70260 record.get('isNew'); // true 70261 record.save().then(function(model) { 70262 model.get('isNew'); // false 70263 }); 70264 ``` 70265 @property isNew 70266 @type {Boolean} 70267 @readOnly 70268 */ 70269 isNew: retrieveFromCurrentState, 70270 /**
70271 If this property is `true` the record is in the `valid` state. 70272 A record will be in the `valid` state when the adapter did not report any 70273 server-side validation failures. 70274 @property isValid 70275 @type {Boolean} 70276 @readOnly 70277 */ 70278 isValid: retrieveFromCurrentState, 70279 /** 70280 If the record is in the dirty state this property will report what 70281 kind of change has caused it to move into the dirty 70282 state. Possible values are: 70283 - `created` The record has been created by the client and not yet saved to the adapter. 70284 - `updated` The record has been updated by the client and not yet saved to the adapter. 70285 - `deleted` The record has been deleted by the client and not yet saved to the adapter. 70286 Example 70287 ```javascript 70288 var record = store.createRecord('model'); 70289 record.get('dirtyType'); // 'created' 70290 ``` 70291 @property dirtyType 70292 @type {String} 70293 @readOnly 70294 */ 70295 dirtyType: retrieveFromCurrentState, 70296 70297 /** 70298 If `true` the adapter reported that it was unable to save local 70299 changes to the backend for any reason other than a server-side 70300 validation error. 70301 Example 70302 ```javascript 70303 record.get('isError'); // false 70304 record.set('foo', 'valid value'); 70305 record.save().then(null, function() { 70306 record.get('isError'); // true 70307 }); 70308 ``` 70309 @property isError 70310 @type {Boolean} 70311 @readOnly 70312 */ 70313 isError: false, 70314 70315 /** 70316 If `true` the store is attempting to reload the record form the adapter. 70317 Example 70318 ```javascript 70319 record.get('isReloading'); // false 70320 record.reload(); 70321 record.get('isReloading'); // true 70322 ``` 70323 @property isReloading 70324 @type {Boolean} 70325 @readOnly 70326 */ 70327 isReloading: false, 70328 70329 /** 70330 All ember models have an id property. This is an identifier 70331 managed by an external source. These are always coerced to be 70332 strings before being used internally. Note when declaring the 70333 attributes for a model it is an error to declare an id 70334 attribute. 70335 ```javascript 70336 var record = store.createRecord('model'); 70337 record.get('id'); // null 70338 store.findRecord('model', 1).then(function(model) { 70339 model.get('id'); // '1' 70340 }); 70341 ``` 70342 @property id 70343 @type {String} 70344 */ 70345 id: null, 70346 70347 /** 70348 @property currentState 70349 @private 70350 @type {Object} 70351 */ 70352 70353 /** 70354 When the record is in the `invalid` state this object will contain 70355 any errors returned by the adapter. When present the errors hash 70356 contains keys corresponding to the invalid property names 70357 and values which are arrays of Javascript objects with two keys: 70358 - `message` A string containing the error message from the backend 70359 - `attribute` The name of the property associated with this error message 70360 ```javascript 70361 record.get('errors.length'); // 0 70362 record.set('foo', 'invalid value'); 70363 record.save().catch(function() { 70364 record.get('errors').get('foo'); 70365 // [{message: 'foo should be a number.', attribute: 'foo'}] 70366 }); 70367 ``` 70368 The `errors` property us useful for displaying error messages to 70369 the user. 70370 ```handlebars 70371 <label>Username: {{input value=username}} </label> 70372 {{#each model.errors.username as |error|}} 70373 <div class="error"> 70374 {{error.message}} 70375 </div> 70376 {{/each}} 70377 <label>Email: {{input value=email}} </label> 70378 {{#each model.errors.email as |error|}} 70379 <div class="error"> 70380 {{error.message}} 70381 </div> 70382 {{/each}} 70383 ``` 70384 You can also access the special `messages` property on the error 70385 object to get an array of all the error strings. 70386 ```handlebars 70387 {{#each model.errors.messages as |message|}} 70388 <div class="error"> 70389 {{message}} 70390 </div> 70391 {{/each}} 70392 ``` 70393 @property errors 70394 @type {DS.Errors} 70395 */ 70396 errors: _ember["default"].computed(function () { 70397 var errors = _emberDataPrivateSystemModelErrors["default"].create(); 70398 70399 errors._registerHandlers(this._internalModel, function () { 70400 this.send('becameInvalid'); 70401 }, function () { 70402 this.send('becameValid'); 70403 }); 70404 return errors; 70405 }).readOnly(), 70406 70407 /** 70408 This property holds the `DS.AdapterError` object with which 70409 last adapter operation was rejected. 70410 @property adapterError 70411 @type {DS.AdapterError} 70412 */ 70413 adapterError: null, 70414 70415 /** 70416 Create a JSON representation of the record, using the serialization 70417 strategy of the store's adapter. 70418 `serialize` takes an optional hash as a parameter, currently 70419 supported options are: 70420 - `includeId`: `true` if the record's ID should be included in the 70421 JSON representation. 70422 @method serialize 70423 @param {Object} options 70424 @return {Object} an object whose values are primitive JSON values only 70425 */ 70426 serialize: function serialize(options) { 70427 return this.store.serialize(this, options); 70428 }, 70429 70430 /** 70431 Use [DS.JSONSerializer](DS.JSONSerializer.html) to 70432 get the JSON representation of a record. 70433 `toJSON` takes an optional hash as a parameter, currently 70434 supported options are: 70435 - `includeId`: `true` if the record's ID should be included in the 70436 JSON representation. 70437 @method toJSON 70438 @param {Object} options 70439 @return {Object} A JSON representation of the object. 70440 */ 70441 toJSON: function toJSON(options) { 70442 // container is for lazy transform lookups 70443 var serializer = this.store.serializerFor('-default'); 70444 var snapshot = this._internalModel.createSnapshot(); 70445 70446 return serializer.serialize(snapshot, options); 70447 }, 70448 70449 /**
70450 Fired when the record is ready to be interacted with, 70451 that is either loaded from the server or created locally. 70452 @event ready 70453 */ 70454 ready: _ember["default"].K, 70455 70456 /** 70457 Fired when the record is loaded from the server. 70458 @event didLoad 70459 */ 70460 didLoad: _ember["default"].K, 70461 70462 /** 70463 Fired when the record is updated. 70464 @event didUpdate 70465 */ 70466 didUpdate: _ember["default"].K, 70467 70468 /** 70469 Fired when a new record is commited to the server. 70470 @event didCreate 70471 */ 70472 didCreate: _ember["default"].K, 70473 70474 /** 70475 Fired when the record is deleted. 70476 @event didDelete 70477 */ 70478 didDelete: _ember["default"].K, 70479 70480 /** 70481 Fired when the record becomes invalid. 70482 @event becameInvalid 70483 */ 70484 becameInvalid: _ember["default"].K, 70485 70486 /** 70487 Fired when the record enters the error state. 70488 @event becameError 70489 */ 70490 becameError: _ember["default"].K, 70491 70492 /** 70493 Fired when the record is rolled back. 70494 @event rolledBack 70495 */ 70496 rolledBack: _ember["default"].K, 70497 70498 /** 70499 @property data 70500 @private 70501 @type {Object} 70502 */ 70503 data: _ember["default"].computed.readOnly('_internalModel._data'), 70504 70505 //TODO Do we want to deprecate these? 70506 /** 70507 @method send 70508 @private 70509 @param {String} name 70510 @param {Object} context 70511 */ 70512 send: function send(name, context) { 70513 return this._internalModel.send(name, context); 70514 }, 70515 70516 /** 70517 @method transitionTo 70518 @private 70519 @param {String} name 70520 */ 70521 transitionTo: function transitionTo(name) { 70522 return this._internalModel.transitionTo(name); 70523 }, 70524 70525 /** 70526 Marks the record as deleted but does not save it. You must call 70527 `save` afterwards if you want to persist it. You might use this 70528 method if you want to allow the user to still `rollbackAttributes()` 70529 after a delete it was made. 70530 Example 70531 ```app/routes/model/delete.js 70532 import Ember from 'ember'; 70533 export default Ember.Route.extend({ 70534 actions: { 70535 softDelete: function() { 70536 this.controller.get('model').deleteRecord(); 70537 }, 70538 confirm: function() { 70539 this.controller.get('model').save(); 70540 }, 70541 undo: function() { 70542 this.controller.get('model').rollbackAttributes(); 70543 } 70544 } 70545 }); 70546 ``` 70547 @method deleteRecord 70548 */ 70549 deleteRecord: function deleteRecord() { 70550 this._internalModel.deleteRecord(); 70551 }, 70552 70553 /** 70554 Same as `deleteRecord`, but saves the record immediately. 70555 Example 70556 ```app/routes/model/delete.js 70557 import Ember from 'ember'; 70558 export default Ember.Route.extend({ 70559 actions: { 70560 delete: function() { 70561 var controller = this.controller; 70562 controller.get('model').destroyRecord().then(function() { 70563 controller.transitionToRoute('model.index'); 70564 }); 70565 } 70566 } 70567 }); 70568 ``` 70569 If you pass an object on the `adapterOptions` property of the options 70570 argument it will be passed to you adapter via the snapshot 70571 ```js 70572 record.destroyRecord({ adapterOptions: { subscribe: false } }); 70573 ``` 70574 ```app/adapters/post.js 70575 import MyCustomAdapter from './custom-adapter'; 70576 export default MyCustomAdapter.extend({ 70577 deleteRecord: function(store, type, snapshot) { 70578 if (snapshot.adapterOptions.subscribe) { 70579 // ... 70580 } 70581 // ... 70582 } 70583 }); 70584 ``` 70585 @method destroyRecord 70586 @param {Object} options 70587 @return {Promise} a promise that will be resolved when the adapter returns 70588 successfully or rejected if the adapter returns with an error. 70589 */ 70590 destroyRecord: function destroyRecord(options) { 70591 this.deleteRecord(); 70592 return this.save(options); 70593 }, 70594 70595 /** 70596 @method unloadRecord 70597 @private 70598 */ 70599 unloadRecord: function unloadRecord() { 70600 if (this.isDestroyed) { 70601 return; 70602 } 70603 this._internalModel.unloadRecord(); 70604 }, 70605 70606 /** 70607 @method _notifyProperties 70608 @private 70609 */ 70610 _notifyProperties: function _notifyProperties(keys) { 70611 _ember["default"].beginPropertyChanges(); 70612 var key; 70613 for (var i = 0, length = keys.length; i < length; i++) { 70614 key = keys[i];
70615 this.notifyPropertyChange(key); 70616 } 70617 _ember["default"].endPropertyChanges(); 70618 }, 70619 70620 /** 70621 Returns an object, whose keys are changed properties, and value is 70622 an [oldProp, newProp] array. 70623 The array represents the diff of the canonical state with the local state 70624 of the model. Note: if the model is created locally, the canonical state is 70625 empty since the adapter hasn't acknowledged the attributes yet: 70626 Example 70627 ```app/models/mascot.js 70628 import DS from 'ember-data'; 70629 export default DS.Model.extend({ 70630 name: attr('string'), 70631 isAdmin: attr('boolean', { 70632 defaultValue: false 70633 }) 70634 }); 70635 ``` 70636 ```javascript 70637 var mascot = store.createRecord('mascot'); 70638 mascot.changedAttributes(); // {} 70639 mascot.set('name', 'Tomster'); 70640 mascot.changedAttributes(); // { name: [undefined, 'Tomster'] } 70641 mascot.set('isAdmin', true); 70642 mascot.changedAttributes(); // { isAdmin: [undefined, true], name: [undefined, 'Tomster'] } 70643 mascot.save().then(function() { 70644 mascot.changedAttributes(); // {} 70645 mascot.set('isAdmin', false); 70646 mascot.changedAttributes(); // { isAdmin: [true, false] } 70647 }); 70648 ``` 70649 @method changedAttributes 70650 @return {Object} an object, whose keys are changed properties, 70651 and value is an [oldProp, newProp] array. 70652 */ 70653 changedAttributes: function changedAttributes() { 70654 return this._internalModel.changedAttributes(); 70655 }, 70656 70657 //TODO discuss with tomhuda about events/hooks 70658 //Bring back as hooks? 70659 /** 70660 @method adapterWillCommit 70661 @private 70662 adapterWillCommit: function() { 70663 this.send('willCommit'); 70664 }, 70665 /** 70666 @method adapterDidDirty 70667 @private 70668 adapterDidDirty: function() { 70669 this.send('becomeDirty'); 70670 this.updateRecordArraysLater(); 70671 }, 70672 */ 70673 70674 /** 70675 If the model `hasDirtyAttributes` this function will discard any unsaved 70676 changes. If the model `isNew` it will be removed from the store. 70677 Example 70678 ```javascript 70679 record.get('name'); // 'Untitled Document' 70680 record.set('name', 'Doc 1'); 70681 record.get('name'); // 'Doc 1' 70682 record.rollbackAttributes(); 70683 record.get('name'); // 'Untitled Document' 70684 ``` 70685 @since 1.13.0 70686 @method rollbackAttributes 70687 */ 70688 rollbackAttributes: function rollbackAttributes() { 70689 this._internalModel.rollbackAttributes(); 70690 }, 70691 70692 /* 70693 @method _createSnapshot 70694 @private 70695 */ 70696 _createSnapshot: function _createSnapshot() { 70697 return this._internalModel.createSnapshot(); 70698 }, 70699 70700 toStringExtension: function toStringExtension() { 70701 return get(this, 'id'); 70702 }, 70703 70704 /** 70705 Save the record and persist any changes to the record to an 70706 external source via the adapter. 70707 Example 70708 ```javascript 70709 record.set('name', 'Tomster'); 70710 record.save().then(function() { 70711 // Success callback 70712 }, function() { 70713 // Error callback 70714 }); 70715 ``` 70716 If you pass an object on the `adapterOptions` property of the options 70717 argument it will be passed to you adapter via the snapshot 70718 ```js 70719 record.save({ adapterOptions: { subscribe: false } }); 70720 ``` 70721 ```app/adapters/post.js 70722 import MyCustomAdapter from './custom-adapter'; 70723 export default MyCustomAdapter.extend({ 70724 updateRecord: function(store, type, snapshot) { 70725 if (snapshot.adapterOptions.subscribe) { 70726 // ... 70727 } 70728 // ... 70729 } 70730 }); 70731 ``` 70732 @method save 70733 @param {Object} options 70734 @return {Promise} a promise that will be resolved when the adapter returns 70735 successfully or rejected if the adapter returns with an error. 70736 */ 70737 save: function save(options) { 70738 var _this = this; 70739 70740 return _emberDataPrivateSystemPromiseProxies.PromiseObject.create({ 70741 promise: this._internalModel.save(options).then(function () { 70742 return _this; 70743 }) 70744 }); 70745 }, 70746 70747 /** 70748 Reload the record from the adapter. 70749 This will only work if the record has already finished loading. 70750 Example 70751 ```app/routes/model/view.js 70752 import Ember from 'ember'; 70753 export default Ember.Route.extend({ 70754 actions: { 70755 reload: function() { 70756 this.controller.get('model').reload().then(function(model) {
70757 // do something with the reloaded model 70758 }); 70759 } 70760 } 70761 }); 70762 ``` 70763 @method reload 70764 @return {Promise} a promise that will be resolved with the record when the 70765 adapter returns successfully or rejected if the adapter returns 70766 with an error. 70767 */ 70768 reload: function reload() { 70769 var _this2 = this; 70770 70771 return _emberDataPrivateSystemPromiseProxies.PromiseObject.create({ 70772 promise: this._internalModel.reload().then(function () { 70773 return _this2; 70774 }) 70775 }); 70776 }, 70777 70778 /** 70779 Override the default event firing from Ember.Evented to 70780 also call methods with the given name. 70781 @method trigger 70782 @private 70783 @param {String} name 70784 */ 70785 trigger: function trigger(name) { 70786 var length = arguments.length; 70787 var args = new Array(length - 1); 70788 70789 for (var i = 1; i < length; i++) { 70790 args[i - 1] = arguments[i]; 70791 } 70792 70793 _ember["default"].tryInvoke(this, name, args); 70794 this._super.apply(this, arguments); 70795 }, 70796 70797 willDestroy: function willDestroy() { 70798 //TODO Move! 70799 this._super.apply(this, arguments); 70800 this._internalModel.clearRelationships(); 70801 this._internalModel.recordObjectWillDestroy(); 70802 //TODO should we set internalModel to null here? 70803 }, 70804 70805 // This is a temporary solution until we refactor DS.Model to not 70806 // rely on the data property. 70807 willMergeMixin: function willMergeMixin(props) { 70808 var constructor = this.constructor; 70809 (0, _emberDataPrivateDebug.assert)('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); 70810 (0, _emberDataPrivateDebug.assert)("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); 70811 }, 70812 70813 attr: function attr() { 70814 (0, _emberDataPrivateDebug.assert)("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); 70815 }, 70816 70817 /** 70818 Get the reference for the specified belongsTo relationship. 70819 Example 70820 ```javascript 70821
70821// models/blog.js 70822 export default DS.Model.extend({ 70823 user: DS.belongsTo({ async: true }) 70824 }); 70825 var blog = store.push({ 70826 type: 'blog', 70827 id: 1, 70828 relationships: { 70829 user: { type: 'user', id: 1 } 70830 } 70831 }); 70832 var userRef = blog.belongsTo('user'); 70833 // check if the user relationship is loaded 70834 var isLoaded = userRef.value() !== null; 70835 // get the record of the reference (null if not yet available) 70836 var user = userRef.value(); 70837 // get the identifier of the reference 70838 if (userRef.remoteType() === "id") { 70839 var id = userRef.id(); 70840 } else if (userRef.remoteType() === "link") { 70841 var link = userRef.link(); 70842 } 70843 // load user (via store.findRecord or store.findBelongsTo) 70844 userRef.load().then(...) 70845 // or trigger a reload 70846 userRef.reload().then(...) 70847 // provide data for reference 70848 userRef.push({ 70849 type: 'user', 70850 id: 1, 70851 attributes: { 70852 username: "@user" 70853 } 70854 }).then(function(user) { 70855 userRef.value() === user; 70856 }); 70857 ``` 70858 @method belongsTo 70859 @param {String} name of the relationship 70860 @since 2.5.0 70861 @return {BelongsToReference} reference for this relationship 70862 */ 70863 belongsTo: function belongsTo(name) { 70864 return this._internalModel.referenceFor('belongsTo', name); 70865 }, 70866 70867 /** 70868 Get the reference for the specified hasMany relationship. 70869 Example 70870 ```javascript 70871
70871// models/blog.js 70872 export default DS.Model.extend({ 70873 comments: DS.hasMany({ async: true }) 70874 }); 70875 var blog = store.push({ 70876 type: 'blog', 70877 id: 1, 70878 relationships: { 70879 comments: { 70880 data: [ 70881 { type: 'comment', id: 1 }, 70882 { type: 'comment', id: 2 } 70883 ] 70884 } 70885 } 70886 }); 70887 var commentsRef = blog.hasMany('comments'); 70888 // check if the comments are loaded already 70889 var isLoaded = commentsRef.value() !== null; 70890 // get the records of the reference (null if not yet available) 70891 var comments = commentsRef.value(); 70892 // get the identifier of the reference 70893 if (commentsRef.remoteType() === "ids") { 70894 var ids = commentsRef.ids(); 70895 } else if (commentsRef.remoteType() === "link") { 70896 var link = commentsRef.link(); 70897 } 70898 // load comments (via store.findMany or store.findHasMany) 70899 commentsRef.load().then(...) 70900 // or trigger a reload 70901 commentsRef.reload().then(...) 70902 // provide data for reference 70903 commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { 70904 commentsRef.value() === comments; 70905 }); 70906 ``` 70907 @method hasMany 70908 @param {String} name of the relationship 70909 @since 2.5.0 70910 @return {HasManyReference} reference for this relationship 70911 */ 70912 hasMany: function hasMany(name) { 70913 return this._internalModel.referenceFor('hasMany', name); 70914 }, 70915 70916 setId: _ember["default"].observer('id', function () { 70917 this._internalModel.setId(this.get('id')); 70918 }) 70919 }); 70920 70921 Model.reopenClass({ 70922 /** 70923 Alias DS.Model's `create` method to `_create`. This allows us to create DS.Model 70924 instances from within the store, but if end users accidentally call `create()` 70925 (instead of `createRecord()`), we can raise an error. 70926 @method _create 70927 @private 70928 @static 70929 */ 70930 _create: Model.create, 70931 70932 /** 70933 Override the class' `create()` method to raise an error. This 70934 prevents end users from inadvertently calling `create()` instead 70935 of `createRecord()`. The store is still able to create instances 70936 by calling the `_create()` method. To create an instance of a 70937 `DS.Model` use [store.createRecord](DS.Store.html#method_createRecord). 70938 @method create 70939 @private 70940 @static 70941 */ 70942 create: function create() { 70943 throw new _ember["default"].Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set."); 70944 }, 70945 70946 /** 70947 Represents the model's class name as a string. This can be used to look up the model through 70948 DS.Store's modelFor method. 70949 `modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string. 70950 For example: 70951 ```javascript 70952 store.modelFor('post').modelName; // 'post' 70953 store.modelFor('blog-post').modelName; // 'blog-post' 70954 ``` 70955 The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload 70956 keys to underscore (instead of dasherized), you might use the following code: 70957 ```javascript 70958 export default var PostSerializer = DS.RESTSerializer.extend({ 70959 payloadKeyFromModelName: function(modelName) { 70960 return Ember.String.underscore(modelName); 70961 } 70962 }); 70963 ``` 70964 @property modelName 70965 @type String 70966 @readonly 70967 */ 70968 modelName: null 70969 }); 70970 70971 // if `Ember.setOwner` is defined, accessing `this.container` is 70972 // deprecated (but functional). In "standard" Ember usage, this 70973 // deprecation is actually created via an `.extend` of the factory 70974 // inside the container itself, but that only happens on models 70975 // with MODEL_FACTORY_INJECTIONS enabled :( 70976 if (_ember["default"].setOwner) { 70977 Object.defineProperty(Model.prototype, 'container', { 70978 configurable: true, 70979 enumerable: false, 70980 get: function get() { 70981 (0, _emberDataPrivateDebug.deprecate)('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', false, { id: 'ember-
70981application.injected-container', until: '3.0.0' }); 70982 70983 return this.store.container; 70984 } 70985 }); 70986 } 70987 70988 Model.reopenClass(_emberDataPrivateSystemRelationshipsExt.RelationshipsClassMethodsMixin); 70989 Model.reopenClass(_emberDataPrivateSystemModelAttr.AttrClassMethodsMixin); 70990 70991 exports["default"] = Model.extend(_emberDataPrivateSystemDebugDebugInfo["default"], _emberDataPrivateSystemRelationshipsBelongsTo.BelongsToMixin, _emberDataPrivateSystemRelationshipsExt.DidDefinePropertyMixin, _emberDataPrivateSystemRelationshipsExt.RelationshipsInstanceMethodsMixin, _emberDataPrivateSystemRelationshipsHasMany.HasManyMixin, _emberDataPrivateSystemModelAttr.AttrInstanceMethodsMixin); 70992}); 70993define('ember-data/-private/system/model/states', ['exports', 'ember', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateDebug) { 70994 /** 70995 @module ember-data 70996 */ 70997 'use strict'; 70998 70999 var get = _ember['default'].get; 71000 /* 71001 This file encapsulates the various states that a record can transition 71002 through during its lifecycle. 71003 */ 71004 /** 71005 ### State 71006 71007 Each record has a `currentState` property that explicitly tracks what 71008 state a record is in at any given time. For instance, if a record is 71009 newly created and has not yet been sent to the adapter to be saved, 71010 it would be in the `root.loaded.created.uncommitted` state. If a 71011 record has had local modifications made to it that are in the 71012 process of being saved, the record would be in the 71013 `root.loaded.updated.inFlight` state. (This state paths will be 71014 explained in more detail below.) 71015 71016 Events are sent by the record or its store to the record's 71017 `currentState` property. How the state reacts to these events is 71018 dependent on which state it is in. In some states, certain events 71019 will be invalid and will cause an exception to be raised. 71020 71021 States are hierarchical and every state is a substate of the 71022 `RootState`. For example, a record can be in the 71023 `root.deleted.uncommitted` state, then transition into the 71024 `root.deleted.inFlight` state. If a child state does not implement 71025 an event handler, the state manager will attempt to invoke the event 71026 on all parent states until the root state is reached. The state 71027 hierarchy of a record is described in terms of a path string. You 71028 can determine a record's current state by getting the state's 71029 `stateName` property: 71030 71031 ```javascript 71032 record.get('currentState.stateName'); 71033 //=> "root.created.uncommitted" 71034 ``` 71035 71036 The hierarchy of valid states that ship with ember data looks like 71037 this: 71038 71039 ```text 71040 * root 71041 * deleted 71042 * saved 71043 * uncommitted 71044 * inFlight 71045 * empty 71046 * loaded 71047 * created 71048 * uncommitted 71049 * inFlight 71050 * saved 71051 * updated 71052 * uncommitted 71053 * inFlight 71054 * loading 71055 ``` 71056 71057 The `DS.Model` states are themselves stateless. What that means is 71058 that, the hierarchical states that each of *those* points to is a 71059 shared data structure. For performance reasons, instead of each 71060 record getting its own copy of the hierarchy of states, each record 71061 points to this global, immutable shared instance. How does a state 71062 know which record it should be acting on? We pass the record 71063 instance into the state's event handlers as the first argument. 71064 71065 The record passed as the first parameter is where you should stash 71066 state about the record if needed; you should never store data on the state 71067 object itself. 71068 71069 ### Events and Flags 71070 71071 A state may implement zero or more events and flags. 71072 71073 #### Events 71074 71075 Events are named functions that are invoked when sent to a record. The 71076 record will first look for a method with the given name on the 71077 current state. If no method is found, it will search the current 71078 state's parent, and then its grandparent, and so on until reaching 71079 the top of the hierarchy. If the root is reached without an event 71080 handler being found, an exception will be raised. This can be very 71081 helpful when debugging new features. 71082 71083 Here's an example implementation of a state with a `myEvent` event handler: 71084 71085 ```javascript 71086 aState: DS.State.create({ 71087 myEvent: function(manager, param) { 71088 console.log("Received myEvent with", param); 71089 } 71090 }) 71091 ``` 71092 71093 To trigger this event: 71094 71095 ```javascript 71096 record.send('myEvent', 'foo'); 71097 //=> "Received myEvent with foo" 71098 ``` 71099 71100 Note that an optional parameter can be sent to a record's `send()` method, 71101 which will be passed as the second parameter to the event handler. 71102 71103 Events should transition to a different state if appropriate. This can be 71104 done by calling the record's `transitionTo()` method with a path to the 71105 desired state. The state manager will attempt to resolve the state path 71106 relative to the current state. If no state is found at that path, it will 71107 attempt to resolve it relative to the current state's parent, and then its 71108 parent, and so on until the root is reached. For example, imagine a hierarchy 71109 like this: 71110 71111 * created 71112 * uncommitted <-- currentState 71113 * inFlight 71114 * updated 71115 * inFlight 71116 71117 If we are currently in the `uncommitted` state, calling 71118 `transitionTo('inFlight')` would transition to the `created.inFlight` state, 71119 while calling `transitionTo('updated.inFlight')` would transition to 71120 the `updated.inFlight` state. 71121 71122 Remember that *only events* should ever cause a state transition. You should 71123 never call `transitionTo()` from outside a state's event handler. If you are 71124 tempted to do so, create a new event and send that to the state manager. 71125 71126 #### Flags 71127 71128 Flags are Boolean values that can be used to introspect a record's current 71129 state in a more user-friendly way than examining its state path. For example, 71130 instead of doing this: 71131 71132 ```javascript 71133 var statePath = record.get('stateManager.currentPath'); 71134 if (statePath === 'created.inFlight') { 71135 doSomething(); 71136 } 71137 ``` 71138 71139 You can say: 71140 71141 ```javascript 71142 if (record.get('isNew') && record.get('isSaving')) { 71143 doSomething(); 71144 } 71145 ``` 71146 71147 If your state does not set a value for a given flag, the value will 71148 be inherited from its parent (or the first place in the state hierarchy 71149 where it is defined). 71150 71151 The current set of flags are defined below. If you want to add a new flag, 71152 in addition to the area below, you will also need to declare it in the 71153 `DS.Model` class. 71154 71155 71156 * [isEmpty](DS.Model.html#property_isEmpty) 71157 * [isLoading](DS.Model.html#property_isLoading) 71158 * [isLoaded](DS.Model.html#property_isLoaded) 71159 * [isDirty](DS.Model.html#property_isDirty) 71160 * [isSaving](DS.Model.html#property_isSaving) 71161 * [isDeleted](DS.Model.html#property_isDeleted) 71162 * [isNew](DS.Model.html#property_isNew) 71163 * [isValid](DS.Model.html#property_isValid) 71164 71165 @namespace DS 71166 @class RootState 71167 */ 71168 71169 function _didSetProperty(internalModel, context) { 71170 if (context.value === context.originalValue) { 71171 delete internalModel._attributes[context.name]; 71172 internalModel.send('propertyWasReset', context.name); 71173 } else if (context.value !== context.oldValue) { 71174 internalModel.send('becomeDirty'); 71175 } 71176 71177 internalModel.updateRecordArraysLater(); 71178 } 71179 71180 // Implementation notes: 71181 // 71182 // Each state has a boolean value for all of the following flags: 71183 // 71184 // * isLoaded: The record has a populated `data` property. When a
71185 // record is loaded via `store.find`, `isLoaded` is false 71186 // until the adapter sets it. When a record is created locally, 71187 // its `isLoaded` property is always true. 71188 // * isDirty: The record has local changes that have not yet been 71189 // saved by the adapter. This includes records that have been 71190 // created (but not yet saved) or deleted. 71191 // * isSaving: The record has been committed, but 71192 // the adapter has not yet acknowledged that the changes have 71193 // been persisted to the backend. 71194 // * isDeleted: The record was marked for deletion. When `isDeleted` 71195 // is true and `isDirty` is true, the record is deleted locally 71196 // but the deletion was not yet persisted. When `isSaving` is 71197 // true, the change is in-flight. When both `isDirty` and 71198 // `isSaving` are false, the change has persisted. 71199 // * isNew: The record was created on the client and the adapter 71200 // did not yet report that it was successfully saved. 71201 // * isValid: The adapter did not report any server-side validation 71202 // failures. 71203 71204 // The dirty state is a abstract state whose functionality is 71205 // shared between the `created` and `updated` states. 71206 // 71207 // The deleted state shares the `isDirty` flag with the 71208 // subclasses of `DirtyState`, but with a very different 71209 // implementation. 71210 // 71211 // Dirty states have three child states: 71212 // 71213 // `uncommitted`: the store has not yet handed off the record 71214 // to be saved. 71215 // `inFlight`: the store has handed off the record to be saved, 71216 // but the adapter has not yet acknowledged success. 71217 // `invalid`: the record has invalid information and cannot be 71218 // send to the adapter yet. 71219 var DirtyState = { 71220 initialState: 'uncommitted', 71221 71222 // FLAGS 71223 isDirty: true, 71224 71225 // SUBSTATES 71226 71227 // When a record first becomes dirty, it is `uncommitted`. 71228 // This means that there are local pending changes, but they 71229 // have not yet begun to be saved, and are not invalid. 71230 uncommitted: { 71231 // EVENTS 71232 didSetProperty: _didSetProperty, 71233 71234 //TODO(Igor) reloading now triggers a 71235 //loadingData event, though it seems fine? 71236 loadingData: _ember['default'].K, 71237 71238 propertyWasReset: function propertyWasReset(internalModel, name) { 71239 if (!internalModel.hasChangedAttributes()) { 71240 internalModel.send('rolledBack'); 71241 } 71242 }, 71243 71244 pushedData: function pushedData(internalModel) { 71245 internalModel.updateChangedAttributes(); 71246 71247 if (!internalModel.hasChangedAttributes()) { 71248 internalModel.transitionTo('loaded.saved'); 71249 } 71250 }, 71251 71252 becomeDirty: _ember['default'].K, 71253 71254 willCommit: function willCommit(internalModel) { 71255 internalModel.transitionTo('inFlight'); 71256 }, 71257 71258 reloadRecord: function reloadRecord(internalModel, resolve) { 71259 resolve(internalModel.store.reloadRecord(internalModel)); 71260 }, 71261 71262 rolledBack: function rolledBack(internalModel) { 71263 internalModel.transitionTo('loaded.saved'); 71264 }, 71265 71266 becameInvalid: function becameInvalid(internalModel) { 71267 internalModel.transitionTo('invalid'); 71268 }, 71269 71270 rollback: function rollback(internalModel) { 71271 internalModel.rollbackAttributes(); 71272 internalModel.triggerLater('ready'); 71273 } 71274 }, 71275 71276 // Once a record has been handed off to the adapter to be 71277 // saved, it is in the 'in flight' state. Changes to the 71278 // record cannot be made during this window. 71279 inFlight: { 71280 // FLAGS 71281 isSaving: true, 71282 71283 // EVENTS 71284 didSetProperty: _didSetProperty, 71285 becomeDirty: _ember['default'].K, 71286 pushedData: _ember['default'].K, 71287 71288 unloadRecord: assertAgainstUnloadRecord, 71289 71290 // TODO: More robust semantics around save-while-in-flight 71291 willCommit: _ember['default'].K, 71292 71293 didCommit: function didCommit(internalModel) { 71294 var dirtyType = get(this, 'dirtyType'); 71295 71296 internalModel.transitionTo('saved'); 71297 internalModel.send('invokeLifecycleCallbacks', dirtyType); 71298 }, 71299 71300 becameInvalid: function becameInvalid(internalModel) { 71301 internalModel.transitionTo('invalid'); 71302 internalModel.send('invokeLifecycleCallbacks'); 71303 }, 71304 71305 becameError: function becameError(internalModel) { 71306 internalModel.transitionTo('uncommitted'); 71307 internalModel.triggerLater('becameError', internalModel); 71308 } 71309 }, 71310
71311 // A record is in the `invalid` if the adapter has indicated 71312 // the the record failed server-side invalidations. 71313 invalid: { 71314 // FLAGS 71315 isValid: false, 71316 71317 // EVENTS 71318 deleteRecord: function deleteRecord(internalModel) { 71319 internalModel.transitionTo('deleted.uncommitted'); 71320 }, 71321 71322 didSetProperty: function didSetProperty(internalModel, context) { 71323 internalModel.removeErrorMessageFromAttribute(context.name); 71324 71325 _didSetProperty(internalModel, context); 71326 71327 if (!internalModel.hasErrors()) { 71328 this.becameValid(internalModel); 71329 } 71330 }, 71331 71332 becameInvalid: _ember['default'].K, 71333 becomeDirty: _ember['default'].K, 71334 pushedData: _ember['default'].K, 71335 71336 willCommit: function willCommit(internalModel) { 71337 internalModel.clearErrorMessages(); 71338 internalModel.transitionTo('inFlight'); 71339 }, 71340 71341 rolledBack: function rolledBack(internalModel) { 71342 internalModel.clearErrorMessages(); 71343 internalModel.transitionTo('loaded.saved'); 71344 internalModel.triggerLater('ready'); 71345 }, 71346 71347 becameValid: function becameValid(internalModel) { 71348 internalModel.transitionTo('uncommitted'); 71349 }, 71350 71351 invokeLifecycleCallbacks: function invokeLifecycleCallbacks(internalModel) { 71352 internalModel.triggerLater('becameInvalid', internalModel); 71353 } 71354 } 71355 }; 71356 71357 // The created and updated states are created outside the state 71358 // chart so we can reopen their substates and add mixins as 71359 // necessary. 71360 71361 function deepClone(object) { 71362 var clone = {}; 71363 var value; 71364 71365 for (var prop in object) { 71366 value = object[prop]; 71367 if (value && typeof value === 'object') { 71368 clone[prop] = deepClone(value); 71369 } else { 71370 clone[prop] = value; 71371 } 71372 } 71373 71374 return clone; 71375 } 71376 71377 function mixin(original, hash) { 71378 for (var prop in hash) { 71379 original[prop] = hash[prop]; 71380 } 71381 71382 return original; 71383 } 71384 71385 function dirtyState(options) { 71386 var newState = deepClone(DirtyState); 71387 return mixin(newState, options); 71388 } 71389 71390 var createdState = dirtyState({ 71391 dirtyType: 'created', 71392 // FLAGS 71393 isNew: true 71394 }); 71395 71396 createdState.invalid.rolledBack = function (internalModel) { 71397 internalModel.transitionTo('deleted.saved'); 71398 }; 71399 createdState.uncommitted.rolledBack = function (internalModel) { 71400 internalModel.transitionTo('deleted.saved'); 71401 }; 71402 71403 var updatedState = dirtyState({ 71404 dirtyType: 'updated' 71405 }); 71406 71407 function createdStateDeleteRecord(internalModel) { 71408 internalModel.transitionTo('deleted.saved'); 71409 internalModel.send('invokeLifecycleCallbacks'); 71410 } 71411 71412 createdState.uncommitted.deleteRecord = createdStateDeleteRecord; 71413 71414 createdState.invalid.deleteRecord = createdStateDeleteRecord; 71415 71416 createdState.uncommitted.rollback = function (internalModel) { 71417 DirtyState.uncommitted.rollback.apply(this, arguments); 71418 internalModel.transitionTo('deleted.saved'); 71419 }; 71420 71421 createdState.uncommitted.pushedData = function (internalModel) { 71422 internalModel.transitionTo('loaded.updated.uncommitted'); 71423 internalModel.triggerLater('didLoad'); 71424 }; 71425 71426 createdState.uncommitted.propertyWasReset = _ember['default'].K; 71427 71428 function assertAgainstUnloadRecord(internalModel) { 71429 (0, _emberDataPrivateDebug.assert)("You can only unload a record which is not inFlight. `" + internalModel + "`", false); 71430 } 71431 71432 updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; 71433 71434 updatedState.uncommitted.deleteRecord = function (internalModel) { 71435 internalModel.transitionTo('deleted.uncommitted'); 71436 }; 71437 71438 var RootState = { 71439 // FLAGS 71440 isEmpty: false, 71441 isLoading: false, 71442 isLoaded: false, 71443 isDirty: false, 71444 isSaving: false, 71445 isDeleted: false, 71446 isNew: false, 71447 isValid: true, 71448 71449 // DEFAULT EVENTS 71450 71451 // Trying to roll back if you're not in the dirty state 71452 // doesn't change your state. For example, if you're in the 71453 // in-flight state, rolling back the record doesn't move 71454 // you out of the in-flight state. 71455 rolledBack: _ember['default'].K, 71456 unloadRecord: function unloadRecord(internalModel) { 71457 // clear relationships before moving to deleted state 71458 // otherwise it fails 71459 internalModel.clearRelationships(); 71460 internalModel.transitionTo('deleted.saved'); 71461 }, 71462 71463 propertyWasReset: _ember['default'].K, 71464 71465 // SUBSTATES 71466 71467 // A record begins its lifecycle in the `empty` state. 71468 // If its data will come from the adapter, it will 71469 // transition into the `loading` state. Otherwise, if
71470 // the record is being created on the client, it will 71471 // transition into the `created` state. 71472 empty: { 71473 isEmpty: true, 71474 71475 // EVENTS 71476 loadingData: function loadingData(internalModel, promise) { 71477 internalModel._loadingPromise = promise; 71478 internalModel.transitionTo('loading'); 71479 }, 71480 71481 loadedData: function loadedData(internalModel) { 71482 internalModel.transitionTo('loaded.created.uncommitted'); 71483 internalModel.triggerLater('ready'); 71484 }, 71485 71486 pushedData: function pushedData(internalModel) { 71487 internalModel.transitionTo('loaded.saved'); 71488 internalModel.triggerLater('didLoad'); 71489 internalModel.triggerLater('ready'); 71490 } 71491 }, 71492 71493 // A record enters this state when the store asks 71494 // the adapter for its data. It remains in this state 71495 // until the adapter provides the requested data. 71496 // 71497 // Usually, this process is asynchronous, using an 71498 // XHR to retrieve the data. 71499 loading: { 71500 // FLAGS 71501 isLoading: true, 71502 71503 exit: function exit(internalModel) { 71504 internalModel._loadingPromise = null; 71505 }, 71506 71507 // EVENTS 71508 pushedData: function pushedData(internalModel) { 71509 internalModel.transitionTo('loaded.saved'); 71510 internalModel.triggerLater('didLoad'); 71511 internalModel.triggerLater('ready'); 71512 //TODO this seems out of place here 71513 internalModel.didCleanError(); 71514 }, 71515 71516 becameError: function becameError(internalModel) { 71517 internalModel.triggerLater('becameError', internalModel); 71518 }, 71519 71520 notFound: function notFound(internalModel) { 71521 internalModel.transitionTo('empty'); 71522 } 71523 }, 71524 71525 // A record enters this state when its data is populated. 71526 // Most of a record's lifecycle is spent inside substates 71527 // of the `loaded` state. 71528 loaded: { 71529 initialState: 'saved', 71530 71531 // FLAGS 71532 isLoaded: true, 71533 71534 //TODO(Igor) Reloading now triggers a loadingData event, 71535 //but it should be ok? 71536 loadingData: _ember['default'].K, 71537 71538 // SUBSTATES 71539 71540 // If there are no local changes to a record, it remains 71541 // in the `saved` state. 71542 saved: { 71543 setup: function setup(internalModel) { 71544 if (internalModel.hasChangedAttributes()) { 71545 internalModel.adapterDidDirty(); 71546 } 71547 }, 71548 71549 // EVENTS 71550 didSetProperty: _didSetProperty, 71551 71552 pushedData: _ember['default'].K, 71553 71554 becomeDirty: function becomeDirty(internalModel) { 71555 internalModel.transitionTo('updated.uncommitted'); 71556 }, 71557 71558 willCommit: function willCommit(internalModel) { 71559 internalModel.transitionTo('updated.inFlight'); 71560 }, 71561 71562 reloadRecord: function reloadRecord(internalModel, resolve) { 71563 resolve(internalModel.store.reloadRecord(internalModel)); 71564 }, 71565 71566 deleteRecord: function deleteRecord(internalModel) { 71567 internalModel.transitionTo('deleted.uncommitted'); 71568 }, 71569 71570 unloadRecord: function unloadRecord(internalModel) { 71571 // clear relationships before moving to deleted state 71572 // otherwise it fails 71573 internalModel.clearRelationships(); 71574 internalModel.transitionTo('deleted.saved'); 71575 }, 71576 71577 didCommit: function didCommit(internalModel) { 71578 internalModel.send('invokeLifecycleCallbacks', get(internalModel, 'lastDirtyType')); 71579 }, 71580 71581 // loaded.saved.notFound would be triggered by a failed 71582 // `reload()` on an unchanged record 71583 notFound: _ember['default'].K 71584 71585 }, 71586 71587 // A record is in this state after it has been locally 71588 // created but before the adapter has indicated that 71589 // it has been saved. 71590 created: createdState, 71591 71592 // A record is in this state if it has already been 71593 // saved to the server, but there are new local changes 71594 // that have not yet been saved. 71595 updated: updatedState 71596 }, 71597 71598 // A record is in this state if it was deleted from the store. 71599 deleted: { 71600 initialState: 'uncommitted', 71601 dirtyType: 'deleted', 71602 71603 // FLAGS 71604 isDeleted: true, 71605 isLoaded: true, 71606 isDirty: true, 71607 71608 // TRANSITIONS 71609 setup: function setup(internalModel) { 71610 internalModel.updateRecordArrays(); 71611 }, 71612 71613 // SUBSTATES 71614 71615 // When a record is deleted, it enters the `start` 71616 // state. It will exit this state when the record 71617 // starts to commit. 71618 uncommitted: { 71619 71620 // EVENTS 71621 71622 willCommit: function willCommit(internalModel) { 71623 internalModel.transitionTo('inFlight'); 71624 }, 71625 71626 rollback: function rollback(internalModel) { 71627 internalModel.rollbackAttributes(); 71628 internalModel.triggerLater('ready'); 71629 }, 71630 71631 pushedData: _ember['default'].K, 71632 becomeDirty: _ember['default'].K, 71633 deleteRecord: _ember['default'].K, 71634 71635 rolledBack: function rolledBack(internalModel) { 71636 internalModel.transitionTo('loaded.saved'); 71637 internalModel.triggerLater('ready'); 71638 } 71639 }, 71640 71641 // After a record starts committing, but 71642 // before the adapter indicates that the deletion 71643 // has saved to the server, a record is in the 71644 // `inFlight` substate of `deleted`. 71645 inFlight: { 71646 // FLAGS 71647 isSaving: true, 71648 71649 // EVENTS 71650 71651 unloadRecord: assertAgainstUnloadRecord, 71652 71653 // TODO: More robust semantics around save-while-in-flight 71654 willCommit: _ember['default'].K, 71655 didCommit: function didCommit(internalModel) { 71656 internalModel.transitionTo('saved'); 71657 71658 internalModel.send('invokeLifecycleCallbacks'); 71659 }, 71660 71661 becameError: function becameError(internalModel) { 71662 internalModel.transitionTo('uncommitted'); 71663 internalModel.triggerLater('becameError', internalModel); 71664 }, 71665 71666 becameInvalid: function becameInvalid(internalModel) { 71667 internalModel.transitionTo('invalid'); 71668 internalModel.triggerLater('becameInvalid', internalModel); 71669 } 71670 }, 71671 71672 // Once the adapter indicates that the deletion has
71673 // been saved, the record enters the `saved` substate 71674 // of `deleted`. 71675 saved: { 71676 // FLAGS 71677 isDirty: false, 71678 71679 setup: function setup(internalModel) { 71680 internalModel.clearRelationships(); 71681 var store = internalModel.store; 71682 store._dematerializeRecord(internalModel); 71683 }, 71684 71685 invokeLifecycleCallbacks: function invokeLifecycleCallbacks(internalModel) { 71686 internalModel.triggerLater('didDelete', internalModel); 71687 internalModel.triggerLater('didCommit', internalModel); 71688 }, 71689 71690 willCommit: _ember['default'].K, 71691 71692 didCommit: _ember['default'].K 71693 }, 71694 71695 invalid: { 71696 isValid: false, 71697 71698 didSetProperty: function didSetProperty(internalModel, context) { 71699 internalModel.removeErrorMessageFromAttribute(context.name); 71700 71701 _didSetProperty(internalModel, context); 71702 71703 if (!internalModel.hasErrors()) { 71704 this.becameValid(internalModel); 71705 } 71706 }, 71707 71708 becameInvalid: _ember['default'].K, 71709 becomeDirty: _ember['default'].K, 71710 deleteRecord: _ember['default'].K, 71711 willCommit: _ember['default'].K, 71712 71713 rolledBack: function rolledBack(internalModel) { 71714 internalModel.clearErrorMessages(); 71715 internalModel.transitionTo('loaded.saved'); 71716 internalModel.triggerLater('ready'); 71717 }, 71718 71719 becameValid: function becameValid(internalModel) { 71720 internalModel.transitionTo('uncommitted'); 71721 } 71722 71723 } 71724 }, 71725 71726 invokeLifecycleCallbacks: function invokeLifecycleCallbacks(internalModel, dirtyType) { 71727 if (dirtyType === 'created') { 71728 internalModel.triggerLater('didCreate', internalModel); 71729 } else { 71730 internalModel.triggerLater('didUpdate', internalModel); 71731 } 71732 71733 internalModel.triggerLater('didCommit', internalModel); 71734 } 71735 }; 71736 71737 function wireState(object, parent, name) { 71738 // TODO: Use Object.create and copy instead 71739 object = mixin(parent ? Object.create(parent) : {}, object); 71740 object.parentState = parent; 71741 object.stateName = name; 71742 71743 for (var prop in object) { 71744 if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { 71745 continue; 71746 } 71747 if (typeof object[prop] === 'object') { 71748 object[prop] = wireState(object[prop], object, name + "." + prop); 71749 } 71750 } 71751 71752 return object; 71753 } 71754 71755 RootState = wireState(RootState, null, "root"); 71756 71757 exports['default'] = RootState; 71758}); 71759define('ember-data/-private/system/normalize-link', ['exports'], function (exports) { 71760 'use strict'; 71761 71762 exports['default'] = _normalizeLink; 71763 71764 /** 71765 This method normalizes a link to an "links object". If the passed link is 71766 already an object it's returned without any modifications. 71767 71768 See http://jsonapi.org/format/#document-links for more information. 71769 71770 @method _normalizeLink 71771 @private 71772 @param {String} link 71773 @return {Object|null} 71774 @for DS 71775 */ 71776 function _normalizeLink(link) { 71777 switch (typeof link) { 71778 case 'object': 71779 return link; 71780 case 'string': 71781 return { href: link }; 71782 } 71783 return null; 71784 } 71785}); 71786define('ember-data/-private/system/normalize-model-name', ['exports', 'ember'], function (exports, _ember) { 71787 'use strict'; 71788 71789 exports['default'] = normalizeModelName; 71790 71791 /** 71792 All modelNames are dasherized internally. Changing this function may 71793 require changes to other normalization hooks (such as typeForRoot). 71794 @method normalizeModelName 71795 @public 71796 @param {String} modelName 71797 @return {String} if the adapter can generate one, an ID 71798 @for DS 71799 */ 71800 function normalizeModelName(modelName) { 71801 return _ember['default'].String.dasherize(modelName); 71802 } 71803}); 71804define('ember-data/-private/system/ordered-set', ['exports', 'ember'], function (exports, _ember) { 71805 'use strict'; 71806 71807 exports['default'] = OrderedSet; 71808 71809 var EmberOrderedSet = _ember['default'].OrderedSet; 71810 var guidFor = _ember['default'].guidFor; 71811 function OrderedSet() { 71812 this._super$constructor(); 71813 } 71814 71815 OrderedSet.create = function () { 71816 var Constructor = this; 71817 return new Constructor(); 71818 }; 71819 71820 OrderedSet.prototype = Object.create(EmberOrderedSet.prototype); 71821 OrderedSet.prototype.constructor = OrderedSet; 71822 OrderedSet.prototype._super$constructor = EmberOrderedSet; 71823 71824 OrderedSet.prototype.addWithIndex = function (obj, idx) { 71825 var guid = guidFor(obj); 71826 var presenceSet = this.presenceSet; 71827 var list = this.list; 71828 71829 if (presenceSet[guid] === true) { 71830 return; 71831 } 71832 71833 presenceSet[guid] = true; 71834 71835 if (idx === undefined || idx === null) { 71836 list.push(obj); 71837 } else { 71838 list.splice(idx, 0, obj); 71839 } 71840 71841 this.size += 1; 71842 71843 return this; 71844 }; 71845}); 71846define('ember-data/-private/system/promise-proxies', ['exports', 'ember', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateDebug) { 71847 'use strict'; 71848 71849 var Promise = _ember['default'].RSVP.Promise; 71850 var get = _ember['default'].get; 71851 71852 /** 71853 A `PromiseArray` is an object that acts like both an `Ember.Array` 71854 and a promise. When the promise is resolved the resulting value 71855 will be set to the `PromiseArray`'s `content` property. This makes 71856 it easy to create data bindings with the `PromiseArray` that will be 71857 updated when the promise resolves. 71858 71859 For more information see the [Ember.PromiseProxyMixin 71860 documentation](/api/classes/Ember.PromiseProxyMixin.html). 71861 71862 Example 71863 71864 ```javascript 71865 var promiseArray = DS.PromiseArray.create({ 71866 promise: $.getJSON('/some/remote/data.json') 71867 }); 71868 71869 promiseArray.get('length'); // 0 71870 71871 promiseArray.then(function() { 71872 promiseArray.get('length'); // 100 71873 }); 71874 ``` 71875 71876 @class PromiseArray 71877 @namespace DS
71878 @extends Ember.ArrayProxy 71879 @uses Ember.PromiseProxyMixin 71880 */ 71881 var PromiseArray = _ember['default'].ArrayProxy.extend(_ember['default'].PromiseProxyMixin); 71882 71883 /** 71884 A `PromiseObject` is an object that acts like both an `Ember.Object` 71885 and a promise. When the promise is resolved, then the resulting value 71886 will be set to the `PromiseObject`'s `content` property. This makes 71887 it easy to create data bindings with the `PromiseObject` that will 71888 be updated when the promise resolves. 71889 71890 For more information see the [Ember.PromiseProxyMixin 71891 documentation](/api/classes/Ember.PromiseProxyMixin.html). 71892 71893 Example 71894 71895 ```javascript 71896 var promiseObject = DS.PromiseObject.create({ 71897 promise: $.getJSON('/some/remote/data.json') 71898 }); 71899 71900 promiseObject.get('name'); // null 71901 71902 promiseObject.then(function() { 71903 promiseObject.get('name'); // 'Tomster' 71904 }); 71905 ``` 71906 71907 @class PromiseObject 71908 @namespace DS 71909 @extends Ember.ObjectProxy 71910 @uses Ember.PromiseProxyMixin 71911 */ 71912 var PromiseObject = _ember['default'].ObjectProxy.extend(_ember['default'].PromiseProxyMixin); 71913 71914 var promiseObject = function promiseObject(promise, label) { 71915 return PromiseObject.create({ 71916 promise: Promise.resolve(promise, label) 71917 }); 71918 }; 71919 71920 var promiseArray = function promiseArray(promise, label) { 71921 return PromiseArray.create({ 71922 promise: Promise.resolve(promise, label) 71923 }); 71924 }; 71925 71926 /** 71927 A PromiseManyArray is a PromiseArray that also proxies certain method calls 71928 to the underlying manyArray. 71929 Right now we proxy: 71930 71931 * `reload()` 71932 * `createRecord()` 71933 * `on()` 71934 * `one()` 71935 * `trigger()` 71936 * `off()` 71937 * `has()` 71938 71939 @class PromiseManyArray 71940 @namespace DS 71941 @extends Ember.ArrayProxy 71942 */ 71943 71944 function proxyToContent(method) { 71945 return function () { 71946 var content = get(this, 'content'); 71947 return content[method].apply(content, arguments); 71948 }; 71949 } 71950 71951 var PromiseManyArray = PromiseArray.extend({ 71952 reload: function reload() { 71953 //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships 71954 (0, _emberDataPrivateDebug.assert)('You are trying to reload an async manyArray before it has been created', get(this, 'content')); 71955 return PromiseManyArray.create({ 71956 promise: get(this, 'content').reload() 71957 }); 71958 }, 71959 71960 createRecord: proxyToContent('createRecord'), 71961 71962 on: proxyToContent('on'), 71963 71964 one: proxyToContent('one'), 71965 71966 trigger: proxyToContent('trigger'), 71967 71968 off: proxyToContent('off'), 71969 71970 has: proxyToContent('has') 71971 }); 71972 71973 var promiseManyArray = function promiseManyArray(promise, label) { 71974 return PromiseManyArray.create({ 71975 promise: Promise.resolve(promise, label) 71976 }); 71977 }; 71978 71979 exports.PromiseArray = PromiseArray; 71980 exports.PromiseObject = PromiseObject; 71981 exports.PromiseManyArray = PromiseManyArray; 71982 exports.promiseArray = promiseArray; 71983 exports.promiseObject = promiseObject; 71984 exports.promiseManyArray = promiseManyArray; 71985}); 71986define("ember-data/-private/system/record-array-manager", ["exports", "ember", "ember-data/-private/system/record-arrays", "ember-data/-private/system/ordered-set"], function (exports, _ember, _emberDataPrivateSystemRecordArrays, _emberDataPrivateSystemOrderedSet) { 71987 /** 71988 @module ember-data 71989 */ 71990 71991 "use strict"; 71992 71993 var MapWithDefault = _ember["default"].MapWithDefault;var get = _ember["default"].get; 71994 71995 /** 71996 @class RecordArrayManager 71997 @namespace DS 71998 @private 71999 @extends Ember.Object 72000 */ 72001 exports["default"] = _ember["default"].Object.extend({ 72002 init: function init() { 72003 var _this = this; 72004 72005 this.filteredRecordArrays = MapWithDefault.create({ 72006 defaultValue: function defaultValue() { 72007 return []; 72008 } 72009 }); 72010 72011 this.liveRecordArrays = MapWithDefault.create({ 72012 defaultValue: function defaultValue(typeClass) { 72013 return _this.createRecordArray(typeClass); 72014 } 72015 }); 72016 72017 this.changedRecords = []; 72018 this._adapterPopulatedRecordArrays = []; 72019 }, 72020 72021 recordDidChange: function recordDidChange(record) { 72022 if (this.changedRecords.push(record) !== 1) { 72023 return; 72024 } 72025 72026 _ember["default"].run.schedule('actions', this, this.updateRecordArrays); 72027 }, 72028 72029 recordArraysForRecord: function recordArraysForRecord(record) { 72030 record._recordArrays = record._recordArrays || _emberDataPrivateSystemOrderedSet["default"].create(); 72031 return record._recordArrays; 72032 }, 72033 72034 /** 72035 This method is invoked whenever data is loaded into the store by the
72036 adapter or updated by the adapter, or when a record has changed. 72037 It updates all record arrays that a record belongs to. 72038 To avoid thrashing, it only runs at most once per run loop. 72039 @method updateRecordArrays 72040 */ 72041 updateRecordArrays: function updateRecordArrays() { 72042 var _this2 = this; 72043 72044 this.changedRecords.forEach(function (internalModel) { 72045 if (get(internalModel, 'record.isDestroyed') || get(internalModel, 'record.isDestroying') || get(internalModel, 'currentState.stateName') === 'root.deleted.saved') { 72046 _this2._recordWasDeleted(internalModel); 72047 } else { 72048 _this2._recordWasChanged(internalModel); 72049 } 72050 }); 72051 72052 this.changedRecords.length = 0; 72053 }, 72054 72055 _recordWasDeleted: function _recordWasDeleted(record) { 72056 var recordArrays = record._recordArrays; 72057 72058 if (!recordArrays) { 72059 return; 72060 } 72061 72062 recordArrays.forEach(function (array) { 72063 return array.removeInternalModel(record); 72064 }); 72065 72066 record._recordArrays = null; 72067 }, 72068 72069 _recordWasChanged: function _recordWasChanged(record) { 72070 var _this3 = this; 72071 72072 var typeClass = record.type; 72073 var recordArrays = this.filteredRecordArrays.get(typeClass); 72074 var filter; 72075 recordArrays.forEach(function (array) { 72076 filter = get(array, 'filterFunction'); 72077 _this3.updateFilterRecordArray(array, filter, typeClass, record); 72078 }); 72079 }, 72080 72081 //Need to update live arrays on loading 72082 recordWasLoaded: function recordWasLoaded(record) { 72083 var _this4 = this; 72084 72085 var typeClass = record.type; 72086 var recordArrays = this.filteredRecordArrays.get(typeClass); 72087 var filter; 72088 72089 recordArrays.forEach(function (array) { 72090 filter = get(array, 'filterFunction'); 72091 _this4.updateFilterRecordArray(array, filter, typeClass, record); 72092 }); 72093 72094 if (this.liveRecordArrays.has(typeClass)) { 72095 var liveRecordArray = this.liveRecordArrays.get(typeClass); 72096 this._addRecordToRecordArray(liveRecordArray, record); 72097 } 72098 }, 72099 /** 72100 Update an individual filter. 72101 @method updateFilterRecordArray 72102 @param {DS.FilteredRecordArray} array 72103 @param {Function} filter 72104 @param {DS.Model} typeClass 72105 @param {InternalModel} record 72106 */ 72107 updateFilterRecordArray: function updateFilterRecordArray(array, filter, typeClass, record) { 72108 var shouldBeInArray = filter(record.getRecord()); 72109 var recordArrays = this.recordArraysForRecord(record); 72110 if (shouldBeInArray) { 72111 this._addRecordToRecordArray(array, record); 72112 } else { 72113 recordArrays["delete"](array); 72114 array.removeInternalModel(record); 72115 } 72116 }, 72117 72118 _addRecordToRecordArray: function _addRecordToRecordArray(array, record) { 72119 var recordArrays = this.recordArraysForRecord(record); 72120 if (!recordArrays.has(array)) { 72121 array.addInternalModel(record); 72122 recordArrays.add(array); 72123 } 72124 }, 72125 72126 populateLiveRecordArray: function populateLiveRecordArray(array, modelName) { 72127 var typeMap = this.store.typeMapFor(modelName); 72128 var records = typeMap.records; 72129 var record; 72130 72131 for (var i = 0; i < records.length; i++) { 72132 record = records[i]; 72133 72134 if (!record.isDeleted() && !record.isEmpty()) { 72135 this._addRecordToRecordArray(array, record); 72136 } 72137 } 72138 }, 72139 72140 /** 72141 This method is invoked if the `filterFunction` property is 72142 changed on a `DS.FilteredRecordArray`. 72143 It essentially re-runs the filter from scratch. This same 72144 method is invoked when the filter is created in th first place. 72145 @method updateFilter 72146 @param {Array} array 72147 @param {String} modelName 72148 @param {Function} filter 72149 */ 72150 updateFilter: function updateFilter(array, modelName, filter) { 72151 var typeMap = this.store.typeMapFor(modelName); 72152 var records = typeMap.records; 72153 var record; 72154 72155 for (var i = 0; i < records.length; i++) { 72156 record = records[i]; 72157 72158 if (!record.isDeleted() && !record.isEmpty()) { 72159 this.updateFilterRecordArray(array, filter, modelName, record); 72160 } 72161 } 72162 }, 72163 72164 /** 72165 Get the `DS.RecordArray` for a type, which contains all loaded records of 72166 given type. 72167 @method liveRecordArrayFor 72168 @param {Class} typeClass 72169 @return {DS.RecordArray} 72170 */ 72171 liveRecordArrayFor: function liveRecordArrayFor(typeClass) { 72172 return this.liveRecordArrays.get(typeClass); 72173 }, 72174 72175 /** 72176 Create a `DS.RecordArray` for a type. 72177 @method createRecordArray 72178 @param {Class} typeClass 72179 @return {DS.RecordArray} 72180 */ 72181 createRecordArray: function createRecordArray(typeClass) { 72182 var array = _emberDataPrivateSystemRecordArrays.RecordArray.create({ 72183 type: typeClass, 72184 content: _ember["default"].A(), 72185 store: this.store, 72186 isLoaded: true, 72187 manager: this 72188 }); 72189 72190 return array; 72191 }, 72192 72193 /** 72194 Create a `DS.FilteredRecordArray` for a type and register it for updates. 72195 @method createFilteredRecordArray 72196 @param {DS.Model} typeClass 72197 @param {Function} filter 72198 @param {Object} query (optional 72199 @return {DS.FilteredRecordArray} 72200 */ 72201 createFilteredRecordArray: function createFilteredRecordArray(typeClass, filter, query) { 72202 var array = _emberDataPrivateSystemRecordArrays.FilteredRecordArray.create({ 72203 query: query, 72204 type: typeClass, 72205 content: _ember["default"].A(), 72206 store: this.store, 72207 manager: this, 72208 filterFunction: filter 72209 }); 72210 72211 this.registerFilteredRecordArray(array, typeClass, filter); 72212 72213 return array; 72214 }, 72215 72216 /**
72217 Create a `DS.AdapterPopulatedRecordArray` for a type with given query. 72218 @method createAdapterPopulatedRecordArray 72219 @param {DS.Model} typeClass 72220 @param {Object} query 72221 @return {DS.AdapterPopulatedRecordArray} 72222 */ 72223 createAdapterPopulatedRecordArray: function createAdapterPopulatedRecordArray(typeClass, query) { 72224 var array = _emberDataPrivateSystemRecordArrays.AdapterPopulatedRecordArray.create({ 72225 type: typeClass, 72226 query: query, 72227 content: _ember["default"].A(), 72228 store: this.store, 72229 manager: this 72230 }); 72231 72232 this._adapterPopulatedRecordArrays.push(array); 72233 72234 return array; 72235 }, 72236 72237 /** 72238 Register a RecordArray for a given type to be backed by 72239 a filter function. This will cause the array to update 72240 automatically when records of that type change attribute 72241 values or states. 72242 @method registerFilteredRecordArray 72243 @param {DS.RecordArray} array 72244 @param {DS.Model} typeClass 72245 @param {Function} filter 72246 */ 72247 registerFilteredRecordArray: function registerFilteredRecordArray(array, typeClass, filter) { 72248 var recordArrays = this.filteredRecordArrays.get(typeClass); 72249 recordArrays.push(array); 72250 72251 this.updateFilter(array, typeClass, filter); 72252 }, 72253 72254 /** 72255 Unregister a RecordArray. 72256 So manager will not update this array. 72257 @method unregisterRecordArray 72258 @param {DS.RecordArray} array 72259 */ 72260 unregisterRecordArray: function unregisterRecordArray(array) { 72261 var typeClass = array.type; 72262 72263 // unregister filtered record array 72264 var recordArrays = this.filteredRecordArrays.get(typeClass); 72265 var removedFromFiltered = remove(recordArrays, array); 72266 72267 // remove from adapter populated record array 72268 var removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); 72269 72270 if (!removedFromFiltered && !removedFromAdapterPopulated) { 72271 72272 // unregister live record array 72273 if (this.liveRecordArrays.has(typeClass)) { 72274 var liveRecordArrayForType = this.liveRecordArrayFor(typeClass); 72275 if (array === liveRecordArrayForType) { 72276 this.liveRecordArrays["delete"](typeClass); 72277 } 72278 } 72279 } 72280 }, 72281 72282 willDestroy: function willDestroy() { 72283 this._super.apply(this, arguments); 72284 72285 this.filteredRecordArrays.forEach(function (value) { 72286 return flatten(value).forEach(destroy); 72287 }); 72288 this.liveRecordArrays.forEach(destroy); 72289 this._adapterPopulatedRecordArrays.forEach(destroy); 72290 } 72291 }); 72292 72293 function destroy(entry) { 72294 entry.destroy(); 72295 } 72296 72297 function flatten(list) { 72298 var length = list.length; 72299 var result = _ember["default"].A(); 72300 72301 for (var i = 0; i < length; i++) { 72302 result = result.concat(list[i]); 72303 } 72304 72305 return result; 72306 } 72307 72308 function remove(array, item) { 72309 var index = array.indexOf(item); 72310 72311 if (index !== -1) { 72312 array.splice(index, 1); 72313 return true; 72314 } 72315 72316 return false; 72317 } 72318}); 72319define("ember-data/-private/system/record-arrays", ["exports", "ember-data/-private/system/record-arrays/record-array", "ember-data/-private/system/record-arrays/filtered-record-array", "ember-data/-private/system/record-arrays/adapter-populated-record-array"], function (exports, _emberDataPrivateSystemRecordArraysRecordArray, _emberDataPrivateSystemRecordArraysFilteredRecordArray, _emberDataPrivateSystemRecordArraysAdapterPopulatedRecordArray) { 72320 /** 72321 @module ember-data 72322 */ 72323 72324 "use strict"; 72325 72326 exports.RecordArray = _emberDataPrivateSystemRecordArraysRecordArray["default"]; 72327 exports.FilteredRecordArray = _emberDataPrivateSystemRecordArraysFilteredRecordArray["default"]; 72328 exports.AdapterPopulatedRecordArray = _emberDataPrivateSystemRecordArraysAdapterPopulatedRecordArray["default"]; 72329}); 72330define("ember-data/-private/system/record-arrays/adapter-populated-record-array", ["exports", "ember", "ember-data/-private/system/record-arrays/record-array", "ember-data/-private/system/clone-null", "ember-data/-private/features"], function (exports, _ember, _emberDataPrivateSystemRecordArraysRecordArray, _emberDataPrivateSystemCloneNull, _emberDataPrivateFeatures) { 72331 "use strict"; 72332 72333 /** 72334 @module ember-data 72335 */ 72336 72337 var get = _ember["default"].get; 72338 72339 /** 72340 Represents an ordered list of records whose order and membership is 72341 determined by the adapter. For example, a query sent to the adapter 72342 may trigger a search on the server, whose results would be loaded
72343 into an instance of the `AdapterPopulatedRecordArray`. 72344 72345 @class AdapterPopulatedRecordArray 72346 @namespace DS 72347 @extends DS.RecordArray 72348 */ 72349 exports["default"] = _emberDataPrivateSystemRecordArraysRecordArray["default"].extend({ 72350 query: null, 72351 72352 replace: function replace() { 72353 var type = get(this, 'type').toString(); 72354 throw new Error("The result of a server query (on " + type + ") is immutable."); 72355 }, 72356 72357 _update: function _update() { 72358 var store = get(this, 'store'); 72359 var modelName = get(this, 'type.modelName'); 72360 var query = get(this, 'query'); 72361 72362 return store._query(modelName, query, this); 72363 }, 72364 72365 /** 72366 @method loadRecords 72367 @param {Array} records 72368 @param {Object} payload normalized payload 72369 @private 72370 */ 72371 loadRecords: function loadRecords(records, payload) { 72372 var _this = this; 72373 72374 //TODO Optimize 72375 var internalModels = _ember["default"].A(records).mapBy('_internalModel'); 72376 this.setProperties({ 72377 content: _ember["default"].A(internalModels), 72378 isLoaded: true, 72379 isUpdating: false, 72380 meta: (0, _emberDataPrivateSystemCloneNull["default"])(payload.meta) 72381 }); 72382 72383 if (true) { 72384 this.set('links', (0, _emberDataPrivateSystemCloneNull["default"])(payload.links)); 72385 } 72386 72387 internalModels.forEach(function (record) { 72388 _this.manager.recordArraysForRecord(record).add(_this); 72389 }); 72390 72391 // TODO: should triggering didLoad event be the last action of the runLoop? 72392 _ember["default"].run.once(this, 'trigger', 'didLoad'); 72393 } 72394 }); 72395}); 72396define('ember-data/-private/system/record-arrays/filtered-record-array', ['exports', 'ember', 'ember-data/-private/system/record-arrays/record-array'], function (exports, _ember, _emberDataPrivateSystemRecordArraysRecordArray) { 72397 'use strict'; 72398 72399 /** 72400 @module ember-data 72401 */ 72402 72403 var get = _ember['default'].get; 72404 72405 /** 72406 Represents a list of records whose membership is determined by the 72407 store. As records are created, loaded, or modified, the store 72408 evaluates them to determine if they should be part of the record 72409 array. 72410 72411 @class FilteredRecordArray 72412 @namespace DS 72413 @extends DS.RecordArray 72414 */ 72415 exports['default'] = _emberDataPrivateSystemRecordArraysRecordArray['default'].extend({ 72416 /** 72417 The filterFunction is a function used to test records from the store to 72418 determine if they should be part of the record array. 72419 Example 72420 ```javascript 72421 var allPeople = store.peekAll('person'); 72422 allPeople.mapBy('name'); // ["Tom Dale", "Yehuda Katz", "Trek Glowacki"] 72423 var people = store.filter('person', function(person) { 72424 if (person.get('name').match(/Katz$/)) { return true; } 72425 }); 72426 people.mapBy('name'); // ["Yehuda Katz"] 72427 var notKatzFilter = function(person) { 72428 return !person.get('name').match(/Katz$/); 72429 }; 72430 people.set('filterFunction', notKatzFilter); 72431 people.mapBy('name'); // ["Tom Dale", "Trek Glowacki"] 72432 ``` 72433 @method filterFunction 72434 @param {DS.Model} record 72435 @return {Boolean} `true` if the record should be in the array 72436 */ 72437 filterFunction: null, 72438 isLoaded: true, 72439 72440 replace: function replace() { 72441 var type = get(this, 'type').toString(); 72442 throw new Error("The result of a client-side filter (on " + type + ") is immutable."); 72443 }, 72444 72445 /** 72446 @method updateFilter 72447 @private 72448 */ 72449 _updateFilter: function _updateFilter() { 72450 var manager = get(this, 'manager'); 72451 manager.updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); 72452 }, 72453 72454 updateFilter: _ember['default'].observer('filterFunction', function () { 72455 _ember['default'].run.once(this, this._updateFilter); 72456 }) 72457 }); 72458}); 72459define("ember-data/-private/system/record-arrays/record-array", ["exports", "ember", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/snapshot-record-array"], function (exports, _ember, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemSnapshotRecordArray) { 72460 /** 72461 @module ember-data 72462 */ 72463 72464 "use strict"; 72465 72466 var get = _ember["default"].get; 72467 var set = _ember["default"].set; 72468 72469 /** 72470 A record array is an array that contains records of a certain type. The record 72471 array materializes records as needed when they are retrieved for the first 72472 time. You should not create record arrays yourself. Instead, an instance of 72473 `DS.RecordArray` or its subclasses will be returned by your application's store 72474 in response to queries. 72475 72476 @class RecordArray 72477 @namespace DS
72478 @extends Ember.ArrayProxy 72479 @uses Ember.Evented 72480 */ 72481 72482 exports["default"] = _ember["default"].ArrayProxy.extend(_ember["default"].Evented, { 72483 /** 72484 The model type contained by this record array. 72485 @property type 72486 @type DS.Model 72487 */ 72488 type: null, 72489 72490 /** 72491 The array of client ids backing the record array. When a 72492 record is requested from the record array, the record 72493 for the client id at the same index is materialized, if 72494 necessary, by the store. 72495 @property content 72496 @private 72497 @type Ember.Array 72498 */ 72499 content: null, 72500 72501 /** 72502 The flag to signal a `RecordArray` is finished loading data. 72503 Example 72504 ```javascript 72505 var people = store.peekAll('person'); 72506 people.get('isLoaded'); // true 72507 ``` 72508 @property isLoaded 72509 @type Boolean 72510 */ 72511 isLoaded: false, 72512 /** 72513 The flag to signal a `RecordArray` is currently loading data. 72514 Example 72515 ```javascript 72516 var people = store.peekAll('person'); 72517 people.get('isUpdating'); // false 72518 people.update(); 72519 people.get('isUpdating'); // true 72520 ``` 72521 @property isUpdating 72522 @type Boolean 72523 */ 72524 isUpdating: false, 72525 72526 /** 72527 The store that created this record array. 72528 @property store 72529 @private 72530 @type DS.Store 72531 */ 72532 store: null, 72533 72534 /** 72535 Retrieves an object from the content by index. 72536 @method objectAtContent 72537 @private 72538 @param {Number} index 72539 @return {DS.Model} record 72540 */ 72541 objectAtContent: function objectAtContent(index) { 72542 var content = get(this, 'content'); 72543 var internalModel = content.objectAt(index); 72544 return internalModel && internalModel.getRecord(); 72545 }, 72546 72547 /** 72548 Used to get the latest version of all of the records in this array 72549 from the adapter. 72550 Example 72551 ```javascript 72552 var people = store.peekAll('person'); 72553 people.get('isUpdating'); // false 72554 people.update().then(function() { 72555 people.get('isUpdating'); // false 72556 }); 72557 people.get('isUpdating'); // true 72558 ``` 72559 @method update 72560 */ 72561 update: function update() { 72562 if (get(this, 'isUpdating')) { 72563 return; 72564 } 72565 72566 this.set('isUpdating', true); 72567 return this._update(); 72568 }, 72569 72570 /* 72571 Update this RecordArray and return a promise which resolves once the update 72572 is finished. 72573 */ 72574 _update: function _update() { 72575 var store = get(this, 'store'); 72576 var modelName = get(this, 'type.modelName'); 72577 72578 return store.findAll(modelName, { reload: true }); 72579 }, 72580 72581 /** 72582 Adds an internal model to the `RecordArray` without duplicates 72583 @method addInternalModel 72584 @private 72585 @param {InternalModel} internalModel 72586 @param {number} an optional index to insert at 72587 */ 72588 addInternalModel: function addInternalModel(internalModel, idx) { 72589 var content = get(this, 'content'); 72590 if (idx === undefined) { 72591 content.addObject(internalModel); 72592 } else if (!content.contains(internalModel)) { 72593 content.insertAt(idx, internalModel); 72594 } 72595 }, 72596 72597 /** 72598 Removes an internalModel to the `RecordArray`. 72599 @method removeInternalModel 72600 @private 72601 @param {InternalModel} internalModel 72602 */ 72603 removeInternalModel: function removeInternalModel(internalModel) { 72604 get(this, 'content').removeObject(internalModel); 72605 }, 72606 72607 /** 72608 Saves all of the records in the `RecordArray`. 72609 Example 72610 ```javascript 72611 var messages = store.peekAll('message'); 72612 messages.forEach(function(message) { 72613 message.set('hasBeenSeen', true); 72614 }); 72615 messages.save(); 72616 ``` 72617 @method save 72618 @return {DS.PromiseArray} promise 72619 */ 72620 save: function save() { 72621 var recordArray = this; 72622 var promiseLabel = "DS: RecordArray#save " + get(this, 'type'); 72623 var promise = _ember["default"].RSVP.all(this.invoke("save"), promiseLabel).then(function (array) { 72624 return recordArray; 72625 }, null, "DS: RecordArray#save return RecordArray"); 72626 72627 return _emberDataPrivateSystemPromiseProxies.PromiseArray.create({ promise: promise }); 72628 }, 72629 72630 _dissociateFromOwnRecords: function _dissociateFromOwnRecords() { 72631 var _this = this; 72632 72633 this.get('content').forEach(function (record) { 72634 var recordArrays = record._recordArrays; 72635 72636 if (recordArrays) { 72637 recordArrays["delete"](_this); 72638 } 72639 }); 72640 }, 72641 72642 /** 72643 @method _unregisterFromManager 72644 @private 72645 */ 72646 _unregisterFromManager: function _unregisterFromManager() { 72647 var manager = get(this, 'manager'); 72648 manager.unregisterRecordArray(this); 72649 }, 72650 72651 willDestroy: function willDestroy() { 72652 this._unregisterFromManager(); 72653 this._dissociateFromOwnRecords(); 72654 set(this, 'content', undefined); 72655 this._super.apply(this, arguments); 72656 }, 72657 72658 createSnapshot: function createSnapshot(options) { 72659 var meta = this.get('meta'); 72660 return new _emberDataPrivateSystemSnapshotRecordArray["default"](this, meta, options); 72661 } 72662 }); 72663}); 72664define('ember-data/-private/system/references', ['exports', 'ember-data/-private/system/references/record', 'ember-data/-private/system/references/belongs-to', 'ember-data/-private/system/references/has-many'], function (exports, _emberDataPrivateSystemReferencesRecord, _emberDataPrivateSystemReferencesBelongsTo, _emberDataPrivateSystemReferencesHasMany) { 72665 'use strict'; 72666 72667 exports.RecordReference = _emberDataPrivateSystemReferencesRecord['default']; 72668 exports.BelongsToReference = _emberDataPrivateSystemReferencesBelongsTo['default']; 72669 exports.HasManyReference = _emberDataPrivateSystemReferencesHasMany['default']; 72670}); 72671define('ember-data/-private/system/references/belongs-to', ['exports', 'ember-data/model', 'ember', 'ember-data/-private/system/references/reference', 'ember-data/-private/features', 'ember-data/-private/debug'], function (exports, _emberDataModel, _ember, _emberDataPrivateSystemReferencesReference, _emberDataPrivateFeatures, _emberDataPrivateDebug) { 72672 'use strict'; 72673 72674 var BelongsToReference = function BelongsToReference(store, parentInternalModel, belongsToRelationship
72674) { 72675 this._super$constructor(store, parentInternalModel); 72676 this.belongsToRelationship = belongsToRelationship; 72677 this.type = belongsToRelationship.relationshipMeta.type; 72678 this.parent = parentInternalModel.recordReference; 72679 72680 // TODO inverse 72681 }; 72682 72683 BelongsToReference.prototype = Object.create(_emberDataPrivateSystemReferencesReference['default'].prototype); 72684 BelongsToReference.prototype.constructor = BelongsToReference; 72685 BelongsToReference.prototype._super$constructor = _emberDataPrivateSystemReferencesReference['default']; 72686 72687 BelongsToReference.prototype.remoteType = function () { 72688 if (this.belongsToRelationship.link) { 72689 return "link"; 72690 } 72691 72692 return "id"; 72693 }; 72694 72695 BelongsToReference.prototype.id = function () { 72696 var inverseRecord = this.belongsToRelationship.inverseRecord; 72697 return inverseRecord && inverseRecord.id; 72698 }; 72699 72700 BelongsToReference.prototype.link = function () { 72701 return this.belongsToRelationship.link; 72702 }; 72703 72704 BelongsToReference.prototype.meta = function () { 72705 return this.belongsToRelationship.meta; 72706 }; 72707 72708 BelongsToReference.prototype.push = function (objectOrPromise) { 72709 var _this = this; 72710 72711 return _ember['default'].RSVP.resolve(objectOrPromise).then(function (data) { 72712 var record; 72713 72714 if (data instanceof _emberDataModel['default']) { 72715 if (false) { 72716 (0, _emberDataPrivateDebug.deprecate)("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { 72717 id: 'ds.references.belongs-to.push-record', 72718 until: '3.0' 72719 }); 72720 } 72721 record = data; 72722 } else { 72723 record = _this.store.push(data); 72724 } 72725 72726 (0, _emberDataPrivateDebug.assertPolymorphicType)(_this.internalModel, _this.belongsToRelationship.relationshipMeta, record._internalModel); 72727 72728 _this.belongsToRelationship.setCanonicalRecord(record._internalModel); 72729 72730 return record; 72731 }); 72732 }; 72733 72734 BelongsToReference.prototype.value = function () { 72735 var inverseRecord = this.belongsToRelationship.inverseRecord; 72736 72737 if (inverseRecord && inverseRecord.record) { 72738 return inverseRecord.record; 72739 } 72740 72741 return null; 72742 }; 72743 72744 BelongsToReference.prototype.load = function () { 72745 var _this2 = this; 72746 72747 if (this.remoteType() === "id") { 72748 return this.belongsToRelationship.getRecord(); 72749 } 72750 72751 if (this.remoteType() === "link") { 72752 return this.belongsToRelationship.findLink().then(function (internalModel) { 72753 return _this2.value(); 72754 }); 72755 } 72756 }; 72757 72758 BelongsToReference.prototype.reload = function () { 72759 var _this3 = this; 72760 72761 return this.belongsToRelationship.reload().then(function (internalModel) { 72762 return _this3.value(); 72763 }); 72764 }; 72765 72766 exports['default'] = BelongsToReference; 72767}); 72768define('ember-data/-private/system/references/has-many', ['exports', 'ember', 'ember-data/-private/system/references/reference', 'ember-data/-private/debug', 'ember-data/-private/features'], function (exports, _ember, _emberDataPrivateSystemReferencesReference, _emberDataPrivateDebug, _emberDataPrivateFeatures) { 72769 'use strict'; 72770 72771 var get = _ember['default'].get; 72772 72773 var HasManyReference = function HasManyReference(store, parentInternalModel, hasManyRelationship) { 72774 this._super$constructor(store, parentInternalModel); 72775 this.hasManyRelationship = hasManyRelationship; 72776 this.type = hasManyRelationship.relationshipMeta.type; 72777 this.parent = parentInternalModel.recordReference; 72778 72779 // TODO inverse 72780 }; 72781 72782 HasManyReference.prototype = Object.create(_emberDataPrivateSystemReferencesReference['default'].prototype); 72783 HasManyReference.prototype.constructor = HasManyReference; 72784 HasManyReference.prototype._super$constructor = _emberDataPrivateSystemReferencesReference['default']; 72785 72786 HasManyReference.prototype.remoteType = function () { 72787 if (this.hasManyRelationship.link) { 72788 return "link"; 72789 } 72790 72791 return "ids"; 72792 }; 72793 72794 HasManyReference.prototype.link = function () { 72795 return this.hasManyRelationship.link; 72796 }; 72797 72798 HasManyReference.prototype.ids = function () { 72799 var members = this.hasManyRelationship.members; 72800 var ids = members.toArray().map(function (internalModel) { 72801 return internalModel.id; 72802 }); 72803 72804 return ids; 72805 }; 72806 72807 HasManyReference.prototype.meta = function () { 72808 return this.hasManyRelationship.manyArray.meta; 72809 }; 72810 72811 HasManyReference.prototype.push = function (objectOrPromise) { 72812 var _this = this; 72813 72814 return _ember['default'].RSVP.resolve(objectOrPromise).then(function (payload) { 72815 var array = payload; 72816 72817 if (false) { 72818 (0, _emberDataPrivateDebug.deprecate)("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { 72819 id: 'ds.references.has-many.push-array', 72820 until: '3.0' 72821 }); 72822 } 72823 72824 var useLegacyArrayPush = true; 72825 if (typeof payload === "object" && payload.data) { 72826 array = payload.data; 72827 useLegacyArrayPush = array.length && array[0].data; 72828 72829 if (false) { 72830 (0, _emberDataPrivateDebug.deprecate)("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { 72831 id: 'ds.references.has-many.push-invalid-json-api', 72832 until: '3.0' 72833 }); 72834 } 72835 } 72836 72837 if (!false) { 72838 useLegacyArrayPush = true; 72839 } 72840 72841 var internalModels = undefined; 72842 if (useLegacyArrayPush) { 72843 internalModels = array.map(function (obj) { 72844 var record = _this.store.push(obj); 72845 72846 (0, _emberDataPrivateDebug.runInDebug)(function () { 72847 var relationshipMeta = _this.hasManyRelationship.relationshipMeta; 72848 (0, _emberDataPrivateDebug.assertPolymorphicType)(_this.internalModel, relationshipMeta, record._internalModel); 72849 }); 72850 72851 return record._internalModel; 72852 }); 72853 } else { 72854 var records = _this.store.push(payload); 72855 internalModels = _ember['default'].A(records).mapBy('_internalModel'); 72856 72857 (0, _emberDataPrivateDebug.runInDebug)(function () {
72858 internalModels.forEach(function (internalModel) { 72859 var relationshipMeta = _this.hasManyRelationship.relationshipMeta; 72860 (0, _emberDataPrivateDebug.assertPolymorphicType)(_this.internalModel, relationshipMeta, internalModel); 72861 }); 72862 }); 72863 } 72864 72865 _this.hasManyRelationship.computeChanges(internalModels); 72866 72867 return _this.hasManyRelationship.manyArray; 72868 }); 72869 }; 72870 72871 HasManyReference.prototype._isLoaded = function () { 72872 var hasData = get(this.hasManyRelationship, 'hasData'); 72873 if (!hasData) { 72874 return false; 72875 } 72876 72877 var members = this.hasManyRelationship.members.toArray(); 72878 var isEveryLoaded = members.every(function (internalModel) { 72879 return internalModel.isLoaded() === true; 72880 }); 72881 72882 return isEveryLoaded; 72883 }; 72884 72885 HasManyReference.prototype.value = function () { 72886 if (this._isLoaded()) { 72887 return this.hasManyRelationship.manyArray; 72888 } 72889 72890 return null; 72891 }; 72892 72893 HasManyReference.prototype.load = function () { 72894 if (!this._isLoaded()) { 72895 return this.hasManyRelationship.getRecords(); 72896 } 72897 72898 var manyArray = this.hasManyRelationship.manyArray; 72899 return _ember['default'].RSVP.resolve(manyArray); 72900 }; 72901 72902 HasManyReference.prototype.reload = function () { 72903 return this.hasManyRelationship.reload(); 72904 }; 72905 72906 exports['default'] = HasManyReference; 72907}); 72908define('ember-data/-private/system/references/record', ['exports', 'ember', 'ember-data/-private/system/references/reference'], function (exports, _ember, _emberDataPrivateSystemReferencesReference) { 72909 'use strict'; 72910 72911 var RecordReference = function RecordReference(store, internalModel) { 72912 this._super$constructor(store, internalModel); 72913 this.type = internalModel.modelName; 72914 this._id = internalModel.id; 72915 }; 72916 72917 RecordReference.prototype = Object.create(_emberDataPrivateSystemReferencesReference['default'].prototype); 72918 RecordReference.prototype.constructor = RecordReference; 72919 RecordReference.prototype._super$constructor = _emberDataPrivateSystemReferencesReference['default']; 72920 72921 RecordReference.prototype.id = function () { 72922 return this._id; 72923 }; 72924 72925 RecordReference.prototype.remoteType = function () { 72926 return 'identity'; 72927 }; 72928 72929 RecordReference.prototype.push = function (objectOrPromise) { 72930 var _this = this; 72931 72932 return _ember['default'].RSVP.resolve(objectOrPromise).then(function (data) { 72933 var record = _this.store.push(data); 72934 return record; 72935 }); 72936 }; 72937 72938 RecordReference.prototype.value = function () { 72939 return this.internalModel.record; 72940 }; 72941 72942 RecordReference.prototype.load = function () { 72943 return this.store.findRecord(this.type, this._id); 72944 }; 72945 72946 RecordReference.prototype.reload = function () { 72947 var record = this.value(); 72948 if (record) { 72949 return record.reload(); 72950 } 72951 72952 return this.load(); 72953 }; 72954 72955 exports['default'] = RecordReference; 72956}); 72957define("ember-data/-private/system/references/reference", ["exports"], function (exports) { 72958 "use strict"; 72959 72960 var Reference = function Reference(store, internalModel) { 72961 this.store = store; 72962 this.internalModel = internalModel; 72963 }; 72964 72965 Reference.prototype = { 72966 constructor: Reference 72967 }; 72968 72969 exports["default"] = Reference; 72970}); 72971define('ember-data/-private/system/relationship-meta', ['exports', 'ember-inflector', 'ember-data/-private/system/normalize-model-name'], function (exports, _emberInflector, _emberDataPrivateSystemNormalizeModelName) { 72972 'use strict'; 72973 72974 exports.typeForRelationshipMeta = typeForRelationshipMeta; 72975 exports.relationshipFromMeta = relationshipFromMeta; 72976 72977 function typeForRelationshipMeta(meta) { 72978 var modelName; 72979 72980 modelName = meta.type || meta.key; 72981 if (meta.kind === 'hasMany') { 72982 modelName = (0, _emberInflector.singularize)((0, _emberDataPrivateSystemNormalizeModelName['default'])(modelName)); 72983 } 72984 return modelName; 72985 } 72986 72987 function relationshipFromMeta(meta) { 72988 return { 72989 key: meta.key, 72990 kind: meta.kind, 72991 type: typeForRelationshipMeta(meta), 72992 options: meta.options, 72993 parentType: meta.parentType, 72994 isRelationship: true 72995 }; 72996 } 72997}); 72998define("ember-data/-private/system/relationships/belongs-to", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/normalize-model-name"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemNormalizeModelName) { 72999 "use strict"; 73000 73001 exports["default"] = belongsTo; 73002 73003 /** 73004 `DS.belongsTo` is used to define One-To-One and One-To-Many 73005 relationships on a [DS.Model](/api/data/classes/DS.Model.html). 73006 73007
73008 `DS.belongsTo` takes an optional hash as a second parameter, currently 73009 supported options are: 73010 73011 - `async`: A boolean value used to explicitly declare this to be an async relationship. 73012 - `inverse`: A string used to identify the inverse property on a 73013 related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) 73014 73015 #### One-To-One 73016 To declare a one-to-one relationship between two models, use 73017 `DS.belongsTo`: 73018 73019 ```app/models/user.js 73020 import DS from 'ember-data'; 73021 73022 export default DS.Model.extend({ 73023 profile: DS.belongsTo('profile') 73024 }); 73025 ``` 73026 73027 ```app/models/profile.js 73028 import DS from 'ember-data'; 73029 73030 export default DS.Model.extend({ 73031 user: DS.belongsTo('user') 73032 }); 73033 ``` 73034 73035 #### One-To-Many 73036 To declare a one-to-many relationship between two models, use 73037 `DS.belongsTo` in combination with `DS.hasMany`, like this: 73038 73039 ```app/models/post.js 73040 import DS from 'ember-data'; 73041 73042 export default DS.Model.extend({ 73043 comments: DS.hasMany('comment') 73044 }); 73045 ``` 73046 73047 ```app/models/comment.js 73048 import DS from 'ember-data'; 73049 73050 export default DS.Model.extend({ 73051 post: DS.belongsTo('post') 73052 }); 73053 ``` 73054 73055 You can avoid passing a string as the first parameter. In that case Ember Data 73056 will infer the type from the key name. 73057 73058 ```app/models/comment.js 73059 import DS from 'ember-data'; 73060 73061 export default DS.Model.extend({ 73062 post: DS.belongsTo() 73063 }); 73064 ``` 73065 73066 will lookup for a Post type. 73067 73068 @namespace 73069 @method belongsTo 73070 @for DS 73071 @param {String} modelName (optional) type of the relationship 73072 @param {Object} options (optional) a hash of options 73073 @return {Ember.computed} relationship 73074 */ 73075 function belongsTo(modelName, options) { 73076 var opts, userEnteredModelName; 73077 if (typeof modelName === 'object') { 73078 opts = modelName; 73079 userEnteredModelName = undefined; 73080 } else { 73081 opts = options; 73082 userEnteredModelName = modelName; 73083 } 73084 73085 if (typeof userEnteredModelName === 'string') { 73086 userEnteredModelName = (0, _emberDataPrivateSystemNormalizeModelName["default"])(userEnteredModelName); 73087 } 73088 73089 (0, _emberDataPrivateDebug.assert)("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + _ember["default"].inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); 73090 73091 opts = opts || {}; 73092 73093 var meta = { 73094 type: userEnteredModelName, 73095 isRelationship: true, 73096 options: opts, 73097 kind: 'belongsTo', 73098 key: null 73099 }; 73100 73101 return _ember["default"].computed({ 73102 get: function get(key) { 73103 if (opts.hasOwnProperty('serialize')) { 73104 (0, _emberDataPrivateDebug.warn)("You provided a serialize option on the \"" + key + "\" property in the \"" + this._internalModel.modelName + "\" class, this belongs in the serializer. See DS.Serializer and it's implementations http://emberjs.com/api/data/classes/DS.Serializer.html", false, { 73105 id: 'ds.model.serialize-option-in-belongs-to' 73106 }); 73107 } 73108 73109 if (opts.hasOwnProperty('embedded')) { 73110 (0, _emberDataPrivateDebug.warn)("You provided an embedded option on the \"" + key + "\" property in the \"" + this._internalModel.modelName + "\" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html", false, { 73111 id: 'ds.model.embedded-option-in-belongs-to' 73112 }); 73113 } 73114 73115 return this._internalModel._relationships.get(key).getRecord(); 73116 }, 73117 set: function set(key, value) { 73118 if (value === undefined) { 73119 value = null; 73120 } 73121 if (value && value.then) { 73122 this._internalModel._relationships.get(key).setRecordPromise(value); 73123 } else if (value) { 73124 this._internalModel._relationships.get(key).setRecord(value._internalModel); 73125 } else { 73126 this._internalModel._relationships.get(key).setRecord(value); 73127 } 73128 73129 return this._internalModel._relationships.get(key).getRecord(); 73130 } 73131 }).meta(meta); 73132 } 73133 73134 /* 73135 These observers observe all `belongsTo` relationships on the record. See 73136 `relationships/ext` to see how these observers get their dependencies. 73137 */ 73138 var BelongsToMixin = _ember["default"].Mixin.create({ 73139 notifyBelongsToChanged: function notifyBelongsToChanged(key) {
73140 this.notifyPropertyChange(key); 73141 } 73142 }); 73143 exports.BelongsToMixin = BelongsToMixin; 73144}); 73145define("ember-data/-private/system/relationships/ext", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/relationship-meta", "ember-data/-private/system/empty-object"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemRelationshipMeta, _emberDataPrivateSystemEmptyObject) { 73146 "use strict"; 73147 73148 var get = _ember["default"].get; 73149 var Map = _ember["default"].Map; 73150 var MapWithDefault = _ember["default"].MapWithDefault; 73151 73152 var relationshipsDescriptor = _ember["default"].computed(function () { 73153 if (_ember["default"].testing === true && relationshipsDescriptor._cacheable === true) { 73154 relationshipsDescriptor._cacheable = false; 73155 } 73156 73157 var map = new MapWithDefault({ 73158 defaultValue: function defaultValue() { 73159 return []; 73160 } 73161 }); 73162 73163 // Loop through each computed property on the class 73164 this.eachComputedProperty(function (name, meta) { 73165 // If the computed property is a relationship, add 73166 // it to the map. 73167 if (meta.isRelationship) { 73168 meta.key = name; 73169 var relationshipsForType = map.get((0, _emberDataPrivateSystemRelationshipMeta.typeForRelationshipMeta)(meta)); 73170 73171 relationshipsForType.push({ 73172 name: name, 73173 kind: meta.kind 73174 }); 73175 } 73176 }); 73177 73178 return map; 73179 }).readOnly(); 73180 73181 var relatedTypesDescriptor = _ember["default"].computed(function () { 73182 var _this = this; 73183 73184 if (_ember["default"].testing === true && relatedTypesDescriptor._cacheable === true) { 73185 relatedTypesDescriptor._cacheable = false; 73186 } 73187 73188 var modelName; 73189 var types = _ember["default"].A(); 73190 73191 // Loop through each computed property on the class, 73192 // and create an array of the unique types involved 73193 // in relationships 73194 this.eachComputedProperty(function (name, meta) { 73195 if (meta.isRelationship) { 73196 meta.key = name; 73197 modelName = (0, _emberDataPrivateSystemRelationshipMeta.typeForRelationshipMeta)(meta); 73198 73199 (0, _emberDataPrivateDebug.assert)("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); 73200 73201 if (!types.contains(modelName)) { 73202 (0, _emberDataPrivateDebug.assert)("Trying to sideload " + name + " on " + _this.toString() + " but the type doesn't exist.", !!modelName); 73203 types.push(modelName); 73204 } 73205 } 73206 }); 73207 73208 return types; 73209 }).readOnly(); 73210 73211 var relationshipsByNameDescriptor = _ember["default"].computed(function () { 73212 if (_ember["default"].testing === true && relationshipsByNameDescriptor._cacheable === true) { 73213 relationshipsByNameDescriptor._cacheable = false; 73214 } 73215 73216 var map = Map.create(); 73217 73218 this.eachComputedProperty(function (name, meta) { 73219 if (meta.isRelationship) { 73220 meta.key = name; 73221 var relationship = (0, _emberDataPrivateSystemRelationshipMeta.relationshipFromMeta)(meta); 73222 relationship.type = (0, _emberDataPrivateSystemRelationshipMeta.typeForRelationshipMeta)(meta); 73223 map.set(name, relationship); 73224 } 73225 }); 73226 73227 return map; 73228 }).readOnly(); 73229 73230 /** 73231 @module ember-data 73232 */ 73233 73234 /* 73235 This file defines several extensions to the base `DS.Model` class that 73236 add support for one-to-many relationships. 73237 */ 73238 73239 /** 73240 @class Model 73241 @namespace DS 73242 */ 73243 var DidDefinePropertyMixin = _ember["default"].Mixin.create({ 73244 73245 /** 73246 This Ember.js hook allows an object to be notified when a property 73247 is defined. 73248 In this case, we use it to be notified when an Ember Data user defines a 73249 belongs-to relationship. In that case, we need to set up observers for 73250 each one, allowing us to track relationship changes and automatically 73251 reflect changes in the inverse has-many array. 73252 This hook passes the class being set up, as well as the key and value 73253 being defined. So, for example, when the user does this: 73254 ```javascript 73255 DS.Model.extend({ 73256 parent: DS.belongsTo('user') 73257 }); 73258 ``` 73259 This hook would be called with "parent" as the key and the computed 73260 property returned by `DS.belongsTo` as the value. 73261 @method didDefineProperty 73262 @param {Object} proto 73263 @param {String} key 73264 @param {Ember.ComputedProperty} value 73265 */ 73266 didDefineProperty: function didDefineProperty(proto, key, value) { 73267 // Check if the value being set is a computed property. 73268 if (value instanceof _ember["default"].ComputedProperty) { 73269 73270 // If it is, get the metadata for the relationship. This is 73271 // populated by the `DS.belongsTo` helper when it is creating 73272 // the computed property. 73273 var meta = value.meta(); 73274 73275 meta.parentType = proto.constructor; 73276 } 73277 } 73278 }); 73279 73280 exports.DidDefinePropertyMixin = DidDefinePropertyMixin; 73281 73282 /* 73283 These DS.Model extensions add class methods that provide relationship 73284 introspection abilities about relationships. 73285 73286 A note about the computed properties contained here: 73287 73288 **These properties are effectively sealed once called for the first time.** 73289 To avoid repeatedly doing expensive iteration over a model's fields, these 73290 values are computed once and then cached for the remainder of the runtime of 73291 your application. 73292 73293 If your application needs to modify a class after its initial definition 73294 (for example, using `reopen()` to add additional attributes), make sure you 73295 do it before using your model with the store, which uses these properties 73296 extensively. 73297 */ 73298 73299 var RelationshipsClassMethodsMixin = _ember["default"].Mixin.create({ 73300 73301 /** 73302 For a given relationship name, returns the model type of the relationship. 73303 For example, if you define a model like this: 73304 ```app/models/post.js 73305 import DS from 'ember-data'; 73306 export default DS.Model.extend({ 73307 comments: DS.hasMany('comment') 73308 }); 73309 ``` 73310 Calling `App.Post.typeForRelationship('comments')` will return `App.Comment`. 73311 @method typeForRelationship 73312 @static 73313 @param {String} name the name of the relationship 73314 @param {store} store an instance of DS.Store 73315 @return {DS.Model} the type of the relationship, or undefined 73316 */ 73317 typeForRelationship: function typeForRelationship(name, store) { 73318 var relationship = get(this, 'relationshipsByName').get(name); 73319 return relationship && store.modelFor(relationship.type); 73320 }, 73321 73322 inverseMap: _ember["default"].computed(function () { 73323 return new _emberDataPrivateSystemEmptyObject["default"](); 73324 }), 73325 73326 /** 73327 Find the relationship which is the inverse of the one asked for. 73328 For example, if you define models like this: 73329 ```app/models/post.js 73330 import DS from 'ember-data'; 73331 export default DS.Model.extend({ 73332 comments: DS.hasMany('message') 73333 }); 73334 ``` 73335 ```app/models/message.js 73336 import DS from 'ember-data'; 73337 export default DS.Model.extend({ 73338 owner: DS.belongsTo('post') 73339 }); 73340 ``` 73341 App.Post.inverseFor('comments') -> { type: App.Message, name: 'owner', kind: 'belongsTo' } 73342 App.Message.inverseFor('owner') -> { type: App.Post, name: 'comments', kind: 'hasMany' } 73343 @method inverseFor 73344 @static 73345 @param {String} name the name of the relationship 73346 @return {Object} the inverse relationship, or null 73347 */ 73348 inverseFor: function inverseFor(name, store) { 73349 var inverseMap = get(this, 'inverseMap'); 73350 if (inverseMap[name]) { 73351 return inverseMap[name]; 73352 } else { 73353 var inverse = this._findInverseFor(name, store); 73354 inverseMap[name] = inverse; 73355 return inverse; 73356 } 73357 }, 73358 73359 //Calculate the inverse, ignoring the cache 73360 _findInverseFor: function _findInverseFor(name, store) { 73361 73362 var inverseType = this.typeForRelationship(name, store); 73363 if (!inverseType) { 73364 return null; 73365 } 73366 73367 var propertyMeta = this.metaForProperty(name); 73368 //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` 73369 var options = propertyMeta.options; 73370 if (options.inverse === null) { 73371 return null; 73372 } 73373 73374 var inverseName, inverseKind, inverse; 73375 73376 //If inverse is specified manually, return the inverse 73377 if (options.inverse) { 73378 inverseName = options.inverse; 73379 inverse = _ember["default"].get(inverseType, 'relationshipsByName').get(inverseName); 73380 73381 (0, _emberDataPrivateDebug.assert)("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + "' model. This is most likely due to a missing attribute on your model definition.", !_ember["default"].isNone(inverse)); 73382 73383 inverseKind = inverse.kind; 73384 } else { 73385 //No inverse was specified manually, we need to use a heuristic to guess one 73386 if (propertyMeta.type === propertyMeta.parentType.modelName) { 73387 (0, _emberDataPrivateDebug.warn)("Detected a reflexive relationship by the name of '" + n
73387ame + "' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.", false, { 73388 id: 'ds.model.reflexive-relationship-without-inverse' 73389 }); 73390 } 73391 73392 var possibleRelationships = findPossibleInverses(this, inverseType); 73393 73394 if (possibleRelationships.length === 0) { 73395 return null; 73396 } 73397 73398 var filteredRelationships = possibleRelationships.filter(function (possibleRelationship) { 73399 var optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; 73400 return name === optionsForRelationship.inverse; 73401 }); 73402 73403 (0, _emberDataPrivateDebug.assert)("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", filteredRelationships.length < 2); 73404 73405 if (filteredRelationships.length === 1) { 73406 possibleRelationships = filteredRelationships; 73407 } 73408 73409 (0, _emberDataPrivateDebug.assert)("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", possibleRelationships.length === 1); 73410 73411 inverseName = possibleRelationships[0].name; 73412 inverseKind = possibleRelationships[0].kind; 73413 } 73414 73415 function findPossibleInverses(type, inverseType, relationshipsSoFar) { 73416 var possibleRelationships = relationshipsSoFar || []; 73417 73418 var relationshipMap = get(inverseType, 'relationships'); 73419 if (!relationshipMap) { 73420 return possibleRelationships; 73421 } 73422 73423 var relationships = relationshipMap.get(type.modelName); 73424 73425 relationships = relationships.filter(function (relationship) { 73426 var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; 73427 73428 if (!optionsForRelationship.inverse) { 73429 return true; 73430 } 73431 73432 return name === optionsForRelationship.inverse; 73433 }); 73434 73435 if (relationships) { 73436 possibleRelationships.push.apply(possibleRelationships, relationships); 73437 } 73438 73439 //Recurse to support polymorphism 73440 if (type.superclass) { 73441 findPossibleInverses(type.superclass, inverseType, possibleRelationships); 73442 } 73443 73444 return possibleRelationships; 73445 } 73446 73447 return { 73448 type: inverseType, 73449 name: inverseName, 73450 kind: inverseKind 73451 }; 73452 }, 73453 73454 /** 73455 The model's relationships as a map, keyed on the type of the 73456 relationship. The value of each entry is an array containing a descriptor 73457 for each relationship with that type, describing the name of the relationship 73458 as well as the type. 73459 For example, given the following model definition: 73460 ```app/models/blog.js 73461 import DS from 'ember-data'; 73462 export default DS.Model.extend({ 73463 users: DS.hasMany('user'), 73464 owner: DS.belongsTo('user'), 73465 posts: DS.hasMany('post') 73466 }); 73467 ``` 73468 This computed property would return a map describing these 73469 relationships, like this: 73470 ```javascript 73471 import Ember from 'ember'; 73472 import Blog from 'app/models/blog'; 73473 var relationships = Ember.get(Blog, 'relationships'); 73474 relationships.get(App.User); 73475 //=> [ { name: 'users', kind: 'hasMany' }, 73476 // { name: 'owner', kind: 'belongsTo' } ] 73477 relationships.get(App.Post); 73478 //=> [ { name: 'posts', kind: 'hasMany' } ] 73479 ``` 73480 @property relationships 73481 @static 73482 @type Ember.Map 73483 @readOnly 73484 */ 73485 73486 relationships: relationshipsDescriptor, 73487 73488 /** 73489 A hash containing lists of the model's relationships, grouped 73490 by the relationship kind. For example, given a model with this 73491 definition: 73492 ```app/models/blog.js 73493 import DS from 'ember-data'; 73494 export default DS.Model.extend({ 73495 users: DS.hasMany('user'), 73496 owner: DS.belongsTo('user'), 73497 posts: DS.hasMany('post') 73498 }); 73499 ```
73500 This property would contain the following: 73501 ```javascript 73502 import Ember from 'ember'; 73503 import Blog from 'app/models/blog'; 73504 var relationshipNames = Ember.get(Blog, 'relationshipNames'); 73505 relationshipNames.hasMany; 73506 //=> ['users', 'posts'] 73507 relationshipNames.belongsTo; 73508 //=> ['owner'] 73509 ``` 73510 @property relationshipNames 73511 @static 73512 @type Object 73513 @readOnly 73514 */ 73515 relationshipNames: _ember["default"].computed(function () { 73516 var names = { 73517 hasMany: [], 73518 belongsTo: [] 73519 }; 73520 73521 this.eachComputedProperty(function (name, meta) { 73522 if (meta.isRelationship) { 73523 names[meta.kind].push(name); 73524 } 73525 }); 73526 73527 return names; 73528 }), 73529 73530 /** 73531 An array of types directly related to a model. Each type will be 73532 included once, regardless of the number of relationships it has with 73533 the model. 73534 For example, given a model with this definition: 73535 ```app/models/blog.js 73536 import DS from 'ember-data'; 73537 export default DS.Model.extend({ 73538 users: DS.hasMany('user'), 73539 owner: DS.belongsTo('user'), 73540 posts: DS.hasMany('post') 73541 }); 73542 ``` 73543 This property would contain the following: 73544 ```javascript 73545 import Ember from 'ember'; 73546 import Blog from 'app/models/blog'; 73547 var relatedTypes = Ember.get(Blog, 'relatedTypes'); 73548 //=> [ App.User, App.Post ] 73549 ``` 73550 @property relatedTypes 73551 @static 73552 @type Ember.Array 73553 @readOnly 73554 */ 73555 relatedTypes: relatedTypesDescriptor, 73556 73557 /** 73558 A map whose keys are the relationships of a model and whose values are 73559 relationship descriptors. 73560 For example, given a model with this 73561 definition: 73562 ```app/models/blog.js 73563 import DS from 'ember-data'; 73564 export default DS.Model.extend({ 73565 users: DS.hasMany('user'), 73566 owner: DS.belongsTo('user'), 73567 posts: DS.hasMany('post') 73568 }); 73569 ``` 73570 This property would contain the following: 73571 ```javascript 73572 import Ember from 'ember'; 73573 import Blog from 'app/models/blog'; 73574 var relationshipsByName = Ember.get(Blog, 'relationshipsByName'); 73575 relationshipsByName.get('users'); 73576 //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } 73577 relationshipsByName.get('owner'); 73578 //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } 73579 ``` 73580 @property relationshipsByName 73581 @static 73582 @type Ember.Map 73583 @readOnly 73584 */ 73585 relationshipsByName: relationshipsByNameDescriptor, 73586 73587 /** 73588 A map whose keys are the fields of the model and whose values are strings 73589 describing the kind of the field. A model's fields are the union of all of its 73590 attributes and relationships. 73591 For example: 73592 ```app/models/blog.js 73593 import DS from 'ember-data'; 73594 export default DS.Model.extend({ 73595 users: DS.hasMany('user'), 73596 owner: DS.belongsTo('user'), 73597 posts: DS.hasMany('post'), 73598 title: DS.attr('string') 73599 }); 73600 ``` 73601 ```js 73602 import Ember from 'ember'; 73603 import Blog from 'app/models/blog'; 73604 var fields = Ember.get(Blog, 'fields'); 73605 fields.forEach(function(kind, field) { 73606 console.log(field, kind); 73607 }); 73608 // prints: 73609 // users, hasMany 73610 // owner, belongsTo 73611 // posts, hasMany 73612 // title, attribute 73613 ``` 73614 @property fields 73615 @static 73616 @type Ember.Map 73617 @readOnly 73618 */ 73619 fields: _ember["default"].computed(function () { 73620 var map = Map.create(); 73621 73622 this.eachComputedProperty(function (name, meta) { 73623 if (meta.isRelationship) { 73624 map.set(name, meta.kind); 73625 } else if (meta.isAttribute) { 73626 map.set(name, 'attribute'); 73627 } 73628 }); 73629 73630 return map; 73631 }).readOnly(), 73632 73633 /** 73634 Given a callback, iterates over each of the relationships in the model, 73635 invoking the callback with the name of each relationship and its relationship 73636 descriptor. 73637 @method eachRelationship 73638 @static 73639 @param {Function} callback the callback to invoke 73640 @param {any} binding the value to which the callback's `this` should be bound 73641 */ 73642 eachRelationship: function eachRelationship(callback, binding) { 73643 get(this, 'relationshipsByName').forEach(function (relationship, name) {
73644 callback.call(binding, name, relationship); 73645 }); 73646 }, 73647 73648 /** 73649 Given a callback, iterates over each of the types related to a model, 73650 invoking the callback with the related type's class. Each type will be 73651 returned just once, regardless of how many different relationships it has 73652 with a model. 73653 @method eachRelatedType 73654 @static 73655 @param {Function} callback the callback to invoke 73656 @param {any} binding the value to which the callback's `this` should be bound 73657 */ 73658 eachRelatedType: function eachRelatedType(callback, binding) { 73659 var relationshipTypes = get(this, 'relatedTypes'); 73660 73661 for (var i = 0; i < relationshipTypes.length; i++) { 73662 var type = relationshipTypes[i]; 73663 callback.call(binding, type); 73664 } 73665 }, 73666 73667 determineRelationshipType: function determineRelationshipType(knownSide, store) { 73668 var knownKey = knownSide.key; 73669 var knownKind = knownSide.kind; 73670 var inverse = this.inverseFor(knownKey, store); 73671 // let key; 73672 var otherKind = undefined; 73673 73674 if (!inverse) { 73675 return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; 73676 } 73677 73678 // key = inverse.name; 73679 otherKind = inverse.kind; 73680 73681 if (otherKind === 'belongsTo') { 73682 return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; 73683 } else { 73684 return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; 73685 } 73686 } 73687 73688 }); 73689 73690 exports.RelationshipsClassMethodsMixin = RelationshipsClassMethodsMixin; 73691 73692 var RelationshipsInstanceMethodsMixin = _ember["default"].Mixin.create({ 73693 /** 73694 Given a callback, iterates over each of the relationships in the model, 73695 invoking the callback with the name of each relationship and its relationship 73696 descriptor. 73697 The callback method you provide should have the following signature (all 73698 parameters are optional): 73699 ```javascript 73700 function(name, descriptor); 73701 ``` 73702 - `name` the name of the current property in the iteration 73703 - `descriptor` the meta object that describes this relationship 73704 The relationship descriptor argument is an object with the following properties. 73705 - **key** <span class="type">String</span> the name of this relationship on the Model 73706 - **kind** <span class="type">String</span> "hasMany" or "belongsTo" 73707 - **options** <span class="type">Object</span> the original options hash passed when the relationship was declared 73708 - **parentType** <span class="type">DS.Model</span> the type of the Model that owns this relationship 73709 - **type** <span class="type">String</span> the type name of the related Model 73710 Note that in addition to a callback, you can also pass an optional target 73711 object that will be set as `this` on the context. 73712 Example 73713 ```app/serializers/application.js 73714 import DS from 'ember-data'; 73715 export default DS.JSONSerializer.extend({ 73716 serialize: function(record, options) { 73717 var json = {}; 73718 record.eachRelationship(function(name, descriptor) { 73719 if (descriptor.kind === 'hasMany') { 73720 var serializedHasManyName = name.toUpperCase() + '_IDS'; 73721 json[serializedHasManyName] = record.get(name).mapBy('id'); 73722 } 73723 }); 73724 return json; 73725 } 73726 }); 73727 ``` 73728 @method eachRelationship 73729 @param {Function} callback the callback to invoke 73730 @param {any} binding the value to which the callback's `this` should be bound 73731 */ 73732 eachRelationship: function eachRelationship(callback, binding) { 73733 this.constructor.eachRelationship(callback, binding); 73734 }, 73735 73736 relationshipFor: function relationshipFor(name) { 73737 return get(this.constructor, 'relationshipsByName').get(name); 73738 }, 73739 73740 inverseFor: function inverseFor(key) { 73741 return this.constructor.inverseFor(key, this.store); 73742 } 73743 73744 }); 73745 exports.RelationshipsInstanceMethodsMixin = RelationshipsInstanceMethodsMixin; 73746}); 73747define("ember-data/-private/system/relationships/has-many", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/normalize-model-name", "ember-data/-private/system/is-array-like"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateSystemIsArrayLike) { 73748 "use strict"; 73749 73750 exports["default"] = hasMany; 73751 73752 /** 73753 @module ember-data 73754 */ 73755 73756 /** 73757 `DS.hasMany` is used to define One-To-Many and Many-To-Many 73758 relationships on a [DS.Model](/api/data/classes/DS.Model.html). 73759
73760 `DS.hasMany` takes an optional hash as a second parameter, currently 73761 supported options are: 73762 73763 - `async`: A boolean value used to explicitly declare this to be an async relationship. 73764 - `inverse`: A string used to identify the inverse property on a related model. 73765 73766 #### One-To-Many 73767 To declare a one-to-many relationship between two models, use 73768 `DS.belongsTo` in combination with `DS.hasMany`, like this: 73769 73770 ```app/models/post.js 73771 import DS from 'ember-data'; 73772 73773 export default DS.Model.extend({ 73774 comments: DS.hasMany('comment') 73775 }); 73776 ``` 73777 73778 ```app/models/comment.js 73779 import DS from 'ember-data'; 73780 73781 export default DS.Model.extend({ 73782 post: DS.belongsTo('post') 73783 }); 73784 ``` 73785 73786 #### Many-To-Many 73787 To declare a many-to-many relationship between two models, use 73788 `DS.hasMany`: 73789 73790 ```app/models/post.js 73791 import DS from 'ember-data'; 73792 73793 export default DS.Model.extend({ 73794 tags: DS.hasMany('tag') 73795 }); 73796 ``` 73797 73798 ```app/models/tag.js 73799 import DS from 'ember-data'; 73800 73801 export default DS.Model.extend({ 73802 posts: DS.hasMany('post') 73803 }); 73804 ``` 73805 73806 You can avoid passing a string as the first parameter. In that case Ember Data 73807 will infer the type from the singularized key name. 73808 73809 ```app/models/post.js 73810 import DS from 'ember-data'; 73811 73812 export default DS.Model.extend({ 73813 tags: DS.hasMany() 73814 }); 73815 ``` 73816 73817 will lookup for a Tag type. 73818 73819 #### Explicit Inverses 73820 73821 Ember Data will do its best to discover which relationships map to 73822 one another. In the one-to-many code above, for example, Ember Data 73823 can figure out that changing the `comments` relationship should update 73824 the `post` relationship on the inverse because post is the only 73825 relationship to that model. 73826 73827 However, sometimes you may have multiple `belongsTo`/`hasManys` for the 73828 same type. You can specify which property on the related model is 73829 the inverse using `DS.hasMany`'s `inverse` option: 73830 73831 ```app/models/comment.js 73832 import DS from 'ember-data'; 73833 73834 export default DS.Model.extend({ 73835 onePost: DS.belongsTo('post'), 73836 twoPost: DS.belongsTo('post'), 73837 redPost: DS.belongsTo('post'), 73838 bluePost: DS.belongsTo('post') 73839 }); 73840 ``` 73841 73842 ```app/models/post.js 73843 import DS from 'ember-data'; 73844 73845 export default DS.Model.extend({ 73846 comments: DS.hasMany('comment', { 73847 inverse: 'redPost' 73848 }) 73849 }); 73850 ``` 73851 73852 You can also specify an inverse on a `belongsTo`, which works how 73853 you'd expect. 73854 73855 @namespace 73856 @method hasMany 73857 @for DS 73858 @param {String} type (optional) type of the relationship 73859 @param {Object} options (optional) a hash of options 73860 @return {Ember.computed} relationship 73861 */ 73862 function hasMany(type, options) { 73863 if (typeof type === 'object') { 73864 options = type; 73865 type = undefined; 73866 } 73867 73868 (0, _emberDataPrivateDebug.assert)("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + _ember["default"].inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); 73869 73870 options = options || {}; 73871 73872 if (typeof type === 'string') { 73873 type = (0, _emberDataPrivateSystemNormalizeModelName["default"])(type); 73874 } 73875 73876 // Metadata about relationships is stored on the meta of 73877 // the relationship. This is used for introspection and 73878 // serialization. Note that `key` is populated lazily 73879 // the first time the CP is called. 73880 var meta = { 73881 type: type, 73882 isRelationship: true, 73883 options: options, 73884 kind: 'hasMany', 73885 key: null 73886 }; 73887 73888 return _ember["default"].computed({ 73889 get: function get(key) { 73890 var relationship = this._internalModel._relationships.get(key); 73891 return relationship.getRecords(); 73892 }, 73893 set: function set(key, records) { 73894 (0, _emberDataPrivateDebug.assert)("You must pass an array of records to set a hasMany relationship", (0, _emberDataPrivateSystemIsArrayLike["default"])(records)); 73895 (0, _emberDataPrivateDebug.assert)("All elements of a hasMany relationship must be instances of DS.Model, you passed " + _ember["default"].inspect(records), (function () { 73896 return _ember["default"].A(records).every(function (record) { 73897 return record.hasOwnProperty('_internalModel') === true; 73898 }); 73899 })()); 73900 73901 var relationship = this._internalModel._relationships.get(key); 73902 relationship.clear(); 73903 relationship.addRecords(_ember["default"].A(records).mapBy('_internalModel')); 73904 return relationship.getRecords(); 73905 } 73906 }).meta(meta); 73907 } 73908 73909 var HasManyMixin = _ember["default"].Mixin.create({ 73910 notifyHasManyAdded: function notifyHasManyAdded(key) { 73911 //We need to notifyPropertyChange in the adding case because we need to make sure 73912 //we fetch the newly added record in case it is unloaded 73913 //TODO(Igor): Consider whether we could do this only if the record state is unloaded 73914 73915 //Goes away once hasMany is double promisified
73916 this.notifyPropertyChange(key); 73917 } 73918 }); 73919 exports.HasManyMixin = HasManyMixin; 73920}); 73921define("ember-data/-private/system/relationships/state/belongs-to", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/relationships/state/relationship"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemRelationshipsStateRelationship) { 73922 "use strict"; 73923 73924 exports["default"] = BelongsToRelationship; 73925 73926 function BelongsToRelationship(store, record, inverseKey, relationshipMeta) { 73927 this._super$constructor(store, record, inverseKey, relationshipMeta); 73928 this.record = record; 73929 this.key = relationshipMeta.key; 73930 this.inverseRecord = null; 73931 this.canonicalState = null; 73932 } 73933 73934 BelongsToRelationship.prototype = Object.create(_emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype); 73935 BelongsToRelationship.prototype.constructor = BelongsToRelationship; 73936 BelongsToRelationship.prototype._super$constructor = _emberDataPrivateSystemRelationshipsStateRelationship["default"]; 73937 73938 BelongsToRelationship.prototype.setRecord = function (newRecord) { 73939 if (newRecord) { 73940 this.addRecord(newRecord); 73941 } else if (this.inverseRecord) { 73942 this.removeRecord(this.inverseRecord); 73943 } 73944 this.setHasData(true); 73945 this.setHasLoaded(true); 73946 }; 73947 73948 BelongsToRelationship.prototype.setCanonicalRecord = function (newRecord) { 73949 if (newRecord) { 73950 this.addCanonicalRecord(newRecord); 73951 } else if (this.canonicalState) { 73952 this.removeCanonicalRecord(this.canonicalState); 73953 } 73954 this.flushCanonicalLater(); 73955 this.setHasData(true); 73956 this.setHasLoaded(true); 73957 }; 73958 73959 BelongsToRelationship.prototype._super$addCanonicalRecord = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.addCanonicalRecord; 73960 BelongsToRelationship.prototype.addCanonicalRecord = function (newRecord) { 73961 if (this.canonicalMembers.has(newRecord)) { 73962 return; 73963 } 73964 73965 if (this.canonicalState) { 73966 this.removeCanonicalRecord(this.canonicalState); 73967 } 73968 73969 this.canonicalState = newRecord; 73970 this._super$addCanonicalRecord(newRecord); 73971 }; 73972 73973 BelongsToRelationship.prototype._super$flushCanonical = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.flushCanonical; 73974 BelongsToRelationship.prototype.flushCanonical = function () { 73975 //temporary fix to not remove newly created records if server returned null. 73976 //TODO remove once we have proper diffing 73977 if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { 73978 return; 73979 } 73980 this.inverseRecord = this.canonicalState; 73981 this.record.notifyBelongsToChanged(this.key); 73982 this._super$flushCanonical(); 73983 }; 73984 73985 BelongsToRelationship.prototype._super$addRecord = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.addRecord; 73986 BelongsToRelationship.prototype.addRecord = function (newRecord) { 73987 if (this.members.has(newRecord)) { 73988 return; 73989 } 73990 73991 (0, _emberDataPrivateDebug.assertPolymorphicType)(this.record, this.relationshipMeta, newRecord); 73992 73993 if (this.inverseRecord) { 73994 this.removeRecord(this.inverseRecord); 73995 } 73996 73997 this.inverseRecord = newRecord; 73998 this._super$addRecord(newRecord); 73999 this.record.notifyBelongsToChanged(this.key); 74000 }; 74001 74002 BelongsToRelationship.prototype.setRecordPromise = function (newPromise) { 74003 var content = newPromise.get && newPromise.get('content'); 74004 (0, _emberDataPrivateDebug.assert)("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); 74005 this.setRecord(content ? content._internalModel : content); 74006 }; 74007 74008 BelongsToRelationship.prototype._super$removeRecordFromOwn = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.removeRecordFromOwn; 74009 BelongsToRelationship.prototype.removeRecordFromOwn = function (record) { 74010 if (!this.members.has(record)) { 74011 return; 74012 } 74013 this.inverseRecord = null; 74014 this._super$removeRecordFromOwn(record); 74015 this.record.notifyBelongsToChanged(this.key); 74016 }; 74017 74018 BelongsToRelationship.prototype._super$removeCanonicalRecordFromOwn = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.removeCanonicalRecordFromOwn; 74019 BelongsToRelationship.prototype.removeCanonicalRecordFromOwn = function (record) { 74020 if (!this.canonicalMembers.has(record)) { 74021 return; 74022 } 74023 this.canonicalState = null; 74024 this._super$removeCanonicalRecordFromOwn(record); 74025 }; 74026 74027 BelongsToRelationship.prototype.findRecord = function () { 74028 if (this.inverseRecord) { 74029 return this.store._findByInternalModel(this.inverseRecord); 74030 } else { 74031 return _ember["default"].RSVP.Promise.resolve(null); 74032 } 74033 }; 74034 74035 BelongsToRelationship.prototype.fetchLink = function () { 74036 var _this = this; 74037 74038 return this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then(function (record) { 74039 if (record) { 74040 _this.addRecord(record); 74041 } 74042 return record; 74043 }); 74044 }; 74045 74046 BelongsToRelationship.prototype.getRecord = function () { 74047 var _this2 = this; 74048 74049 //TODO(Igor) flushCanonical here once our syncing is not stupid 74050 if (this.isAsync) { 74051 var promise; 74052 if (this.link) { 74053 if (this.hasLoaded) { 74054 promise = this.findRecord(); 74055 } else { 74056 promise = this.findLink().then(function () { 74057 return _this2.findRecord(); 74058 }); 74059 } 74060 } else { 74061 promise = this.findRecord(); 74062 } 74063 74064 return _emberDataPrivateSystemPromiseProxies.PromiseObject.create({ 74065 promise: promise, 74066 content: this.inverseRecord ? this.inverseRecord.getRecord() : null 74067 }); 74068 } else { 74069 if (this.inverseRecord === null) { 74070 return null; 74071 } 74072 var toReturn = this.inverseRecord.getRecord(); 74073 (0, _emberDataPrivateDebug.assert)("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with i
74073d " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); 74074 return toReturn; 74075 } 74076 }; 74077 74078 BelongsToRelationship.prototype.reload = function () { 74079 // TODO handle case when reload() is triggered multiple times 74080 74081 if (this.link) { 74082 return this.fetchLink(); 74083 } 74084 74085 // reload record, if it is already loaded 74086 if (this.inverseRecord && this.inverseRecord.record) { 74087 return this.inverseRecord.record.reload(); 74088 } 74089 74090 return this.findRecord(); 74091 }; 74092}); 74093define("ember-data/-private/system/relationships/state/create", ["exports", "ember", "ember-data/-private/system/relationships/state/has-many", "ember-data/-private/system/relationships/state/belongs-to", "ember-data/-private/system/empty-object"], function (exports, _ember, _emberDataPrivateSystemRelationshipsStateHasMany, _emberDataPrivateSystemRelationshipsStateBelongsTo, _emberDataPrivateSystemEmptyObject) { 74094 "use strict"; 74095 74096 exports["default"] = Relationships; 74097 74098 var get = _ember["default"].get; 74099 74100 function shouldFindInverse(relationshipMeta) { 74101 var options = relationshipMeta.options; 74102 return !(options && options.inverse === null); 74103 } 74104 74105 function createRelationshipFor(record, relationshipMeta, store) { 74106 var inverseKey = undefined; 74107 var inverse = null; 74108 if (shouldFindInverse(relationshipMeta)) { 74109 inverse = record.type.inverseFor(relationshipMeta.key, store); 74110 } 74111 74112 if (inverse) { 74113 inverseKey = inverse.name; 74114 } 74115 74116 if (relationshipMeta.kind === 'hasMany') { 74117 return new _emberDataPrivateSystemRelationshipsStateHasMany["default"](store, record, inverseKey, relationshipMeta); 74118 } else { 74119 return new _emberDataPrivateSystemRelationshipsStateBelongsTo["default"](store, record, inverseKey, relationshipMeta); 74120 } 74121 } 74122 function Relationships(record) { 74123 this.record = record; 74124 this.initializedRelationships = new _emberDataPrivateSystemEmptyObject["default"](); 74125 } 74126 74127 Relationships.prototype.has = function (key) { 74128 return !!this.initializedRelationships[key]; 74129 }; 74130 74131 Relationships.prototype.get = function (key) { 74132 var relationships = this.initializedRelationships; 74133 var relationshipsByName = get(this.record.type, 'relationshipsByName'); 74134 if (!relationships[key] && relationshipsByName.get(key)) { 74135 relationships[key] = createRelationshipFor(this.record, relationshipsByName.get(key), this.record.store); 74136 } 74137 return relationships[key]; 74138 }; 74139}); 74140define("ember-data/-private/system/relationships/state/has-many", ["exports", "ember-data/-private/debug", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/relationships/state/relationship", "ember-data/-private/system/ordered-set", "ember-data/-private/system/many-array"], function (exports, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemRelationshipsStateRelationship, _emberDataPrivateSystemOrderedSet, _emberDataPrivateSystemManyArray) { 74141 "use strict"; 74142 74143 exports["default"] = ManyRelationship; 74144 74145 function ManyRelationship(store, record, inverseKey, relationshipMeta) { 74146 this._super$constructor(store, record, inverseKey, relationshipMeta); 74147 this.belongsToType = relationshipMeta.type; 74148 this.canonicalState = []; 74149 this.manyArray = _emberDataPrivateSystemManyArray["default"].create({ 74150 canonicalState: this.canonicalState, 74151 store: this.store, 74152 relationship: this, 74153 type: this.store.modelFor(this.belongsToType), 74154 record: record 74155 }); 74156 this.isPolymorphic = relationshipMeta.options.polymorphic; 74157 this.manyArray.isPolymorphic = this.isPolymorphic; 74158 } 74159 74160 ManyRelationship.prototype = Object.create(_emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype); 74161 ManyRelationship.prototype.constructor = ManyRelationship; 74162 ManyRelationship.prototype._super$constructor = _emberDataPrivateSystemRelationshipsStateRelationship["default"]; 74163 74164 ManyRelationship.prototype.destroy = function () { 74165 this.manyArray.destroy(); 74166 }; 74167 74168 ManyRelationship.prototype._super$updateMeta = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.updateMeta; 74169 ManyRelationship.prototype.updateMeta = function (meta) { 74170 this._super$updateMeta(meta); 74171 this.manyArray.set('meta', meta); 74172 }; 74173 74174 ManyRelationship.prototype._super$addCanonicalRecord = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.addCanonicalRecord; 74175 ManyRelationship.prototype.addCanonicalRecord = function (record, idx) { 74176 if (this.canonicalMembers.has(record)) { 74177 return; 74178 } 74179 if (idx !== undefined) { 74180 this.canonicalState.splice(idx, 0, record); 74181 } else { 74182 this.canonicalState.push(record); 74183 } 74184 this._super$addCanonicalRecord(record, idx); 74185 }; 74186 74187 ManyRelationship.prototype._super$addRecord = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.addRecord; 74188 ManyRelationship.prototype.addRecord = function (record, idx) { 74189 if (this.members.has(record)) { 74190 return; 74191 } 74192 this._super$addRecord(record, idx); 74193 this.manyArray.internalAddRecords([record], idx); 74194 }; 74195 74196 ManyRelationship.prototype._super$removeCanonicalRecordFromOwn = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.removeCanonicalRecordFromOwn; 74197 ManyRelationship.prototype.removeCanonicalRecordFromOwn = function (record, idx) { 74198 var i = idx; 74199 if (!this.canonicalMembers.has(record)) { 74200 return; 74201 } 74202 if (i === undefined) { 74203 i = this.canonicalState.indexOf(record); 74204 } 74205 if (i > -1) { 74206 this.canonicalState.splice(i, 1); 74207 } 74208 this._super$removeCanonicalRecordFromOwn(record, idx); 74209 }; 74210 74211 ManyRelationship.prototype._super$flushCanonical = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.flushCanonical; 74212 ManyRelationship.prototype.flushCanonical = function () { 74213 this.manyArray.flushCanonical(); 74214 this._super$flushCanonical(); 74215 }; 74216 74217 ManyRelationship.prototype._super$removeRecordFromOwn = _emberDataPrivateSystemRelationshipsStateRelationship["default"].prototype.removeRecordFromOwn; 74218 ManyRelationship.prototype.removeRecordFromOwn = function (record, idx) { 74219 if (!this.members.has(record)) { 74220 return; 74221 } 74222 this._super$removeRecordFromOwn(record, idx); 74223 if (idx !== undefined) { 74224 //TODO(Igor) not used currently, fix 74225 this.manyArray.currentState.removeAt(idx); 74226 } else { 74227 this.manyArray.internalRemoveRecords([record]); 74228 } 74229 }; 74230 74231 ManyRelationship.prototype.notifyRecordRelationshipAdded = function (record, idx) { 74232 (0, _emberDataPrivateDebug.assertPolymorphicType)(this.record, this.relationshipMeta, record); 74233 74234 this.record.notifyHasManyAdded(this.key, record, idx); 74235 }; 74236 74237 ManyRelationship.prototype.reload = function () { 74238 var _this = this; 74239 74240 var manyArrayLoadedState = this.manyArray.get('isLoaded'); 74241 74242 if (this._loadingPromise) { 74243 if (this._loadingPromise.get('isPending')) { 74244 return this._loadingPromise; 74245 } 74246 if (this._loadingPromise.get('isRejected')) { 74247 this.manyArray.set('isLoaded', manyArrayLoadedState); 74248 } 74249 } 74250 74251 if (this.link) { 74252 this._loadingPromise = (0, _emberDataPrivateSystemPromiseProxies.promiseManyArray)(this.fetchLink(), 'Reload with link'); 74253 return this._loadingPromise; 74254 } else { 74255 this._loadingPromise = (0, _emberDataPrivateSystemPromiseProxies.promiseManyArray)(this.store.scheduleFetchMany(this.manyArray.toArray()).then(function () { 74256 return _this.manyArray; 74257 }), 'Reload with ids'); 74258 return this._loadingPromise; 74259 } 74260 }; 74261 74262 ManyRelationship.prototype.computeChanges = function (records) { 74263 var members = this.canonicalMembers; 74264 var recordsToRemove = []; 74265 var length; 74266 var record; 74267 var i; 74268 74269 records = setForArray(records); 74270
74271 members.forEach(function (member) { 74272 if (records.has(member)) { 74273 return; 74274 } 74275 74276 recordsToRemove.push(member); 74277 }); 74278 74279 this.removeCanonicalRecords(recordsToRemove); 74280 74281 // Using records.toArray() since currently using 74282 // removeRecord can modify length, messing stuff up 74283 // forEach since it directly looks at "length" each 74284 // iteration 74285 records = records.toArray(); 74286 length = records.length; 74287 for (i = 0; i < length; i++) { 74288 record = records[i]; 74289 this.removeCanonicalRecord(record); 74290 this.addCanonicalRecord(record, i); 74291 } 74292 }; 74293 74294 ManyRelationship.prototype.fetchLink = function () { 74295 var _this2 = this; 74296 74297 return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function (records) { 74298 if (records.hasOwnProperty('meta')) { 74299 _this2.updateMeta(records.meta); 74300 } 74301 _this2.store._backburner.join(function () { 74302 _this2.updateRecordsFromAdapter(records); 74303 _this2.manyArray.set('isLoaded', true); 74304 }); 74305 return _this2.manyArray; 74306 }); 74307 }; 74308 74309 ManyRelationship.prototype.findRecords = function () { 74310 var _this3 = this; 74311 74312 var manyArray = this.manyArray.toArray(); 74313 var internalModels = new Array(manyArray.length); 74314 74315 for (var i = 0; i < manyArray.length; i++) { 74316 internalModels[i] = manyArray[i]._internalModel; 74317 } 74318 74319 //TODO CLEANUP 74320 return this.store.findMany(internalModels).then(function () { 74321 if (!_this3.manyArray.get('isDestroyed')) { 74322 //Goes away after the manyArray refactor 74323 _this3.manyArray.set('isLoaded', true); 74324 } 74325 return _this3.manyArray; 74326 }); 74327 }; 74328 ManyRelationship.prototype.notifyHasManyChanged = function () { 74329 this.record.notifyHasManyAdded(this.key); 74330 }; 74331 74332 ManyRelationship.prototype.getRecords = function () { 74333 var _this4 = this; 74334 74335 //TODO(Igor) sync server here, once our syncing is not stupid 74336 if (this.isAsync) { 74337 var promise; 74338 if (this.link) { 74339 if (this.hasLoaded) { 74340 promise = this.findRecords(); 74341 } else { 74342 promise = this.findLink().then(function () { 74343 return _this4.findRecords(); 74344 }); 74345 } 74346 } else { 74347 promise = this.findRecords(); 74348 } 74349 this._loadingPromise = _emberDataPrivateSystemPromiseProxies.PromiseManyArray.create({ 74350 content: this.manyArray, 74351 promise: promise 74352 }); 74353 return this._loadingPromise; 74354 } else { 74355 (0, _emberDataPrivateDebug.assert)("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); 74356 74357 //TODO(Igor) WTF DO I DO HERE? 74358 if (!this.manyArray.get('isDestroyed')) { 74359 this.manyArray.set('isLoaded', true); 74360 } 74361 return this.manyArray; 74362 } 74363 }; 74364 74365 function setForArray(array) { 74366 var set = new _emberDataPrivateSystemOrderedSet["default"](); 74367 74368 if (array) { 74369 for (var i = 0, l = array.length; i < l; i++) { 74370 set.add(array[i]); 74371 } 74372 } 74373 74374 return set; 74375 } 74376}); 74377define("ember-data/-private/system/relationships/state/relationship", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/ordered-set"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemOrderedSet) { 74378 "use strict"; 74379 74380 exports["default"] = Relationship; 74381 74382 function Relationship(store, record, inverseKey, relationshipMeta) { 74383 var async = relationshipMeta.options.async; 74384 this.members = new _emberDataPrivateSystemOrderedSet["default"](); 74385 this.canonicalMembers = new _emberDataPrivateSystemOrderedSet["default"](); 74386 this.store = store; 74387 this.key = relationshipMeta.key; 74388 this.inverseKey = inverseKey; 74389 this.record = record; 74390 this.isAsync = typeof async === 'undefined' ? true : async; 74391 this.relationshipMeta = relationshipMeta; 74392 //This probably breaks for polymorphic relationship in complex scenarios, due to 74393 //multiple possible modelNames 74394 this.inverseKeyForImplicit = this.record.constructor.modelName + this.key; 74395 this.linkPromise = null; 74396 this.meta = null; 74397 this.hasData = false;
74398 this.hasLoaded = false; 74399 } 74400 74401 Relationship.prototype = { 74402 constructor: Relationship, 74403 74404 destroy: _ember["default"].K, 74405 74406 updateMeta: function updateMeta(meta) { 74407 this.meta = meta; 74408 }, 74409 74410 clear: function clear() { 74411 var members = this.members.list; 74412 var member; 74413 74414 while (members.length > 0) { 74415 member = members[0]; 74416 this.removeRecord(member); 74417 } 74418 }, 74419 74420 removeRecords: function removeRecords(records) { 74421 var _this = this; 74422 74423 records.forEach(function (record) { 74424 return _this.removeRecord(record); 74425 }); 74426 }, 74427 74428 addRecords: function addRecords(records, idx) { 74429 var _this2 = this; 74430 74431 records.forEach(function (record) { 74432 _this2.addRecord(record, idx); 74433 if (idx !== undefined) { 74434 idx++; 74435 } 74436 }); 74437 }, 74438 74439 addCanonicalRecords: function addCanonicalRecords(records, idx) { 74440 for (var i = 0; i < records.length; i++) { 74441 if (idx !== undefined) { 74442 this.addCanonicalRecord(records[i], i + idx); 74443 } else { 74444 this.addCanonicalRecord(records[i]); 74445 } 74446 } 74447 }, 74448 74449 addCanonicalRecord: function addCanonicalRecord(record, idx) { 74450 if (!this.canonicalMembers.has(record)) { 74451 this.canonicalMembers.add(record); 74452 if (this.inverseKey) { 74453 record._relationships.get(this.inverseKey).addCanonicalRecord(this.record); 74454 } else { 74455 if (!record._implicitRelationships[this.inverseKeyForImplicit]) { 74456 record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); 74457 } 74458 record._implicitRelationships[this.inverseKeyForImplicit].addCanonicalRecord(this.record); 74459 } 74460 } 74461 this.flushCanonicalLater(); 74462 this.setHasData(true); 74463 }, 74464 74465 removeCanonicalRecords: function removeCanonicalRecords(records, idx) { 74466 for (var i = 0; i < records.length; i++) { 74467 if (idx !== undefined) { 74468 this.removeCanonicalRecord(records[i], i + idx); 74469 } else { 74470 this.removeCanonicalRecord(records[i]); 74471 } 74472 } 74473 }, 74474 74475 removeCanonicalRecord: function removeCanonicalRecord(record, idx) { 74476 if (this.canonicalMembers.has(record)) { 74477 this.removeCanonicalRecordFromOwn(record); 74478 if (this.inverseKey) { 74479 this.removeCanonicalRecordFromInverse(record); 74480 } else { 74481 if (record._implicitRelationships[this.inverseKeyForImplicit]) { 74482 record._implicitRelationships[this.inverseKeyForImplicit].removeCanonicalRecord(this.record); 74483 } 74484 } 74485 } 74486 this.flushCanonicalLater(); 74487 }, 74488 74489 addRecord: function addRecord(record, idx) { 74490 if (!this.members.has(record)) { 74491 this.members.addWithIndex(record, idx); 74492 this.notifyRecordRelationshipAdded(record, idx); 74493 if (this.inverseKey) { 74494 record._relationships.get(this.inverseKey).addRecord(this.record); 74495 } else { 74496 if (!record._implicitRelationships[this.inverseKeyForImplicit]) { 74497 record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); 74498 } 74499 record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record); 74500 } 74501 this.record.updateRecordArraysLater(); 74502 } 74503 this.setHasData(true); 74504 }, 74505 74506 removeRecord: function removeRecord(record) { 74507 if (this.members.has(record)) { 74508 this.removeRecordFromOwn(record); 74509 if (this.inverseKey) { 74510 this.removeRecordFromInverse(record); 74511 } else { 74512 if (record._implicitRelationships[this.inverseKeyForImplicit]) { 74513 record._implicitRelationships[this.inverseKeyForImplicit].removeRecord(this.record); 74514 } 74515 } 74516 } 74517 }, 74518 74519 removeRecordFromInverse: function removeRecordFromInverse(record) { 74520 var inverseRelationship = record._relationships.get(this.inverseKey); 74521 //Need to check for existence, as the record might unloading at the moment
74522 if (inverseRelationship) { 74523 inverseRelationship.removeRecordFromOwn(this.record); 74524 } 74525 }, 74526 74527 removeRecordFromOwn: function removeRecordFromOwn(record) { 74528 this.members["delete"](record); 74529 this.notifyRecordRelationshipRemoved(record); 74530 this.record.updateRecordArrays(); 74531 }, 74532 74533 removeCanonicalRecordFromInverse: function removeCanonicalRecordFromInverse(record) { 74534 var inverseRelationship = record._relationships.get(this.inverseKey); 74535 //Need to check for existence, as the record might unloading at the moment 74536 if (inverseRelationship) { 74537 inverseRelationship.removeCanonicalRecordFromOwn(this.record); 74538 } 74539 }, 74540 74541 removeCanonicalRecordFromOwn: function removeCanonicalRecordFromOwn(record) { 74542 this.canonicalMembers["delete"](record); 74543 this.flushCanonicalLater(); 74544 }, 74545 74546 flushCanonical: function flushCanonical() { 74547 this.willSync = false; 74548 //a hack for not removing new records 74549 //TODO remove once we have proper diffing 74550 var newRecords = []; 74551 for (var i = 0; i < this.members.list.length; i++) { 74552 if (this.members.list[i].isNew()) { 74553 newRecords.push(this.members.list[i]); 74554 } 74555 } 74556 //TODO(Igor) make this less abysmally slow 74557 this.members = this.canonicalMembers.copy(); 74558 for (i = 0; i < newRecords.length; i++) { 74559 this.members.add(newRecords[i]); 74560 } 74561 }, 74562 74563 flushCanonicalLater: function flushCanonicalLater() { 74564 var _this3 = this; 74565 74566 if (this.willSync) { 74567 return; 74568 } 74569 this.willSync = true; 74570 this.store._backburner.join(function () { 74571 return _this3.store._backburner.schedule('syncRelationships', _this3, _this3.flushCanonical); 74572 }); 74573 }, 74574 74575 updateLink: function updateLink(link) { 74576 (0, _emberDataPrivateDebug.warn)("You have pushed a record of type '" + this.record.type.modelName + "' with '" + this.key + "' as a link, but the association is not an async relationship.", this.isAsync, { 74577 id: 'ds.store.push-link-for-sync-relationship' 74578 }); 74579 (0, _emberDataPrivateDebug.assert)("You have pushed a record of type '" + this.record.type.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); 74580 if (link !== this.link) { 74581 this.link = link; 74582 this.linkPromise = null; 74583 this.setHasLoaded(false); 74584 this.record.notifyPropertyChange(this.key); 74585 } 74586 }, 74587 74588 findLink: function findLink() { 74589 if (this.linkPromise) { 74590 return this.linkPromise; 74591 } else { 74592 var promise = this.fetchLink(); 74593 this.linkPromise = promise; 74594 return promise.then(function (result) { 74595 return result; 74596 }); 74597 } 74598 }, 74599
74600 updateRecordsFromAdapter: function updateRecordsFromAdapter(records) { 74601 //TODO(Igor) move this to a proper place 74602 //TODO Once we have adapter support, we need to handle updated and canonical changes 74603 this.computeChanges(records); 74604 this.setHasData(true); 74605 this.setHasLoaded(true); 74606 }, 74607 74608 notifyRecordRelationshipAdded: _ember["default"].K, 74609 notifyRecordRelationshipRemoved: _ember["default"].K, 74610 74611 /* 74612 `hasData` for a relationship is a flag to indicate if we consider the 74613 content of this relationship "known". Snapshots uses this to tell the 74614 difference between unknown (`undefined`) or empty (`null`). The reason for 74615 this is that we wouldn't want to serialize unknown relationships as `null` 74616 as that might overwrite remote state. 74617 All relationships for a newly created (`store.createRecord()`) are 74618 considered known (`hasData === true`). 74619 */ 74620 setHasData: function setHasData(value) { 74621 this.hasData = value; 74622 }, 74623 74624 /* 74625 `hasLoaded` is a flag to indicate if we have gotten data from the adapter or 74626 not when the relationship has a link. 74627 This is used to be able to tell when to fetch the link and when to return 74628 the local data in scenarios where the local state is considered known 74629 (`hasData === true`). 74630 Updating the link will automatically set `hasLoaded` to `false`. 74631 */ 74632 setHasLoaded: function setHasLoaded(value) { 74633 this.hasLoaded = value; 74634 } 74635 }; 74636}); 74637define('ember-data/-private/system/snapshot-record-array', ['exports'], function (exports) { 74638 'use strict'; 74639 74640 exports['default'] = SnapshotRecordArray; 74641 74642 /** 74643 @module ember-data 74644 */ 74645 74646 /** 74647 @class SnapshotRecordArray 74648 @namespace DS 74649 @private 74650 @constructor 74651 @param {Array} snapshots An array of snapshots 74652 @param {Object} meta 74653 */ 74654 function SnapshotRecordArray(recordArray, meta) { 74655 var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; 74656 74657 /** 74658 An array of snapshots 74659 @private 74660 @property _snapshots 74661 @type {Array} 74662 */ 74663 this._snapshots = null; 74664 /** 74665 An array of records 74666 @private 74667 @property _recordArray 74668 @type {Array} 74669 */ 74670 this._recordArray = recordArray; 74671 /** 74672 Number of records in the array 74673 @property length 74674 @type {Number} 74675 */ 74676 this.length = recordArray.get('length'); 74677 /** 74678 The type of the underlying records for the snapshots in the array, as a DS.Model 74679 @property type 74680 @type {DS.Model} 74681 */ 74682 this.type = recordArray.get('type'); 74683 /** 74684 Meta object 74685 @property meta 74686 @type {Object} 74687 */ 74688 this.meta = meta; 74689 /** 74690 A hash of adapter options 74691 @property adapterOptions 74692 @type {Object} 74693 */ 74694 this.adapterOptions = options.adapterOptions; 74695 74696 this.include = options.include; 74697 } 74698 74699 /** 74700 Get snapshots of the underlying record array 74701 @method snapshots 74702 @return {Array} Array of snapshots 74703 */ 74704 SnapshotRecordArray.prototype.snapshots = function () { 74705 if (this._snapshots) { 74706 return this._snapshots; 74707 } 74708 var recordArray = this._recordArray; 74709 this._snapshots = recordArray.invoke('createSnapshot'); 74710 74711 return this._snapshots; 74712 }; 74713}); 74714define("ember-data/-private/system/snapshot", ["exports", "ember", "ember-data/-private/system/empty-object"], function (exports, _ember, _emberDataPrivateSystemEmptyObject) { 74715 "use strict"; 74716 74717 exports["default"] = Snapshot; 74718 74719 /** 74720 @module ember-data 74721 */ 74722 74723 var get = _ember["default"].get; 74724 74725 /** 74726 @class Snapshot 74727 @namespace DS 74728 @private 74729 @constructor 74730 @param {DS.Model} internalModel The model to create a snapshot from 74731 */ 74732 function Snapshot(internalModel) { 74733 var _this = this; 74734 74735 var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 74736 74737 this._attributes = new _emberDataPrivateSystemEmptyObject["default"](); 74738 this._belongsToRelationships = new _emberDataPrivateSystemEmptyObject["default"](); 74739 this._belongsToIds = new _emberDataPrivateSystemEmptyObject["default"](); 74740 this._hasManyRelationships = new _emberDataPrivateSystemEmptyObject["default"](); 74741 this._hasManyIds = new _emberDataPrivateSystemEmptyObject["default"](); 74742 74743 var record = internalModel.getRecord(); 74744 this.record = record; 74745 record.eachAttribute(function (keyName) { 74746 return _this._attributes[keyName] = get(record, keyName); 74747 }); 74748 74749 this.id = internalModel.id; 74750 this._internalModel = internalModel; 74751 this.type = internalModel.type; 74752 this.modelName = internalModel.type.modelName; 74753 74754 /** 74755 A hash of adapter options 74756 @property adapterOptions 74757 @type {Object} 74758 */ 74759 this.adapterOptions = options.adapterOptions; 74760 74761 this.include = options.include; 74762 74763 this._changedAttributes = record.changedAttributes(); 74764 } 74765 74766 Snapshot.prototype = { 74767 constructor: Snapshot, 74768 74769 /** 74770 The id of the snapshot's underlying record 74771 Example 74772 ```javascript 74773 // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); 74774 postSnapshot.id; // => '1' 74775 ``` 74776 @property id 74777 @type {String} 74778 */ 74779 id: null, 74780 74781 /** 74782 The underlying record for this snapshot. Can be used to access methods and 74783 properties defined on the record. 74784 Example 74785 ```javascript 74786 var json = snapshot.record.toJSON(); 74787 ``` 74788 @property record 74789 @type {DS.Model} 74790 */ 74791 record: null, 74792 74793 /** 74794 The type of the underlying record for this snapshot, as a DS.Model. 74795 @property type 74796 @type {DS.Model} 74797 */ 74798 type: null, 74799 74800 /** 74801 The name of the type of the underlying record for this snapshot, as a string. 74802 @property modelName 74803 @type {String} 74804 */ 74805 modelName: null, 74806 74807 /** 74808 Returns the value of an attribute. 74809 Example 74810 ```javascript 74811 // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); 74812 postSnapshot.attr('author'); // => 'Tomster' 74813 postSnapshot.attr('title'); // => 'Ember.js rocks' 74814 ``` 74815 Note: Values are loaded eagerly and cached when the snapshot is created. 74816 @method attr 74817 @param {String} keyName 74818 @return {Object} The attribute value or undefined 74819 */ 74820 attr: function attr(keyName) { 74821 if (keyName in this._attributes) { 74822 return this._attributes[keyName]; 74823 } 74824 throw new _ember["default"].Error("Model '" + _ember["default"].inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); 74825 }, 74826 74827 /** 74828 Returns all attributes and their corresponding values. 74829 Example 74830 ```javascript 74831 // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); 74832 postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } 74833 ``` 74834 @method attributes 74835 @return {Object} All attributes of the current snapshot 74836 */ 74837 attributes: function attributes() { 74838 return _ember["default"].copy(this._attributes); 74839 }, 74840 74841 /** 74842 Returns all changed attributes and their old and new values. 74843 Example 74844 ```javascript 74845 // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); 74846 postModel.set('title', 'Ember.js rocks!'); 74847 postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } 74848 ``` 74849 @method changedAttributes 74850 @return {Object} All changed attributes of the current snapshot 74851 */ 74852 changedAttributes: function changedAttributes() { 74853 var changedAttributes = new _emberDataPrivateSystemEmptyObject["default"](); 74854 var changedAttributeKeys = Object.keys(this._changedAttributes); 74855 74856 for (var i = 0, _length = changedAttributeKeys.length; i < _length; i++) { 74857 var key = changedAttributeKeys[i]; 74858 changedAttributes[key] = _ember["default"].copy(this._changedAttributes[key]); 74859 } 74860 74861 return changedAttributes; 74862 }, 74863 74864 /** 74865 Returns the current value of a belongsTo relationship. 74866 `belongsTo` takes an optional hash of options as a second parameter, 74867 currently supported options are: 74868 - `id`: set to `true` if you only want the ID of the related record to be 74869 returned. 74870 Example 74871 ```javascript 74872 // store.push('post', { id: 1, title: 'Hello World' }); 74873 // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); 74874 commentSnapshot.belongsTo('post'); // => DS.Snapshot 74875 commentSnapshot.belongsTo('post', { id: true }); // => '1' 74876 // store.push('comment', { id: 1, body: 'Lorem ipsum' }); 74877 commentSnapshot.belongsTo('post'); // => undefined 74878 ``` 74879 Calling `belongsTo` will return a new Snapshot as long as there's any known 74880 data for the relationship available, such as an ID. If the relationship is 74881 known but unset, `belongsTo` will return `null`. If the contents of the 74882 relationship is unknown `belongsTo` will return `undefined`. 74883 Note: Relationships are loaded lazily and cached upon first access. 74884 @method belongsTo 74885 @param {String} keyName 74886 @param {Object} [options] 74887 @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known 74888 relationship or null if the relationship is known but unset. undefined 74889 will be returned if the contents of the relationship is unknown. 74890 */ 74891 belongsTo: function belongsTo(keyName, options) { 74892 var id = options && options.id; 74893 var relationship, inverseRecord, hasData; 74894 var result; 74895 74896 if (id && keyName in this._belongsToIds) { 74897 return this._belongsToIds[keyName]; 74898 } 74899 74900 if (!id && keyName in this._belongsToRelationships) { 74901 return this._belongsToRelationships[keyName]; 74902 } 74903 74904 relationship = this._internalModel._relationships.get(keyName); 74905 if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { 74906 throw new _ember["default"].Error("Model '" + _ember["default"].inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); 74907 } 74908 74909 hasData = get(relationship, 'hasData'); 74910 inverseRecord = get(relationship, 'inverseRecord'); 74911 74912 if (hasData) { 74913 if (inverseRecord && !inverseRecord.isDeleted()) { 74914 if (id) { 74915 result = get(inverseRecord, 'id'); 74916 } else { 74917 result = inverseRecord.createSnapshot(); 74918 } 74919 } else { 74920 result = null; 74921 } 74922 } 74923 74924 if (id) { 74925 this._belongsToIds[keyName] = result; 74926 } else { 74927 this._belongsToRelationships[keyName] = result; 74928 } 74929 74930 return result; 74931 }, 74932 74933 /** 74934 Returns the current value of a hasMany relationship. 74935 `hasMany` takes an optional hash of options as a second parameter, 74936 currently supported options are: 74937 - `ids`: set to `true` if you only want the IDs of the related records to be 74938 returned. 74939 Example 74940 ```javascript 74941 // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); 74942 postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] 74943 postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] 74944 // store.push('post', { id: 1, title: 'Hello World' }); 74945 postSnapshot.hasMany('comments'); // => undefined 74946 ``` 74947 Note: Relationships are loaded lazily and cached upon first access. 74948 @method hasMany 74949 @param {String} keyName 74950 @param {Object} [options] 74951 @return {(Array|undefined)} An array of snapshots or IDs of a known 74952 relationship or an empty array if the relationship is known but unset. 74953 undefined will be returned if the contents of the relationship is unknown. 74954 */ 74955 hasMany: function hasMany(keyName, options) { 74956 var ids = options && options.ids; 74957 var relationship, members, hasData; 74958 var results; 74959 74960 if (ids && keyName in this._hasManyIds) { 74961 return this._hasManyIds[keyName]; 74962 } 74963 74964 if (!ids && keyName in this._hasManyRelationships) { 74965 return this._hasManyRelationships[keyName]; 74966 } 74967 74968 relationship = this._internalModel._relationships.get(keyName); 74969 if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { 74970 throw new _ember["default"].Error("Model '" + _ember["default"].inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); 74971 } 74972 74973 hasData = get(relationship, 'hasData'); 74974 members = get(relationship, 'members'); 74975 74976 if (hasData) { 74977 results = [];
74978 members.forEach(function (member) { 74979 if (!member.isDeleted()) { 74980 if (ids) { 74981 results.push(member.id); 74982 } else { 74983 results.push(member.createSnapshot()); 74984 } 74985 } 74986 }); 74987 } 74988 74989 if (ids) { 74990 this._hasManyIds[keyName] = results; 74991 } else { 74992 this._hasManyRelationships[keyName] = results; 74993 } 74994 74995 return results; 74996 }, 74997 74998 /** 74999 Iterates through all the attributes of the model, calling the passed 75000 function on each attribute. 75001 Example 75002 ```javascript 75003 snapshot.eachAttribute(function(name, meta) { 75004 // ... 75005 }); 75006 ``` 75007 @method eachAttribute 75008 @param {Function} callback the callback to execute 75009 @param {Object} [binding] the value to which the callback's `this` should be bound 75010 */ 75011 eachAttribute: function eachAttribute(callback, binding) { 75012 this.record.eachAttribute(callback, binding); 75013 }, 75014 75015 /** 75016 Iterates through all the relationships of the model, calling the passed 75017 function on each relationship. 75018 Example 75019 ```javascript 75020 snapshot.eachRelationship(function(name, relationship) { 75021 // ... 75022 }); 75023 ``` 75024 @method eachRelationship 75025 @param {Function} callback the callback to execute 75026 @param {Object} [binding] the value to which the callback's `this` should be bound 75027 */ 75028 eachRelationship: function eachRelationship(callback, binding) { 75029 this.record.eachRelationship(callback, binding); 75030 }, 75031 75032 /** 75033 @method serialize 75034 @param {Object} options 75035 @return {Object} an object whose values are primitive JSON values only 75036 */ 75037 serialize: function serialize(options) { 75038 return this.record.store.serializerFor(this.modelName).serialize(this, options); 75039 } 75040 }; 75041}); 75042define('ember-data/-private/system/store', ['exports', 'ember', 'ember-data/model', 'ember-data/-private/debug', 'ember-data/-private/system/normalize-link', 'ember-data/-private/system/normalize-model-name', 'ember-data/adapters/errors', 'ember-data/-private/system/promise-proxies', 'ember-data/-private/system/store/common', 'ember-data/-private/system/store/serializer-response', 'ember-data/-private/system/store/serializers', 'ember-data/-private/system/store/finders', 'ember-data/-private/utils', 'ember-data/-private/system/coerce-id', 'ember-data/-private/system/record-array-manager', 'ember-data/-private/system/store/container-instance-cache', 'ember-data/-private/system/model/internal-model', 'ember-data/-private/system/empty-object', 'ember-data/-private/features'], function (exports, _ember, _emberDataModel, _emberDataPrivateDebug, _emberDataPrivateSystemNormalizeLink, _emberDataPrivateSystemNormalizeModelName, _emberDataAdaptersErrors, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStoreCommon, _emberDataPrivateSystemStoreSerializerResponse, _emberDataPrivateSystemStoreSerializers, _emberDataPrivateSystemStoreFinders, _emberDataPrivateUtils, _emberDataPrivateSystemCoerceId, _emberDataPrivateSystemRecordArrayManager, _emberDataPrivateSystemStoreContainerInstanceCache, _emberDataPrivateSystemModelInternalModel, _emberDataPrivateSystemEmptyObject, _emberDataPrivateFeatures) { 75043 /** 75044 @module ember-data 75045 */ 75046 75047 'use strict'; 75048 75049 var badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; 75050 75051 exports.badIdFormatAssertion = badIdFormatAssertion; 75052 75053 var Backburner = _ember['default']._Backburner; 75054 var Map = _ember['default'].Map; 75055 75056 //Get the materialized model from the internalModel/promise that returns 75057 //an internal model and return it in a promiseObject. Useful for returning 75058 //from find methods 75059 function promiseRecord(internalModel, label) { 75060 var toReturn = internalModel.then(function (model) { 75061 return model.getRecord(); 75062 }); 75063 return (0, _emberDataPrivateSystemPromiseProxies.promiseObject)(toReturn, label); 75064 } 75065 75066 var get = _ember['default'].get; 75067 var set = _ember['default'].set; 75068 var once = _ember['default'].run.once; 75069 var isNone = _ember['default'].isNone; 75070 var isPresent = _ember['default'].isPresent; 75071 var Promise = _ember['default'].RSVP.Promise; 75072 var copy = _ember['default'].copy; 75073 var Store; 75074 75075 var Service = _ember['default'].Service; 75076 75077 // Implementors Note: 75078 // 75079 // The variables in this file are consistently named according to the following 75080 // scheme: 75081 // 75082 // * +id+ means an identifier managed by an external source, provided inside 75083 // the data provided by that source. These are always coerced to be strings 75084 // before being used internally. 75085 // * +clientId+ means a transient numerical identifier generated at runtime by 75086 // the data store. It is important primarily because newly created objects may 75087 // not yet have an externally generated id. 75088 // * +internalModel+ means a record internalModel object, which holds metadata about a 75089 // record, even if it has not yet been fully materialized. 75090 // * +type+ means a DS.Model. 75091 75092 /** 75093 The store contains all of the data for records loaded from the server. 75094 It is also responsible for creating instances of `DS.Model` that wrap 75095 the individual data for a record, so that they can be bound to in your 75096 Handlebars templates. 75097 75098 Define your application's store like this: 75099 75100 ```app/services/store.js 75101 import DS from 'ember-data'; 75102 75103 export default DS.Store.extend({ 75104 }); 75105 ``` 75106 75107 Most Ember.js applications will only have a single `DS.Store` that is 75108 automatically created by their `Ember.Application`. 75109 75110 You can retrieve models from the store in several ways. To retrieve a record 75111 for a specific id, use `DS.Store`'s `findRecord()` method: 75112 75113 ```javascript 75114 store.findRecord('person', 123).then(function (person) { 75115 }); 75116 ``` 75117 75118 By default, the store will talk to your backend using a standard 75119 REST mechanism. You can customize how the store talks to your 75120 backend by specifying a custom adapter: 75121
75122 ```app/adapters/application.js 75123 import DS from 'ember-data'; 75124 75125 export default DS.Adapter.extend({ 75126 }); 75127 ``` 75128 75129 You can learn more about writing a custom adapter by reading the `DS.Adapter` 75130 documentation. 75131 75132 ### Store createRecord() vs. push() vs. pushPayload() 75133 75134 The store provides multiple ways to create new record objects. They have 75135 some subtle differences in their use which are detailed below: 75136 75137 [createRecord](#method_createRecord) is used for creating new 75138 records on the client side. This will return a new record in the 75139 `created.uncommitted` state. In order to persist this record to the 75140 backend you will need to call `record.save()`. 75141 75142 [push](#method_push) is used to notify Ember Data's store of new or 75143 updated records that exist in the backend. This will return a record 75144 in the `loaded.saved` state. The primary use-case for `store#push` is 75145 to notify Ember Data about record updates (full or partial) that happen 75146 outside of the normal adapter methods (for example 75147 [SSE](http://dev.w3.org/html5/eventsource/) or [Web 75148 Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). 75149 75150 [pushPayload](#method_pushPayload) is a convenience wrapper for 75151 `store#push` that will deserialize payloads if the 75152 Serializer implements a `pushPayload` method. 75153 75154 Note: When creating a new record using any of the above methods 75155 Ember Data will update `DS.RecordArray`s such as those returned by 75156 `store#peekAll()`, `store#findAll()` or `store#filter()`. This means any 75157 data bindings or computed properties that depend on the RecordArray 75158 will automatically be synced to include the new or updated record 75159 values. 75160 75161 @class Store 75162 @namespace DS 75163 @extends Ember.Service 75164 */ 75165 exports.Store = Store = Service.extend({ 75166 75167 /** 75168 @method init 75169 @private 75170 */ 75171 init: function init() { 75172 this._super.apply(this, arguments); 75173 this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); 75174 // internal bookkeeping; not observable 75175 this.typeMaps = {}; 75176 this.recordArrayManager = _emberDataPrivateSystemRecordArrayManager['default'].create({ 75177 store: this 75178 }); 75179 this._pendingSave = []; 75180 this._instanceCache = new _emberDataPrivateSystemStoreContainerInstanceCache['default']((0, _emberDataPrivateUtils.getOwner)(this)); 75181 //Used to keep track of all the find requests that need to be coalesced 75182 this._pendingFetch = Map.create(); 75183 }, 75184 75185 /** 75186 The adapter to use to communicate to a backend server or other persistence layer. 75187 This can be specified as an instance, class, or string. 75188 If you want to specify `app/adapters/custom.js` as a string, do: 75189 ```js 75190 adapter: 'custom' 75191 ``` 75192 @property adapter 75193 @default DS.JSONAPIAdapter 75194 @type {(DS.Adapter|String)} 75195 */ 75196 adapter: '-json-api', 75197 75198 /** 75199 Returns a JSON representation of the record using a custom 75200 type-specific serializer, if one exists. 75201 The available options are: 75202 * `includeId`: `true` if the record's ID should be included in 75203 the JSON representation 75204 @method serialize 75205 @private 75206 @param {DS.Model} record the record to serialize 75207 @param {Object} options an options hash 75208 */ 75209 serialize: function serialize(record, options) { 75210 var snapshot = record._internalModel.createSnapshot(); 75211 return snapshot.serialize(options); 75212 }, 75213 75214 /** 75215 This property returns the adapter, after resolving a possible 75216 string key. 75217 If the supplied `adapter` was a class, or a String property 75218 path resolved to a class, this property will instantiate the 75219 class. 75220 This property is cacheable, so the same instance of a specified 75221 adapter class should be used for the lifetime of the store. 75222 @property defaultAdapter 75223 @private 75224 @return DS.Adapter 75225 */ 75226 defaultAdapter: _ember['default'].computed('adapter', function () { 75227 var adapter = get(this, 'adapter'); 75228 75229 (0, _emberDataPrivateDebug.assert)('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); 75230 75231 adapter = this.retrieveManagedInstance('adapter', adapter); 75232 75233 return adapter; 75234 }), 75235 75236 // ..................... 75237 // . CREATE NEW RECORD . 75238 // ..................... 75239 75240 /** 75241 Create a new record in the current store. The properties passed 75242 to this method are set on the newly created record. 75243 To create a new instance of a `Post`: 75244 ```js 75245 store.createRecord('post', { 75246 title: "Rails is omakase" 75247 }); 75248 ``` 75249 To create a new instance of a `Post` that has a relationship with a `User` record: 75250 ```js 75251 var user = this.store.peekRecord('user', 1); 75252 store.createRecord('post', { 75253 title: "Rails is omakase", 75254 user: user 75255 }); 75256 ``` 75257 @method createRecord 75258 @param {String} modelName 75259 @param {Object} inputProperties a hash of properties to set on the 75260 newly created record. 75261 @return {DS.Model} record 75262 */ 75263 createRecord: function createRecord(modelName, inputProperties) { 75264 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's createRecord method", isPresent(modelName)); 75265 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75266 var typeClass = this.modelFor(modelName); 75267 var properties = copy(inputProperties) || new _emberDataPrivateSystemEmptyObject['default'](); 75268 75269 // If the passed properties do not include a primary key, 75270 // give the adapter an opportunity to generate one. Typically, 75271 // client-side ID generators will use something like uuid.js 75272 // to avoid conflicts. 75273 75274 if (isNone(properties.id)) { 75275 properties.id = this._generateId(modelName, properties); 75276 } 75277 75278 // Coerce ID to a string 75279 properties.id = (0, _emberDataPrivateSystemCoerceId['default'])(properties.id); 75280 75281 var internalModel = this.buildInternalModel(typeClass, properties.id); 75282 var record = internalModel.getRecord(); 75283 75284 // Move the record out of its initial `empty` state into 75285 // the `loaded` state. 75286 internalModel.loadedData(); 75287 75288 // Set the properties specified on the record. 75289 record.setProperties(properties); 75290 75291 internalModel.eachRelationship(function (key, descriptor) { 75292 internalModel._relationships.get(key).setHasData(true); 75293 }); 75294 75295 return record; 75296 }, 75297 75298 /** 75299 If possible, this method asks the adapter to generate an ID for 75300 a newly created record. 75301 @method _generateId 75302 @private 75303 @param {String} modelName 75304 @param {Object} properties from the new record 75305 @return {String} if the adapter can generate one, an ID 75306 */ 75307 _generateId: function _generateId(modelName, properties) { 75308 var adapter = this.adapterFor(modelName); 75309 75310 if (adapter && adapter.generateIdForRecord) { 75311 return adapter.generateIdForRecord(this, modelName, properties); 75312 } 75313 75314 return null; 75315 }, 75316 75317 // ................. 75318 // . DELETE RECORD . 75319 // ................. 75320 75321 /** 75322 For symmetry, a record can be deleted via the store. 75323 Example 75324 ```javascript 75325 var post = store.createRecord('post', { 75326 title: "Rails is omakase" 75327 }); 75328 store.deleteRecord(post); 75329 ``` 75330 @method deleteRecord 75331 @param {DS.Model} record 75332 */ 75333 deleteRecord: function deleteRecord(record) { 75334 record.deleteRecord(); 75335 }, 75336 75337 /** 75338 For symmetry, a record can be unloaded via the store. Only 75339 non-dirty records can be unloaded. 75340 Example 75341 ```javascript 75342 store.findRecord('post', 1).then(function(post) { 75343 store.unloadRecord(post); 75344 }); 75345 ``` 75346 @method unloadRecord 75347 @param {DS.Model} record 75348 */ 75349 unloadRecord: function unloadRecord(record) { 75350 record.unloadRecord(); 75351 }, 75352 75353 // ................ 75354 // . FIND RECORDS . 75355 // ................ 75356 75357 /** 75358 @method find 75359 @param {String} modelName 75360 @param {String|Integer} id 75361 @param {Object} options 75362 @return {Promise} promise 75363 @private 75364 */ 75365 find: function find(modelName, id, options) { 75366 // The default `model` hook in Ember.Route calls `find(modelName, id)`, 75367 // that's why we have to keep this method around even though `findRecord` is 75368 // the public way to get a record by modelName and id. 75369 75370 if (arguments.length === 1) { 75371 (0, _emberDataPrivateDebug.assert)('Using store.find(type) has been removed. Use store.findAll(type) to retrieve all records for a given type.'); 75372 } 75373 75374 if (_ember['default'].typeOf(id) === 'object') { 75375 (0, _emberDataPrivateDebug.assert)('Calling store.find() with a query object is no longer supported. Use store.query() instead.'); 75376 } 75377 75378 if (options) { 75379 (0, _emberDataPrivateDebug.assert)('Calling store.find(type, id, { preload: preload }) is no longer supported. Use store.findRecord(type, id, { preload: preload }) instead.'); 75380 } 75381 75382 (0, _emberDataPrivateDebug.assert)("You need to pass the model name and id to the store's find method", arguments.length === 2); 75383 (0, _emberDataPrivateDebug.assert)("You cannot pass `" + _ember['default'].inspect(id) + "` as id to the store's find method", _ember['default'].typeOf(id) === 'string' || _ember['default'].typeOf(id) === 'number'); 75384 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75385 75386 return this.findRecord(modelName, id); 75387 }, 75388 75389 /** 75390 This method returns a record for a given type and id combination. 75391 The `findRecord` method will always resolve its promise with the same 75392 object for a given type and `id`. 75393 The `findRecord` method will always return a **promise** that will be 75394 resolved with the record. 75395 Example 75396 ```app/routes/post.js 75397 import Ember from 'ember'; 75398 export default Ember.Route.extend({ 75399 model: function(params) { 75400 return this.store.findRecord('post', params.post_id); 75401 } 75402 }); 75403 ```
75404 If the record is not yet available, the store will ask the adapter's `find` 75405 method to find the necessary data. If the record is already present in the 75406 store, it depends on the reload behavior _when_ the returned promise 75407 resolves. 75408 ### Reloading 75409 The reload behavior is configured either via the passed `options` hash or 75410 the result of the adapter's `shouldReloadRecord`. 75411 If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates 75412 to `true`, then the returned promise resolves once the adapter returns 75413 data, regardless if the requested record is already in the store: 75414 ```js 75415 store.push({ 75416 data: { 75417 id: 1, 75418 type: 'post', 75419 revision: 1 75420 } 75421 }); 75422 // adapter#findRecord resolves with 75423 // [ 75424 // { 75425 // id: 1, 75426 // type: 'post', 75427 // revision: 2 75428 // } 75429 // ] 75430 store.findRecord('post', 1, { reload: true }).then(function(post) { 75431 post.get("revision"); // 2 75432 }); 75433 ``` 75434 If no reload is indicated via the abovementioned ways, then the promise 75435 immediately resolves with the cached version in the store. 75436 ### Background Reloading 75437 Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`, 75438 then a background reload is started, which updates the records' data, once 75439 it is available: 75440 ```js 75441
75441// app/adapters/post.js 75442 import ApplicationAdapter from "./application"; 75443 export default ApplicationAdapter.extend({ 75444 shouldReloadRecord(store, snapshot) { 75445 return false; 75446 }, 75447 shouldBackgroundReloadRecord(store, snapshot) { 75448 return true; 75449 } 75450 }); 75451 // ... 75452 store.push({ 75453 data: { 75454 id: 1, 75455 type: 'post', 75456 revision: 1 75457 } 75458 }); 75459 var blogPost = store.findRecord('post', 1).then(function(post) { 75460 post.get('revision'); // 1 75461 }); 75462 // later, once adapter#findRecord resolved with 75463 // [ 75464 // { 75465 // id: 1, 75466 // type: 'post', 75467 // revision: 2 75468 // } 75469 // ] 75470 blogPost.get('revision'); // 2 75471 ``` 75472 If you would like to force or prevent background reloading, you can set a 75473 boolean value for `backgroundReload` in the options object for 75474 `findRecord`. 75475 ```app/routes/post/edit.js 75476 import Ember from 'ember'; 75477 export default Ember.Route.extend({ 75478 model: function(params) { 75479 return this.store.findRecord('post', params.post_id, { backgroundReload: false }); 75480 } 75481 }); 75482 ``` 75483 If you pass an object on the `adapterOptions` property of the options 75484 argument it will be passed to you adapter via the snapshot 75485 ```app/routes/post/edit.js 75486 import Ember from 'ember'; 75487 export default Ember.Route.extend({ 75488 model: function(params) { 75489 return this.store.findRecord('post', params.post_id, { 75490 adapterOptions: { subscribe: false } 75491 }); 75492 } 75493 }); 75494 ``` 75495 ```app/adapters/post.js 75496 import MyCustomAdapter from './custom-adapter'; 75497 export default MyCustomAdapter.extend({ 75498 findRecord: function(store, type, id, snapshot) { 75499 if (snapshot.adapterOptions.subscribe) { 75500 // ... 75501 } 75502 // ... 75503 } 75504 }); 75505 ``` 75506 See [peekRecord](#method_peekRecord) to get the cached version of a record. 75507 @since 1.13.0 75508 @method findRecord 75509 @param {String} modelName 75510 @param {(String|Integer)} id 75511 @param {Object} options 75512 @return {Promise} promise 75513 */ 75514 findRecord: function findRecord(modelName, id, options) { 75515 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's findRecord method", isPresent(modelName)); 75516 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75517 (0, _emberDataPrivateDebug.assert)(badIdFormatAssertion, typeof id === 'string' && id.length > 0 || typeof id === 'number' && !isNaN(id)); 75518 75519 var internalModel = this._internalModelForId(modelName, id); 75520 options = options || {}; 75521 75522 if (!this.hasRecordForId(modelName, id)) { 75523 return this._findByInternalModel(internalModel, options); 75524 } 75525 75526 var fetchedInternalModel = this._findRecord(internalModel, options); 75527 75528 return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); 75529 }, 75530 75531 _findRecord: function _findRecord(internalModel, options) { 75532 // Refetch if the reload option is passed 75533 if (options.reload) { 75534 return this.scheduleFetch(internalModel, options); 75535 } 75536 75537 var snapshot = internalModel.createSnapshot(options); 75538 var typeClass = internalModel.type; 75539 var adapter = this.adapterFor(typeClass.modelName); 75540 75541 // Refetch the record if the adapter thinks the record is stale 75542 if (adapter.shouldReloadRecord(this, snapshot)) { 75543 return this.scheduleFetch(internalModel, options); 75544 } 75545 75546 if (options.backgroundReload === false) { 75547 return Promise.resolve(internalModel); 75548 } 75549 75550 // Trigger the background refetch if backgroundReload option is passed 75551 if (options.backgroundReload || adapter.shouldBackgroundReloadRecord(this, snapshot)) { 75552 this.scheduleFetch(internalModel, options); 75553 } 75554 75555 // Return the cached record 75556 return Promise.resolve(internalModel); 75557 }, 75558 75559 _findByInternalModel: function _findByInternalModel(internalModel, options) { 75560 options = options || {}; 75561 75562 if (options.preload) { 75563 internalModel._preloadData(options.preload); 75564 } 75565 75566 var fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); 75567 75568 return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with i
75568d: " + get(internalModel, 'id')); 75569 }, 75570 75571 _findEmptyInternalModel: function _findEmptyInternalModel(internalModel, options) { 75572 if (internalModel.isEmpty()) { 75573 return this.scheduleFetch(internalModel, options); 75574 } 75575 75576 //TODO double check about reloading 75577 if (internalModel.isLoading()) { 75578 return internalModel._loadingPromise; 75579 } 75580 75581 return Promise.resolve(internalModel); 75582 }, 75583 75584 /** 75585 This method makes a series of requests to the adapter's `find` method 75586 and returns a promise that resolves once they are all loaded. 75587 @private 75588 @method findByIds 75589 @param {String} modelName 75590 @param {Array} ids 75591 @return {Promise} promise 75592 */ 75593 findByIds: function findByIds(modelName, ids) { 75594 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's findByIds method", isPresent(modelName)); 75595 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75596 var promises = new Array(ids.length); 75597 75598 for (var i = 0; i < ids.length; i++) { 75599 promises[i] = this.findRecord(modelName, ids[i]); 75600 } 75601 75602 return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(_ember['default'].RSVP.all(promises).then(_ember['default'].A, null, "DS: Store#findByIds of " + modelName + " complete")); 75603 }, 75604 75605 /** 75606 This method is called by `findRecord` if it discovers that a particular 75607 type/id pair hasn't been loaded yet to kick off a request to the 75608 adapter. 75609 @method fetchRecord 75610 @private 75611 @param {InternalModel} internalModel model 75612 @return {Promise} promise 75613 */ 75614 // TODO rename this to have an underscore 75615 fetchRecord: function fetchRecord(internalModel, options) { 75616 var typeClass = internalModel.type; 75617 var id = internalModel.id; 75618 var adapter = this.adapterFor(typeClass.modelName); 75619 75620 (0, _emberDataPrivateDebug.assert)("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); 75621 (0, _emberDataPrivateDebug.assert)("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); 75622 75623 var promise = (0, _emberDataPrivateSystemStoreFinders._find)(adapter, this, typeClass, id, internalModel, options); 75624 return promise; 75625 }, 75626 75627 scheduleFetchMany: function scheduleFetchMany(records) { 75628 var internalModels = new Array(records.length); 75629 var fetches = new Array(records.length); 75630 for (var i = 0; i < records.length; i++) { 75631 internalModels[i] = records[i]._internalModel; 75632 } 75633 75634 for (var i = 0; i < internalModels.length; i++) { 75635 fetches[i] = this.scheduleFetch(internalModels[i]); 75636 } 75637 75638 return _ember['default'].RSVP.Promise.all(fetches); 75639 }, 75640 75641 scheduleFetch: function scheduleFetch(internalModel, options) { 75642 var typeClass = internalModel.type; 75643 75644 if (internalModel._loadingPromise) { 75645 return internalModel._loadingPromise; 75646 } 75647 75648 var resolver = _ember['default'].RSVP.defer('Fetching ' + typeClass + 'with id: ' + internalModel.id); 75649 var pendingFetchItem = { 75650 record: internalModel, 75651 resolver: resolver, 75652 options: options 75653 }; 75654 var promise = resolver.promise; 75655 75656 internalModel.loadingData(promise); 75657 75658 if (!this._pendingFetch.get(typeClass)) { 75659 this._pendingFetch.set(typeClass, [pendingFetchItem]); 75660 } else { 75661 this._pendingFetch.get(typeClass).push(pendingFetchItem); 75662 } 75663 _ember['default'].run.scheduleOnce('afterRender', this, this.flushAllPendingFetches); 75664 75665 return promise; 75666 }, 75667 75668 flushAllPendingFetches: function flushAllPendingFetches() { 75669 if (this.isDestroyed || this.isDestroying) { 75670 return; 75671 } 75672 75673 this._pendingFetch.forEach(this._flushPendingFetchForType, this); 75674 this._pendingFetch = Map.create(); 75675 }, 75676 75677 _flushPendingFetchForType: function _flushPendingFetchForType(pendingFetchItems, typeClass) { 75678 var store = this; 75679 var adapter = store.adapterFor(typeClass.modelName); 75680 var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; 75681 var records = _ember['default'].A(pendingFetchItems).mapBy('record'); 75682 75683 function _fetchRecord(recordResolverPair) { 75684 recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record, recordResolverPair.options)); // TODO adapter options 75685 } 75686 75687 function resolveFoundRecords(records) { 75688 records.forEach(function (record) { 75689 var pair = _ember['default'].A(pendingFetchItems).findBy('record', record); 75690 if (pair) { 75691 var resolver = pair.resolver; 75692 resolver.resolve(record); 75693 } 75694 }); 75695 return records; 75696 } 75697 75698 function makeMissingRecordsRejector(requestedRecords) { 75699 return function rejectMissingRecords(resolvedRecords) { 75700 resolvedRecords = _ember['default'].A(resolvedRecords); 75701 var missingRecords = requestedRecords.reject(function (record) { 75702 return resolvedRecords.contains(record); 75703 }); 75704 if (missingRecords.length) { 75705 (0, _emberDataPrivateDebug.warn)('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + _ember['default'].inspect(_ember['default'].A(missingRecords).mapBy('id')), false, { 75706 id: 'ds.store.missing-records-from-adapter' 75707 }); 75708 } 75709 rejectRecords(missingRecords); 75710 }; 75711 } 75712 75713 function makeRecordsRejector(records) { 75714 return function (error) { 75715 rejectRecords(records, error); 75716 }; 75717 } 75718 75719 function rejectRecords(records, error) { 75720 records.forEach(function (record) { 75721 var pair = _ember['default'].A(pendingFetchItems).findBy('record', record); 75722 if (pair) { 75723 var resolver = pair.resolver; 75724 resolver.reject(error); 75725 } 75726 }); 75727 } 75728 75729 if (pendingFetchItems.length === 1) { 75730 _fetchRecord(pendingFetchItems[0]); 75731 } else if (shouldCoalesce) { 75732 75733 // TODO: Improve records => snapshots => records => snapshots 75734 // 75735 // We want to provide records to all store methods and snapshots to all 75736 // adapter methods. To make sure we're doing that we're providing an array 75737 // of snapshots to adapter.groupRecordsForFindMany(), which in turn will 75738 // return grouped snapshots instead of grouped records. 75739 // 75740 // But since the _findMany() finder is a store method we need to get the 75741 // records from the grouped snapshots even though the _findMany() finder 75742 // will once again convert the records to snapshots for adapter.findMany() 75743 75744 var snapshots = _ember['default'].A(records).invoke('createSnapshot'); 75745 var groups = adapter.groupRecordsForFindMany(this, snapshots); 75746 groups.forEach(function (groupOfSnapshots) { 75747 var groupOfRecords = _ember['default'].A(groupOfSnapshots).mapBy('_internalModel'); 75748 var requestedRecords = _ember['default'].A(groupOfRecords); 75749 var ids = requestedRecords.mapBy('id'); 75750 if (ids.length > 1) { 75751 (0, _emberDataPrivateSystemStoreFinders._findMany)(adapter, store, typeClass, ids, requestedRecords).then(resolveFoundRecords).then(makeMissingRecordsRejector(requestedRecords)).then(null, makeRecordsRejector(requestedRecords)); 75752 } else if (ids.length === 1) { 75753 var pair = _ember['default'].A(pendingFetchItems).findBy('record', groupOfRecords[0]);
75754 _fetchRecord(pair); 75755 } else { 75756 (0, _emberDataPrivateDebug.assert)("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); 75757 } 75758 }); 75759 } else { 75760 pendingFetchItems.forEach(_fetchRecord); 75761 } 75762 }, 75763 75764 /** 75765 Get the reference for the specified record. 75766 Example 75767 ```javascript 75768 var userRef = store.getReference('user', 1); 75769 // check if the user is loaded 75770 var isLoaded = userRef.value() !== null; 75771 // get the record of the reference (null if not yet available) 75772 var user = userRef.value(); 75773 // get the identifier of the reference 75774 if (userRef.remoteType() === "id") { 75775 var id = userRef.id(); 75776 } 75777 // load user (via store.find) 75778 userRef.load().then(...) 75779 // or trigger a reload 75780 userRef.reload().then(...) 75781 // provide data for reference 75782 userRef.push({ id: 1, username: "@user" }).then(function(user) { 75783 userRef.value() === user; 75784 }); 75785 ``` 75786 @method getReference 75787 @param {String} type 75788 @param {String|Integer} id 75789 @since 2.5.0 75790 @return {RecordReference} 75791 */ 75792 getReference: function getReference(type, id) { 75793 return this._internalModelForId(type, id).recordReference; 75794 }, 75795 75796 /** 75797 Get a record by a given type and ID without triggering a fetch. 75798 This method will synchronously return the record if it is available in the store, 75799 otherwise it will return `null`. A record is available if it has been fetched earlier, or 75800 pushed manually into the store. 75801 _Note: This is an synchronous method and does not return a promise._ 75802 ```js 75803 var post = store.peekRecord('post', 1); 75804 post.get('id'); // 1 75805 ``` 75806 @since 1.13.0 75807 @method peekRecord 75808 @param {String} modelName 75809 @param {String|Integer} id 75810 @return {DS.Model|null} record 75811 */ 75812 peekRecord: function peekRecord(modelName, id) { 75813 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's peekRecord method", isPresent(modelName)); 75814 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75815 if (this.hasRecordForId(modelName, id)) { 75816 return this._internalModelForId(modelName, id).getRecord(); 75817 } else { 75818 return null; 75819 } 75820 }, 75821 75822 /** 75823 This method is called by the record's `reload` method. 75824 This method calls the adapter's `find` method, which returns a promise. When 75825 **that** promise resolves, `reloadRecord` will resolve the promise returned 75826 by the record's `reload`. 75827 @method reloadRecord 75828 @private 75829 @param {DS.Model} internalModel 75830 @return {Promise} promise 75831 */ 75832 reloadRecord: function reloadRecord(internalModel) { 75833 var modelName = internalModel.type.modelName; 75834 var adapter = this.adapterFor(modelName); 75835 var id = internalModel.id; 75836 75837 (0, _emberDataPrivateDebug.assert)("You cannot reload a re
75837cord without an ID", id); 75838 (0, _emberDataPrivateDebug.assert)("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); 75839 (0, _emberDataPrivateDebug.assert)("You tried to reload a record but your adapter does not implement `findRecord`", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); 75840 75841 return this.scheduleFetch(internalModel); 75842 }, 75843 75844 /** 75845 Returns true if a record for a given type and ID is already loaded. 75846 @method hasRecordForId 75847 @param {(String|DS.Model)} modelName 75848 @param {(String|Integer)} inputId 75849 @return {Boolean} 75850 */ 75851 hasRecordForId: function hasRecordForId(modelName, inputId) { 75852 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's hasRecordForId method", isPresent(modelName)); 75853 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75854 var typeClass = this.modelFor(modelName); 75855 var id = (0, _emberDataPrivateSystemCoerceId['default'])(inputId); 75856 var internalModel = this.typeMapFor(typeClass).idToRecord[id]; 75857 return !!internalModel && internalModel.isLoaded(); 75858 }, 75859 75860 /** 75861 Returns id record for a given type and ID. If one isn't already loaded, 75862 it builds a new record and leaves it in the `empty` state. 75863 @method recordForId 75864 @private 75865 @param {String} modelName 75866 @param {(String|Integer)} id 75867 @return {DS.Model} record 75868 */ 75869 recordForId: function recordForId(modelName, id) { 75870 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's recordForId method", isPresent(modelName)); 75871 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75872 return this._internalModelForId(modelName, id).getRecord(); 75873 }, 75874 75875 _internalModelForId: function _internalModelForId(typeName, inputId) { 75876 var typeClass = this.modelFor(typeName); 75877 var id = (0, _emberDataPrivateSystemCoerceId['default'])(inputId); 75878 var idToRecord = this.typeMapFor(typeClass).idToRecord; 75879 var record = idToRecord[id]; 75880 75881 if (!record || !idToRecord[id]) { 75882 record = this.buildInternalModel(typeClass, id); 75883 } 75884 75885 return record; 75886 }, 75887 75888 /** 75889 @method findMany 75890 @private 75891 @param {Array} internalModels 75892 @return {Promise} promise 75893 */ 75894 findMany: function findMany(internalModels) { 75895 var finds = new Array(internalModels.length); 75896 75897 for (var i = 0; i < internalModels.length; i++) { 75898 finds[i] = this._findByInternalModel(internalModels[i]); 75899 } 75900 75901 return Promise.all(finds); 75902 }, 75903 75904 /** 75905 If a relationship was originally populated by the adapter as a link 75906 (as opposed to a list of IDs), this method is called when the 75907 relationship is fetched. 75908 The link (which is usually a URL) is passed through unchanged, so the 75909 adapter can make whatever request it wants. 75910 The usual use-case is for the server to register a URL as a link, and 75911 then use that URL in the future to make a request for the relationship. 75912 @method findHasMany 75913 @private 75914 @param {DS.Model} owner 75915 @param {any} link 75916 @param {(Relationship)} relationship 75917 @return {Promise} promise 75918 */ 75919 findHasMany: function findHasMany(owner, link, relationship) { 75920 var adapter = this.adapterFor(owner.type.modelName); 75921 75922 (0, _emberDataPrivateDebug.assert)("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); 75923 (0, _emberDataPrivateDebug.assert)("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); 75924 75925 return (0, _emberDataPrivateSystemStoreFinders._findHasMany)(adapter, this, owner, link, relationship
75925); 75926 }, 75927 75928 /** 75929 @method findBelongsTo 75930 @private 75931 @param {DS.Model} owner 75932 @param {any} link 75933 @param {Relationship} relationship 75934 @return {Promise} promise 75935 */ 75936 findBelongsTo: function findBelongsTo(owner, link, relationship) { 75937 var adapter = this.adapterFor(owner.type.modelName); 75938 75939 (0, _emberDataPrivateDebug.assert)("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); 75940 (0, _emberDataPrivateDebug.assert)("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); 75941 75942 return (0, _emberDataPrivateSystemStoreFinders._findBelongsTo)(adapter, this, owner, link, relationship); 75943 }, 75944 75945 /** 75946 This method delegates a query to the adapter. This is the one place where 75947 adapter-level semantics are exposed to the application. 75948 Exposing queries this way seems preferable to creating an abstract query 75949 language for all server-side queries, and then require all adapters to 75950 implement them. 75951 --- 75952 If you do something like this: 75953 ```javascript 75954 store.query('person', { page: 1 }); 75955 ``` 75956 The call made to the server, using a Rails backend, will look something like this: 75957 ``` 75958 Started GET "/api/v1/person?page=1" 75959 Processing by Api::V1::PersonsController#index as HTML 75960 Parameters: { "page"=>"1" } 75961 ``` 75962 --- 75963 If you do something like this: 75964 ```javascript 75965 store.query('person', { ids: [1, 2, 3] }); 75966 ``` 75967 The call to the server, using a Rails backend, will look something like this: 75968 ``` 75969 Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" 75970 Processing by Api::V1::PersonsController#index as HTML 75971 Parameters: { "ids" => ["1", "2", "3"] } 75972 ``` 75973 This method returns a promise, which is resolved with a `RecordArray` 75974 once the server returns. 75975 @since 1.13.0 75976 @method query 75977 @param {String} modelName 75978 @param {any} query an opaque query to be used by the adapter 75979 @return {Promise} promise 75980 */ 75981 query: function query(modelName, _query2) { 75982 return this._query(modelName, _query2); 75983 }, 75984 75985 _query: function _query(modelName, query, array) { 75986 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's query method", isPresent(modelName)); 75987 (0, _emberDataPrivateDebug.assert)("You need to pass a query hash to the store's query method", query); 75988 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 75989 var typeClass = this.modelFor(modelName); 75990 array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(typeClass, query); 75991 75992 var adapter = this.adapterFor(modelName); 75993 75994 (0, _emberDataPrivateDebug.assert)("You tried to load a query but you have no adapter (for " + typeClass + ")", adapter); 75995 (0, _emberDataPrivateDebug.assert)("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function'); 75996 75997 return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._query)(adapter, this, typeClass, query, array)); 75998 }, 75999 76000 /** 76001 This method makes a request for one record, where the `id` is not known 76002 beforehand (if the `id` is known, use `findRecord` instead). 76003 This method can be used when it is certain that the server will return a 76004 single object for the primary data. 76005 Let's assume our API provides an endpoint for the currently logged in user 76006 via: 76007 ``` 76008 // GET /api/current_user 76009 { 76010 user: { 76011 id: 1234, 76012 username: 'admin' 76013 } 76014 } 76015 ``` 76016 Since the specific `id` of the `user` is not known beforehand, we can use 76017 `queryRecord` to get the user: 76018 ```javascript 76019 store.queryRecord('user', {}).then(function(user) { 76020 let username = user.get('username'); 76021 console.log(`Currently logged in as ${username}`); 76022 }); 76023 ``` 76024 The request is made through the adapters' `queryRecord`: 76025 ```javascript 76026
76026// app/adapters/user.js 76027 import DS from "ember-data"; 76028 export default DS.Adapter.extend({ 76029 queryRecord(modelName, query) { 76030 return Ember.$.getJSON("/api/current_user"); 76031 } 76032 }); 76033 ``` 76034 Note: the primary use case for `store.queryRecord` is when a single record 76035 is queried and the `id` is not known beforehand. In all other cases 76036 `store.query` and using the first item of the array is likely the preferred 76037 way: 76038 ``` 76039 // GET /users?username=unique 76040 { 76041 data: [{ 76042 id: 1234, 76043 type: 'user', 76044 attributes: { 76045 username: "unique" 76046 } 76047 }] 76048 } 76049 ``` 76050 ```javascript 76051 store.query('user', { username: 'unique' }).then(function(users) { 76052 return users.get('firstObject'); 76053 }).then(function(user) { 76054 let id = user.get('id'); 76055 }); 76056 ``` 76057 This method returns a promise, which resolves with the found record. 76058 If the adapter returns no data for the primary data of the payload, then 76059 `queryRecord` resolves with `null`: 76060 ``` 76061 // GET /users?username=unique 76062 { 76063 data: null 76064 } 76065 ``` 76066 ```javascript 76067 store.queryRecord('user', { username: 'unique' }).then(function(user) { 76068 console.log(user); // null 76069 }); 76070 ``` 76071 @since 1.13.0 76072 @method queryRecord 76073 @param {String} modelName 76074 @param {any} query an opaque query to be used by the adapter 76075 @return {Promise} promise which resolves with the found record or `null` 76076 */ 76077 queryRecord: function queryRecord(modelName, query) { 76078 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's queryRecord method", isPresent(modelName)); 76079 (0, _emberDataPrivateDebug.assert)("You need to pass a query hash to the store's queryRecord method", query); 76080 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76081 76082 var typeClass = this.modelFor(modelName); 76083 var adapter = this.adapterFor(modelName); 76084 76085 (0, _emberDataPrivateDebug.assert)("You tried to make a query but you have no adapter (for " + typeClass + ")", adapter); 76086 (0, _emberDataPrivateDebug.assert)("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); 76087 76088 return (0, _emberDataPrivateSystemPromiseProxies.promiseObject)((0, _emberDataPrivateSystemStoreFinders._queryRecord)(adapter, this, typeClass, query)); 76089 }, 76090 76091 /** 76092 `findAll` asks the adapter's `findAll` method to find the records for the 76093 given type, and returns a promise which will resolve with all records of 76094 this type present in the store, even if the adapter only returns a subset 76095 of them. 76096 ```app/routes/authors.js 76097 import Ember from 'ember'; 76098 export default Ember.Route.extend({ 76099 model: function(params) { 76100 return this.store.findAll('author'); 76101 } 76102 }); 76103 ``` 76104 _When_ the returned promise resolves depends on the reload behavior, 76105 configured via the passed `options` hash and the result of the adapter's 76106 `shouldReloadAll` method. 76107 ### Reloading 76108 If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to 76109 `true`, then the returned promise resolves once the adapter returns data, 76110 regardless if there are already records in the store: 76111 ```js 76112 store.push({ 76113 data: { 76114 id: 'first', 76115 type: 'author' 76116 } 76117 }); 76118 // adapter#findAll resolves with 76119 // [ 76120 // { 76121 // id: 'second', 76122 // type: 'author' 76123 // } 76124 // ] 76125 store.findAll('author', { reload: true }).then(function(authors) { 76126 authors.getEach("id"); // ['first', 'second'] 76127 }); 76128 ``` 76129 If no reload is indicated via the abovementioned ways, then the promise 76130 immediately resolves with all the records currently loaded in the store.
76131 ### Background Reloading 76132 Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`, 76133 then a background reload is started. Once this resolves, the array with 76134 which the promise resolves, is updated automatically so it contains all the 76135 records in the store: 76136 ```js 76137
76137// app/adapters/application.js 76138 export default DS.Adapter.extend({ 76139 shouldReloadAll(store, snapshotsArray) { 76140 return false; 76141 }, 76142 shouldBackgroundReloadAll(store, snapshotsArray) { 76143 return true; 76144 } 76145 }); 76146 // ... 76147 store.push({ 76148 data: { 76149 id: 'first', 76150 type: 'author' 76151 } 76152 }); 76153 var allAuthors; 76154 store.findAll('author').then(function(authors) { 76155 authors.getEach('id'); // ['first'] 76156 allAuthors = authors; 76157 }); 76158 // later, once adapter#findAll resolved with 76159 // [ 76160 // { 76161 // id: 'second', 76162 // type: 'author' 76163 // } 76164 // ] 76165 allAuthors.getEach('id'); // ['first', 'second'] 76166 ``` 76167 If you would like to force or prevent background reloading, you can set a 76168 boolean value for `backgroundReload` in the options object for 76169 `findAll`. 76170 ```app/routes/post/edit.js 76171 import Ember from 'ember'; 76172 export default Ember.Route.extend({ 76173 model: function() { 76174 return this.store.findAll('post', { backgroundReload: false }); 76175 } 76176 }); 76177 ``` 76178 If you pass an object on the `adapterOptions` property of the options 76179 argument it will be passed to you adapter via the `snapshotRecordArray` 76180 ```app/routes/posts.js 76181 import Ember from 'ember'; 76182 export default Ember.Route.extend({ 76183 model: function(params) { 76184 return this.store.findAll('post', { 76185 adapterOptions: { subscribe: false } 76186 }); 76187 } 76188 }); 76189 ``` 76190 ```app/adapters/post.js 76191 import MyCustomAdapter from './custom-adapter'; 76192 export default MyCustomAdapter.extend({ 76193 findAll: function(store, type, sinceToken, snapshotRecordArray) { 76194 if (snapshotRecordArray.adapterOptions.subscribe) { 76195 // ... 76196 } 76197 // ... 76198 } 76199 }); 76200 ``` 76201 See [peekAll](#method_peekAll) to get an array of current records in the 76202 store, without waiting until a reload is finished. 76203 See [query](#method_query) to only get a subset of records from the server. 76204 @since 1.13.0 76205 @method findAll 76206 @param {String} modelName 76207 @param {Object} options 76208 @return {Promise} promise 76209 */ 76210 findAll: function findAll(modelName, options) { 76211 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's findAll method", isPresent(modelName)); 76212 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76213 var typeClass = this.modelFor(modelName); 76214 76215 return this._fetchAll(typeClass, this.peekAll(modelName), options); 76216 }, 76217 76218 /** 76219 @method _fetchAll 76220 @private 76221 @param {DS.Model} typeClass 76222 @param {DS.RecordArray} array 76223 @return {Promise} promise 76224 */ 76225 _fetchAll: function _fetchAll(typeClass, array, options) { 76226 options = options || {}; 76227 var adapter = this.adapterFor(typeClass.modelName); 76228 var sinceToken = this.typeMapFor(typeClass).metadata.since; 76229 76230 (0, _emberDataPrivateDebug.assert)("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); 76231 (0, _emberDataPrivateDebug.assert)("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); 76232 76233 set(array, 'isUpdating', true); 76234 76235 if (options.reload) { 76236 return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, typeClass, sinceToken, options)); 76237 } 76238 76239 var snapshotArray = array.createSnapshot(options); 76240 76241 if (adapter.shouldReloadAll(this, snapshotArray)) { 76242 return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, typeClass, sinceToken, options)); 76243 } 76244 76245 if (options.backgroundReload === false) { 76246 return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(Promise.resolve(array)); 76247 } 76248
76249 if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { 76250 (0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, typeClass, sinceToken, options); 76251 } 76252 76253 return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(Promise.resolve(array)); 76254 }, 76255 76256 /** 76257 @method didUpdateAll 76258 @param {DS.Model} typeClass 76259 @private 76260 */ 76261 didUpdateAll: function didUpdateAll(typeClass) { 76262 var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); 76263 set(liveRecordArray, 'isUpdating', false); 76264 }, 76265 76266 /** 76267 This method returns a filtered array that contains all of the 76268 known records for a given type in the store. 76269 Note that because it's just a filter, the result will contain any 76270 locally created records of the type, however, it will not make a 76271 request to the backend to retrieve additional records. If you 76272 would like to request all the records from the backend please use 76273 [store.findAll](#method_findAll). 76274 Also note that multiple calls to `peekAll` for a given type will always 76275 return the same `RecordArray`. 76276 Example 76277 ```javascript 76278 var localPosts = store.peekAll('post'); 76279 ``` 76280 @since 1.13.0 76281 @method peekAll 76282 @param {String} modelName 76283 @return {DS.RecordArray} 76284 */ 76285 peekAll: function peekAll(modelName) { 76286 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's peekAll method", isPresent(modelName)); 76287 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76288 var typeClass = this.modelFor(modelName); 76289 76290 var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); 76291 this.recordArrayManager.populateLiveRecordArray(liveRecordArray, typeClass); 76292 76293 return liveRecordArray; 76294 }, 76295 76296 /** 76297 This method unloads all records in the store. 76298 Optionally you can pass a type which unload all records for a given type. 76299 ```javascript 76300 store.unloadAll(); 76301 store.unloadAll('post'); 76302 ``` 76303 @method unloadAll 76304 @param {String=} modelName 76305 */ 76306 unloadAll: function unloadAll(modelName) { 76307 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), !modelName || typeof modelName === 'string'); 76308 if (arguments.length === 0) { 76309 var typeMaps = this.typeMaps; 76310 var keys = Object.keys(typeMaps); 76311 var types = new Array(keys.length); 76312 76313 for (var i = 0; i < keys.length; i++) { 76314 types[i] = typeMaps[keys[i]]['type'].modelName; 76315 } 76316 76317 types.forEach(this.unloadAll, this); 76318 } else { 76319 var typeClass = this.modelFor(modelName); 76320 var typeMap = this.typeMapFor(typeClass); 76321 var records = typeMap.records.slice(); 76322 var record = undefined; 76323 76324 for (var i = 0; i < records.length; i++) { 76325 record = records[i]; 76326 record.unloadRecord(); 76327 record.destroy(); // maybe within unloadRecord 76328 } 76329 76330 typeMap.metadata = new _emberDataPrivateSystemEmptyObject['default'](); 76331 } 76332 }, 76333 76334 /** 76335 Takes a type and filter function, and returns a live RecordArray that 76336 remains up to date as new records are loaded into the store or created 76337 locally. 76338 The filter function takes a materialized record, and returns true 76339 if the record should be included in the filter and false if it should 76340 not. 76341 Example 76342 ```javascript 76343 store.filter('post', function(post) { 76344 return post.get('unread'); 76345 }); 76346 ``` 76347 The filter function is called once on all records for the type when 76348 it is created, and then once on each newly loaded or created record. 76349 If any of a record's properties change, or if it changes state, the 76350 filter function will be invoked again to determine whether it should 76351 still be in the array. 76352 Optionally you can pass a query, which is the equivalent of calling 76353 [query](#method_query) with that same query, to fetch additional records 76354 from the server. The results returned by the server could then appear 76355 in the filter if they match the filter function. 76356 The query itself is not used to filter records, it's only sent to your 76357 server for you to be able to do server-side filtering. The filter 76358 function will be applied on the returned results regardless. 76359 Example 76360 ```javascript 76361 store.filter('post', { unread: true }, function(post) { 76362 return post.get('unread'); 76363 }).then(function(unreadPosts) { 76364 unreadPosts.get('length'); // 5 76365 var unreadPost = unreadPosts.objectAt(0); 76366 unreadPost.set('unread', false); 76367 unreadPosts.get('length'); // 4 76368 }); 76369 ``` 76370 @method filter 76371 @private 76372 @param {String} modelName 76373 @param {Object} query optional query 76374 @param {Function} filter 76375 @return {DS.PromiseArray} 76376 @deprecated 76377 */ 76378 filter: function filter(modelName, query, _filter) { 76379 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's filter method", isPresent(modelName)); 76380 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76381 76382 if (!_ember['default'].ENV.ENABLE_DS_FILTER) { 76383 (0, _emberDataPrivateDebug.assert)('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); 76384 } 76385 76386 var promise; 76387 var length = arguments.length; 76388 var array; 76389 var hasQuery = length === 3; 76390 76391 // allow an optional server query 76392 if (hasQuery) { 76393 promise = this.query(modelName, query); 76394 } else if (arguments.length === 2) { 76395 _filter = query; 76396 } 76397 76398 modelName = this.modelFor(modelName); 76399 76400 if (hasQuery) { 76401 array = this.recordArrayManager.createFilteredRecordArray(modelName, _filter, query); 76402 } else { 76403 array = this.recordArrayManager.createFilteredRecordArray(modelName, _filter); 76404 } 76405 76406 promise = promise || Promise.resolve(array); 76407 76408 return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(promise.then(function () { 76409 return array; 76410 }, null, 'DS: Store#filter of ' + modelName)); 76411 }, 76412 76413 /** 76414 This method returns if a certain record is already loaded 76415 in the store. Use this function to know beforehand if a findRecord() 76416 will result in a request or that it will be a cache hit. 76417 Example 76418 ```javascript 76419 store.recordIsLoaded('post', 1); // false 76420 store.findRecord('post', 1).then(function() { 76421 store.recordIsLoaded('post', 1); // true 76422 }); 76423 ``` 76424 @method recordIsLoaded 76425 @param {String} modelName 76426 @param {string} id 76427 @return {boolean} 76428 */ 76429 recordIsLoaded: function recordIsLoaded(modelName, id) { 76430 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's recordIsLoaded method", isPresent(modelName)); 76431 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76432 return this.hasRecordForId(modelName, id); 76433 }, 76434 76435 // ............ 76436 // . UPDATING . 76437 // ............ 76438 76439 /** 76440 If the adapter updates attributes the record will notify 76441 the store to update its membership in any filters. 76442 To avoid thrashing, this method is invoked only once per 76443 run loop per record.
76444 @method dataWasUpdated 76445 @private 76446 @param {Class} type 76447 @param {InternalModel} internalModel 76448 */ 76449 dataWasUpdated: function dataWasUpdated(type, internalModel) { 76450 this.recordArrayManager.recordDidChange(internalModel); 76451 }, 76452 76453 // .............. 76454 // . PERSISTING . 76455 // .............. 76456 76457 /** 76458 This method is called by `record.save`, and gets passed a 76459 resolver for the promise that `record.save` returns. 76460 It schedules saving to happen at the end of the run loop. 76461 @method scheduleSave 76462 @private 76463 @param {InternalModel} internalModel 76464 @param {Resolver} resolver 76465 @param {Object} options 76466 */ 76467 scheduleSave: function scheduleSave(internalModel, resolver, options) { 76468 var snapshot = internalModel.createSnapshot(options); 76469 internalModel.flushChangedAttributes(); 76470 internalModel.adapterWillCommit(); 76471 this._pendingSave.push({ 76472 snapshot: snapshot, 76473 resolver: resolver 76474 }); 76475 once(this, 'flushPendingSave'); 76476 }, 76477 76478 /** 76479 This method is called at the end of the run loop, and 76480 flushes any records passed into `scheduleSave` 76481 @method flushPendingSave 76482 @private 76483 */ 76484 flushPendingSave: function flushPendingSave() { 76485 var _this = this; 76486 76487 var pending = this._pendingSave.slice(); 76488 this._pendingSave = []; 76489 76490 pending.forEach(function (pendingItem) { 76491 var snapshot = pendingItem.snapshot; 76492 var resolver = pendingItem.resolver; 76493 var record = snapshot._internalModel; 76494 var adapter = _this.adapterFor(record.type.modelName); 76495 var operation; 76496 76497 if (get(record, 'currentState.stateName') === 'root.deleted.saved') { 76498 return resolver.resolve(); 76499 } else if (record.isNew()) { 76500 operation = 'createRecord'; 76501 } else if (record.isDeleted()) { 76502 operation = 'deleteRecord'; 76503 } else { 76504 operation = 'updateRecord'; 76505 } 76506 76507 resolver.resolve(_commit(adapter, _this, operation, snapshot)); 76508 }); 76509 }, 76510 76511 /** 76512 This method is called once the promise returned by an 76513 adapter's `createRecord`, `updateRecord` or `deleteRecord` 76514 is resolved. 76515 If the data provides a server-generated ID, it will 76516 update the record and the store's indexes. 76517 @method didSaveRecord 76518 @private 76519 @param {InternalModel} internalModel the in-flight internal model 76520 @param {Object} data optional data (see above) 76521 */ 76522 didSaveRecord: function didSaveRecord(internalModel, dataArg) { 76523 var data; 76524 if (dataArg) { 76525 data = dataArg.data; 76526 } 76527 if (data) { 76528 // normalize relationship IDs into records 76529 this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); 76530 this.updateId(internalModel, data); 76531 } 76532 76533 //We first make sure the primary data has been updated 76534 //TODO try to move notification to the user to the end of the runloop 76535 internalModel.adapterDidCommit(data); 76536 }, 76537 76538 /** 76539 This method is called once the promise returned by an 76540 adapter's `createRecord`, `updateRecord` or `deleteRecord` 76541 is rejected with a `DS.InvalidError`. 76542 @method recordWasInvalid 76543 @private 76544 @param {InternalModel} internalModel 76545 @param {Object} errors 76546 */ 76547 recordWasInvalid: function recordWasInvalid(internalModel, errors) { 76548 internalModel.adapterDidInvalidate(errors); 76549 }, 76550 76551 /** 76552 This method is called once the promise returned by an 76553 adapter's `createRecord`, `updateRecord` or `deleteRecord` 76554 is rejected (with anything other than a `DS.InvalidError`). 76555 @method recordWasError 76556 @private 76557 @param {InternalModel} internalModel 76558 @param {Error} error 76559 */ 76560 recordWasError: function recordWasError(internalModel, error) { 76561 internalModel.adapterDidError(error); 76562 }, 76563 76564 /** 76565 When an adapter's `createRecord`, `updateRecord` or `deleteRecord` 76566 resolves with data, this method extracts the ID from the supplied 76567 data. 76568 @method updateId 76569 @private 76570 @param {InternalModel} internalModel 76571 @param {Object} data 76572 */ 76573 updateId: function updateId(internalModel, data) { 76574 var oldId = internalModel.id; 76575 var id = (0, _emberDataPrivateSystemCoerceId['default'])(data.id); 76576 76577 (0, _emberDataPrivateDebug.assert)("An adapter cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); 76578 76579 this.typeMapFor(internalModel.type).idToRecord[id] = internalModel; 76580 76581 internalModel.setId(id); 76582 }, 76583 76584 /** 76585 Returns a map of IDs to client IDs for a given type. 76586 @method typeMapFor 76587 @private 76588 @param {DS.Model} typeClass 76589 @return {Object} typeMap 76590 */ 76591 typeMapFor: function typeMapFor(typeClass) { 76592 var typeMaps = get(this, 'typeMaps'); 76593 var guid = _ember['default'].guidFor(typeClass); 76594 var typeMap = typeMaps[guid]; 76595 76596 if (typeMap) { 76597 return typeMap; 76598 } 76599 76600 typeMap = { 76601 idToRecord: new _emberDataPrivateSystemEmptyObject['default'](), 76602 records: [], 76603 metadata: new _emberDataPrivateSystemEmptyObject['default'](), 76604 type: typeClass 76605 }; 76606 76607 typeMaps[guid] = typeMap; 76608 76609 return typeMap; 76610 }, 76611 76612 // ................ 76613 // . LOADING DATA . 76614 // ................ 76615 76616 /** 76617 This internal method is used by `push`. 76618 @method _load 76619 @private 76620 @param {(String|DS.Model)} type 76621 @param {Object} data 76622 */ 76623 _load: function _load(data) { 76624 var internalModel = this._internalModelForId(data.type, data.id); 76625 76626 internalModel.setupData(data); 76627 76628 this.recordArrayManager.recordDidChange(internalModel); 76629 76630 return internalModel; 76631 }, 76632 76633 /* 76634 In case someone defined a relationship to a mixin, for example: 76635 ``` 76636 var Comment = DS.Model.extend({ 76637 owner: belongsTo('commentable'. { polymorphic: true}) 76638 }); 76639 var Commentable = Ember.Mixin.create({ 76640 comments: hasMany('comment') 76641 }); 76642 ``` 76643 we want to look up a Commentable class which has all the necessary 76644 relationship metadata. Thus, we look up the mixin and create a mock 76645 DS.Model, so we can access the relationship CPs of the mixin (`comments`) 76646 in this case 76647 */ 76648 76649 _modelForMixin: function _modelForMixin(modelName) { 76650 var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName['default'])(modelName); 76651 // container.registry = 2.1 76652 // container._registry = 1.11 - 2.0 76653 // container = < 1.11 76654 var owner = (0, _emberDataPrivateUtils.getOwner)(this); 76655 76656 var mixin = owner._lookupFactory('mixin:' + normalizedModelName); 76657 if (mixin) { 76658 //Cache the class as a model 76659 owner.register('model:' + normalizedModelName, _emberDataModel['default'].extend(mixin)); 76660 } 76661 var factory = this.modelFactoryFor(normalizedModelName); 76662 if (factory) { 76663 factory.__isMixin = true; 76664 factory.__mixin = mixin; 76665 } 76666 76667 return factory; 76668 }, 76669 76670 /** 76671 Returns a model class for a particular key. Used by 76672 methods that take a type key (like `find`, `createRecord`, 76673 etc.) 76674 @method modelFor 76675 @param {String} modelName 76676 @return {DS.Model} 76677 */ 76678 modelFor: function modelFor(modelName) { 76679 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's modelFor method", isPresent(modelName)); 76680 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76681 76682 var factory = this.modelFactoryFor(modelName); 76683 if (!factory) { 76684 //Support looking up mixins as base types for polymorphic relationships 76685 factory = this._modelForMixin(modelName); 76686 } 76687 if (!factory) { 76688 throw new _ember['default'].Error("No model was found for '" + modelName + "'"); 76689 } 76690 factory.modelName = factory.modelName || (0, _emberDataPrivateSystemNormalizeModelName['default'])(modelName); 76691 76692 return factory; 76693 }, 76694 76695 modelFactoryFor: function modelFactoryFor(modelName) { 76696 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName)); 76697 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76698 var normalizedKey = (0, _emberDataPrivateSystemNormalizeModelName['default'])(modelName); 76699 76700 var owner = (0, _emberDataPrivateUtils.getOwner)(this); 76701 76702 return owner._lookupFactory('model:' + normalizedKey); 76703 }, 76704 76705 /** 76706 Push some data for a given type into the store. 76707 This method expects normalized [JSON API](http://jsonapi.org/) document. This means you have to follow [JSON API specification](http://jsonapi.org/format/) with few minor adjustments: 76708 - record's `type` should always be in singular, dasherized form
76709 - members (properties) should be camelCased 76710 [Your primary data should be wrapped inside `data` property](http://jsonapi.org/format/#document-top-level): 76711 ```js 76712 store.push({ 76713 data: { 76714 // primary data for single record of type `Person` 76715 id: '1', 76716 type: 'person', 76717 attributes: { 76718 firstName: 'Daniel', 76719 lastName: 'Kmak' 76720 } 76721 } 76722 }); 76723 ``` 76724 [Demo.](http://ember-twiddle.com/fb99f18cd3b4d3e2a4c7) 76725 `data` property can also hold an array (of records): 76726 ```js 76727 store.push({ 76728 data: [ 76729 // an array of records 76730 { 76731 id: '1', 76732 type: 'person', 76733 attributes: { 76734 firstName: 'Daniel', 76735 lastName: 'Kmak' 76736 } 76737 }, 76738 { 76739 id: '2', 76740 type: 'person', 76741 attributes: { 76742 firstName: 'Tom', 76743 lastName: 'Dale' 76744 } 76745 } 76746 ] 76747 }); 76748 ``` 76749 [Demo.](http://ember-twiddle.com/69cdbeaa3702159dc355) 76750 There are some typical properties for `JSONAPI` payload: 76751 * `id` - mandatory, unique record's key 76752 * `type` - mandatory string which matches `model`'s dasherized name in singular form 76753 * `attributes` - object which holds data for record attributes - `DS.attr`'s declared in model 76754 * `relationships` - object which must contain any of the following properties under each relationships' respective key (example path is `relationships.achievements.data`): 76755 - [`links`](http://jsonapi.org/format/#document-links) 76756 - [`data`](http://jsonapi.org/format/#document-resource-object-linkage) - place for primary data 76757 - [`meta`](http://jsonapi.org/format/#document-meta) - object which contains meta-information about relationship 76758 For this model: 76759 ```app/models/person.js 76760 import DS from 'ember-data'; 76761 export default DS.Model.extend({ 76762 firstName: DS.attr('string'), 76763 lastName: DS.attr('string'), 76764 children: DS.hasMany('person') 76765 }); 76766 ``` 76767 To represent the children as IDs: 76768 ```js 76769 { 76770 data: { 76771 id: '1', 76772 type: 'person', 76773 attributes: { 76774 firstName: 'Tom', 76775 lastName: 'Dale' 76776 }, 76777 relationships: { 76778 children: { 76779 data: [ 76780 { 76781 id: '2', 76782 type: 'person' 76783 }, 76784 { 76785 id: '3', 76786 type: 'person' 76787 }, 76788 { 76789 id: '4', 76790 type: 'person' 76791 } 76792 ] 76793 } 76794 } 76795 } 76796 } 76797 ``` 76798 [Demo.](http://ember-twiddle.com/343e1735e034091f5bde) 76799 To represent the children relationship as a URL: 76800 ```js 76801 { 76802 data: { 76803 id: '1', 76804 type: 'person', 76805 attributes: { 76806 firstName: 'Tom', 76807 lastName: 'Dale' 76808 }, 76809 relationships: { 76810 children: { 76811 links: { 76812 related: '/people/1/children' 76813 } 76814 } 76815 } 76816 } 76817 } 76818 ``` 76819 If you're streaming data or implementing an adapter, make sure 76820 that you have converted the incoming data into this form. The 76821 store's [normalize](#method_normalize) method is a convenience 76822 helper for converting a json payload into the form Ember Data 76823 expects. 76824 ```js 76825 store.push(store.normalize('person', data)); 76826 ``` 76827 This method can be used both to push in brand new 76828 records, as well as to update existing records. 76829 @method push 76830 @param {Object} data 76831 @return {DS.Model|Array} the record(s) that was created or 76832 updated. 76833 */ 76834 push: function push(data) { 76835 var included = data.included; 76836 var i, length; 76837 if (included) { 76838 for (i = 0, length = included.length; i < length; i++) { 76839 this._pushInternalModel(included[i]); 76840 } 76841 } 76842 76843 if (Array.isArray(data.data)) { 76844 length = data.data.length; 76845 var internalModels = new Array(length); 76846 for (i = 0; i < length; i++) { 76847 internalModels[i] = this._pushInternalModel(data.data[i]).getRecord(); 76848 } 76849 return internalModels; 76850 } 76851 76852 if (data.data === null) { 76853 return null; 76854 } 76855 76856 (0, _emberDataPrivateDebug.assert)('Expected an object in the \'data\' property in a call to \'push\' for ' + data.type + ', but was ' + _ember['default'].typeOf(data.data), _ember['default'].typeOf(data.data) === 'object'); 76857 76858 var internalModel = this._pushInternalModel(data.data); 76859 76860 return internalModel.getRecord(); 76861 }, 76862 76863 _hasModelFor: function _hasModelFor(type) { 76864 return !!(0, _emberDataPrivateUtils.getOwner)(this)._lookupFactory('model:' + type); 76865 }, 76866 76867 _pushInternalModel: function _pushInternalModel(data) { 76868 var _this2 = this; 76869 76870 var modelName = data.type; 76871 (0, _emberDataPrivateDebug.assert)('You must include an \'id\' for ' + modelName + ' in an object passed to \'push\'', data.id !== null && data.id !== undefined && data.id !== ''); 76872 (0, _emberDataPrivateDebug.assert)('You tried to push data with a type \'' + modelName + '\' but no model could be found with that name.', this._hasModelFor(modelName)); 76873 76874 (0, _emberDataPrivateDebug.runInDebug)(function () { 76875 // If Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload 76876 // contains unknown attributes or relationships, log a warning. 76877 76878 if (_ember['default'].ENV.DS_WARN_ON_UNKNOWN_KEYS) { 76879 (function () { 76880 var type = _this2.modelFor(modelName); 76881 76882 // Check unknown attributes 76883 var unknownAttributes = Object.keys(data.attributes || {}).filter(function (key) { 76884 return !get(type, 'fields').has(key); 76885 }); 76886 var unknownAttributesMessage = 'The payload for \'' + type.modelName + '\' contains these unknown attributes: ' + unknownAttributes + '. Make sure they\'ve been defined in your model.'; 76887 (0, _emberDataPrivateDebug.warn)(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); 76888 76889 // Check unknown relationships 76890 var unknownRelationships = Object.keys(data.relationships || {}).filter(function (key) { 76891 return !get(type, 'fields').has(key); 76892 }); 76893 var unknownRelationshipsMessage = 'The payload for \'' + type.modelName + '\' contains these unknown relationships: ' + unknownRelationships + '. Make sure they\'ve been defined in your model.'; 76894 (0, _emberDataPrivateDebug.warn)(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); 76895 })(); 76896 } 76897 }); 76898
76899 // Actually load the record into the store. 76900 var internalModel = this._load(data); 76901 76902 this._backburner.join(function () { 76903 _this2._backburner.schedule('normalizeRelationships', _this2, '_setupRelationships', internalModel, data); 76904 }); 76905 76906 return internalModel; 76907 }, 76908 76909 _setupRelationships: function _setupRelationships(record, data) { 76910 // This will convert relationships specified as IDs into DS.Model instances 76911 // (possibly unloaded) and also create the data structures used to track 76912 // relationships. 76913 setupRelationships(this, record, data); 76914 }, 76915 76916 /** 76917 Push some raw data into the store. 76918 This method can be used both to push in brand new 76919 records, as well as to update existing records. You 76920 can push in more than one type of object at once. 76921 All objects should be in the format expected by the 76922 serializer. 76923 ```app/serializers/application.js 76924 import DS from 'ember-data'; 76925 export default DS.ActiveModelSerializer; 76926 ``` 76927 ```js 76928 var pushData = { 76929 posts: [ 76930 { id: 1, post_title: "Great post", comment_ids: [2] } 76931 ], 76932 comments: [ 76933 { id: 2, comment_body: "Insightful comment" } 76934 ] 76935 } 76936 store.pushPayload(pushData); 76937 ``` 76938 By default, the data will be deserialized using a default 76939 serializer (the application serializer if it exists). 76940 Alternatively, `pushPayload` will accept a model type which 76941 will determine which serializer will process the payload. 76942 ```app/serializers/application.js 76943 import DS from 'ember-data'; 76944 export default DS.ActiveModelSerializer; 76945 ``` 76946 ```app/serializers/post.js 76947 import DS from 'ember-data'; 76948 export default DS.JSONSerializer; 76949 ``` 76950 ```js 76951 store.pushPayload('comment', pushData); // Will use the application serializer 76952 store.pushPayload('post', pushData); // Will use the post serializer 76953 ``` 76954 @method pushPayload 76955 @param {String} modelName Optionally, a model type used to determine which serializer will be used 76956 @param {Object} inputPayload 76957 */ 76958 pushPayload: function pushPayload(modelName, inputPayload) { 76959 var _this3 = this; 76960 76961 var serializer; 76962 var payload; 76963 if (!inputPayload) { 76964 payload = modelName; 76965 serializer = defaultSerializer(this); 76966 (0, _emberDataPrivateDebug.assert)("You cannot use `store#pushPayload` without a modelName unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); 76967 } else { 76968 payload = inputPayload; 76969 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 76970 serializer = this.serializerFor(modelName); 76971 } 76972 if (false) { 76973 return this._adapterRun(function () { 76974 return serializer.pushPayload(_this3, payload); 76975 }); 76976 } else { 76977 this._adapterRun(function () { 76978 return serializer.pushPayload(_this3, payload); 76979 }); 76980 } 76981 }, 76982 76983 /** 76984 `normalize` converts a json payload into the normalized form that 76985 [push](#method_push) expects. 76986 Example 76987 ```js 76988 socket.on('message', function(message) { 76989 var modelName = message.model; 76990 var data = message.data; 76991 store.push(store.normalize(modelName, data)); 76992 }); 76993 ``` 76994 @method normalize 76995 @param {String} modelName The name of the model type for this payload 76996 @param {Object} payload 76997 @return {Object} The normalized payload 76998 */ 76999 normalize: function normalize(modelName, payload) { 77000 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's normalize method", isPresent(modelName)); 77001 (0, _emberDataPrivateDebug.assert)('Passing classes to store methods has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 77002 var serializer = this.serializerFor(modelName); 77003 var model = this.modelFor(modelName); 77004 return serializer.normalize(model, payload); 77005 }, 77006 77007 /** 77008 Build a brand new record for a given type, ID, and 77009 initial data. 77010 @method buildRecord 77011 @private 77012 @param {DS.Model} type 77013 @param {String} id 77014 @param {Object} data 77015 @return {InternalModel} internal model 77016 */ 77017 buildInternalModel: function buildInternalModel(type, id, data) { 77018 var typeMap = this.typeMapFor(type); 77019 var idToRecord = typeMap.idToRecord; 77020 77021 (0, _emberDataPrivateDebug.assert)('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord[id]); 77022 (0, _emberDataPrivateDebug.assert)('\'' + _ember['default'].inspect(type) + '\' does not appear to be an ember-data model', typeof type._create === 'function'); 77023 77024 // lookupFactory should really return an object that creates 77025 // instances with the injections applied 77026 var internalModel = new _emberDataPrivateSystemModelInternalModel['default'](type, id, this, null, data); 77027 77028 // if we're creating an item, this process will be done 77029 // later, once the object has been persisted. 77030 if (id) { 77031 idToRecord[id] = internalModel; 77032 } 77033 77034 typeMap.records.push(internalModel); 77035 77036 return internalModel; 77037 }, 77038 77039 //Called by the state machine to notify the store that the record
77039is ready to be interacted with 77040 recordWasLoaded: function recordWasLoaded(record) { 77041 this.recordArrayManager.recordWasLoaded(record); 77042 }, 77043 77044 // ............... 77045 // . DESTRUCTION . 77046 // ............... 77047 77048 /** 77049 When a record is destroyed, this un-indexes it and 77050 removes it from any record arrays so it can be GCed. 77051 @method _dematerializeRecord 77052 @private 77053 @param {InternalModel} internalModel 77054 */ 77055 _dematerializeRecord: function _dematerializeRecord(internalModel) { 77056 var type = internalModel.type; 77057 var typeMap = this.typeMapFor(type); 77058 var id = internalModel.id; 77059 77060 internalModel.updateRecordArrays(); 77061 77062 if (id) { 77063 delete typeMap.idToRecord[id]; 77064 } 77065 77066 var loc = typeMap.records.indexOf(internalModel); 77067 typeMap.records.splice(loc, 1); 77068 }, 77069 77070 // ...................... 77071 // . PER-TYPE ADAPTERS 77072 // ...................... 77073 77074 /** 77075 Returns an instance of the adapter for a given type. For 77076 example, `adapterFor('person')` will return an instance of 77077 `App.PersonAdapter`. 77078 If no `App.PersonAdapter` is found, this method will look 77079 for an `App.ApplicationAdapter` (the default adapter for 77080 your entire application). 77081 If no `App.ApplicationAdapter` is found, it will return 77082 the value of the `defaultAdapter`. 77083 @method adapterFor 77084 @public 77085 @param {String} modelName 77086 @return DS.Adapter 77087 */ 77088 adapterFor: function adapterFor(modelName) { 77089 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's adapterFor method", isPresent(modelName)); 77090 (0, _emberDataPrivateDebug.assert)('Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 77091 77092 return this.lookupAdapter(modelName); 77093 }, 77094 77095 _adapterRun: function _adapterRun(fn) { 77096 return this._backburner.run(fn); 77097 }, 77098 77099 // .............................. 77100 // . RECORD CHANGE NOTIFICATION . 77101 // .............................. 77102 77103 /** 77104 Returns an instance of the serializer for a given type. For 77105 example, `serializerFor('person')` will return an instance of 77106 `App.PersonSerializer`. 77107 If no `App.PersonSerializer` is found, this method will look 77108 for an `App.ApplicationSerializer` (the default serializer for 77109 your entire application). 77110 if no `App.ApplicationSerializer` is found, it will attempt 77111 to get the `defaultSerializer` from the `PersonAdapter` 77112 (`adapterFor('person')`). 77113 If a serializer cannot be found on the adapter, it will fall back 77114 to an instance of `DS.JSONSerializer`. 77115 @method serializerFor 77116 @public 77117 @param {String} modelName the record to serialize 77118 @return {DS.Serializer} 77119 */ 77120 serializerFor: function serializerFor(modelName) { 77121 (0, _emberDataPrivateDebug.assert)("You need to pass a model name to the store's serializerFor method", isPresent(modelName)); 77122 (0, _emberDataPrivateDebug.assert)('Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ' + _ember['default'].inspect(modelName), typeof modelName === 'string'); 77123 77124 var fallbacks = ['application', this.adapterFor(modelName).get('defaultSerializer'), '-default']; 77125 77126 var serializer = this.lookupSerializer(modelName, fallbacks); 77127 return serializer; 77128 }, 77129 77130 /** 77131 Retrieve a particular instance from the 77132 container cache. If not found, creates it and 77133 placing it in the cache. 77134 Enabled a store to manage local instances of 77135 adapters and serializers. 77136 @method retrieveManagedInstance 77137 @private 77138 @param {String} modelName the object modelName 77139 @param {String} name the object name 77140 @param {Array} fallbacks the fallback objects to lookup if the lookup for modelName or 'application' fails 77141 @return {Ember.Object} 77142 */ 77143 retrieveManagedInstance: function retrieveManagedInstance(type, modelName, fallbacks) { 77144 var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName['default'])(modelName); 77145 77146 var instance = this._instanceCache.get(type, normalizedModelName, fallbacks); 77147 set(instance, 'store', this); 77148 return instance; 77149 }, 77150 77151 lookupAdapter: function lookupAdapter(name) { 77152 return this.retrieveManagedInstance('adapter', name, this.get('_adapterFallbacks')); 77153 }, 77154 77155 _adapterFallbacks: _ember['default'].computed('adapter', function () { 77156 var adapter = this.get('adapter'); 77157 return ['application', adapter, '-json-api']; 77158 }), 77159 77160 lookupSerializer: function lookupSerializer(name, fallbacks) { 77161 return this.retrieveManagedInstance('serializer', name, fallbacks); 77162 }, 77163 77164 willDestroy: function willDestroy() { 77165 this._super.apply(this, arguments); 77166 this.recordArrayManager.destroy(); 77167 77168 this.unloadAll(); 77169 } 77170 77171 }); 77172 77173 function deserializeRecordId(store, key, relationship, id) { 77174 if (isNone(id)) { 77175 return; 77176 } 77177 77178 (0, _emberDataPrivateDebug.assert)('A ' + relationship.parentType + ' record was pushed into the store with the value of ' + key + ' being ' + _ember['default'].inspect(id) + ', but ' + key + ' is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.', !Array.isArray(id)); 77179 77180 //TODO:Better asserts 77181 return store._internalModelForId(id.type, id.id); 77182 } 77183 77184 function deserializeRecordIds(store, key, relationship, ids) { 77185 if (isNone(ids)) { 77186 return; 77187 } 77188 77189 (0, _emberDataPrivateDebug.assert)('A ' + relationship.parentType + ' record was pushed into the store with the value of ' + key + ' being \'' + _ember['default'].inspect(ids) + '\', but ' + key + ' is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.', Array.isArray(ids)); 77190 var _ids = new Array(ids.length); 77191 77192 for (var i = 0; i < ids.length; i++) { 77193 _ids[i] = deserializeRecordId(store, key, relationship, ids[i]); 77194 } 77195 77196 return _ids; 77197 } 77198 77199 // Delegation to the adapter and promise management 77200 77201 function defaultSerializer(store) { 77202 return store.serializerFor('application'); 77203 } 77204 77205 function _commit(adapter, store, operation, snapshot) { 77206 var internalModel = snapshot._internalModel; 77207 var modelName = snapshot.modelName; 77208 var typeClass = store.modelFor(modelName); 77209 var promise = adapter[operation](store, typeClass, snapshot); 77210 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); 77211 var label = 'DS: Extract and notify about ' + operation + ' completion of ' + internalModel; 77212 77213 (0, _emberDataPrivateDebug.assert)('Your adapter\'s \'' + operation + '\' method must return a value, but it returned \'undefined\'', promise !== undefined); 77214 77215 promise = Promise.resolve(promise, label); 77216 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77217 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, internalModel)); 77218 77219 return promise.then(function (adapterPayload) { 77220 store._adapterRun(function () { 77221 var payload, data; 77222 if (adapterPayload) { 77223 payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, snapshot.id, operation); 77224 if (payload.included) { 77225 store.push({ data: payload.included }); 77226 } 77227 data = payload.data; 77228 } 77229 store.didSaveRecord(internalModel, { data: data }); 77230 }); 77231 77232 return internalModel; 77233 }, function (error) { 77234 if (error instanceof _emberDataAdaptersErrors.InvalidError) { 77235 var errors = serializer.extractErrors(store, typeClass, error, snapshot.id); 77236 store.recordWasInvalid(internalModel, errors); 77237 } else { 77238 store.recordWasError(internalModel, error); 77239 } 77240 77241 throw error; 77242 }, label); 77243 } 77244 77245 function setupRelationships(store, record, data) { 77246 if (!data.relationships) { 77247 return; 77248 } 77249 77250 record.type.eachRelationship(function (key, descriptor) { 77251 var kind = descriptor.kind; 77252 77253 if (!data.relationships[key]) { 77254 return; 77255 } 77256 77257 var relationship; 77258 77259 if (data.relationships[key].links && data.relationships[key].links.related) { 77260 var relatedLink = (0, _emberDataPrivateSystemNormalizeLink['default'])(data.relationships[key].links.related); 77261 if (relatedLink && relatedLink.href) { 77262 relationship = record._relationships.get(key); 77263 relationship.updateLink(relatedLink.href); 77264 } 77265 } 77266 77267 if (data.relationships[key].meta) { 77268 relationship = record._relationships.get(key); 77269 relationship.updateMeta(data.relationships[key].meta); 77270 } 77271 77272 // If the data contains a relationship that is specified as an ID (or IDs), 77273 // normalizeRelationship will convert them into DS.Model instances 77274 // (possibly unloaded) before we push the payload into the store. 77275 normalizeRelationship(store, key, descriptor, data.relationships[key]); 77276 77277 var value = data.relationships[key].data; 77278 77279 if (value !== undefined) { 77280 if (kind === 'belongsTo') { 77281 relationship = record._relationships.get(key); 77282 relationship.setCanonicalRecord(value); 77283 } else if (kind === 'hasMany') { 77284 relationship = record._relationships.get(key); 77285 relationship.updateRecordsFromAdapter(value); 77286 } 77287 } 77288 }); 77289 } 77290 77291 function normalizeRelationship(store, key, relationship, jsonPayload) { 77292 var data = jsonPayload.data; 77293 if (data) { 77294 var kind = relationship.kind; 77295 if (kind === 'belongsTo') { 77296 jsonPayload.data = deserializeRecordId(store, key, relationship, data); 77297 } else if (kind === 'hasMany') { 77298 jsonPayload.data = deserializeRecordIds(store, key, relationship, data); 77299 } 77300 } 77301 } 77302
77303 exports.Store = Store; 77304 exports['default'] = Store; 77305}); 77306define('ember-data/-private/system/store/common', ['exports', 'ember'], function (exports, _ember) { 77307 'use strict'; 77308 77309 exports._bind = _bind; 77310 exports._guard = _guard; 77311 exports._objectIsAlive = _objectIsAlive; 77312 77313 var get = _ember['default'].get; 77314 77315 function _bind(fn) { 77316 var args = Array.prototype.slice.call(arguments, 1); 77317 77318 return function () { 77319 return fn.apply(undefined, args); 77320 }; 77321 } 77322 77323 function _guard(promise, test) { 77324 var guarded = promise['finally'](function () { 77325 if (!test()) { 77326 guarded._subscribers.length = 0; 77327 } 77328 }); 77329 77330 return guarded; 77331 } 77332 77333 function _objectIsAlive(object) { 77334 return !(get(object, "isDestroyed") || get(object, "isDestroying")); 77335 } 77336}); 77337define('ember-data/-private/system/store/container-instance-cache', ['exports', 'ember', 'ember-data/-private/system/empty-object'], function (exports, _ember, _emberDataPrivateSystemEmptyObject) { 77338 'use strict'; 77339 77340 exports['default'] = ContainerInstanceCache; 77341 77342 var assign = _ember['default'].assign || _ember['default'].merge; 77343 77344 /** 77345 * The `ContainerInstanceCache` serves as a lazy cache for looking up 77346 * instances of serializers and adapters. It has some additional logic for 77347 * finding the 'fallback' adapter or serializer. 77348 * 77349 * The 'fallback' adapter or serializer is an adapter or serializer that is looked up 77350 * when the preferred lookup fails. For example, say you try to look up `adapter:post`, 77351 * but there is no entry (app/adapters/post.js in EmberCLI) for `adapter:post` in the registry. 77352 * 77353 * The `fallbacks` array passed will then be used; the first entry in the fallbacks array 77354 * that exists in the container will then be cached for `adapter:post`. So, the next time you 77355 * look up `adapter:post`, you'll get the `adapter:application` instance (or whatever the fallback 77356 * was if `adapter:application` doesn't exist). 77357 * 77358 * @private 77359 * @class ContainerInstanceCache 77360 * 77361 */ 77362 function ContainerInstanceCache(owner) { 77363 this._owner = owner; 77364 this._cache = new _emberDataPrivateSystemEmptyObject['default'](); 77365 } 77366 77367 ContainerInstanceCache.prototype = new _emberDataPrivateSystemEmptyObject['default'](); 77368 77369 assign(ContainerInstanceCache.prototype, { 77370 get: function get(type, preferredKey, fallbacks) { 77371 var cache = this._cache; 77372 var preferredLookupKey = type + ':' + preferredKey; 77373 77374 if (!(preferredLookupKey in cache)) { 77375 var instance = this.instanceFor(preferredLookupKey) || this._findInstance(type, fallbacks); 77376 if (instance) { 77377 cache[preferredLookupKey] = instance; 77378 } 77379 } 77380 return cache[preferredLookupKey]; 77381 }, 77382 77383 _findInstance: function _findInstance(type, fallbacks) { 77384 for (var i = 0, _length = fallbacks.length; i < _length; i++) { 77385 var fallback = fallbacks[i]; 77386 var lookupKey = type + ':' + fallback; 77387 var instance = this.instanceFor(lookupKey); 77388 77389 if (instance) { 77390 return instance; 77391 } 77392 } 77393 }, 77394 77395 instanceFor: function instanceFor(key) { 77396 var cache = this._cache; 77397 if (!cache[key]) { 77398 var instance = this._owner.lookup(key); 77399 if (instance) { 77400 cache[key] = instance; 77401 } 77402 } 77403 return cache[key]; 77404 }, 77405 77406 destroy: function destroy() { 77407 var cache = this._cache; 77408 var cacheEntries = Object.keys(cache); 77409 77410 for (var i = 0, _length2 = cacheEntries.length; i < _length2; i++) { 77411 var cacheKey = cacheEntries[i]; 77412 var cacheEntry = cache[cacheKey]; 77413 if (cacheEntry) { 77414 cacheEntry.destroy(); 77415 } 77416 } 77417 this._owner = null; 77418 }, 77419 77420 constructor: ContainerInstanceCache, 77421 77422 toString: function toString() { 77423 return 'ContainerInstanceCache'; 77424 } 77425 }); 77426}); 77427define("ember-data/-private/system/store/finders", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/store/common", "ember-data/-private/system/store/serializer-response", "ember-data/-private/system/store/serializers"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemStoreCommon, _emberDataPrivateSystemStoreSerializerResponse, _emberDataPrivateSystemStoreSerializers) { 77428 "use strict"; 77429 77430 exports._find = _find; 77431 exports._findMany = _findMany;
77432 exports._findHasMany = _findHasMany; 77433 exports._findBelongsTo = _findBelongsTo; 77434 exports._findAll = _findAll; 77435 exports._query = _query; 77436 exports._queryRecord = _queryRecord; 77437 77438 var Promise = _ember["default"].RSVP.Promise; 77439 77440 function payloadIsNotBlank(adapterPayload) { 77441 if (Array.isArray(adapterPayload)) { 77442 return true; 77443 } else { 77444 return Object.keys(adapterPayload || {}).length; 77445 } 77446 } 77447 77448 function _find(adapter, store, typeClass, id, internalModel, options) { 77449 var snapshot = internalModel.createSnapshot(options); 77450 var promise = adapter.findRecord(store, typeClass, id, snapshot); 77451 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, internalModel.type.modelName); 77452 var label = "DS: Handle Adapter#findRecord of " + typeClass + " with id: " + id; 77453 77454 promise = Promise.resolve(promise, label); 77455 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77456 77457 return promise.then(function (adapterPayload) { 77458 (0, _emberDataPrivateDebug.assert)("You made a `findRecord` request for a " + typeClass.modelName + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); 77459 return store._adapterRun(function () { 77460 var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, id, 'findRecord'); 77461 (0, _emberDataPrivateDebug.assert)('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); 77462 //TODO Optimize 77463 var record = store.push(payload); 77464 return record._internalModel; 77465 }); 77466 }, function (error) { 77467 internalModel.notFound(); 77468 if (internalModel.isEmpty()) { 77469 internalModel.unloadRecord(); 77470 } 77471 77472 throw error; 77473 }, "DS: Extract payload of '" + typeClass + "'"); 77474 } 77475 77476 function _findMany(adapter, store, typeClass, ids, internalModels) { 77477 var snapshots = _ember["default"].A(internalModels).invoke('createSnapshot'); 77478 var promise = adapter.findMany(store, typeClass, ids, snapshots); 77479 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, typeClass.modelName); 77480 var label = "DS: Handle Adapter#findMany of " + typeClass; 77481 77482 if (promise === undefined) { 77483 throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); 77484 } 77485 77486 promise = Promise.resolve(promise, label); 77487 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77488 77489 return promise.then(function (adapterPayload) { 77490 (0, _emberDataPrivateDebug.assert)("You made a `findMany` request for " + typeClass.modelName + " records with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); 77491 return store._adapterRun(function () { 77492 var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, null, 'findMany'); 77493 //TODO Optimize, no need to materialize here 77494 var records = store.push(payload); 77495 var internalModels = new Array(records.length); 77496 77497 for (var i = 0; i < records.length; i++) { 77498 internalModels[i] = records[i]._internalModel; 77499 } 77500 77501 return internalModels; 77502 }); 77503 }, null, "DS: Extract payload of " + typeClass); 77504 } 77505 77506 function _findHasMany(adapter, store, internalModel, link, relationship) { 77507 var snapshot = internalModel.createSnapshot(); 77508 var typeClass = store.modelFor(relationship.type); 77509 var promise = adapter.findHasMany(store, snapshot, link, relationship); 77510 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, relationship.type); 77511 var label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; 77512 77513 promise = Promise.resolve(promise, label); 77514 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77515 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, internalModel)); 77516 77517 return promise.then(function (adapterPayload) { 77518 (0, _emberDataPrivateDebug.assert)("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); 77519 return store._adapterRun(function () { 77520 var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); 77521 //TODO Use a non record creating push 77522 var records = store.push(payload); 77523 var recordArray = records.map(function (record) { 77524 return record._internalModel; 77525 }); 77526 recordArray.meta = payload.meta; 77527 return recordArray; 77528 }); 77529 }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); 77530 } 77531 77532 function _findBelongsTo(adapter, store, internalModel, link, relationship
77532) { 77533 var snapshot = internalModel.createSnapshot(); 77534 var typeClass = store.modelFor(relationship.type); 77535 var promise = adapter.findBelongsTo(store, snapshot, link, relationship); 77536 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, relationship.type); 77537 var label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; 77538 77539 promise = Promise.resolve(promise, label); 77540 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77541 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, internalModel)); 77542 77543 return promise.then(function (adapterPayload) { 77544 return store._adapterRun(function () { 77545 var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, null, 'findBelongsTo'); 77546 77547 if (!payload.data) { 77548 return null; 77549 } 77550 77551 //TODO Optimize 77552 var record = store.push(payload); 77553 return record._internalModel; 77554 }); 77555 }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); 77556 } 77557 77558 function _findAll(adapter, store, typeClass, sinceToken, options) { 77559 var modelName = typeClass.modelName; 77560 var recordArray = store.peekAll(modelName); 77561 var snapshotArray = recordArray.createSnapshot(options); 77562 var promise = adapter.findAll(store, typeClass, sinceToken, snapshotArray); 77563 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); 77564 var label = "DS: Handle Adapter#findAll of " + typeClass; 77565 77566 promise = Promise.resolve(promise, label); 77567 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77568 77569 return promise.then(function (adapterPayload) { 77570 (0, _emberDataPrivateDebug.assert)("You made a `findAll` request for " + typeClass.modelName + " records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); 77571 store._adapterRun(function () { 77572 var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, null, 'findAll'); 77573 //TODO Optimize 77574 store.push(payload); 77575 }); 77576 77577 store.didUpdateAll(typeClass); 77578 return store.peekAll(modelName); 77579 }, null, "DS: Extract payload of findAll " + typeClass); 77580 } 77581 77582 function _query(adapter, store, typeClass, query, recordArray) { 77583 var modelName = typeClass.modelName; 77584 var promise = adapter.query(store, typeClass, query, recordArray); 77585 77586 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); 77587 var label = "DS: Handle Adapter#query of " + typeClass; 77588 77589 promise = Promise.resolve(promise, label); 77590 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77591 77592 return promise.then(function (adapterPayload) { 77593 var records, payload; 77594 store._adapterRun(function () { 77595 payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, null, 'query'); 77596 //TODO Optimize 77597 records = store.push(payload); 77598 }); 77599 77600 (0, _emberDataPrivateDebug.assert)('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(records)); 77601 recordArray.loadRecords(records, payload); 77602 return recordArray; 77603 }, null, "DS: Extract payload of query " + typeClass); 77604 } 77605 77606 function _queryRecord(adapter, store, typeClass, query) { 77607 var modelName = typeClass.modelName; 77608 var promise = adapter.queryRecord(store, typeClass, query); 77609 var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); 77610 var label = "DS: Handle Adapter#queryRecord of " + typeClass; 77611 77612 promise = Promise.resolve(promise, label); 77613 promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); 77614 77615 return promise.then(function (adapterPayload) { 77616 var record; 77617 store._adapterRun(function () { 77618 var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); 77619 77620 (0, _emberDataPrivateDebug.assert)("Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array.", !Array.isArray(payload.data), { 77621 id: 'ds.store.queryRecord-array-response' 77622 }); 77623 77624 //TODO Optimize 77625 record = store.push(payload); 77626 }); 77627 77628 return record; 77629 }, null, "DS: Extract payload of queryRecord " + typeClass); 77630 } 77631}); 77632define('ember-data/-private/system/store/serializer-response', ['exports', 'ember', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateDebug) { 77633 'use strict'; 77634 77635 exports.validateDocumentStructure = validateDocumentStructure; 77636 exports.normalizeResponseHelper = normalizeResponseHelper; 77637 77638 /* 77639 This is a helper method that validates a JSON API top-level document 77640 77641 The format of a document is described here: 77642 http://jsonapi.org/format/#document-top-level 77643 77644 @method validateDocumentStructure 77645 @param {Object} doc JSON API document 77646 @return {array} An array of errors found in the document structure 77647 */ 77648 77649 function validateDocumentStructure(doc) { 77650 var errors = []; 77651 if (!doc || typeof doc !== 'object') { 77652 errors.push('Top level of a JSON API document must be an object'); 77653 } else { 77654 if (!('data' in doc) && !('errors' in doc) && !('meta' in doc)) { 77655 errors.push('One or more of the following keys must be present: "data", "errors", "meta".'); 77656 } else { 77657 if ('data' in doc && 'errors' in doc) { 77658 errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document'); 77659 } 77660 } 77661 if ('data' in doc) { 77662 if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) { 77663 errors.push('data must be null, an object, or an array'); 77664 } 77665 } 77666 if ('meta' in doc) { 77667 if (typeof doc.meta !== 'object') { 77668 errors.push('meta must be an object'); 77669 } 77670 } 77671 if ('errors' in doc) { 77672 if (!Array.isArray(doc.errors)) { 77673 errors.push('errors must be an array'); 77674 } 77675 } 77676 if ('links' in doc) { 77677 if (typeof doc.links !== 'object') { 77678 errors.push('links must be an object'); 77679 } 77680 } 77681 if ('jsonapi' in doc) { 77682 if (typeof doc.jsonapi !== 'object') { 77683 errors.push('jsonapi must be an object'); 77684 } 77685 } 77686 if ('included' in doc) { 77687 if (typeof doc.included !== 'object') { 77688 errors.push('included must be an array'); 77689 } 77690 } 77691 } 77692 77693 return errors; 77694 } 77695 77696 /* 77697 This is a helper method that always returns a JSON-API Document. 77698 77699 @method normalizeResponseHelper 77700 @param {DS.Serializer} serializer 77701 @param {DS.Store} store 77702 @param {subclass of DS.Model} modelClass 77703 @param {Object} payload 77704 @param {String|Number} id 77705 @param {String} requestType 77706 @return {Object} JSON-API Document 77707 */ 77708 77709 function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { 77710 var normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType);
77711 var validationErrors = []; 77712 (0, _emberDataPrivateDebug.runInDebug)(function () { 77713 validationErrors = validateDocumentStructure(normalizedResponse); 77714 }); 77715 (0, _emberDataPrivateDebug.assert)('normalizeResponse must return a valid JSON API document:\n\t* ' + validationErrors.join('\n\t* '), _ember['default'].isEmpty(validationErrors)); 77716 77717 return normalizedResponse; 77718 } 77719}); 77720define("ember-data/-private/system/store/serializers", ["exports"], function (exports) { 77721 "use strict"; 77722 77723 exports.serializerForAdapter = serializerForAdapter; 77724 77725 function serializerForAdapter(store, adapter, type) { 77726 var serializer = adapter.serializer; 77727 77728 if (serializer === undefined) { 77729 serializer = store.serializerFor(type); 77730 } 77731 77732 if (serializer === null || serializer === undefined) { 77733 serializer = { 77734 extract: function extract(store, type, payload) { 77735 return payload; 77736 } 77737 }; 77738 } 77739 77740 return serializer; 77741 } 77742}); 77743define("ember-data/-private/transforms", ["exports", "ember-data/transform", "ember-data/-private/transforms/number", "ember-data/-private/transforms/date", "ember-data/-private/transforms/string", "ember-data/-private/transforms/boolean"], function (exports, _emberDataTransform, _emberDataPrivateTransformsNumber, _emberDataPrivateTransformsDate, _emberDataPrivateTransformsString, _emberDataPrivateTransformsBoolean) { 77744 "use strict"; 77745 77746 exports.Transform = _emberDataTransform["default"]; 77747 exports.NumberTransform = _emberDataPrivateTransformsNumber["default"]; 77748 exports.DateTransform = _emberDataPrivateTransformsDate["default"]; 77749 exports.StringTransform = _emberDataPrivateTransformsString["default"]; 77750 exports.BooleanTransform = _emberDataPrivateTransformsBoolean["default"]; 77751}); 77752define('ember-data/-private/transforms/boolean', ['exports', 'ember', 'ember-data/transform', 'ember-data/-private/features'], function (exports, _ember, _emberDataTransform, _emberDataPrivateFeatures) { 77753 'use strict'; 77754 77755 var isNone = _ember['default'].isNone; 77756 77757 /** 77758 The `DS.BooleanTransform` class is used to serialize and deserialize 77759 boolean attributes on Ember Data record objects. This transform is 77760 used when `boolean` is passed as the type parameter to the 77761 [DS.attr](../../data#method_attr) function. 77762 77763 Usage 77764 77765 ```app/models/user.js 77766 import DS from 'ember-data'; 77767 77768 export default DS.Model.extend({ 77769 isAdmin: DS.attr('boolean'), 77770 name: DS.attr('string'), 77771 email: DS.attr('string') 77772 }); 77773 ``` 77774 77775 @class BooleanTransform 77776 @extends DS.Transform 77777 @namespace DS 77778 */ 77779 exports['default'] = _emberDataTransform['default'].extend({ 77780 deserialize: function deserialize(serialized, options) { 77781 var type = typeof serialized; 77782 77783 if (true) { 77784 if (isNone(serialized) && options.allowNull === true) { 77785 return null; 77786 } 77787 } 77788 77789 if (type === "boolean") { 77790 return serialized; 77791 } else if (type === "string") { 77792 return serialized.match(/^true$|^t$|^1$/i) !== null; 77793 } else if (type === "number") { 77794 return serialized === 1; 77795 } else { 77796 return false; 77797 } 77798 }, 77799 77800 serialize: function serialize(deserialized, options) { 77801 if (true) { 77802 if (isNone(deserialized) && options.allowNull === true) { 77803 return null; 77804 } 77805 } 77806 77807 return Boolean(deserialized); 77808 } 77809 }); 77810}); 77811define("ember-data/-private/transforms/date", ["exports", "ember-data/-private/ext/date", "ember-data/transform"], function (exports, _emberDataPrivateExtDate, _emberDataTransform) { 77812 "use strict"; 77813 77814 exports["default"] = _emberDataTransform["default"].extend({ 77815 deserialize: function deserialize(serialized) { 77816 var type = typeof serialized; 77817 77818 if (type === "string") { 77819 return new Date((0, _emberDataPrivateExtDate.parseDate)(serialized)); 77820 } else if (type === "number") { 77821 return new Date(serialized); 77822 } else if (serialized === null || serialized === undefined) { 77823 // if the value is null return null 77824 // if the value is not present in the data return undefined 77825 return serialized; 77826 } else { 77827 return null; 77828 } 77829 }, 77830 77831 serialize: function serialize(date) { 77832 if (date instanceof Date) { 77833 return date.toISOString(); 77834 } else { 77835 return null; 77836 } 77837 } 77838 }); 77839}); 77840 77841/** 77842 The `DS.DateTransform` class is used to serialize and deserialize 77843 date attributes on Ember Data record objects. This transform is used 77844 when `date` is passed as the type parameter to the 77845 [DS.attr](../../data#method_attr) function. 77846 77847 ```app/models/score.js 77848 import DS from 'ember-data'; 77849 77850 export default DS.Model.extend({ 77851 value: DS.attr('number'), 77852 player: DS.belongsTo('player'), 77853 date: DS.attr('date') 77854 }); 77855 ``` 77856 77857 @class DateTransform 77858 @extends DS.Transform 77859 @namespace DS 77860 */ 77861define("ember-data/-private/transforms/number", ["exports", "ember", "ember-data/transform"], function (exports, _ember, _emberDataTransform) { 77862 "use strict"; 77863 77864 var empty = _ember["default"].isEmpty; 77865 77866 function isNumber(value) { 77867 return value === value && value !== Infinity && value !== -Infinity; 77868 } 77869 77870 /** 77871 The `DS.NumberTransform` class is used to serialize and deserialize 77872 numeric attributes on Ember Data record objects. This transform is 77873 used when `number` is passed as the type parameter to the 77874 [DS.attr](../../data#method_attr) function. 77875 77876 Usage 77877 77878 ```app/models/score.js 77879 import DS from 'ember-data'; 77880 77881 export default DS.Model.extend({ 77882 value: DS.attr('number'), 77883 player: DS.belongsTo('player'), 77884 date: DS.attr('date') 77885 }); 77886 ``` 77887 77888 @class NumberTransform 77889 @extends DS.Transform 77890 @namespace DS 77891 */ 77892 exports["default"] = _emberDataTransform["default"].extend({ 77893 deserialize: function deserialize(serialized) { 77894 var transformed; 77895 77896 if (empty(serialized)) { 77897 return null; 77898 } else { 77899 transformed = Number(serialized); 77900 77901 return isNumber(transformed) ? transformed : null; 77902 } 77903 }, 77904 77905 serialize: function serialize(deserialized) { 77906 var transformed; 77907 77908 if (empty(deserialized)) { 77909 return null; 77910 } else { 77911 transformed = Number(deserialized); 77912 77913 return isNumber(transformed) ? transformed : null; 77914 } 77915 } 77916 }); 77917}); 77918define("ember-data/-private/transforms/string", ["exports", "ember", "ember-data/transform"], function (exports, _ember, _emberDataTransform) { 77919 "use strict"; 77920 77921 var none = _ember["default"].isNone; 77922 77923 /**
77924 The `DS.StringTransform` class is used to serialize and deserialize 77925 string attributes on Ember Data record objects. This transform is 77926 used when `string` is passed as the type parameter to the 77927 [DS.attr](../../data#method_attr) function. 77928 77929 Usage 77930 77931 ```app/models/user.js 77932 import DS from 'ember-data'; 77933 77934 export default DS.Model.extend({ 77935 isAdmin: DS.attr('boolean'), 77936 name: DS.attr('string'), 77937 email: DS.attr('string') 77938 }); 77939 ``` 77940 77941 @class StringTransform 77942 @extends DS.Transform 77943 @namespace DS 77944 */ 77945 exports["default"] = _emberDataTransform["default"].extend({ 77946 deserialize: function deserialize(serialized) { 77947 return none(serialized) ? null : String(serialized); 77948 }, 77949 serialize: function serialize(deserialized) { 77950 return none(deserialized) ? null : String(deserialized); 77951 } 77952 }); 77953}); 77954define('ember-data/-private/utils', ['exports', 'ember'], function (exports, _ember) { 77955 'use strict'; 77956 77957 var get = _ember['default'].get; 77958 77959 /** 77960 Check if the passed model has a `type` attribute or a relationship named `type`. 77961 77962 @method modelHasAttributeOrRelationshipNamedType 77963 @param modelClass 77964 */ 77965 function modelHasAttributeOrRelationshipNamedType(modelClass) { 77966 return get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type'); 77967 } 77968 77969 /* 77970 ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public 77971 API for looking items up. This function serves as a super simple polyfill to avoid 77972 triggering deprecations. 77973 */ 77974 function getOwner(context) { 77975 var owner; 77976 77977 if (_ember['default'].getOwner) { 77978 owner = _ember['default'].getOwner(context); 77979 } 77980 77981 if (!owner && context.container) { 77982 owner = context.container; 77983 } 77984 77985 if (owner && owner.lookupFactory && !owner._lookupFactory) { 77986 // `owner` is a container, we are just making this work 77987 owner._lookupFactory = owner.lookupFactory; 77988 owner.register = function () { 77989 var registry = owner.registry || owner._registry || owner; 77990 77991 return registry.register.apply(registry, arguments); 77992 }; 77993 } 77994 77995 return owner; 77996 } 77997 77998 exports.modelHasAttributeOrRelationshipNamedType = modelHasAttributeOrRelationshipNamedType; 77999 exports.getOwner = getOwner; 78000}); 78001define('ember-data/-private/utils/parse-response-headers', ['exports', 'ember-data/-private/system/empty-object'], function (exports, _emberDataPrivateSystemEmptyObject) { 78002 'use strict'; 78003 78004 exports['default'] = parseResponseHeaders; 78005 78006 function _toArray(arr) { 78007 return Array.isArray(arr) ? arr : Array.from(arr); 78008 } 78009 78010 var CLRF = '\r\n'; 78011 function parseResponseHeaders(headersString) { 78012 var headers = new _emberDataPrivateSystemEmptyObject['default'](); 78013 78014 if (!headersString) { 78015 return headers; 78016 } 78017 78018 var headerPairs = headersString.split(CLRF); 78019 78020 headerPairs.forEach(function (header) { 78021 var _header$split = header.split(':'); 78022 78023 var _header$split2 = _toArray(_header$split); 78024 78025 var field = _header$split2[0]; 78026 78027 var value = _header$split2.slice(1); 78028 78029 field = field.trim(); 78030 value = value.join(':').trim(); 78031 78032 if (value) { 78033 headers[field] = value; 78034 } 78035 }); 78036 78037 return headers; 78038 } 78039}); 78040define('ember-data/adapter', ['exports', 'ember'], function (exports, _ember) { 78041 /** 78042 @module ember-data 78043 */ 78044 78045 'use strict'; 78046 78047 var get = _ember['default'].get; 78048 78049 /** 78050 An adapter is an object that receives requests from a store and 78051 translates them into the appropriate action to take against your 78052 persistence layer. The persistence layer is usually an HTTP API, but 78053 may be anything, such as the browser's local storage. Typically the 78054 adapter is not invoked directly instead its functionality is accessed 78055 through the `store`. 78056 78057 ### Creating an Adapter 78058 78059 Create a new subclass of `DS.Adapter` in the `app/adapters` folder: 78060 78061 ```app/adapters/application.js 78062 import DS from 'ember-data'; 78063 78064 export default DS.Adapter.extend({ 78065 // ...your code here 78066 }); 78067 ``` 78068 78069 Model-specific adapters can be created by putting your adapter
78070 class in an `app/adapters/` + `model-name` + `.js` file of the application. 78071 78072 ```app/adapters/post.js 78073 import DS from 'ember-data'; 78074 78075 export default DS.Adapter.extend({ 78076 // ...Post-specific adapter code goes here 78077 }); 78078 ``` 78079 78080 `DS.Adapter` is an abstract base class that you should override in your 78081 application to customize it for your backend. The minimum set of methods 78082 that you should implement is: 78083 78084 * `findRecord()` 78085 * `createRecord()` 78086 * `updateRecord()` 78087 * `deleteRecord()` 78088 * `findAll()` 78089 * `query()` 78090 78091 To improve the network performance of your application, you can optimize 78092 your adapter by overriding these lower-level methods: 78093 78094 * `findMany()` 78095 78096 78097 For an example implementation, see `DS.RESTAdapter`, the 78098 included REST adapter. 78099 78100 @class Adapter 78101 @namespace DS 78102 @extends Ember.Object 78103 */ 78104 78105 exports['default'] = _ember['default'].Object.extend({ 78106 78107 /** 78108 If you would like your adapter to use a custom serializer you can 78109 set the `defaultSerializer` property to be the name of the custom 78110 serializer. 78111 Note the `defaultSerializer` serializer has a lower priority than 78112 a model specific serializer (i.e. `PostSerializer`) or the 78113 `application` serializer. 78114 ```app/adapters/django.js 78115 import DS from 'ember-data'; 78116 export default DS.Adapter.extend({ 78117 defaultSerializer: 'django' 78118 }); 78119 ``` 78120 @property defaultSerializer 78121 @type {String} 78122 */ 78123 defaultSerializer: '-default', 78124 78125 /** 78126 The `findRecord()` method is invoked when the store is asked for a record that 78127 has not previously been loaded. In response to `findRecord()` being called, you 78128 should query your persistence layer for a record with the given ID. The `findRecord` 78129 method should return a promise that will resolve to a JavaScript object that will be 78130 normalized by the serializer. 78131 Here is an example `findRecord` implementation: 78132 ```app/adapters/application.js 78133 import DS from 'ember-data'; 78134 export default DS.Adapter.extend({ 78135 findRecord: function(store, type, id, snapshot) { 78136 var url = [type.modelName, id].join('/'); 78137 return new Ember.RSVP.Promise(function(resolve, reject) { 78138 Ember.$.getJSON(url).then(function(data) { 78139 Ember.run(null, resolve, data); 78140 }, function(jqXHR) { 78141 jqXHR.then = null; // tame jQuery's ill mannered promises 78142 Ember.run(null, reject, jqXHR); 78143 }); 78144 }); 78145 } 78146 }); 78147 ``` 78148 @method findRecord 78149 @param {DS.Store} store 78150 @param {DS.Model} type 78151 @param {String} id 78152 @param {DS.Snapshot} snapshot 78153 @return {Promise} promise 78154 */ 78155 findRecord: null, 78156 78157 /** 78158 The `findAll()` method is used to retrieve all records for a given type. 78159 Example 78160 ```app/adapters/application.js 78161 import DS from 'ember-data'; 78162 export default DS.Adapter.extend({ 78163 findAll: function(store, type, sinceToken) { 78164 var url = type; 78165 var query = { since: sinceToken }; 78166 return new Ember.RSVP.Promise(function(resolve, reject) { 78167 Ember.$.getJSON(url, query).then(function(data) { 78168 Ember.run(null, resolve, data); 78169 }, function(jqXHR) { 78170 jqXHR.then = null; // tame jQuery's ill mannered promises 78171 Ember.run(null, reject, jqXHR); 78172 }); 78173 }); 78174 } 78175 }); 78176 ``` 78177 @method findAll 78178 @param {DS.Store} store 78179 @param {DS.Model} type 78180 @param {String} sinceToken 78181 @param {DS.SnapshotRecordArray} snapshotRecordArray 78182 @return {Promise} promise 78183 */ 78184 findAll: null, 78185 78186 /** 78187 This method is called when you call `query` on the store. 78188 Example 78189 ```app/adapters/application.js 78190 import DS from 'ember-data'; 78191 export default DS.Adapter.extend({ 78192 query: function(store, type, query) { 78193 var url = type; 78194 return new Ember.RSVP.Promise(function(resolve, reject) { 78195 Ember.$.getJSON(url, query).then(function(data) { 78196 Ember.run(null, resolve, data); 78197 }, function(jqXHR) { 78198 jqXHR.then = null; // tame jQuery's ill mannered promises 78199 Ember.run(null, reject, jqXHR); 78200 }); 78201 }); 78202 } 78203 }); 78204 ``` 78205 @method query 78206 @param {DS.Store} store 78207 @param {DS.Model} type 78208 @param {Object} query
78209 @param {DS.AdapterPopulatedRecordArray} recordArray 78210 @return {Promise} promise 78211 */ 78212 query: null, 78213 78214 /** 78215 The `queryRecord()` method is invoked when the store is asked for a single 78216 record through a query object. 78217 In response to `queryRecord()` being called, you should always fetch fresh 78218 data. Once found, you can asynchronously call the store's `push()` method 78219 to push the record into the store. 78220 Here is an example `queryRecord` implementation: 78221 Example 78222 ```app/adapters/application.js 78223 import DS from 'ember-data'; 78224 import Ember from 'ember'; 78225 export default DS.Adapter.extend(DS.BuildURLMixin, { 78226 queryRecord: function(store, type, query) { 78227 var urlForQueryRecord = this.buildURL(type.modelName, null, null, 'queryRecord', query); 78228 return new Ember.RSVP.Promise(function(resolve, reject) { 78229 Ember.$.getJSON(urlForQueryRecord, query).then(function(data) { 78230 Ember.run(null, resolve, data); 78231 }, function(jqXHR) { 78232 jqXHR.then = null; // tame jQuery's ill mannered promises 78233 Ember.run(null, reject, jqXHR); 78234 }); 78235 }); 78236 } 78237 }); 78238 ``` 78239 @method queryRecord 78240 @param {DS.Store} store 78241 @param {subclass of DS.Model} type 78242 @param {Object} query 78243 @return {Promise} promise 78244 */ 78245 queryRecord: null, 78246 78247 /** 78248 If the globally unique IDs for your records should be generated on the client, 78249 implement the `generateIdForRecord()` method. This method will be invoked 78250 each time you create a new record, and the value returned from it will be 78251 assigned to the record's `primaryKey`. 78252 Most traditional REST-like HTTP APIs will not use this method. Instead, the ID 78253 of the record will be set by the server, and your adapter will update the store 78254 with the new ID when it calls `didCreateRecord()`. Only implement this method if 78255 you intend to generate record IDs on the client-side. 78256 The `generateIdForRecord()` method will be invoked with the requesting store as 78257 the first parameter and the newly created record as the second parameter: 78258 ```javascript 78259 generateIdForRecord: function(store, inputProperties) { 78260 var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision(); 78261 return uuid; 78262 } 78263 ``` 78264 @method generateIdForRecord 78265 @param {DS.Store} store 78266 @param {DS.Model} type the DS.Model class of the record 78267 @param {Object} inputProperties a hash of properties to set on the 78268 newly created record. 78269 @return {(String|Number)} id 78270 */ 78271 generateIdForRecord: null, 78272 78273 /** 78274 Proxies to the serializer's `serialize` method. 78275 Example 78276 ```app/adapters/application.js 78277 import DS from 'ember-data'; 78278 export default DS.Adapter.extend({ 78279 createRecord: function(store, type, snapshot) { 78280 var data = this.serialize(snapshot, { includeId: true }); 78281 var url = type; 78282 // ... 78283 } 78284 }); 78285 ``` 78286 @method serialize 78287 @param {DS.Snapshot} snapshot 78288 @param {Object} options 78289 @return {Object} serialized snapshot 78290 */ 78291 serialize: function serialize(snapshot, options) { 78292 return get(snapshot.record, 'store').serializerFor(snapshot.modelName).serialize(snapshot, options); 78293 }, 78294 78295 /** 78296 Implement this method in a subclass to handle the creation of 78297 new records. 78298 Serializes the record and sends it to the server. 78299 Example 78300 ```app/adapters/application.js 78301 import DS from 'ember-data'; 78302 export default DS.Adapter.extend({ 78303 createRecord: function(store, type, snapshot) { 78304 var data = this.serialize(snapshot, { includeId: true }); 78305 var url = type; 78306 return new Ember.RSVP.Promise(function(resolve, reject) { 78307 Ember.$.ajax({ 78308 type: 'POST', 78309 url: url, 78310 dataType: 'json', 78311 data: data 78312 }).then(function(data) { 78313 Ember.run(null, resolve, data); 78314 }, function(jqXHR) { 78315 jqXHR.then = null; // tame jQuery's ill mannered promises 78316 Ember.run(null, reject, jqXHR); 78317 }); 78318 }); 78319 } 78320 }); 78321 ``` 78322 @method createRecord 78323 @param {DS.Store} store 78324 @param {DS.Model} type the DS.Model class of the record 78325 @param {DS.Snapshot} snapshot 78326 @return {Promise} promise 78327 */ 78328 createRecord: null, 78329 78330 /** 78331 Implement this method in a subclass to handle the updating of 78332 a record.
78333 Serializes the record update and sends it to the server. 78334 The updateRecord method is expected to return a promise that will 78335 resolve with the serialized record. This allows the backend to 78336 inform the Ember Data store the current state of this record after 78337 the update. If it is not possible to return a serialized record 78338 the updateRecord promise can also resolve with `undefined` and the 78339 Ember Data store will assume all of the updates were successfully 78340 applied on the backend. 78341 Example 78342 ```app/adapters/application.js 78343 import DS from 'ember-data'; 78344 export default DS.Adapter.extend({ 78345 updateRecord: function(store, type, snapshot) { 78346 var data = this.serialize(snapshot, { includeId: true }); 78347 var id = snapshot.id; 78348 var url = [type, id].join('/'); 78349 return new Ember.RSVP.Promise(function(resolve, reject) { 78350 Ember.$.ajax({ 78351 type: 'PUT', 78352 url: url, 78353 dataType: 'json', 78354 data: data 78355 }).then(function(data) { 78356 Ember.run(null, resolve, data); 78357 }, function(jqXHR) { 78358 jqXHR.then = null; // tame jQuery's ill mannered promises 78359 Ember.run(null, reject, jqXHR); 78360 }); 78361 }); 78362 } 78363 }); 78364 ``` 78365 @method updateRecord 78366 @param {DS.Store} store 78367 @param {DS.Model} type the DS.Model class of the record 78368 @param {DS.Snapshot} snapshot 78369 @return {Promise} promise 78370 */ 78371 updateRecord: null, 78372 78373 /** 78374 Implement this method in a subclass to handle the deletion of 78375 a record. 78376 Sends a delete request for the record to the server. 78377 Example 78378 ```app/adapters/application.js 78379 import DS from 'ember-data'; 78380 export default DS.Adapter.extend({ 78381 deleteRecord: function(store, type, snapshot) { 78382 var data = this.serialize(snapshot, { includeId: true }); 78383 var id = snapshot.id; 78384 var url = [type, id].join('/'); 78385 return new Ember.RSVP.Promise(function(resolve, reject) { 78386 Ember.$.ajax({ 78387 type: 'DELETE', 78388 url: url, 78389 dataType: 'json', 78390 data: data 78391 }).then(function(data) { 78392 Ember.run(null, resolve, data); 78393 }, function(jqXHR) { 78394 jqXHR.then = null; // tame jQuery's ill mannered promises 78395 Ember.run(null, reject, jqXHR); 78396 }); 78397 }); 78398 } 78399 }); 78400 ``` 78401 @method deleteRecord 78402 @param {DS.Store} store 78403 @param {DS.Model} type the DS.Model class of the record 78404 @param {DS.Snapshot} snapshot 78405 @return {Promise} promise 78406 */ 78407 deleteRecord: null, 78408 78409 /** 78410 By default the store will try to coalesce all `fetchRecord` calls within the same runloop 78411 into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call. 78412 You can opt out of this behaviour by either not implementing the findMany hook or by setting 78413 coalesceFindRequests to false. 78414 @property coalesceFindRequests 78415 @type {boolean} 78416 */ 78417 coalesceFindRequests: true, 78418 78419 /** 78420 Find multiple records at once if coalesceFindRequests is true. 78421 @method findMany 78422 @param {DS.Store} store 78423 @param {DS.Model} type the DS.Model class of the records 78424 @param {Array} ids 78425 @param {Array} snapshots 78426 @return {Promise} promise 78427 */ 78428 findMany: null, 78429 78430 /** 78431 Organize records into groups, each of which is to be passed to separate 78432 calls to `findMany`. 78433 For example, if your api has nested URLs that depend on the parent, you will 78434 want to group records by their parent. 78435 The default implementation returns the records as a single group. 78436 @method groupRecordsForFindMany 78437 @param {DS.Store} store 78438 @param {Array} snapshots 78439 @return {Array} an array of arrays of records, each of which is to be 78440 loaded separately by `findMany`. 78441 */ 78442 groupRecordsForFindMany: function groupRecordsForFindMany(store, snapshots) { 78443 return [snapshots]; 78444 }, 78445 78446 /** 78447 This method is used by the store to determine if the store should
78448 reload a record from the adapter when a record is requested by 78449 `store.findRecord`. 78450 If this method returns `true`, the store will re-fetch a record from 78451 the adapter. If this method returns `false`, the store will resolve 78452 immediately using the cached record. 78453 For example, if you are building an events ticketing system, in which users 78454 can only reserve tickets for 20 minutes at a time, and want to ensure that 78455 in each route you have data that is no more than 20 minutes old you could 78456 write: 78457 ```javascript 78458 shouldReloadRecord: function(store, ticketSnapshot) { 78459 var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt')).minutes(); 78460 if (timeDiff > 20) { 78461 return true; 78462 } else { 78463 return false; 78464 } 78465 } 78466 ``` 78467 This method would ensure that whenever you do `store.findRecord('ticket', 78468 id)` you will always get a ticket that is no more than 20 minutes old. In 78469 case the cached version is more than 20 minutes old, `findRecord` will not 78470 resolve until you fetched the latest version. 78471 By default this hook returns `false`, as most UIs should not block user 78472 interactions while waiting on data update. 78473 @since 1.13.0 78474 @method shouldReloadRecord 78475 @param {DS.Store} store 78476 @param {DS.Snapshot} snapshot 78477 @return {Boolean} 78478 */ 78479 shouldReloadRecord: function shouldReloadRecord(store, snapshot) { 78480 return false; 78481 }, 78482 78483 /** 78484 This method is used by the store to determine if the store should 78485 reload all records from the adapter when records are requested by 78486 `store.findAll`. 78487 If this method returns `true`, the store will re-fetch all records from 78488 the adapter. If this method returns `false`, the store will resolve 78489 immediately using the cached records. 78490 For example, if you are building an events ticketing system, in which users 78491 can only reserve tickets for 20 minutes at a time, and want to ensure that 78492 in each route you have data that is no more than 20 minutes old you could 78493 write: 78494 ```javascript 78495 shouldReloadAll: function(store, snapshotArray) { 78496 var snapshots = snapshotArray.snapshots(); 78497 return snapshots.any(function(ticketSnapshot) { 78498 var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt')).minutes(); 78499 if (timeDiff > 20) { 78500 return true; 78501 } else { 78502 return false; 78503 } 78504 }); 78505 } 78506 ``` 78507 This method would ensure that whenever you do `store.findAll('ticket')` you 78508 will always get a list of tickets that are no more than 20 minutes old. In 78509 case a cached version is more than 20 minutes old, `findAll` will not 78510 resolve until you fetched the latest versions. 78511 By default this methods returns `true` if the passed `snapshotRecordArray` 78512 is empty (meaning that there are no records locally available yet), 78513 otherwise it returns `false`. 78514 @since 1.13.0 78515 @method shouldReloadAll 78516 @param {DS.Store} store 78517 @param {DS.SnapshotRecordArray} snapshotRecordArray 78518 @return {Boolean} 78519 */ 78520 shouldReloadAll: function shouldReloadAll(store, snapshotRecordArray) { 78521 return !snapshotRecordArray.length; 78522 }, 78523 78524 /** 78525 This method is used by the store to determine if the store should
78526 reload a record after the `store.findRecord` method resolves a 78527 cached record. 78528 This method is *only* checked by the store when the store is 78529 returning a cached record. 78530 If this method returns `true` the store will re-fetch a record from 78531 the adapter. 78532 For example, if you do not want to fetch complex data over a mobile 78533 connection, or if the network is down, you can implement 78534 `shouldBackgroundReloadRecord` as follows: 78535 ```javascript 78536 shouldBackgroundReloadRecord: function(store, snapshot) { 78537 var connection = window.navigator.connection; 78538 if (connection === 'cellular' || connection === 'none') { 78539 return false; 78540 } else { 78541 return true; 78542 } 78543 } 78544 ``` 78545 By default this hook returns `true` so the data for the record is updated 78546 in the background. 78547 @since 1.13.0 78548 @method shouldBackgroundReloadRecord 78549 @param {DS.Store} store 78550 @param {DS.Snapshot} snapshot 78551 @return {Boolean} 78552 */ 78553 shouldBackgroundReloadRecord: function shouldBackgroundReloadRecord(store, snapshot) { 78554 return true; 78555 }, 78556 78557 /** 78558 This method is used by the store to determine if the store should
78559 reload a record array after the `store.findAll` method resolves 78560 with a cached record array. 78561 This method is *only* checked by the store when the store is 78562 returning a cached record array. 78563 If this method returns `true` the store will re-fetch all records 78564 from the adapter. 78565 For example, if you do not want to fetch complex data over a mobile 78566 connection, or if the network is down, you can implement 78567 `shouldBackgroundReloadAll` as follows: 78568 ```javascript 78569 shouldBackgroundReloadAll: function(store, snapshotArray) { 78570 var connection = window.navigator.connection; 78571 if (connection === 'cellular' || connection === 'none') { 78572 return false; 78573 } else { 78574 return true; 78575 } 78576 } 78577 ``` 78578 By default this method returns `true`, indicating that a background reload 78579 should always be triggered. 78580 @since 1.13.0 78581 @method shouldBackgroundReloadAll 78582 @param {DS.Store} store 78583 @param {DS.SnapshotRecordArray} snapshotRecordArray 78584 @return {Boolean} 78585 */ 78586 shouldBackgroundReloadAll: function shouldBackgroundReloadAll(store, snapshotRecordArray) { 78587 return true; 78588 } 78589 }); 78590}); 78591define('ember-data/adapters/errors', ['exports', 'ember', 'ember-data/-private/debug', 'ember-data/-private/features'], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateFeatures) { 78592 'use strict'; 78593 78594 exports.AdapterError = AdapterError; 78595 exports.errorsHashToArray = errorsHashToArray; 78596 exports.errorsArrayToHash = errorsArrayToHash; 78597 78598 var EmberError = _ember['default'].Error; 78599 78600 var SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; 78601 var SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; 78602 var PRIMARY_ATTRIBUTE_KEY = 'base'; 78603 78604 /** 78605 @class AdapterError 78606 @namespace DS 78607 */ 78608 78609 function AdapterError(errors) { 78610 var message = arguments.length <= 1 || arguments[1] === undefined ? 'Adapter operation failed' : arguments[1]; 78611 78612 this.isAdapterError = true; 78613 EmberError.call(this, message); 78614 78615 this.errors = errors || [{ 78616 title: 'Adapter Error', 78617 detail: message 78618 }]; 78619 } 78620 78621 var extendedErrorsEnabled = false; 78622 if (false) { 78623 extendedErrorsEnabled = true; 78624 } 78625 78626 function extendFn(ErrorClass) { 78627 return function () { 78628 var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; 78629 78630 var defaultMessage = _ref.message; 78631 78632 return extend(ErrorClass, defaultMessage); 78633 }; 78634 } 78635 78636 function extend(ParentErrorClass, defaultMessage) { 78637 var ErrorClass = function ErrorClass(errors, message) { 78638 (0, _emberDataPrivateDebug.assert)('`AdapterError` expects json-api formatted errors array.', Array.isArray(errors || [])); 78639 ParentErrorClass.call(this, errors, message || defaultMessage); 78640 }; 78641 ErrorClass.prototype = Object.create(ParentErrorClass.prototype); 78642 78643 if (extendedErrorsEnabled) { 78644 ErrorClass.extend = extendFn(ErrorClass); 78645 } 78646 78647 return ErrorClass; 78648 } 78649 78650 AdapterError.prototype = Object.create(EmberError.prototype); 78651 78652 if (extendedErrorsEnabled) { 78653 AdapterError.extend = extendFn(AdapterError); 78654 } 78655 78656 /** 78657 A `DS.InvalidError` is used by an adapter to signal the external API 78658 was unable to process a request because the content was not 78659 semantically correct or meaningful per the API. Usually this means a 78660 record failed some form of server side validation. When a promise 78661 from an adapter is rejected with a `DS.InvalidError` the record will 78662 transition to the `invalid` state and the errors will be set to the 78663 `errors` property on the record. 78664 78665 For Ember Data to correctly map errors to their corresponding 78666 properties on the model, Ember Data expects each error to be 78667 a valid json-api error object with a `source/pointer` that matches 78668 the property name. For example if you had a Post model that 78669 looked like this. 78670 78671 ```app/models/post.js 78672 import DS from 'ember-data'; 78673 78674 export default DS.Model.extend({ 78675 title: DS.attr('string'), 78676 content: DS.attr('string') 78677 }); 78678 ``` 78679 78680 To show an error from the server related to the `title` and 78681 `content` properties your adapter could return a promise that 78682 rejects with a `DS.InvalidError` object that looks like this: 78683
78684 ```app/adapters/post.js 78685 import Ember from 'ember'; 78686 import DS from 'ember-data'; 78687 78688 export default DS.RESTAdapter.extend({ 78689 updateRecord: function() { 78690 // Fictional adapter that always rejects 78691 return Ember.RSVP.reject(new DS.InvalidError([ 78692 { 78693 detail: 'Must be unique', 78694 source: { pointer: '/data/attributes/title' } 78695 }, 78696 { 78697 detail: 'Must not be blank', 78698 source: { pointer: '/data/attributes/content'} 78699 } 78700 ])); 78701 } 78702 }); 78703 ``` 78704 78705 Your backend may use different property names for your records the 78706 store will attempt extract and normalize the errors using the 78707 serializer's `extractErrors` method before the errors get added to 78708 the the model. As a result, it is safe for the `InvalidError` to 78709 wrap the error payload unaltered. 78710 78711 @class InvalidError 78712 @namespace DS 78713 */ 78714 var InvalidError = extend(AdapterError, 'The adapter rejected the commit because it was invalid'); 78715 78716 exports.InvalidError = InvalidError; 78717 78718 /** 78719 @class TimeoutError 78720 @namespace DS 78721 */ 78722 var TimeoutError = extend(AdapterError, 'The adapter operation timed out'); 78723 78724 exports.TimeoutError = TimeoutError; 78725 78726 /** 78727 @class AbortError 78728 @namespace DS 78729 */ 78730 var AbortError = extend(AdapterError, 'The adapter operation was aborted'); 78731 78732 exports.AbortError = AbortError; 78733 78734 /** 78735 @class UnauthorizedError 78736 @namespace DS 78737 */ 78738 var UnauthorizedError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation is unauthorized') : null; 78739 78740 exports.UnauthorizedError = UnauthorizedError; 78741 78742 /** 78743 @class ForbiddenError 78744 @namespace DS 78745 */ 78746 var ForbiddenError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation is forbidden') : null; 78747 78748 exports.ForbiddenError = ForbiddenError; 78749 78750 /** 78751 @class NotFoundError 78752 @namespace DS 78753 */ 78754 var NotFoundError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter could not find the resource') : null; 78755 78756 exports.NotFoundError = NotFoundError; 78757 78758 /** 78759 @class ConflictError 78760 @namespace DS 78761 */ 78762 var ConflictError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation failed due to a conflict') : null; 78763 78764 exports.ConflictError = ConflictError; 78765 78766 /** 78767 @class ServerError 78768 @namespace DS 78769 */ 78770 var ServerError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation failed due to a server error') : null; 78771 78772 exports.ServerError = ServerError; 78773 78774 /** 78775 @method errorsHashToArray 78776 @private 78777 */ 78778 78779 function errorsHashToArray(errors) { 78780 var out = []; 78781 78782 if (_ember['default'].isPresent(errors)) { 78783 Object.keys(errors).forEach(function (key) { 78784 var messages = _ember['default'].makeArray(errors[key]); 78785 for (var i = 0; i < messages.length; i++) { 78786 var title = 'Invalid Attribute'; 78787 var pointer = '/data/attributes/' + key; 78788 if (key === PRIMARY_ATTRIBUTE_KEY) { 78789 title = 'Invalid Document'; 78790 pointer = '/data'; 78791 } 78792 out.push({ 78793 title: title, 78794 detail: messages[i], 78795 source: { 78796 pointer: pointer 78797 } 78798 }); 78799 } 78800 }); 78801 } 78802 78803 return out; 78804 } 78805 78806 /** 78807 @method errorsArrayToHash 78808 @private 78809 */ 78810 78811 function errorsArrayToHash(errors) { 78812 var out = {}; 78813 78814 if (_ember['default'].isPresent(errors)) { 78815 errors.forEach(function (error) { 78816 if (error.source && error.source.pointer) { 78817 var key = error.source.pointer.match(SOURCE_POINTER_REGEXP); 78818 78819 if (key) { 78820 key = key[2]; 78821 } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) { 78822 key = PRIMARY_ATTRIBUTE_KEY; 78823 } 78824 78825 if (key) { 78826 out[key] = out[key] || []; 78827 out[key].push(error.detail || error.title); 78828 } 78829 } 78830 }); 78831 } 78832 78833 return out; 78834 } 78835}); 78836define('ember-data/adapters/json-api', ['exports', 'ember', 'ember-data/adapters/rest', 'ember-data/-private/features', 'ember-data/-private/debug'], function (exports, _ember, _emberDataAdaptersRest, _emberDataPrivateFeatures, _emberDataPrivateDebug) { 78837 /** 78838 @module ember-data 78839 */ 78840 78841 'use strict'; 78842 78843 /** 78844 @since 1.13.0 78845 @class JSONAPIAdapter 78846 @constructor 78847 @namespace DS 78848 @extends DS.RESTAdapter 78849 */ 78850 var JSONAPIAdapter = _emberDataAdaptersRest['default'].extend({ 78851 defaultSerializer: '-json-api', 78852 78853 /** 78854 @method ajaxOptions 78855 @private 78856 @param {String} url 78857 @param {String} type The request type GET, POST, PUT, DELETE etc. 78858 @param {Object} options 78859 @return {Object} 78860 */ 78861 ajaxOptions: function ajaxOptions(url, type, options) { 78862 var hash = this._super.apply(this, arguments); 78863 78864 if (hash.contentType) { 78865 hash.contentType = 'application/vnd.api+json'; 78866 } 78867 78868 var beforeSend = hash.beforeSend; 78869 hash.beforeSend = function (xhr) { 78870 xhr.setRequestHeader('Accept', 'application/vnd.api+json'); 78871 if (beforeSend) { 78872 beforeSend(xhr); 78873 } 78874 }; 78875 78876 return hash; 78877 }, 78878 78879 /** 78880 By default the JSONAPIAdapter will send each find request coming from a `store.find` 78881 or from accessing a relationship separately to the server. If your server supports passing 78882 ids as a query string, you can set coalesceFindRequests to true to co
78882alesce all find requests 78883 within a single runloop. 78884 For example, if you have an initial payload of: 78885 ```javascript 78886 { 78887 post: { 78888 id: 1, 78889 comments: [1, 2] 78890 } 78891 } 78892 ``` 78893 By default calling `post.get('comments')` will trigger the following requests(assuming the 78894 comments haven't been loaded before): 78895 ``` 78896 GET /comments/1 78897 GET /comments/2 78898 ``` 78899 If you set coalesceFindRequests to `true` it will instead trigger the following request: 78900 ``` 78901 GET /comments?filter[id]=1,2 78902 ``` 78903 Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` 78904 relationships accessed within the same runloop. If you set `coalesceFindRequests: true` 78905 ```javascript 78906 store.findRecord('comment', 1); 78907 store.findRecord('comment', 2); 78908 ``` 78909 will also send a request to: `GET /comments?filter[id]=1,2` 78910 Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app 78911 `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. 78912 @property coalesceFindRequests 78913 @type {boolean} 78914 */ 78915 coalesceFindRequests: false, 78916 78917 /** 78918 @method findMany 78919 @param {DS.Store} store 78920 @param {DS.Model} type 78921 @param {Array} ids 78922 @param {Array} snapshots 78923 @return {Promise} promise 78924 */ 78925 findMany: function findMany(store, type, ids, snapshots) { 78926 if (false && !this._hasCustomizedAjax()) { 78927 return this._super.apply(this, arguments); 78928 } else { 78929 var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); 78930 return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); 78931 } 78932 }, 78933 78934 /** 78935 @method pathForType 78936 @param {String} modelName 78937 @return {String} path 78938 **/ 78939 pathForType: function pathForType(modelName) { 78940 var dasherized = _ember['default'].String.dasherize(modelName); 78941 return _ember['default'].String.pluralize(dasherized); 78942 }, 78943 78944 // TODO: Remove this once we have a better way to override HTTP verbs. 78945 /** 78946 @method updateRecord 78947 @param {DS.Store} store 78948 @param {DS.Model} type 78949 @param {DS.Snapshot} snapshot 78950 @return {Promise} promise 78951 */ 78952 updateRecord: function updateRecord(store, type, snapshot) { 78953 if (false && !this._hasCustomizedAjax()) { 78954 return this._super.apply(this, arguments); 78955 } else { 78956 var data = {}; 78957 var serializer = store.serializerFor(type.modelName); 78958 78959 serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); 78960 78961 var id = snapshot.id; 78962 var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); 78963 78964 return this.ajax(url, 'PATCH', { data: data }); 78965 } 78966 }, 78967 78968 _hasCustomizedAjax: function _hasCustomizedAjax() { 78969 if (this.ajax !== JSONAPIAdapter.prototype.ajax) { 78970 (0, _emberDataPrivateDebug.deprecate)('JSONAPIAdapter#ajax has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { 78971 id: 'ds.json-api-adapter.ajax', 78972 until: '3.0.0' 78973 }); 78974 return true; 78975 } 78976 78977 if (this.ajaxOptions !== JSONAPIAdapter.prototype.ajaxOptions) { 78978 (0, _emberDataPrivateDebug.deprecate)('JSONAPIAdapterr#ajaxOptions has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { 78979 id: 'ds.json-api-adapter.ajax-options', 78980 until: '3.0.0' 78981 }); 78982 return true; 78983 } 78984 78985 return false; 78986 } 78987 }); 78988 78989 if (false) { 78990 78991 JSONAPIAdapter.reopen({ 78992 78993 methodForRequest: function methodForRequest(params) { 78994 if (params.requestType === 'updateRecord') { 78995 return 'PATCH'; 78996 } 78997 78998 return this._super.apply(this, arguments); 78999 }, 79000 79001 dataForRequest: function dataForRequest(params) { 79002 var requestType = params.requestType; 79003 var ids = params.ids; 79004 79005 if (requestType === 'findMany') { 79006 return { 79007 filter: { id: ids.join(',') } 79008 }; 79009 } 79010 79011 if (requestType === 'updateRecord') { 79012 var store = params.store; 79013 var type = params.type; 79014 var snapshot = params.snapshot; 79015 79016 var data = {}; 79017 var serializer = store.serializerFor(type.modelName); 79018 79019 serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); 79020 79021 return data; 79022 } 79023 79024 return this._super.apply(this, arguments); 79025 }, 79026 79027 headersForRequest: function headersForRequest() { 79028 var headers = this._super.apply(this, arguments) || {}; 79029 79030 headers['Accept'] = 'application/vnd.api+json'; 79031 79032 return headers; 79033 }, 79034 79035 _requestToJQueryAjaxHash: function _requestToJQueryAjaxHash() { 79036 var hash = this._super.apply(this, arguments); 79037 79038 if (hash.contentType) { 79039 hash.contentType = 'application/vnd.api+json'; 79040 } 79041 79042 return hash; 79043 } 79044 79045 }); 79046 } 79047 79048 exports['default'] = JSONAPIAdapter; 79049});
79050define('ember-data/adapters/rest', ['exports', 'ember', 'ember-data/adapter', 'ember-data/adapters/errors', 'ember-data/-private/adapters/build-url-mixin', 'ember-data/-private/features', 'ember-data/-private/debug', 'ember-data/-private/utils/parse-response-headers'], function (exports, _ember, _emberDataAdapter, _emberDataAdaptersErrors, _emberDataPrivateAdaptersBuildUrlMixin, _emberDataPrivateFeatures, _emberDataPrivateDebug, _emberDataPrivateUtilsParseResponseHeaders) { 79051 /** 79052 @module ember-data 79053 */ 79054 79055 'use strict'; 79056 79057 var MapWithDefault = _ember['default'].MapWithDefault; 79058 var get = _ember['default'].get; 79059 79060 /** 79061 The REST adapter allows your store to communicate with an HTTP server by 79062 transmitting JSON via XHR. Most Ember.js apps that consume a JSON API 79063 should use the REST adapter. 79064 79065 This adapter is designed around the idea that the JSON exchanged with 79066 the server should be conventional. 79067 79068 ## Success and failure 79069 79070 The REST adapter will consider a success any response with a status code 79071 of the 2xx family ("Success"), as well as 304 ("Not Modified"). Any other 79072 status code will be considered a failure. 79073 79074 On success, the request promise will be resolved with the full response 79075 payload. 79076 79077 Failed responses with status code 422 ("Unprocessable Entity") will be 79078 considered "invalid". The response will be discarded, except for the 79079 `errors` key. The request promise will be rejected with a `DS.InvalidError`. 79080 This error object will encapsulate the saved `errors` value. 79081 79082 Any other status codes will be treated as an "adapter error". The request 79083 promise will be rejected, similarly to the "invalid" case, but with 79084 an instance of `DS.AdapterError` instead. 79085 79086 ## JSON Structure 79087 79088 The REST adapter expects the JSON returned from your server to follow 79089 these conventions. 79090 79091 ### Object Root 79092 79093 The JSON payload should be an object that contains the record inside a 79094 root property. For example, in response to a `GET` request for 79095 `/posts/1`, the JSON should look like this: 79096 79097 ```js 79098 { 79099 "post": { 79100 "id": 1, 79101 "title": "I'm Running to Reform the W3C's Tag", 79102 "author": "Yehuda Katz" 79103 } 79104 } 79105 ``` 79106 79107 Similarly, in response to a `GET` request for `/posts`, the JSON should 79108 look like this: 79109 79110 ```js 79111 { 79112 "posts": [ 79113 { 79114 "id": 1, 79115 "title": "I'm Running to Reform the W3C's Tag", 79116 "author": "Yehuda Katz" 79117 }, 79118 { 79119 "id": 2, 79120 "title": "Rails is omakase", 79121 "author": "D2H" 79122 } 79123 ] 79124 } 79125 ``` 79126 79127 Note that the object root can be pluralized for both a single-object response 79128 and an array response: the REST adapter is not strict on this. Further, if the 79129 HTTP server responds to a `GET` request to `/posts/1` (e.g. the response to a 79130 `findRecord` query) with more than one object in the array, Ember Data will 79131 only display the object with the matching ID. 79132 79133 ### Conventional Names 79134 79135 Attribute names in your JSON payload should be the camelCased versions of 79136 the attributes in your Ember.js models. 79137 79138 For example, if you have a `Person` model: 79139 79140 ```app/models/person.js 79141 import DS from 'ember-data'; 79142 79143 export default DS.Model.extend({ 79144 firstName: DS.attr('string'), 79145 lastName: DS.attr('string'), 79146 occupation: DS.attr('string') 79147 }); 79148 ``` 79149 79150 The JSON returned should look like this: 79151 79152 ```js 79153 { 79154 "person": { 79155 "id": 5, 79156 "firstName": "Barack", 79157 "lastName": "Obama", 79158 "occupation": "President" 79159 } 79160 } 79161 ``` 79162 79163 ### Errors 79164 79165 If a response is considered a failure, the JSON payload is expected to include 79166 a top-level key `errors`, detailing any specific issues. For example: 79167 79168 ```js 79169 { 79170 "errors": { 79171 "msg": "Something went wrong" 79172 } 79173 } 79174 ``` 79175 79176 This adapter does not make any assumptions as to the format of the `errors` 79177 object. It will simply be passed along as is, wrapped in an instance
79178 of `DS.InvalidError` or `DS.AdapterError`. The serializer can interpret it 79179 afterwards. 79180 79181 ## Customization 79182 79183 ### Endpoint path customization 79184 79185 Endpoint paths can be prefixed with a `namespace` by setting the namespace 79186 property on the adapter: 79187 79188 ```app/adapters/application.js 79189 import DS from 'ember-data'; 79190 79191 export default DS.RESTAdapter.extend({ 79192 namespace: 'api/1' 79193 }); 79194 ``` 79195 Requests for the `Person` model would now target `/api/1/people/1`. 79196 79197 ### Host customization 79198 79199 An adapter can target other hosts by setting the `host` property. 79200 79201 ```app/adapters/application.js 79202 import DS from 'ember-data'; 79203 79204 export default DS.RESTAdapter.extend({ 79205 host: 'https://api.example.com' 79206 }); 79207 ``` 79208 79209 ### Headers customization 79210 79211 Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary 79212 headers can be set as key/value pairs on the `RESTAdapter`'s `headers` 79213 object and Ember Data will send them along with each ajax request. 79214 79215 79216 ```app/adapters/application.js 79217 import DS from 'ember-data'; 79218 79219 export default DS.RESTAdapter.extend({ 79220 headers: { 79221 "API_KEY": "secret key", 79222 "ANOTHER_HEADER": "Some header value" 79223 } 79224 }); 79225 ``` 79226 79227 `headers` can also be used as a computed property to support dynamic 79228 headers. In the example below, the `session` object has been 79229 injected into an adapter by Ember's container. 79230 79231 ```app/adapters/application.js 79232 import DS from 'ember-data'; 79233 79234 export default DS.RESTAdapter.extend({ 79235 headers: Ember.computed('session.authToken', function() { 79236 return { 79237 "API_KEY": this.get("session.authToken"), 79238 "ANOTHER_HEADER": "Some header value" 79239 }; 79240 }) 79241 }); 79242 ``` 79243 79244 In some cases, your dynamic headers may require data from some 79245 object outside of Ember's observer system (for example 79246 `document.cookie`). You can use the 79247 [volatile](/api/classes/Ember.ComputedProperty.html#method_volatile) 79248 function to set the property into a non-cached mode causing the headers to 79249 be recomputed with every request. 79250 79251 ```app/adapters/application.js 79252 import DS from 'ember-data'; 79253 79254 export default DS.RESTAdapter.extend({ 79255 headers: Ember.computed(function() { 79256 return { 79257 "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), 79258 "ANOTHER_HEADER": "Some header value" 79259 }; 79260 }).volatile() 79261 }); 79262 ``` 79263 79264 @class RESTAdapter 79265 @constructor 79266 @namespace DS 79267 @extends DS.Adapter 79268 @uses DS.BuildURLMixin 79269 */ 79270 var RESTAdapter = _emberDataAdapter['default'].extend(_emberDataPrivateAdaptersBuildUrlMixin['default'], { 79271 defaultSerializer: '-rest', 79272 79273 /** 79274 By default, the RESTAdapter will send the query params sorted alphabetically to the 79275 server. 79276 For example: 79277 ```js 79278 store.query('posts', { sort: 'price', category: 'pets' }); 79279 ``` 79280 will generate a requests like this `/posts?category=pets&sort=price`, even if the 79281 parameters were specified in a different order. 79282 That way the generated URL will be deterministic and that simplifies caching mechanisms 79283 in the backend. 79284 Setting `sortQueryParams` to a falsey value will respect the original order. 79285 In case you want to sort the query parameters with a different criteria, set 79286 `sortQueryParams` to your custom sort function. 79287 ```app/adapters/application.js 79288 import DS from 'ember-data'; 79289 export default DS.RESTAdapter.extend({ 79290 sortQueryParams: function(params) { 79291 var sortedKeys = Object.keys(params).sort().reverse(); 79292 var len = sortedKeys.length, newParams = {}; 79293 for (var i = 0; i < len; i++) { 79294 newParams[sortedKeys[i]] = params[sortedKeys[i]]; 79295 } 79296 return newParams; 79297 } 79298 }); 79299 ``` 79300 @method sortQueryParams 79301 @param {Object} obj 79302 @return {Object} 79303 */ 79304 sortQueryParams: function sortQueryParams(obj) { 79305 var keys = Object.keys(obj); 79306 var len = keys.length; 79307 if (len < 2) { 79308 return obj; 79309 } 79310 var newQueryParams = {}; 79311 var sortedKeys = keys.sort(); 79312 79313 for (var i = 0; i < len; i++) { 79314 newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; 79315 } 79316 return newQueryParams; 79317 }, 79318 79319 /** 79320 By default the RESTAdapter will send each find request coming from a `store.find` 79321 or from accessing a relationship separately to the server. If your server supports passing 79322 ids as a query string, you can set coalesceFindRequests to true to co
79322alesce all find requests 79323 within a single runloop. 79324 For example, if you have an initial payload of: 79325 ```javascript 79326 { 79327 post: { 79328 id: 1, 79329 comments: [1, 2] 79330 } 79331 } 79332 ``` 79333 By default calling `post.get('comments')` will trigger the following requests(assuming the 79334 comments haven't been loaded before): 79335 ``` 79336 GET /comments/1 79337 GET /comments/2 79338 ``` 79339 If you set coalesceFindRequests to `true` it will instead trigger the following request: 79340 ``` 79341 GET /comments?ids[]=1&ids[]=2 79342 ``` 79343 Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` 79344 relationships accessed within the same runloop. If you set `coalesceFindRequests: true` 79345 ```javascript 79346 store.findRecord('comment', 1); 79347 store.findRecord('comment', 2); 79348 ``` 79349 will also send a request to: `GET /comments?ids[]=1&ids[]=2` 79350 Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app 79351 `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. 79352 @property coalesceFindRequests 79353 @type {boolean} 79354 */ 79355 coalesceFindRequests: false, 79356 79357 /** 79358 Endpoint paths can be prefixed with a `namespace` by setting the namespace 79359 property on the adapter: 79360 ```app/adapters/application.js 79361 import DS from 'ember-data'; 79362 export default DS.RESTAdapter.extend({ 79363 namespace: 'api/1' 79364 }); 79365 ``` 79366 Requests for the `Post` model would now target `/api/1/post/`. 79367 @property namespace 79368 @type {String} 79369 */ 79370 79371 /** 79372 An adapter can target other hosts by setting the `host` property. 79373 ```app/adapters/application.js 79374 import DS from 'ember-data'; 79375 export default DS.RESTAdapter.extend({ 79376 host: 'https://api.example.com' 79377 }); 79378 ``` 79379 Requests for the `Post` model would now target `https://api.example.com/post/`. 79380 @property host 79381 @type {String} 79382 */ 79383 79384 /** 79385 Some APIs require HTTP headers, e.g. to provide an API 79386 key. Arbitrary headers can be set as key/value pairs on the 79387 `RESTAdapter`'s `headers` object and Ember Data will send them 79388 along with each ajax request. For dynamic headers see [headers 79389 customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). 79390 ```app/adapters/application.js 79391 import DS from 'ember-data'; 79392 export default DS.RESTAdapter.extend({ 79393 headers: { 79394 "API_KEY": "secret key", 79395 "ANOTHER_HEADER": "Some header value" 79396 } 79397 }); 79398 ``` 79399 @property headers 79400 @type {Object} 79401 */ 79402 79403 /** 79404 Called by the store in order to fetch the JSON for a given 79405 type and ID. 79406 The `findRecord` method makes an Ajax request to a URL computed by 79407 `buildURL`, and returns a promise for the resulting payload. 79408 This method performs an HTTP `GET` request with the id provided as part of the query string. 79409 @since 1.13.0 79410 @method findRecord 79411 @param {DS.Store} store 79412 @param {DS.Model} type 79413 @param {String} id 79414 @param {DS.Snapshot} snapshot 79415 @return {Promise} promise 79416 */ 79417 findRecord: function findRecord(store, type, id, snapshot) { 79418 if (false && !this._hasCustomizedAjax()) { 79419 var request = this._requestFor({ 79420 store: store, type: type, id: id, snapshot: snapshot, 79421 requestType: 'findRecord' 79422 }); 79423 79424 return this._makeRequest(request); 79425 } else { 79426 var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); 79427 var query = this.buildQuery(snapshot); 79428 79429 return this.ajax(url, 'GET', { data: query }); 79430 } 79431 }, 79432 79433 /** 79434 Called by the store in order to fetch a JSON array for all 79435 of the records for a given type. 79436 The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a 79437 promise for the resulting payload. 79438 @method findAll 79439 @param {DS.Store} store 79440 @param {DS.Model} type 79441 @param {String} sinceToken 79442 @param {DS.SnapshotRecordArray} snapshotRecordArray 79443 @return {Promise} promise 79444 */ 79445 findAll: function findAll(store, type, sinceToken, snapshotRecordArray) { 79446 var query = this.buildQuery(snapshotRecordArray); 79447 79448 if (false && !this._hasCustomizedAjax()) { 79449 var request = this._requestFor({ 79450 store: store, type: type, sinceToken: sinceToken, query: query, 79451 snapshots: snapshotRecordArray, 79452 requestType: 'findAll' 79453 }); 79454
79455 return this._makeRequest(request); 79456 } else { 79457 var url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll'); 79458 79459 if (sinceToken) { 79460 query.since = sinceToken; 79461 } 79462 79463 return this.ajax(url, 'GET', { data: query }); 79464 } 79465 }, 79466 79467 /** 79468 Called by the store in order to fetch a JSON array for 79469 the records that match a particular query. 79470 The `query` method makes an Ajax (HTTP GET) request to a URL 79471 computed by `buildURL`, and returns a promise for the resulting 79472 payload. 79473 The `query` argument is a simple JavaScript object that will be passed directly 79474 to the server as parameters. 79475 @method query 79476 @param {DS.Store} store 79477 @param {DS.Model} type 79478 @param {Object} query 79479 @return {Promise} promise 79480 */ 79481 query: function query(store, type, _query) { 79482 if (false && !this._hasCustomizedAjax()) { 79483 var request = this._requestFor({ 79484 store: store, type: type, query: _query, 79485 requestType: 'query' 79486 }); 79487 79488 return this._makeRequest(request); 79489 } else { 79490 var url = this.buildURL(type.modelName, null, null, 'query', _query); 79491 79492 if (this.sortQueryParams) { 79493 _query = this.sortQueryParams(_query); 79494 } 79495 79496 return this.ajax(url, 'GET', { data: _query }); 79497 } 79498 }, 79499 79500 /** 79501 Called by the store in order to fetch a JSON object for 79502 the record that matches a particular query. 79503 The `queryRecord` method makes an Ajax (HTTP GET) request to a URL 79504 computed by `buildURL`, and returns a promise for the resulting 79505 payload. 79506 The `query` argument is a simple JavaScript object that will be passed directly 79507 to the server as parameters. 79508 @since 1.13.0 79509 @method queryRecord 79510 @param {DS.Store} store 79511 @param {DS.Model} type 79512 @param {Object} query 79513 @return {Promise} promise 79514 */ 79515 queryRecord: function queryRecord(store, type, query) { 79516 if (false && !this._hasCustomizedAjax()) { 79517 var request = this._requestFor({ 79518 store: store, type: type, query: query, 79519 requestType: 'queryRecord' 79520 }); 79521 79522 return this._makeRequest(request); 79523 } else { 79524 var url = this.buildURL(type.modelName, null, null, 'queryRecord', query); 79525 79526 if (this.sortQueryParams) { 79527 query = this.sortQueryParams(query); 79528 } 79529 79530 return this.ajax(url, 'GET', { data: query }); 79531 } 79532 }, 79533 79534 /** 79535 Called by the store in order to fetch several records together if `coalesceFindRequests` is true 79536 For example, if the original payload looks like: 79537 ```js 79538 { 79539 "id": 1, 79540 "title": "Rails is omakase", 79541 "comments": [ 1, 2, 3 ] 79542 } 79543 ``` 79544 The IDs will be passed as a URL-encoded Array of IDs, in this form: 79545 ``` 79546 ids[]=1&ids[]=2&ids[]=3 79547 ``` 79548 Many servers, such as Rails and PHP, will automatically convert this URL-encoded array 79549 into an Array for you on the server-side. If you want to encode the 79550 IDs, differently, just override this (one-line) method. 79551 The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a 79552 promise for the resulting payload. 79553 @method findMany 79554 @param {DS.Store} store 79555 @param {DS.Model} type 79556 @param {Array} ids 79557 @param {Array} snapshots 79558 @return {Promise} promise 79559 */ 79560 findMany: function findMany(store, type, ids, snapshots) { 79561 if (false && !this._hasCustomizedAjax()) { 79562 var request = this._requestFor({ 79563 store: store, type: type, ids: ids, snapshots: snapshots, 79564 requestType: 'findMany' 79565 }); 79566 79567 return this._makeRequest(request); 79568 } else { 79569 var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); 79570 return this.ajax(url, 'GET', { data: { ids: ids } }); 79571 } 79572 }, 79573 79574 /** 79575 Called by the store in order to fetch a JSON array for 79576 the unloaded records in a has-many relationship that were originally 79577 specified as a URL (inside of `links`). 79578 For example, if your original payload looks like this: 79579 ```js 79580 { 79581 "post": { 79582 "id": 1, 79583 "title": "Rails is omakase", 79584 "links": { "comments": "/posts/1/comments" } 79585 } 79586 } 79587 ``` 79588 This method will be called with the parent record and `/posts/1/comments`. 79589 The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL. 79590 The format of your `links` value will influence the final request URL via the `urlPrefix` method: 79591 * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation. 79592 * Links beginning with a single `/` will have the current adapter's `host` value prepended to it.
79593 * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`. 79594 @method findHasMany 79595 @param {DS.Store} store 79596 @param {DS.Snapshot} snapshot 79597 @param {String} url 79598 @return {Promise} promise 79599 */ 79600 findHasMany: function findHasMany(store, snapshot, url, relationship) { 79601 if (false && !this._hasCustomizedAjax()) { 79602 var request = this._requestFor({ 79603 store: store, snapshot: snapshot, url: url, relationship: relationship, 79604 requestType: 'findHasMany' 79605 }); 79606 79607 return this._makeRequest(request); 79608 } else { 79609 var id = snapshot.id; 79610 var type = snapshot.modelName; 79611 79612 url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany')); 79613 79614 return this.ajax(url, 'GET'); 79615 } 79616 }, 79617 79618 /** 79619 Called by the store in order to fetch the JSON for the unloaded record in a 79620 belongs-to relationship that was originally specified as a URL (inside of 79621 `links`). 79622 For example, if your original payload looks like this: 79623 ```js 79624 { 79625 "person": { 79626 "id": 1, 79627 "name": "Tom Dale", 79628 "links": { "group": "/people/1/group" } 79629 } 79630 } 79631 ``` 79632 This method will be called with the parent record and `/people/1/group`. 79633 The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL. 79634 The format of your `links` value will influence the final request URL via the `urlPrefix` method: 79635 * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation. 79636 * Links beginning with a single `/` will have the current adapter's `host` value prepended to it. 79637 * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`. 79638 @method findBelongsTo 79639 @param {DS.Store} store 79640 @param {DS.Snapshot} snapshot 79641 @param {String} url 79642 @return {Promise} promise 79643 */ 79644 findBelongsTo: function findBelongsTo(store, snapshot, url, relationship) { 79645 if (false && !this._hasCustomizedAjax()) { 79646 var request = this._requestFor({ 79647 store: store, snapshot: snapshot, url: url, relationship: relationship, 79648 requestType: 'findBelongsTo' 79649 }); 79650 79651 return this._makeRequest(request); 79652 } else { 79653 var id = snapshot.id; 79654 var type = snapshot.modelName; 79655 79656 url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo')); 79657 return this.ajax(url, 'GET'); 79658 } 79659 }, 79660 79661 /** 79662 Called by the store when a newly created record is 79663 saved via the `save` method on a model record instance. 79664 The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request 79665 to a URL computed by `buildURL`. 79666 See `serialize` for information on how to customize the serialized form 79667 of a record. 79668 @method createRecord 79669 @param {DS.Store} store 79670 @param {DS.Model} type 79671 @param {DS.Snapshot} snapshot 79672 @return {Promise} promise 79673 */ 79674 createRecord: function createRecord(store, type, snapshot) { 79675 if (false && !this._hasCustomizedAjax()) { 79676 var request = this._requestFor({ 79677 store: store, type: type, snapshot: snapshot, 79678 requestType: 'createRecord' 79679 }); 79680 79681 return this._makeRequest(request); 79682 } else { 79683 var data = {}; 79684 var serializer = store.serializerFor(type.modelName); 79685 var url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); 79686 79687 serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); 79688 79689 return this.ajax(url, "POST", { data: data }); 79690 } 79691 }, 79692 79693 /**
79694 Called by the store when an existing record is saved 79695 via the `save` method on a model record instance. 79696 The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request 79697 to a URL computed by `buildURL`. 79698 See `serialize` for information on how to customize the serialized form 79699 of a record. 79700 @method updateRecord 79701 @param {DS.Store} store 79702 @param {DS.Model} type 79703 @param {DS.Snapshot} snapshot 79704 @return {Promise} promise 79705 */ 79706 updateRecord: function updateRecord(store, type, snapshot) { 79707 if (false && !this._hasCustomizedAjax()) { 79708 var request = this._requestFor({ 79709 store: store, type: type, snapshot: snapshot, 79710 requestType: 'updateRecord' 79711 }); 79712 79713 return this._makeRequest(request); 79714 } else { 79715 var data = {}; 79716 var serializer = store.serializerFor(type.modelName); 79717 79718 serializer.serializeIntoHash(data, type, snapshot); 79719 79720 var id = snapshot.id; 79721 var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); 79722 79723 return this.ajax(url, "PUT", { data: data }); 79724 } 79725 }, 79726 79727 /** 79728 Called by the store when a record is deleted. 79729 The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`. 79730 @method deleteRecord 79731 @param {DS.Store} store 79732 @param {DS.Model} type 79733 @param {DS.Snapshot} snapshot 79734 @return {Promise} promise 79735 */ 79736 deleteRecord: function deleteRecord(store, type, snapshot) { 79737 if (false && !this._hasCustomizedAjax()) { 79738 var request = this._requestFor({ 79739 store: store, type: type, snapshot: snapshot, 79740 requestType: 'deleteRecord' 79741 }); 79742 79743 return this._makeRequest(request); 79744 } else { 79745 var id = snapshot.id; 79746 79747 return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); 79748 } 79749 }, 79750 79751 _stripIDFromURL: function _stripIDFromURL(store, snapshot) { 79752 var url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); 79753 79754 var expandedURL = url.split('/'); 79755 // Case when the url is of the format ...something/:id 79756 // We are decodeURIComponent-ing the lastSegment because if it represents 79757 // the id, it has been encodeURIComponent-ified within `buildURL`. If we 79758 // don't do this, then records with id having special characters are not 79759 // coalesced correctly (see GH #4190 for the reported bug) 79760 var lastSegment = expandedURL[expandedURL.length - 1]; 79761 var id = snapshot.id; 79762 if (decodeURIComponent(lastSegment) === id) { 79763 expandedURL[expandedURL.length - 1] = ""; 79764 } else if (endsWith(lastSegment, '?id=' + id)) { 79765 //Case when the url is of the format ...something?id=:id 79766 expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); 79767 } 79768 79769 return expandedURL.join('/'); 79770 }, 79771 79772 // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 79773 maxURLLength: 2048, 79774 79775 /** 79776 Organize records into groups, each of which is to be passed to separate 79777 calls to `findMany`. 79778 This implementation groups together records that have the same base URL but 79779 differing ids. For example `/comments/1` and `/comments/2` will be grouped together 79780 because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2` 79781 It also supports urls where ids are passed as a query param, such as `/comments?id=1` 79782 but not those where there is more than 1 query param such as `/comments?id=2&name=David` 79783 Currently only the query param of `id` is supported. If you need to support others, please 79784 override this or the `_stripIDFromURL` method. 79785 It does not group records that have differing base urls, such as for example: `/posts/1/comments/2` 79786 and `/posts/2/comments/3` 79787 @method groupRecordsForFindMany 79788 @param {DS.Store} store 79789 @param {Array} snapshots 79790 @return {Array} an array of arrays of records, each of which is to be 79791 loaded separately by `findMany`. 79792 */ 79793 groupRecordsForFindMany: function groupRecordsForFindMany(store, snapshots) { 79794 var groups = MapWithDefault.create({ defaultValue: function defaultValue() { 79795 return []; 79796 } }); 79797 var adapter = this; 79798 var maxURLLength = this.maxURLLength; 79799
79800 snapshots.forEach(function (snapshot) { 79801 var baseUrl = adapter._stripIDFromURL(store, snapshot); 79802 groups.get(baseUrl).push(snapshot); 79803 }); 79804 79805 function splitGroupToFitInUrl(group, maxURLLength, paramNameLength) { 79806 var baseUrl = adapter._stripIDFromURL(store, group[0]); 79807 var idsSize = 0; 79808 var splitGroups = [[]]; 79809 79810 group.forEach(function (snapshot) { 79811 var additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; 79812 if (baseUrl.length + idsSize + additionalLength >= maxURLLength) { 79813 idsSize = 0; 79814 splitGroups.push([]); 79815 } 79816 79817 idsSize += additionalLength; 79818 79819 var lastGroupIndex = splitGroups.length - 1; 79820 splitGroups[lastGroupIndex].push(snapshot); 79821 }); 79822 79823 return splitGroups; 79824 } 79825 79826 var groupsArray = []; 79827 groups.forEach(function (group, key) { 79828 var paramNameLength = '&ids%5B%5D='.length; 79829 var splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength); 79830 79831 splitGroups.forEach(function (splitGroup) { 79832 return groupsArray.push(splitGroup); 79833 }); 79834 }); 79835 79836 return groupsArray; 79837 }, 79838 79839 /** 79840 Takes an ajax response, and returns the json payload or an error. 79841 By default this hook just returns the json payload passed to it. 79842 You might want to override it in two cases: 79843 1. Your API might return useful results in the response headers. 79844 Response headers are passed in as the second argument. 79845 2. Your API might return errors as successful responses with status code 79846 200 and an Errors text or object. You can return a `DS.InvalidError` or a 79847 `DS.AdapterError` (or a sub class) from this hook and it will automatically 79848 reject the promise and put your record into the invalid or error state. 79849 Returning a `DS.InvalidError` from this method will cause the 79850 record to transition into the `invalid` state and make the 79851 `errors` object available on the record. When returning an 79852 `DS.InvalidError` the store will attempt to normalize the error data 79853 returned from the server using the serializer's `extractErrors` 79854 method. 79855 @since 1.13.0 79856 @method handleResponse 79857 @param {Number} status 79858 @param {Object} headers 79859 @param {Object} payload 79860 @param {Object} requestData - the original request information 79861 @return {Object | DS.AdapterError} response 79862 */ 79863 handleResponse: function handleResponse(status, headers, payload, requestData) { 79864 if (this.isSuccess(status, headers, payload)) { 79865 return payload; 79866 } else if (this.isInvalid(status, headers, payload)) { 79867 return new _emberDataAdaptersErrors.InvalidError(payload.errors); 79868 } 79869 79870 var errors = this.normalizeErrorResponse(status, headers, payload); 79871 var detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); 79872 79873 if (false) { 79874 switch (status) { 79875 case 401: 79876 return new _emberDataAdaptersErrors.UnauthorizedError(errors, detailedMessage); 79877 case 403: 79878 return new _emberDataAdaptersErrors.ForbiddenError(errors, detailedMessage); 79879 case 404: 79880 return new _emberDataAdaptersErrors.NotFoundError(errors, detailedMessage); 79881 case 409: 79882 return new _emberDataAdaptersErrors.ConflictError(errors, detailedMessage); 79883 default: 79884 if (status >= 500) { 79885 return new _emberDataAdaptersErrors.ServerError(errors, detailedMessage); 79886 } 79887 } 79888 } 79889 79890 return new _emberDataAdaptersErrors.AdapterError(errors, detailedMessage); 79891 }, 79892 79893 /** 79894 Default `handleResponse` implementation uses this hook to decide if the 79895 response is a success. 79896 @since 1.13.0 79897 @method isSuccess 79898 @param {Number} status 79899 @param {Object} headers 79900 @param {Object} payload 79901 @return {Boolean} 79902 */ 79903 isSuccess: function isSuccess(status, headers, payload) { 79904 return status >= 200 && status < 300 || status === 304; 79905 }, 79906 79907 /** 79908 Default `handleResponse` implementation uses this hook to decide if the
79909 response is a an invalid error. 79910 @since 1.13.0 79911 @method isInvalid 79912 @param {Number} status 79913 @param {Object} headers 79914 @param {Object} payload 79915 @return {Boolean} 79916 */ 79917 isInvalid: function isInvalid(status, headers, payload) { 79918 return status === 422; 79919 }, 79920 79921 /** 79922 Takes a URL, an HTTP method and a hash of data, and makes an 79923 HTTP request. 79924 When the server responds with a payload, Ember Data will call into `extractSingle` 79925 or `extractArray` (depending on whether the original query was for one record or 79926 many records). 79927 By default, `ajax` method has the following behavior: 79928 * It sets the response `dataType` to `"json"` 79929 * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be 79930 `application/json; charset=utf-8` 79931 * If the HTTP method is not `"GET"`, it stringifies the data passed in. The 79932 data is the serialized record in the case of a save. 79933 * Registers success and failure handlers. 79934 @method ajax 79935 @private 79936 @param {String} url 79937 @param {String} type The request type GET, POST, PUT, DELETE etc. 79938 @param {Object} options 79939 @return {Promise} promise 79940 */ 79941 ajax: function ajax(url, type, options) { 79942 var adapter = this; 79943 79944 var requestData = { 79945 url: url, 79946 method: type 79947 }; 79948 79949 return new _ember['default'].RSVP.Promise(function (resolve, reject) { 79950 var hash = adapter.ajaxOptions(url, type, options); 79951 79952 hash.success = function (payload, textStatus, jqXHR) { 79953 79954 var response = adapter.handleResponse(jqXHR.status, (0, _emberDataPrivateUtilsParseResponseHeaders['default'])(jqXHR.getAllResponseHeaders()), payload, requestData); 79955 79956 if (response && response.isAdapterError) { 79957 _ember['default'].run.join(null, reject, response); 79958 } else { 79959 _ember['default'].run.join(null, resolve, response); 79960 } 79961 }; 79962 79963 hash.error = function (jqXHR, textStatus, errorThrown) { 79964 (0, _emberDataPrivateDebug.runInDebug)(function () { 79965 var message = 'The server returned an empty string for ' + type + ' ' + url + ', which cannot be parsed into a valid JSON. Return either null or {}.'; 79966 var validJSONString = !(textStatus === "parsererror" && jqXHR.responseText === ""); 79967 (0, _emberDataPrivateDebug.warn)(message, validJSONString, { 79968 id: 'ds.adapter.returned-empty-string-as-JSON' 79969 }); 79970 }); 79971 79972 var error = undefined; 79973 79974 if (errorThrown instanceof Error) { 79975 error = errorThrown; 79976 } else if (textStatus === 'timeout') { 79977 error = new _emberDataAdaptersErrors.TimeoutError(); 79978 } else if (textStatus === 'abort') { 79979 error = new _emberDataAdaptersErrors.AbortError(); 79980 } else { 79981 error = adapter.handleResponse(jqXHR.status, (0, _emberDataPrivateUtilsParseResponseHeaders['default'])(jqXHR.getAllResponseHeaders()), adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, requestData); 79982 } 79983 79984 _ember['default'].run.join(null, reject, error); 79985 }; 79986 79987 adapter._ajaxRequest(hash); 79988 }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); 79989 }, 79990 79991 /** 79992 @method _ajaxRequest 79993 @private 79994 @param {Object} options jQuery ajax options to be used for the ajax request 79995 */ 79996 _ajaxRequest: function _ajaxRequest(options) { 79997 _ember['default'].$.ajax(options); 79998 }, 79999 80000 /** 80001 @method ajaxOptions 80002 @private 80003 @param {String} url 80004 @param {String} type The request type GET, POST, PUT, DELETE etc. 80005 @param {Object} options 80006 @return {Object} 80007 */ 80008 ajaxOptions: function ajaxOptions(url, type, options) { 80009 var hash = options || {}; 80010 hash.url = url; 80011 hash.type = type; 80012 hash.dataType = 'json'; 80013 hash.context = this; 80014 80015 if (hash.data && type !== 'GET') { 80016 hash.contentType = 'application/json; charset=utf-8'; 80017 hash.data = JSON.stringify(hash.data); 80018 } 80019 80020 var headers = get(this, 'headers'); 80021 if (headers !== undefined) { 80022 hash.beforeSend = function (xhr) {
80023 Object.keys(headers).forEach(function (key) { 80024 return xhr.setRequestHeader(key, headers[key]); 80025 }); 80026 }; 80027 } 80028 80029 return hash; 80030 }, 80031 80032 /** 80033 @method parseErrorResponse 80034 @private 80035 @param {String} responseText 80036 @return {Object} 80037 */ 80038 parseErrorResponse: function parseErrorResponse(responseText) { 80039 var json = responseText; 80040 80041 try { 80042 json = _ember['default'].$.parseJSON(responseText); 80043 } catch (e) { 80044 // ignored 80045 } 80046 80047 return json; 80048 }, 80049 80050 /** 80051 @method normalizeErrorResponse 80052 @private 80053 @param {Number} status 80054 @param {Object} headers 80055 @param {Object} payload 80056 @return {Array} errors payload 80057 */ 80058 normalizeErrorResponse: function normalizeErrorResponse(status, headers, payload) { 80059 if (payload && typeof payload === 'object' && payload.errors) { 80060 return payload.errors; 80061 } else { 80062 return [{ 80063 status: '' + status, 80064 title: "The backend responded with an error", 80065 detail: '' + payload 80066 }]; 80067 } 80068 }, 80069 80070 /** 80071 Generates a detailed ("friendly") error message, with plenty 80072 of information for debugging (good luck!) 80073 @method generatedDetailedMessage 80074 @private 80075 @param {Number} status 80076 @param {Object} headers 80077 @param {Object} payload 80078 @param {Object} requestData 80079 @return {String} detailed error message 80080 */ 80081 generatedDetailedMessage: function generatedDetailedMessage(status, headers, payload, requestData) { 80082 var shortenedPayload; 80083 var payloadContentType = headers["Content-Type"] || "Empty Content-Type"; 80084 80085 if (payloadContentType === "text/html" && payload.length > 250) { 80086 shortenedPayload = "[Omitted Lengthy HTML]"; 80087 } else { 80088 shortenedPayload = payload; 80089 } 80090 80091 var requestDescription = requestData.method + ' ' + requestData.url; 80092 var payloadDescription = 'Payload (' + payloadContentType + ')'; 80093 80094 return ['Ember Data Request ' + requestDescription + ' returned a ' + status, payloadDescription, shortenedPayload].join('\n'); 80095 }, 80096 80097 // @since 2.5.0 80098 buildQuery: function buildQuery(snapshot) { 80099 var query = {}; 80100 80101 if (snapshot) { 80102 var include = snapshot.include; 80103 80104 if (include) { 80105 query.include = include; 80106 } 80107 } 80108 80109 return query; 80110 }, 80111 80112 _hasCustomizedAjax: function _hasCustomizedAjax() { 80113 if (this.ajax !== RESTAdapter.prototype.ajax) { 80114 (0, _emberDataPrivateDebug.deprecate)('RESTAdapter#ajax has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { 80115 id: 'ds.rest-adapter.ajax', 80116 until: '3.0.0' 80117 }); 80118 return true; 80119 } 80120 80121 if (this.ajaxOptions !== RESTAdapter.prototype.ajaxOptions) { 80122 (0, _emberDataPrivateDebug.deprecate)('RESTAdapter#ajaxOptions has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { 80123 id: 'ds.rest-adapter.ajax-options', 80124 until: '3.0.0' 80125 }); 80126 return true; 80127 } 80128 80129 return false; 80130 } 80131 }); 80132 80133 if (false) { 80134 80135 RESTAdapter.reopen({ 80136 80137 /** 80138 * Get the data (body or query params) for a request. 80139 * 80140 * @public 80141 * @method dataForRequest 80142 * @param {Object} params 80143 * @return {Object} data 80144 */ 80145 dataForRequest: function dataForRequest(params) { 80146 var store = params.store; 80147 var type = params.type; 80148 var snapshot = params.snapshot; 80149 var requestType = params.requestType; 80150 var query = params.query; 80151 80152 // type is not passed to findBelongsTo and findHasMany 80153 type = type || snapshot && snapshot.type; 80154 80155 var serializer = store.serializerFor(type.modelName); 80156 var data = {}; 80157 80158 switch (requestType) { 80159 case 'createRecord': 80160 serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); 80161 break; 80162 80163 case 'updateRecord': 80164 serializer.serializeIntoHash(data, type, snapshot); 80165 break; 80166 80167 case 'findRecord': 80168 data = this.buildQuery(snapshot); 80169 break; 80170 80171 case 'findAll': 80172 if (params.sinceToken) { 80173 query = query || {}; 80174 query.since = params.sinceToken; 80175 } 80176 data = query; 80177 break; 80178 80179 case 'query': 80180 case 'queryRecord': 80181 if (this.sortQueryParams) { 80182 query = this.sortQueryParams(query); 80183 } 80184 data = query; 80185 break; 80186 80187 case 'findMany': 80188 data = { ids: params.ids }; 80189 break; 80190 80191 default: 80192 data = undefined; 80193 break; 80194 } 80195 80196 return data; 80197 }, 80198 80199 /** 80200 * Get the HTTP method for a request. 80201 * 80202 * @public 80203 * @method methodForRequest 80204 * @param {Object} params 80205 * @return {String} HTTP method 80206 */ 80207 methodForRequest: function methodForRequest(params) { 80208 var requestType = params.requestType; 80209 80210 switch (requestType) { 80211 case 'createRecord': 80212 return 'POST'; 80213 case 'updateRecord': 80214 return 'PUT'; 80215 case 'deleteRecord': 80216 return 'DELETE'; 80217 } 80218 80219 return 'GET'; 80220 }, 80221 80222 /** 80223 * Get the URL for a request. 80224 * 80225 * @public 80226 * @method urlForRequest 80227 * @param {Object} params 80228 * @return {String} URL 80229 */ 80230 urlForRequest: function urlForRequest(params) { 80231 var type = params.type; 80232 var id = params.id; 80233 var ids = params.ids; 80234 var snapshot = params.snapshot; 80235 var snapshots = params.snapshots; 80236 var requestType = params.requestType; 80237 var query = params.query; 80238 80239 // type and id are not passed from updateRecord and deleteRecord, hence they 80240 // are defined if not set 80241 type = type || snapshot && snapshot.type; 80242 id = id || snapshot && snapshot.id; 80243 80244 switch (requestType) { 80245 case 'findAll': 80246 return this.buildURL(type.modelName, null, snapshots, requestType); 80247 80248 case 'query': 80249 case 'queryRecord': 80250 return this.buildURL(type.modelName, null, null, requestType, query); 80251 80252 case 'findMany': 80253 return this.buildURL(type.modelName, ids, snapshots, requestType); 80254 80255 case 'findHasMany': 80256 case 'findBelongsTo': 80257 { 80258 var url = this.buildURL(type.modelName, id, snapshot, requestType); 80259 return this.urlPrefix(params.url, url); 80260 } 80261 } 80262 80263 return this.buildURL(type.modelName, id, snapshot, requestType, query); 80264 }, 80265 80266 /** 80267 * Get the headers for a request. 80268 * 80269 * By default the value of the `headers` property of the adapter is 80270 * returned. 80271 * 80272 * @public 80273 * @method headersForRequest 80274 * @param {Object} params 80275 * @return {Object} headers 80276 */ 80277 headersForRequest: function headersForRequest(params) { 80278 return this.get('headers'); 80279 }, 80280 80281 /** 80282 * Get an object which contains all properties for a request which should 80283 * be made. 80284 * 80285 * @private 80286 * @method _requestFor 80287 * @param {Object} params 80288 * @return {Object} request object 80289 */ 80290 _requestFor: function _requestFor(params) { 80291 var method = this.methodForRequest(params); 80292 var url = this.urlForRequest(params); 80293 var headers = this.headersForRequest(params); 80294 var data = this.dataForRequest(params); 80295 80296 return { method: method, url: url, headers: headers, data: data }; 80297 }, 80298 80299 /** 80300 * Convert a request object into a hash which can be passed to `jQuery.ajax`. 80301 * 80302 * @private 80303 * @method _requestToJQueryAjaxHash 80304 * @param {Object} request 80305 * @return {Object} jQuery ajax hash 80306 */ 80307 _requestToJQueryAjaxHash: function _requestToJQueryAjaxHash(request) { 80308 var hash = {}; 80309 80310 hash.type = request.method; 80311 hash.url = request.url; 80312 hash.dataType = 'json'; 80313 hash.context = this; 80314 80315 if (request.data) { 80316 if (request.method !== 'GET') { 80317 hash.contentType = 'application/json; charset=utf-8'; 80318 hash.data = JSON.stringify(request.data); 80319 } else { 80320 hash.data = request.data; 80321 } 80322 } 80323 80324 var headers = request.headers; 80325 if (headers !== undefined) { 80326 hash.beforeSend = function (xhr) {
80327 Object.keys(headers).forEach(function (key) { 80328 return xhr.setRequestHeader(key, headers[key]); 80329 }); 80330 }; 80331 } 80332 80333 return hash; 80334 }, 80335 80336 /** 80337 * Make a request using `jQuery.ajax`. 80338 * 80339 * @private 80340 * @method _makeRequest 80341 * @param {Object} request 80342 * @return {Promise} promise 80343 */ 80344 _makeRequest: function _makeRequest(request) { 80345 var adapter = this; 80346 var hash = this._requestToJQueryAjaxHash(request); 80347 80348 var method = request.method; 80349 var url = request.url; 80350 80351 var requestData = { method: method, url: url }; 80352 80353 return new _ember['default'].RSVP.Promise(function (resolve, reject) { 80354 80355 hash.success = function (payload, textStatus, jqXHR) { 80356 var response = adapter.handleResponse(jqXHR.status, (0, _emberDataPrivateUtilsParseResponseHeaders['default'])(jqXHR.getAllResponseHeaders()), payload, requestData); 80357 80358 if (response instanceof _emberDataAdaptersErrors.AdapterError) { 80359 _ember['default'].run.join(null, reject, response); 80360 } else { 80361 _ember['default'].run.join(null, resolve, response); 80362 } 80363 }; 80364 80365 hash.error = function (jqXHR, textStatus, errorThrown) { 80366 (0, _emberDataPrivateDebug.runInDebug)(function () { 80367 var message = 'The server returned an empty string for ' + method + ' ' + url + ', which cannot be parsed into a valid JSON. Return either null or {}.'; 80368 var validJSONString = !(textStatus === "parsererror" && jqXHR.responseText === ""); 80369 (0, _emberDataPrivateDebug.warn)(message, validJSONString, { 80370 id: 'ds.adapter.returned-empty-string-as-JSON' 80371 }); 80372 }); 80373 80374 var error = undefined; 80375 80376 if (errorThrown instanceof Error) { 80377 error = errorThrown; 80378 } else if (textStatus === 'timeout') { 80379 error = new _emberDataAdaptersErrors.TimeoutError(); 80380 } else if (textStatus === 'abort') { 80381 error = new _emberDataAdaptersErrors.AbortError(); 80382 } else { 80383 error = adapter.handleResponse(jqXHR.status, (0, _emberDataPrivateUtilsParseResponseHeaders['default'])(jqXHR.getAllResponseHeaders()), adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, requestData); 80384 } 80385 80386 _ember['default'].run.join(null, reject, error); 80387 }; 80388 80389 adapter._ajaxRequest(hash); 80390 }, 'DS: RESTAdapter#makeRequest: ' + method + ' ' + url); 80391 } 80392 }); 80393 } 80394 80395 //From http://stackoverflow.com/questions/280634/endswith-in-javascript 80396 function endsWith(string, suffix) { 80397 if (typeof String.prototype.endsWith !== 'function') { 80398 return string.indexOf(suffix, string.length - suffix.length) !== -1; 80399 } else { 80400 return string.endsWith(suffix); 80401 } 80402 } 80403 80404 exports['default'] = RESTAdapter; 80405}); 80406define('ember-data/attr', ['exports', 'ember', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateDebug) { 80407 'use strict'; 80408 80409 exports['default'] = attr; 80410 80411 /** 80412 @module ember-data 80413 */ 80414 80415 function getDefaultValue(record, options, key) { 80416 if (typeof options.defaultValue === 'function') { 80417 return options.defaultValue.apply(null, arguments); 80418 } else { 80419 var defaultValue = options.defaultValue; 80420 (0, _emberDataPrivateDebug.deprecate)('Non primitive defaultValues are deprecated because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.', typeof defaultValue !== 'object' || defaultValue === null, { 80421 id: 'ds.defaultValue.complex-object', 80422 until: '3.0.0' 80423 }); 80424 return defaultValue; 80425 } 80426 } 80427 80428 function hasValue(record, key) { 80429 return key in record._attributes || key in record._inFlightAttributes || key in record._data; 80430 } 80431 80432 function getValue(record, key) { 80433 if (key in record._attributes) { 80434 return record._attributes[key]; 80435 } else if (key in record._inFlightAttributes) { 80436 return record._inFlightAttributes[key]; 80437 } else { 80438 return record._data[key]; 80439 } 80440 } 80441 80442 /** 80443 `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). 80444 By default, attributes are passed through as-is, however you can specify an 80445 optional type to have the value automatically transformed. 80446 Ember Data ships with four basic transform types: `string`, `number`, 80447 `boolean` and `date`. You can define your own transforms by subclassing 80448 [DS.Transform](/api/data/classes/DS.Transform.html). 80449 80450 Note that you cannot use `attr` to define an attribute of `id`. 80451
80452 `DS.attr` takes an optional hash as a second parameter, currently 80453 supported options are: 80454 80455 - `defaultValue`: Pass a string or a function to be called to set the attribute 80456 to a default value if none is supplied. 80457 80458 Example 80459 80460 ```app/models/user.js 80461 import DS from 'ember-data'; 80462 80463 export default DS.Model.extend({ 80464 username: DS.attr('string'), 80465 email: DS.attr('string'), 80466 verified: DS.attr('boolean', { defaultValue: false }) 80467 }); 80468 ``` 80469 80470 Default value can also be a function. This is useful it you want to return 80471 a new object for each attribute. 80472 80473 ```app/models/user.js 80474 import DS from 'ember-data'; 80475 80476 export default DS.Model.extend({ 80477 username: attr('string'), 80478 email: attr('string'), 80479 settings: attr({defaultValue: function() { 80480 return {}; 80481 }}) 80482 }); 80483 ``` 80484 80485 The `options` hash is passed as second argument to a transforms' 80486 `serialize` and `deserialize` method. This allows to configure a 80487 transformation and adapt the corresponding value, based on the config: 80488 80489 ```app/models/post.js 80490 export default DS.Model.extend({ 80491 text: DS.attr('text', { 80492 uppercase: true 80493 }) 80494 }); 80495 ``` 80496 80497 ```app/transforms/text.js 80498 export default DS.Transform.extend({ 80499 serialize: function(value, options) { 80500 if (options.uppercase) { 80501 return value.toUpperCase(); 80502 } 80503 80504 return value; 80505 }, 80506 80507 deserialize: function(value) { 80508 return value; 80509 } 80510 }) 80511 ``` 80512 80513 @namespace 80514 @method attr 80515 @for DS 80516 @param {String} type the attribute type 80517 @param {Object} options a hash of options 80518 @return {Attribute} 80519 */ 80520 function attr(type, options) { 80521 if (typeof type === 'object') { 80522 options = type; 80523 type = undefined; 80524 } else { 80525 options = options || {}; 80526 } 80527 80528 var meta = { 80529 type: type, 80530 isAttribute: true, 80531 options: options 80532 }; 80533 80534 return _ember['default'].computed({ 80535 get: function get(key) { 80536 var internalModel = this._internalModel; 80537 if (hasValue(internalModel, key)) { 80538 return getValue(internalModel, key); 80539 } else { 80540 return getDefaultValue(this, options, key); 80541 } 80542 }, 80543 set: function set(key, value) { 80544 var internalModel = this._internalModel; 80545 var oldValue = getValue(internalModel, key); 80546 var originalValue; 80547 80548 if (value !== oldValue) { 80549 // Add the new value to the changed attributes hash; it will get deleted by 80550 // the 'didSetProperty' handler if it is no different from the original value 80551 internalModel._attributes[key] = value; 80552 80553 if (key in internalModel._inFlightAttributes) { 80554 originalValue = internalModel._inFlightAttributes[key]; 80555 } else { 80556 originalValue = internalModel._data[key]; 80557 } 80558 80559 this._internalModel.send('didSetProperty', { 80560 name: key, 80561 oldValue: oldValue, 80562 originalValue: originalValue, 80563 value: value 80564 }); 80565 } 80566 80567 return value; 80568 } 80569 }).meta(meta); 80570 } 80571}); 80572define("ember-data/index", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/features", "ember-data/-private/global", "ember-data/-private/core", "ember-data/-private/system/normalize-model-name", "ember-data/-private/system/model/internal-model", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/store", "ember-data/-private/system/model", "ember-data/model", "ember-data/-private/system/snapshot", "ember-data/adapter", "ember-data/serializer", "ember-data/-private/system/debug", "ember-data/adapters/errors", "ember-data/-private/system/record-arrays", "ember-data/-private/system/many-array", "ember-data/-private/system/record-array-manager", "ember-data/-private/adapters", "ember-data/-private/adapters/build-url-mixin", "ember-data/-private/serializers", "ember-inflector", "ember-data/serializers/embedded-records-mixin", "ember-data/-private/transforms", "ember-data/relationships", "ember-data/setup-container", "ember-data/-private/instance-initializer
80572s/initialize-store-service", "ember-data/-private/system/container-proxy", "ember-data/-private/system/relationships/state/relationship"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateFeatures, _emberDataPrivateGlobal, _emberDataPrivateCore, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateSystemModelInternalModel, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStore, _emberDataPrivateSystemModel, _emberDataModel, _emberDataPrivateSystemSnapshot, _emberDataAdapter, _emberDataSerializer, _emberDataPrivateSystemDebug, _emberDataAdaptersErrors, _emberDataPrivateSystemRecordArrays, _emberDataPrivateSystemManyArray, _emberDataPrivateSystemRecordArrayManager, _emberDataPrivateAdapters, _emberDataPrivateAdaptersBuildUrlMixin, _emberDataPrivateSerializers, _emberInflector, _emberDataSerializersEmbeddedRecordsMixin, _emberDataPrivateTransforms, _emberDataRelationships, _emberDataSetupContainer, _emberDataPrivateInstanceInitializersInitializeStoreService, _emberDataPrivateSystemContainerProxy, _emberDataPrivateSystemRelationshipsStateRelationship) { 80573 "use strict"; 80574 80575 if (_ember["default"].VERSION.match(/^1\.([0-9]|1[0-2])\./)) { 80576 throw new _ember["default"].Error("Ember Data requires at least Ember 1.13.0, but you have " + _ember["default"].VERSION + ". Please upgrade your version of Ember, then upgrade Ember Data."); 80577 }_emberDataPrivateCore["default"].Store = _emberDataPrivateSystemStore.Store; 80578 _emberDataPrivateCore["default"].PromiseArray = _emberDataPrivateSystemPromiseProxies.PromiseArray; 80579 _emberDataPrivateCore["default"].PromiseObject = _emberDataPrivateSystemPromiseProxies.PromiseObject; 80580 80581 _emberDataPrivateCore["default"].PromiseManyArray = _emberDataPrivateSystemPromiseProxies.PromiseManyArray; 80582 80583 _emberDataPrivateCore["default"].Model = _emberDataModel["default"]; 80584 _emberDataPrivateCore["default"].RootState = _emberDataPrivateSystemModel.RootState; 80585 _emberDataPrivateCore["default"].attr = _emberDataPrivateSystemModel.attr; 80586 _emberDataPrivateCore["default"].Errors = _emberDataPrivateSystemModel.Errors; 80587 80588 _emberDataPrivateCore["default"].InternalModel = _emberDataPrivateSystemModelInternalModel["default"]; 80589 _emberDataPrivateCore["default"].Snapshot = _emberDataPrivateSystemSnapshot["default"]; 80590 80591 _emberDataPrivateCore["default"].Adapter = _emberDataAdapter["default"]; 80592 80593 _emberDataPrivateCore["default"].AdapterError = _emberDataAdaptersErrors.AdapterError; 80594 _emberDataPrivateCore["default"].InvalidError = _emberDataAdaptersErrors.InvalidError; 80595 _emberDataPrivateCore["default"].TimeoutError = _emberDataAdaptersErrors.TimeoutError; 80596 _emberDataPrivateCore["default"].AbortError = _emberDataAdaptersErrors.AbortError; 80597 80598 if (false) { 80599 _emberDataPrivateCore["default"].UnauthorizedError = _emberDataAdaptersErrors.UnauthorizedError; 80600 _emberDataPrivateCore["default"].ForbiddenError = _emberDataAdaptersErrors.ForbiddenError; 80601 _emberDataPrivateCore["default"].NotFoundError = _emberDataAdaptersErrors.NotFoundError; 80602 _emberDataPrivateCore["default"].ConflictError = _emberDataAdaptersErrors.ConflictError; 80603 _emberDataPrivateCore["default"].ServerError = _emberDataAdaptersErrors.ServerError; 80604 } 80605 80606 _emberDataPrivateCore["default"].errorsHashToArray = _emberDataAdaptersErrors.errorsHashToArray; 80607 _emberDataPrivateCore["default"].errorsArrayToHash = _emberDataAdaptersErrors.errorsArrayToHash; 80608 80609 _emberDataPrivateCore["default"].Serializer = _emberDataSerializer["default"]; 80610 80611 _emberDataPrivateCore["default"].DebugAdapter = _emberDataPrivateSystemDebug["default"]; 80612 80613 _emberDataPrivateCore["default"].RecordArray = _emberDataPrivateSystemRecordArrays.RecordArray; 80614 _emberDataPrivateCore["default"].FilteredRecordArray = _emberDataPrivateSystemRecordArrays.FilteredRecordArray; 80615 _emberDataPrivateCore["default"].AdapterPopulatedRecordArray = _emberDataPrivateSystemRecordArrays.AdapterPopulatedRecordArray; 80616 _emberDataPrivateCore["default"].ManyArray = _emberDataPrivateSystemManyArray["default"]; 80617 80618 _emberDataPrivateCore["default"].RecordArrayManager = _emberDataPrivateSystemRecordArrayManager["default"]; 80619 80620 _emberDataPrivateCore["default"].RESTAdapter = _emberDataPrivateAdapters.RESTAdapter; 80621 _emberDataPrivateCore["default"].BuildURLMixin = _emberDataPrivateAdaptersBuildUrlMixin["default"]; 80622 80623 _emberDataPrivateCore["default"].RESTSerializer = _emberDataPrivateSerializers.RESTSerializer; 80624 _emberDataPrivateCore["default"].JSONSerializer = _emberDataPrivateSerializers.JSONSerializer; 80625 80626 _emberDataPrivateCore["default"].JSONAPIAdapter = _emberDataPrivateAdapters.JSONAPIAdapter; 80627 _emberDataPrivateCore["default"].JSONAPISerializer = _emberDataPrivateSerializers.JSONAPISerializer; 80628 80629 _emberDataPrivateCore["default"].Transform = _emberDataPrivateTransforms.Transform; 80630 _emberDataPrivateCore["default"].DateTransform = _emberDataPrivateTransforms.DateTransform; 80631 _emberDataPrivateCore["default"].StringTransform = _emberDataPrivateTransforms.StringTransform; 80632 _emberDataPrivateCore["default"].NumberTransform = _emberDataPrivateTransforms.NumberTransform; 80633 _emberDataPrivateCore["default"].BooleanTransform = _emberDataPrivateTransforms.BooleanTransform; 80634 80635 _emberDataPrivateCore["default"].EmbeddedRecordsMixin = _emberDataSerializersEmbeddedRecordsMixin["default"]; 80636 80637 _emberDataPrivateCore["default"].belongsTo = _emberDataRelationships.belongsTo; 80638 _emberDataPrivateCore["default"].hasMany = _emberDataRelationships.hasMany; 80639 80640 _emberDataPrivateCore["default"].Relationship = _emberDataPrivateSystemRelationshipsStateRelationship["default"]; 80641 80642 _emberDataPrivateCore["default"].ContainerProxy = _emberDataPrivateSystemContainerProxy["default"]; 80643 80644 _emberDataPrivateCore["default"]._setupContainer = _emberDataSetupContainer["default"]; 80645 _emberDataPrivateCore["default"]._initializeStoreService = _emberDataPrivateInstanceInitializer
80645sInitializeStoreService["default"]; 80646 80647 Object.defineProperty(_emberDataPrivateCore["default"], 'normalizeModelName', { 80648 enumerable: true, 80649 writable: false, 80650 configurable: false, 80651 value: _emberDataPrivateSystemNormalizeModelName["default"] 80652 }); 80653 80654 Object.defineProperty(_emberDataPrivateGlobal["default"], 'DS', { 80655 configurable: true, 80656 get: function get() { 80657 (0, _emberDataPrivateDebug.deprecate)('Using the global version of DS is deprecated. Please either import ' + 'the specific modules needed or `import DS from \'ember-data\';`.', false, { id: 'ember-data.global-ds', until: '3.0.0' }); 80658 80659 return _emberDataPrivateCore["default"]; 80660 } 80661 }); 80662 80663 exports["default"] = _emberDataPrivateCore["default"]; 80664}); 80665 80666/** 80667 Ember Data 80668 @module ember-data 80669 @main ember-data 80670*/ 80671define("ember-data/model", ["exports", "ember-data/-private/system/model"], function (exports, _emberDataPrivateSystemModel) { 80672 "use strict"; 80673 80674 exports["default"] = _emberDataPrivateSystemModel["default"]; 80675}); 80676define("ember-data/relationships", ["exports", "ember-data/-private/system/relationships/belongs-to", "ember-data/-private/system/relationships/has-many"], function (exports, _emberDataPrivateSystemRelationshipsBelongsTo, _emberDataPrivateSystemRelationshipsHasMany) { 80677 /** 80678 @module ember-data 80679 */ 80680 80681 "use strict"; 80682 80683 exports.belongsTo = _emberDataPrivateSystemRelationshipsBelongsTo["default"]; 80684 exports.hasMany = _emberDataPrivateSystemRelationshipsHasMany["default"]; 80685}); 80686define('ember-data/serializer', ['exports', 'ember'], function (exports, _ember) { 80687 /** 80688 @module ember-data 80689 */ 80690 80691 'use strict'; 80692 80693 /** 80694 `DS.Serializer` is an abstract base class that you should override in your 80695 application to customize it for your backend. The minimum set of methods 80696 that you should implement is: 80697 80698 * `normalizeResponse()` 80699 * `serialize()` 80700 80701 And you can optionally override the following methods: 80702 80703 * `normalize()` 80704 80705 For an example implementation, see 80706 [DS.JSONSerializer](DS.JSONSerializer.html), the included JSON serializer. 80707 80708 @class Serializer 80709 @namespace DS 80710 @extends Ember.Object 80711 */ 80712 80713 exports['default'] = _ember['default'].Object.extend({ 80714 80715 /** 80716 The `store` property is the application's `store` that contains all records. 80717 It's injected as a service. 80718 It can be used to push records from a non flat data structure server 80719 response. 80720 @property store 80721 @type {DS.Store} 80722 @public 80723 */ 80724 80725 /** 80726 The `normalizeResponse` method is used to normalize a payload from the 80727 server to a JSON-API Document. 80728 http://jsonapi.org/format/#document-structure 80729 @since 1.13.0 80730 @method normalizeResponse 80731 @param {DS.Store} store 80732 @param {DS.Model} primaryModelClass 80733 @param {Object} payload 80734 @param {String|Number} id 80735 @param {String} requestType 80736 @return {Object} JSON-API Document 80737 */ 80738 normalizeResponse: null, 80739 80740 /** 80741 The `serialize` method is used when a record is saved in order to convert 80742 the record into the form that your external data source expects. 80743 `serialize` takes an optional `options` hash with a single option: 80744 - `includeId`: If this is `true`, `serialize` should include the ID 80745 in the serialized object it builds. 80746 @method serialize 80747 @param {DS.Model} record 80748 @param {Object} [options] 80749 @return {Object} 80750 */ 80751 serialize: null, 80752 80753 /** 80754 The `normalize` method is used to convert a payload received from your 80755 external data source into the normalized form `store.push()` expects. You 80756 should override this method, munge the hash and return the normalized 80757 payload. 80758 @method normalize 80759 @param {DS.Model} typeClass 80760 @param {Object} hash 80761 @return {Object} 80762 */ 80763 normalize: function normalize(typeClass, hash) { 80764 return hash; 80765 } 80766 80767 }); 80768}); 80769define('ember-data/serializers/embedded-records-mixin', ['exports', 'ember', 'ember-data/-private/debug', 'ember-data/-private/features'], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateFeatures) { 80770 'use strict'; 80771 80772 function _toConsumableArray(arr) { 80773 if (Array.isArray(arr)) { 80774 for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];return arr2; 80775 } else { 80776 return Array.from(arr); 80777 } 80778 } 80779 80780 var get = _ember['default'].get; 80781 var set = _ember['default'].set; 80782 var camelize = _ember['default'].String.camelize; 80783 80784 /** 80785 ## Using Embedded Records 80786 80787 `DS.EmbeddedRecordsMixin` supports serializing embedded records. 80788 80789 To set up embedded records, include the mixin when extending a serializer, 80790 then define and configure embedded (model) relationships. 80791 80792 Below is an example of a per-type serializer (`post` type). 80793 80794 ```app/serializers/post.js 80795 import DS from 'ember-data'; 80796 80797 export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
80798 attrs: { 80799 author: { embedded: 'always' }, 80800 comments: { serialize: 'ids' } 80801 } 80802 }); 80803 ``` 80804 Note that this use of `{ embedded: 'always' }` is unrelated to 80805 the `{ embedded: 'always' }` that is defined as an option on `DS.attr` as part of 80806 defining a model while working with the `ActiveModelSerializer`. Nevertheless, 80807 using `{ embedded: 'always' }` as an option to `DS.attr` is not a valid way to setup 80808 embedded records. 80809 80810 The `attrs` option for a resource `{ embedded: 'always' }` is shorthand for: 80811 80812 ```js 80813 { 80814 serialize: 'records', 80815 deserialize: 'records' 80816 } 80817 ``` 80818 80819 ### Configuring Attrs 80820 80821 A resource's `attrs` option may be set to use `ids`, `records` or false for the 80822 `serialize` and `deserialize` settings. 80823 80824 The `attrs` property can be set on the `ApplicationSerializer` or a per-type 80825 serializer. 80826 80827 In the case where embedded JSON is expected while extracting a payload (reading) 80828 the setting is `deserialize: 'records'`, there is no need to use `ids` when 80829 extracting as that is the default behavior without this mixin if you are using 80830 the vanilla `EmbeddedRecordsMixin`. Likewise, to embed JSON in the payload while 80831 serializing `serialize: 'records'` is the setting to use. There is an option of 80832 not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you 80833 do not want the relationship sent at all, you can use `serialize: false`. 80834 80835 80836 ### EmbeddedRecordsMixin defaults 80837 If you do not overwrite `attrs` for a specific relationship, the `EmbeddedRecordsMixin` 80838 will behave in the following way: 80839 80840 BelongsTo: `{ serialize: 'id', deserialize: 'id' }` 80841 HasMany: `{ serialize: false, deserialize: 'ids' }` 80842 80843 ### Model Relationships 80844 80845 Embedded records must have a model defined to be extracted and serialized. Note that 80846 when defining any relationships on your model such as `belongsTo` and `hasMany`, you 80847 should not both specify `async: true` and also indicate through the serializer's 80848 `attrs` attribute that the related model should be embedded for deserialization. 80849 If a model is declared embedded for deserialization (`embedded: 'always'` or `deserialize: 'records'`), 80850 then do not use `async: true`. 80851 80852 To successfully extract and serialize embedded records the model relationships 80853 must be setup correcty. See the 80854 [defining relationships](/guides/models/defining-models/#toc_defining-relationships) 80855 section of the **Defining Models** guide page. 80856 80857 Records without an `id` property are not considered embedded records, model 80858 instances must have an `id` property to be used with Ember Data. 80859 80860 ### Example JSON payloads, Models and Serializers 80861 80862 **When customizing a serializer it is important to grok what the customizations 80863 are. Please read the docs for the methods this mixin provides, in case you need 80864 to modify it to fit your specific needs.** 80865 80866 For example review the docs for each method of this mixin: 80867 * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) 80868 * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) 80869 * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) 80870 80871 @class EmbeddedRecordsMixin 80872 @namespace DS 80873 */ 80874 exports['default'] = _ember['default'].Mixin.create({ 80875 80876 /** 80877 Normalize the record and recursively normalize/extract all the embedded records 80878 while pushing them into the store as they are encountered 80879 A payload with an attr configured for embedded records needs to be extracted: 80880 ```js 80881 { 80882 "post": { 80883 "id": "1" 80884 "title": "Rails is omakase", 80885 "comments": [{ 80886 "id": "1", 80887 "body": "Rails is unagi" 80888 }, { 80889 "id": "2", 80890 "body": "Omakase O_o" 80891 }] 80892 } 80893 } 80894 ``` 80895 @method normalize 80896 @param {DS.Model} typeClass 80897 @param {Object} hash to be normalized 80898 @param {String} prop the hash has been referenced by 80899 @return {Object} the normalized hash 80900 **/ 80901 normalize: function normalize(typeClass, hash, prop) { 80902 var normalizedHash = this._super(typeClass, hash, prop); 80903 return this._extractEmbeddedRecords(this, this.store, typeClass, normalizedHash); 80904 }, 80905 80906 keyForRelationship: function keyForRelationship(key, typeClass, method) { 80907 if (method === 'serialize' && this.hasSerializeRecordsOption(key) || method === 'deserialize' && this.hasDeserializeRecordsOption(key)) { 80908 return this.keyForAttribute(key, method); 80909 } else { 80910 return this._super(key, typeClass, method) || key; 80911 } 80912 }, 80913 80914 /**
80915 Serialize `belongsTo` relationship when it is configured as an embedded object. 80916 This example of an author model belongs to a post model: 80917 ```js 80918 Post = DS.Model.extend({ 80919 title: DS.attr('string'), 80920 body: DS.attr('string'), 80921 author: DS.belongsTo('author') 80922 }); 80923 Author = DS.Model.extend({ 80924 name: DS.attr('string'), 80925 post: DS.belongsTo('post') 80926 }); 80927 ``` 80928 Use a custom (type) serializer for the post model to configure embedded author 80929 ```app/serializers/post.js 80930 import DS from 'ember-data'; 80931 export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { 80932 attrs: { 80933 author: { embedded: 'always' } 80934 } 80935 }) 80936 ``` 80937 A payload with an attribute configured for embedded records can serialize 80938 the records together under the root attribute's payload: 80939 ```js 80940 { 80941 "post": { 80942 "id": "1" 80943 "title": "Rails is omakase", 80944 "author": { 80945 "id": "2" 80946 "name": "dhh" 80947 } 80948 } 80949 } 80950 ``` 80951 @method serializeBelongsTo 80952 @param {DS.Snapshot} snapshot 80953 @param {Object} json 80954 @param {Object} relationship 80955 */ 80956 serializeBelongsTo: function serializeBelongsTo(snapshot, json, relationship) { 80957 var attr = relationship.key; 80958 if (this.noSerializeOptionSpecified(attr)) { 80959 this._super(snapshot, json, relationship); 80960 return; 80961 } 80962 var includeIds = this.hasSerializeIdsOption(attr); 80963 var includeRecords = this.hasSerializeRecordsOption(attr); 80964 var embeddedSnapshot = snapshot.belongsTo(attr); 80965 var key; 80966 if (includeIds) { 80967 key = this.keyForRelationship(attr, relationship.kind, 'serialize'); 80968 if (!embeddedSnapshot) { 80969 json[key] = null; 80970 } else { 80971 json[key] = embeddedSnapshot.id; 80972 80973 if (relationship.options.polymorphic) { 80974 this.serializePolymorphicType(snapshot, json, relationship); 80975 } 80976 } 80977 } else if (includeRecords) { 80978 this._serializeEmbeddedBelongsTo(snapshot, json, relationship); 80979 } 80980 }, 80981 80982 _serializeEmbeddedBelongsTo: function _serializeEmbeddedBelongsTo(snapshot, json, relationship) { 80983 var embeddedSnapshot = snapshot.belongsTo(relationship.key); 80984 var serializedKey = this._getMappedKey(relationship.key, snapshot.type); 80985 if (serializedKey === relationship.key && this.keyForRelationship) { 80986 serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); 80987 } 80988 80989 if (!embeddedSnapshot) { 80990 json[serializedKey] = null; 80991 } else { 80992 json[serializedKey] = embeddedSnapshot.serialize({ includeId: true }); 80993 this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json[serializedKey]); 80994 80995 if (relationship.options.polymorphic) { 80996 this.serializePolymorphicType(snapshot, json, relationship); 80997 } 80998 } 80999 }, 81000 81001 /** 81002 Serializes `hasMany` relationships when it is configured as embedded objects. 81003 This example of a post model has many comments: 81004 ```js 81005 Post = DS.Model.extend({ 81006 title: DS.attr('string'), 81007 body: DS.attr('string'), 81008 comments: DS.hasMany('comment') 81009 }); 81010 Comment = DS.Model.extend({ 81011 body: DS.attr('string'), 81012 post: DS.belongsTo('post') 81013 }); 81014 ``` 81015 Use a custom (type) serializer for the post model to configure embedded comments 81016 ```app/serializers/post.js 81017 import DS from 'ember-data; 81018 export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { 81019 attrs: { 81020 comments: { embedded: 'always' } 81021 } 81022 }) 81023 ``` 81024 A payload with an attribute configured for embedded records can serialize 81025 the records together under the root attribute's payload: 81026 ```js 81027 { 81028 "post": { 81029 "id": "1" 81030 "title": "Rails is omakase", 81031 "body": "I want this for my ORM, I want that for my template language..." 81032 "comments": [{ 81033 "id": "1", 81034 "body": "Rails is unagi" 81035 }, { 81036 "id": "2", 81037 "body": "Omakase O_o" 81038 }] 81039 } 81040 } 81041 ``` 81042 The attrs options object can use more specific instruction for extracting and 81043 serializing. When serializing, an option to embed `ids`, `ids-and-types` or `records` can be set. 81044 When extracting the only option is `records`. 81045 So `{ embedded: 'always' }` is shorthand for:
81046 `{ serialize: 'records', deserialize: 'records' }` 81047 To embed the `ids` for a related object (using a hasMany relationship): 81048 ```app/serializers/post.js 81049 import DS from 'ember-data; 81050 export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { 81051 attrs: { 81052 comments: { serialize: 'ids', deserialize: 'records' } 81053 } 81054 }) 81055 ``` 81056 ```js 81057 { 81058 "post": { 81059 "id": "1" 81060 "title": "Rails is omakase", 81061 "body": "I want this for my ORM, I want that for my template language..." 81062 "comments": ["1", "2"] 81063 } 81064 } 81065 ``` 81066 To embed the relationship as a collection of objects with `id` and `type` keys, set 81067 `ids-and-types` for the related object. 81068 This is particularly useful for polymorphic relationships where records don't share 81069 the same table and the `id` is not enough information. 81070 By example having a user that has many pets: 81071 ```js 81072 User = DS.Model.extend({ 81073 name: DS.attr('string'), 81074 pets: DS.hasMany('pet', { polymorphic: true }) 81075 }); 81076 Pet = DS.Model.extend({ 81077 name: DS.attr('string'), 81078 }); 81079 Cat = Pet.extend({ 81080 // ... 81081 }); 81082 Parrot = Pet.extend({ 81083 // ... 81084 }); 81085 ``` 81086 ```app/serializers/user.js 81087 import DS from 'ember-data; 81088 export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { 81089 attrs: { 81090 pets: { serialize: 'ids-and-types', deserialize: 'records' } 81091 } 81092 }); 81093 ``` 81094 ```js 81095 { 81096 "user": { 81097 "id": "1" 81098 "name": "Bertin Osborne", 81099 "pets": [ 81100 { "id": "1", "type": "Cat" }, 81101 { "id": "1", "type": "Parrot"} 81102 ] 81103 } 81104 } 81105 ``` 81106 Note that the `ids-and-types` strategy is still behind the `ds-serialize-ids-and-types` feature flag. 81107 @method serializeHasMany 81108 @param {DS.Snapshot} snapshot 81109 @param {Object} json 81110 @param {Object} relationship 81111 */ 81112 serializeHasMany: function serializeHasMany(snapshot, json, relationship) { 81113 var attr = relationship.key; 81114 if (this.noSerializeOptionSpecified(attr)) { 81115 this._super(snapshot, json, relationship); 81116 return; 81117 } 81118 81119 if (this.hasSerializeIdsOption(attr)) { 81120 var serializedKey = this.keyForRelationship(attr, relationship.kind, 'serialize'); 81121 json[serializedKey] = snapshot.hasMany(attr, { ids: true }); 81122 } else if (this.hasSerializeRecordsOption(attr)) { 81123 this._serializeEmbeddedHasMany(snapshot, json, relationship); 81124 } else { 81125 if (true) { 81126 if (this.hasSerializeIdsAndTypesOption(attr)) { 81127 this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); 81128 } 81129 } 81130 } 81131 }, 81132 81133 /** 81134 Serializes a hasMany relationship as an array of objects containing only `id` and `type` 81135 keys. 81136 This has its use case on polymorphic hasMany relationships where the server is not storing 81137 all records in the same table using STI, and therefore the `id` is not enough information 81138 TODO: Make the default in Ember-data 3.0?? 81139 */ 81140 _serializeHasManyAsIdsAndTypes: function _serializeHasManyAsIdsAndTypes(snapshot, json, relationship) { 81141 var serializedKey = this.keyForAttribute(relationship.key, 'serialize'); 81142 var hasMany = snapshot.hasMany(relationship.key); 81143 81144 json[serializedKey] = _ember['default'].A(hasMany).map(function (recordSnapshot) { 81145 // 81146 // I'm sure I'm being utterly naive here. Propably id is a configurate property and 81147 // type too, and the modelName has to be normalized somehow. 81148 // 81149 return { id: recordSnapshot.id, type: recordSnapshot.modelName }; 81150 }); 81151 }, 81152 81153 _serializeEmbeddedHasMany: function _serializeEmbeddedHasMany(snapshot, json, relationship) { 81154 var serializedKey = this._getMappedKey(relationship.key, snapshot.type); 81155 if (serializedKey === relationship.key && this.keyForRelationship) { 81156 serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); 81157 } 81158 81159 (0, _emberDataPrivateDebug.warn)('The embedded relationship \'' + serializedKey + '\' is undefined for \'' + snapshot.modelName + '\' with i
81159d \'' + snapshot.id + '\'. Please include it in your original payload.', _ember['default'].typeOf(snapshot.hasMany(relationship.key)) !== 'undefined', { id: 'ds.serializer.embedded-relationship-undefined' }); 81160 81161 json[serializedKey] = this._generateSerializedHasMany(snapshot, relationship); 81162 }, 81163 81164 /* 81165 Returns an array of embedded records serialized to JSON 81166 */ 81167 _generateSerializedHasMany: function _generateSerializedHasMany(snapshot, relationship) { 81168 var hasMany = snapshot.hasMany(relationship.key); 81169 var manyArray = _ember['default'].A(hasMany); 81170 var ret = new Array(manyArray.length); 81171 81172 for (var i = 0; i < manyArray.length; i++) { 81173 var embeddedSnapshot = manyArray[i]; 81174 var embeddedJson = embeddedSnapshot.serialize({ includeId: true }); 81175 this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); 81176 ret[i] = embeddedJson; 81177 } 81178 81179 return ret; 81180 }, 81181 81182 /** 81183 When serializing an embedded record, modify the property (in the json payload) 81184 that refers to the parent record (foreign key for relationship). 81185 Serializing a `belongsTo` relationship removes the property that refers to the 81186 parent record 81187 Serializing a `hasMany` relationship does not remove the property that refers to 81188 the parent record. 81189 @method removeEmbeddedForeignKey 81190 @param {DS.Snapshot} snapshot 81191 @param {DS.Snapshot} embeddedSnapshot 81192 @param {Object} relationship 81193 @param {Object} json 81194 */ 81195 removeEmbeddedForeignKey: function removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json) { 81196 if (relationship.kind === 'hasMany') { 81197 return; 81198 } else if (relationship.kind === 'belongsTo') { 81199 var parentRecord = snapshot.type.inverseFor(relationship.key, this.store); 81200 if (parentRecord) { 81201 var name = parentRecord.name; 81202 var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); 81203 var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind, 'deserialize'); 81204 if (parentKey) { 81205 delete json[parentKey]; 81206 } 81207 } 81208 } 81209 }, 81210 81211 // checks config for attrs option to embedded (always) - serialize and deserialize 81212 hasEmbeddedAlwaysOption: function hasEmbeddedAlwaysOption(attr) { 81213 var option = this.attrsOption(attr); 81214 return option && option.embedded === 'always'; 81215 }, 81216 81217 // checks config for attrs option to serialize ids 81218 hasSerializeRecordsOption: function hasSerializeRecordsOption(attr) { 81219 var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); 81220 var option = this.attrsOption(attr); 81221 return alwaysEmbed || option && option.serialize === 'records'; 81222 }, 81223 81224 // checks config for attrs option to serialize records 81225 hasSerializeIdsOption: function hasSerializeIdsOption(attr) { 81226 var option = this.attrsOption(attr); 81227 return option && (option.serialize === 'ids' || option.serialize === 'id'); 81228 }, 81229 81230 // checks config for attrs option to serialize records as objects containing id and types 81231 hasSerializeIdsAndTypesOption: function hasSerializeIdsAndTypesOption(attr) { 81232 var option = this.attrsOption(attr); 81233 return option && (option.serialize === 'ids-and-types' || option.serialize === 'id-and-type'); 81234 }, 81235 81236 // checks config for attrs option to serialize records 81237 noSerializeOptionSpecified: function noSerializeOptionSpecified(attr) { 81238 var option = this.attrsOption(attr); 81239 return !(option && (option.serialize || option.embedded)); 81240 }, 81241 81242 // checks config for attrs option to deserialize records 81243 // a defined option object for a resource is treated the same as 81244 // `deserialize: 'records'` 81245 hasDeserializeRecordsOption: function hasDeserializeRecordsOption(attr) { 81246 var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); 81247 var option = this.attrsOption(attr); 81248 return alwaysEmbed || option && option.deserialize === 'records'; 81249 }, 81250 81251 attrsOption: function attrsOption(attr) { 81252 var attrs = this.get('attrs'); 81253 return attrs && (attrs[camelize(attr)] || attrs[attr]); 81254 }, 81255 81256 /** 81257 @method _extractEmbeddedRecords 81258 @private 81259 */ 81260 _extractEmbeddedRecords: function _extractEmbeddedRecords(serializer, store, typeClass, partial) { 81261 var _this = this; 81262
81263 typeClass.eachRelationship(function (key, relationship) { 81264 if (serializer.hasDeserializeRecordsOption(key)) { 81265 if (relationship.kind === "hasMany") { 81266 _this._extractEmbeddedHasMany(store, key, partial, relationship); 81267 } 81268 if (relationship.kind === "belongsTo") { 81269 _this._extractEmbeddedBelongsTo(store, key, partial, relationship); 81270 } 81271 } 81272 }); 81273 return partial; 81274 }, 81275 81276 /** 81277 @method _extractEmbeddedHasMany 81278 @private 81279 */ 81280 _extractEmbeddedHasMany: function _extractEmbeddedHasMany(store, key, hash, relationshipMeta) { 81281 var relationshipHash = get(hash, 'data.relationships.' + key + '.data'); 81282 81283 if (!relationshipHash) { 81284 return; 81285 } 81286 81287 var hasMany = new Array(relationshipHash.length); 81288 81289 for (var i = 0; i < relationshipHash.length; i++) { 81290 var item = relationshipHash[i]; 81291 81292 var _normalizeEmbeddedRelationship2 = this._normalizeEmbeddedRelationship(store, relationshipMeta, item); 81293 81294 var data = _normalizeEmbeddedRelationship2.data; 81295 var included = _normalizeEmbeddedRelationship2.included; 81296 81297 hash.included = hash.included || []; 81298 hash.included.push(data); 81299 if (included) { 81300 var _hash$included; 81301 81302 (_hash$included = hash.included).push.apply(_hash$included, _toConsumableArray(included)); 81303 } 81304 81305 hasMany[i] = { id: data.id, type: data.type }; 81306 } 81307 81308 var relationship = { data: hasMany }; 81309 set(hash, 'data.relationships.' + key, relationship); 81310 }, 81311 81312 /** 81313 @method _extractEmbeddedBelongsTo 81314 @private 81315 */ 81316 _extractEmbeddedBelongsTo: function _extractEmbeddedBelongsTo(store, key, hash, relationshipMeta) { 81317 var relationshipHash = get(hash, 'data.relationships.' + key + '.data'); 81318 if (!relationshipHash) { 81319 return; 81320 } 81321 81322 var _normalizeEmbeddedRelationship3 = this._normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash); 81323 81324 var data = _normalizeEmbeddedRelationship3.data; 81325 var included = _normalizeEmbeddedRelationship3.included; 81326 81327 hash.included = hash.included || []; 81328 hash.included.push(data); 81329 if (included) { 81330 var _hash$included2; 81331 81332 (_hash$included2 = hash.included).push.apply(_hash$included2, _toConsumableArray(included)); 81333 } 81334 81335 var belongsTo = { id: data.id, type: data.type }; 81336 var relationship = { data: belongsTo }; 81337 81338 set(hash, 'data.relationships.' + key, relationship); 81339 }, 81340 81341 /** 81342 @method _normalizeEmbeddedRelationship 81343 @private 81344 */ 81345 _normalizeEmbeddedRelationship: function _normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash) { 81346 var modelName = relationshipMeta.type; 81347 if (relationshipMeta.options.polymorphic) { 81348 modelName = relationshipHash.type; 81349 } 81350 var modelClass = store.modelFor(modelName); 81351 var serializer = store.serializerFor(modelName); 81352 81353 return serializer.normalize(modelClass, relationshipHash, null); 81354 }, 81355 isEmbeddedRecordsMixin: true 81356 }); 81357}); 81358define('ember-data/serializers/json-api', ['exports', 'ember', 'ember-data/-private/debug', 'ember-data/serializers/json', 'ember-data/-private/system/normalize-model-name', 'ember-inflector', 'ember-data/-private/features'], function (exports, _ember, _emberDataPrivateDebug, _emberDataSerializersJson, _emberDataPrivateSystemNormalizeModelName, _emberInflector, _emberDataPrivateFeatures) { 81359 /** 81360 @module ember-data 81361 */ 81362 81363 'use strict'; 81364 81365 var dasherize = _ember['default'].String.dasherize; 81366 81367 /** 81368 Ember Data 2.0 Serializer: 81369 81370 In Ember Data a Serializer is used to serialize and deserialize 81371 records when they are transferred in and out of an external source. 81372 This process involves normalizing property names, transforming 81373 attribute values and serializing relationships. 81374 81375 `JSONAPISerializer` supports the http://jsonapi.org/ spec and is the 81376 serializer recommended by Ember Data. 81377 81378 This serializer normalizes a JSON API payload that looks like: 81379 81380 ```js 81381 81382
81382// models/player.js 81383 import DS from "ember-data"; 81384 81385 export default DS.Model.extend({ 81386 name: DS.attr(), 81387 skill: DS.attr(), 81388 gamesPlayed: DS.attr(), 81389 club: DS.belongsTo('club') 81390 }); 81391 81392
81392// models/club.js 81393 import DS from "ember-data"; 81394 81395 export default DS.Model.extend({ 81396 name: DS.attr(), 81397 location: DS.attr(), 81398 players: DS.hasMany('player') 81399 }); 81400 ``` 81401 81402 ```js 81403 81404 { 81405 "data": [ 81406 { 81407 "attributes": { 81408 "name": "Benfica", 81409 "location": "Portugal" 81410 }, 81411 "id": "1", 81412 "relationships": { 81413 "players": { 81414 "data": [ 81415 { 81416 "id": "3", 81417 "type": "players" 81418 } 81419 ] 81420 } 81421 }, 81422 "type": "clubs" 81423 } 81424 ], 81425 "included": [ 81426 { 81427 "attributes": { 81428 "name": "Eusebio Silva Ferreira", 81429 "skill": "Rocket shot", 81430 "games-played": 431 81431 }, 81432 "id": "3", 81433 "relationships": { 81434 "club": { 81435 "data": { 81436 "id": "1", 81437 "type": "clubs" 81438 } 81439 } 81440 }, 81441 "type": "players" 81442 } 81443 ] 81444 } 81445 ``` 81446 81447 to the format that the Ember Data store expects. 81448 81449 @since 1.13.0 81450 @class JSONAPISerializer 81451 @namespace DS 81452 @extends DS.JSONSerializer 81453 */ 81454 var JSONAPISerializer = _emberDataSerializersJson['default'].extend({ 81455 81456 /** 81457 @method _normalizeDocumentHelper 81458 @param {Object} documentHash 81459 @return {Object} 81460 @private 81461 */ 81462 _normalizeDocumentHelper: function _normalizeDocumentHelper(documentHash) { 81463 81464 if (_ember['default'].typeOf(documentHash.data) === 'object') { 81465 documentHash.data = this._normalizeResourceHelper(documentHash.data); 81466 } else if (Array.isArray(documentHash.data)) { 81467 var ret = new Array(documentHash.data.length); 81468 81469 for (var i = 0; i < documentHash.data.length; i++) { 81470 var data = documentHash.data[i]; 81471 ret[i] = this._normalizeResourceHelper(data); 81472 } 81473 81474 documentHash.data = ret; 81475 } 81476 81477 if (Array.isArray(documentHash.included)) { 81478 var ret = new Array(documentHash.included.length); 81479 81480 for (var i = 0; i < documentHash.included.length; i++) { 81481 var included = documentHash.included[i]; 81482 ret[i] = this._normalizeResourceHelper(included); 81483 } 81484 81485 documentHash.included = ret; 81486 } 81487 81488 return documentHash; 81489 }, 81490 81491 /**
81492 @method _normalizeRelationshipDataHelper 81493 @param {Object} relationshipDataHash 81494 @return {Object} 81495 @private 81496 */ 81497 _normalizeRelationshipDataHelper: function _normalizeRelationshipDataHelper(relationshipDataHash) { 81498 if (false) { 81499 var modelName = this.modelNameFromPayloadType(relationshipDataHash.type); 81500 var deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipDataHash.type); 81501 81502 if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { 81503 (0, _emberDataPrivateDebug.deprecate)("You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { 81504 id: 'ds.json-api-serializer.deprecated-model-name-for-relationship', 81505 until: '3.0.0' 81506 }); 81507 81508 modelName = deprecatedModelNameLookup; 81509 } 81510 81511 relationshipDataHash.type = modelName; 81512 } else { 81513 var type = this.modelNameFromPayloadKey(relationshipDataHash.type); 81514 relationshipDataHash.type = type; 81515 } 81516 81517 return relationshipDataHash; 81518 }, 81519 81520 /** 81521 @method _normalizeResourceHelper 81522 @param {Object} resourceHash 81523 @return {Object} 81524 @private 81525 */ 81526 _normalizeResourceHelper: function _normalizeResourceHelper(resourceHash) { 81527 (0, _emberDataPrivateDebug.assert)(this.warnMessageForUndefinedType(), !_ember['default'].isNone(resourceHash.type), { 81528 id: 'ds.serializer.type-is-undefined' 81529 }); 81530 81531 var modelName = undefined, 81532 usedLookup = undefined; 81533 81534 if (false) { 81535 modelName = this.modelNameFromPayloadType(resourceHash.type); 81536 var deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); 81537 81538 usedLookup = 'modelNameFromPayloadType'; 81539 81540 if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { 81541 (0, _emberDataPrivateDebug.deprecate)("You are using modelNameFromPayloadKey to normalize the type for a resource. This has been deprecated in favor of modelNameFromPayloadType", false, { 81542 id: 'ds.json-api-serializer.deprecated-model-name-for-resource', 81543 until: '3.0.0' 81544 }); 81545 81546 modelName = deprecatedModelNameLookup; 81547 usedLookup = 'modelNameFromPayloadKey'; 81548 } 81549 } else { 81550 modelName = this.modelNameFromPayloadKey(resourceHash.type); 81551 usedLookup = 'modelNameFromPayloadKey'; 81552 } 81553 81554 if (!this.store._hasModelFor(modelName)) { 81555 (0, _emberDataPrivateDebug.warn)(this.warnMessageNoModelForType(modelName, resourceHash.type, usedLookup), false, { 81556 id: 'ds.serializer.model-for-type-missing' 81557 }); 81558 return null; 81559 } 81560 81561 var modelClass = this.store.modelFor(modelName); 81562 var serializer = this.store.serializerFor(modelName); 81563 81564 var _serializer$normalize = serializer.normalize(modelClass, resourceHash); 81565 81566 var data = _serializer$normalize.data; 81567 81568 return data; 81569 }, 81570 81571 /** 81572 @method pushPayload 81573 @param {DS.Store} store 81574 @param {Object} payload 81575 */ 81576 pushPayload: function pushPayload(store, payload) { 81577 var normalizedPayload = this._normalizeDocumentHelper(payload); 81578 if (false) { 81579 return store.push(normalizedPayload); 81580 } else { 81581 store.push(normalizedPayload); 81582 } 81583 }, 81584 81585 /** 81586 @method _normalizeResponse 81587 @param {DS.Store} store 81588 @param {DS.Model} primaryModelClass 81589 @param {Object} payload 81590 @param {String|Number} id 81591 @param {String} requestType 81592 @param {Boolean} isSingle 81593 @return {Object} JSON-API Document 81594 @private 81595 */ 81596 _normalizeResponse: function _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { 81597 var normalizedPayload = this._normalizeDocumentHelper(payload); 81598 return normalizedPayload; 81599 }, 81600 81601 normalizeQueryRecordResponse: function normalizeQueryRecordResponse() { 81602 var normalized = this._super.apply(this, arguments); 81603 81604 (0, _emberDataPrivateDebug.assert)('Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array.', !Array.isArray(normalized.data), { 81605 id: 'ds.serializer.json-api.queryRecord-array-response' 81606 }); 81607 81608 return normalized; 81609 }, 81610 81611 /** 81612 @method extractAttributes 81613 @param {DS.Model} modelClass 81614 @param {Object} resourceHash 81615 @return {Object} 81616 */ 81617 extractAttributes: function extractAttributes(modelClass, resourceHash) { 81618 var _this = this; 81619 81620 var attributes = {}; 81621 81622 if (resourceHash.attributes) { 81623 modelClass.eachAttribute(function (key) { 81624 var attributeKey = _this.keyForAttribute(key, 'deserialize'); 81625 if (resourceHash.attributes[attributeKey] !== undefined) { 81626 attributes[key] = resourceHash.attributes[attributeKey]; 81627 } 81628 }); 81629 } 81630 81631 return attributes; 81632 }, 81633 81634 /** 81635 @method extractRelationship 81636 @param {Object} relationshipHash 81637 @return {Object} 81638 */ 81639 extractRelationship: function extractRelationship(relationshipHash) { 81640 81641 if (_ember['default'].typeOf(relationshipHash.data) === 'object') {
81642 relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); 81643 } 81644 81645 if (Array.isArray(relationshipHash.data)) { 81646 var ret = new Array(relationshipHash.data.length); 81647 81648 for (var i = 0; i < relationshipHash.data.length; i++) { 81649 var data = relationshipHash.data[i]; 81650 ret[i] = this._normalizeRelationshipDataHelper(data); 81651 } 81652 81653 relationshipHash.data = ret; 81654 } 81655 81656 return relationshipHash; 81657 }, 81658 81659 /** 81660 @method extractRelationships 81661 @param {Object} modelClass 81662 @param {Object} resourceHash 81663 @return {Object} 81664 */ 81665 extractRelationships: function extractRelationships(modelClass, resourceHash) { 81666 var _this2 = this; 81667 81668 var relationships = {}; 81669 81670 if (resourceHash.relationships) { 81671 modelClass.eachRelationship(function (key, relationshipMeta) { 81672 var relationshipKey = _this2.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); 81673 if (resourceHash.relationships[relationshipKey] !== undefined) { 81674 81675 var relationshipHash = resourceHash.relationships[relationshipKey]; 81676 relationships[key] = _this2.extractRelationship(relationshipHash); 81677 } 81678 }); 81679 } 81680 81681 return relationships; 81682 }, 81683 81684 /** 81685 @method _extractType 81686 @param {DS.Model} modelClass 81687 @param {Object} resourceHash 81688 @return {String} 81689 @private 81690 */ 81691 _extractType: function _extractType(modelClass, resourceHash) { 81692 if (false) { 81693 var modelName = this.modelNameFromPayloadType(resourceHash.type); 81694 var deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); 81695 81696 if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { 81697 (0, _emberDataPrivateDebug.deprecate)("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { 81698 id: 'ds.json-api-serializer.deprecated-model-name-for-polymorphic-type', 81699 until: '3.0.0' 81700 }); 81701 81702 modelName = deprecatedModelNameLookup; 81703 } 81704 81705 return modelName; 81706 } else { 81707 return this.modelNameFromPayloadKey(resourceHash.type); 81708 } 81709 }, 81710 81711 /** 81712 @method modelNameFromPayloadKey 81713 @param {String} key 81714 @return {String} the model's modelName 81715 */ 81716 // TODO @deprecated Use modelNameFromPayloadType instead 81717 modelNameFromPayloadKey: function modelNameFromPayloadKey(key) { 81718 return (0, _emberInflector.singularize)((0, _emberDataPrivateSystemNormalizeModelName['default'])(key)); 81719 }, 81720 81721 /** 81722 @method payloadKeyFromModelName 81723 @param {String} modelName 81724 @return {String} 81725 */ 81726 // TODO @deprecated Use payloadTypeFromModelName instead 81727 payloadKeyFromModelName: function payloadKeyFromModelName(modelName) { 81728 return (0, _emberInflector.pluralize)(modelName); 81729 }, 81730 81731 /** 81732 @method normalize 81733 @param {DS.Model} modelClass 81734 @param {Object} resourceHash the resource hash from the adapter 81735 @return {Object} the normalized resource hash 81736 */ 81737 normalize: function normalize(modelClass, resourceHash) { 81738 if (resourceHash.attributes) { 81739 this.normalizeUsingDeclaredMapping(modelClass, resourceHash.attributes); 81740 } 81741 81742 if (resourceHash.relationships) { 81743 this.normalizeUsingDeclaredMapping(modelClass, resourceHash.relationships); 81744 } 81745 81746 var data = { 81747 id: this.extractId(modelClass, resourceHash), 81748 type: this._extractType(modelClass, resourceHash), 81749 attributes: this.extractAttributes(modelClass, resourceHash), 81750 relationships: this.extractRelationships(modelClass, resourceHash) 81751 }; 81752 81753 this.applyTransforms(modelClass, data.attributes); 81754 81755 return { data: data }; 81756 }, 81757 81758 /** 81759 `keyForAttribute` can be used to define rules for how to convert an 81760 attribute name in your model to a key in your JSON. 81761 By default `JSONAPISerializer` follows the format used on the examples of 81762 http://jsonapi.org/format and uses dashes as the word separator in the JSON 81763 attribute keys. 81764 This behaviour can be easily customized by extending this method. 81765 Example 81766 ```app/serializers/application.js 81767 import DS from 'ember-data'; 81768 export default DS.JSONAPISerializer.extend({ 81769 keyForAttribute: function(attr, method) { 81770 return Ember.String.dasherize(attr).toUpperCase(); 81771 } 81772 }); 81773 ``` 81774 @method keyForAttribute 81775 @param {String} key 81776 @param {String} method 81777 @return {String} normalized key 81778 */ 81779 keyForAttribute: function keyForAttribute(key, method) { 81780 return dasherize(key); 81781 }, 81782 81783 /** 81784 `keyForRelationship` can be used to define a custom key when 81785 serializing and deserializing relationship properties. 81786 By default `JSONAPISerializer` follows the format used on the examples of 81787 http://jsonapi.org/format and uses dashes as word separators in 81788 relationship properties. 81789 This behaviour can be easily customized by extending this method. 81790 Example 81791 ```app/serializers/post.js 81792 import DS from 'ember-data'; 81793 export default DS.JSONAPISerializer.extend({ 81794 keyForRelationship: function(key, relationship, method) { 81795 return Ember.String.underscore(key); 81796 } 81797 }); 81798 ``` 81799 @method keyForRelationship 81800 @param {String} key 81801 @param {String} typeClass 81802 @param {String} method 81803 @return {String} normalized key 81804 */ 81805 keyForRelationship: function keyForRelationship(key, typeClass, method) { 81806 return dasherize(key); 81807 }, 81808 81809 /** 81810 @method serialize 81811 @param {DS.Snapshot} snapshot 81812 @param {Object} options 81813 @return {Object} json 81814 */ 81815 serialize: function serialize(snapshot, options) { 81816 var data = this._super.apply(this, arguments); 81817 81818 var payloadType = undefined; 81819 if (false) { 81820 payloadType = this.payloadTypeFromModelName(snapshot.modelName); 81821 var deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(snapshot.modelName); 81822 81823 if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { 81824 (0, _emberDataPrivateDebug.deprecate)("You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead.", false, { 81825 id: 'ds.json-api-serializer.deprecated-payload-type-for-model', 81826 until: '3.0.0' 81827 }); 81828 81829 payloadType = deprecatedPayloadTypeLookup; 81830 } 81831 } else { 81832 payloadType = this.payloadKeyFromModelName(snapshot.modelName); 81833 } 81834 81835 data.type = payloadType; 81836 return { data: data }; 81837 }, 81838 81839 /** 81840 @method serializeAttribute 81841 @param {DS.Snapshot} snapshot 81842 @param {Object} json 81843 @param {String} key 81844 @param {Object} attribute 81845 */ 81846 serializeAttribute: function serializeAttribute(snapshot, json, key, attribute) { 81847 var type = attribute.type; 81848 81849 if (this._canSerialize(key)) { 81850 json.attributes = json.attributes || {}; 81851 81852 var value = snapshot.attr(key); 81853 if (type) { 81854 var transform = this.transformFor(type); 81855 value = transform.serialize(value, attribute.options); 81856 } 81857 81858 var payloadKey = this._getMappedKey(key, snapshot.type); 81859 81860 if (payloadKey === key) { 81861 payloadKey = this.keyForAttribute(key, 'serialize'); 81862 } 81863 81864 json.attributes[payloadKey] = value; 81865 } 81866 }, 81867 81868 /** 81869 @method serializeBelongsTo 81870 @param {DS.Snapshot} snapshot 81871 @param {Object} json 81872 @param {Object} relationship 81873 */ 81874 serializeBelongsTo: function serializeBelongsTo(snapshot, json, relationship
81874) { 81875 var key = relationship.key; 81876 81877 if (this._canSerialize(key)) { 81878 var belongsTo = snapshot.belongsTo(key); 81879 if (belongsTo !== undefined) { 81880 81881 json.relationships = json.relationships || {}; 81882 81883 var payloadKey = this._getMappedKey(key, snapshot.type); 81884 if (payloadKey === key) { 81885 payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); 81886 } 81887 81888 var data = null; 81889 if (belongsTo) { 81890 var payloadType = undefined; 81891 81892 if (false) { 81893 payloadType = this.payloadTypeFromModelName(belongsTo.modelName); 81894 var deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(belongsTo.modelName); 81895 81896 if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { 81897 (0, _emberDataPrivateDebug.deprecate)("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { 81898 id: 'ds.json-api-serializer.deprecated-payload-type-for-belongs-to', 81899 until: '3.0.0' 81900 }); 81901 81902 payloadType = deprecatedPayloadTypeLookup; 81903 } 81904 } else { 81905 payloadType = this.payloadKeyFromModelName(belongsTo.modelName); 81906 } 81907 81908 data = { 81909 type: payloadType, 81910 id: belongsTo.id 81911 }; 81912 } 81913 81914 json.relationships[payloadKey] = { data: data }; 81915 } 81916 } 81917 }, 81918 81919 /** 81920 @method serializeHasMany 81921 @param {DS.Snapshot} snapshot 81922 @param {Object} json 81923 @param {Object} relationship 81924 */ 81925 serializeHasMany: function serializeHasMany(snapshot, json, relationship) { 81926 var key = relationship.key; 81927 var shouldSerializeHasMany = '_shouldSerializeHasMany'; 81928 if (false) { 81929 shouldSerializeHasMany = 'shouldSerializeHasMany'; 81930 } 81931 81932 if (this[shouldSerializeHasMany](snapshot, key, relationship)) { 81933 var hasMany = snapshot.hasMany(key); 81934 if (hasMany !== undefined) { 81935 81936 json.relationships = json.relationships || {}; 81937 81938 var payloadKey = this._getMappedKey(key, snapshot.type); 81939 if (payloadKey === key && this.keyForRelationship) { 81940 payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); 81941 } 81942 81943 var data = new Array(hasMany.length); 81944 81945 for (var i = 0; i < hasMany.length; i++) { 81946 var item = hasMany[i]; 81947 81948 var payloadType = undefined; 81949 81950 if (false) { 81951 payloadType = this.payloadTypeFromModelName(item.modelName); 81952 var deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(item.modelName); 81953 81954 if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { 81955 (0, _emberDataPrivateDebug.deprecate)("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { 81956 id: 'ds.json-api-serializer.deprecated-payload-type-for-has-many', 81957 until: '3.0.0' 81958 }); 81959 81960 payloadType = deprecatedPayloadTypeLookup; 81961 } 81962 } else { 81963 payloadType = this.payloadKeyFromModelName(item.modelName); 81964 } 81965 81966 data[i] = { 81967 type: payloadType, 81968 id: item.id 81969 }; 81970 } 81971 81972 json.relationships[payloadKey] = { data: data }; 81973 } 81974 } 81975 } 81976 }); 81977 81978 if (false) { 81979 81980 JSONAPISerializer.reopen({ 81981 81982 /** 81983 `modelNameFromPayloadType` can be used to change the mapping for a DS model 81984 name, taken from the value in the payload. 81985 Say your API namespaces the type of a model and returns the following 81986 payload for the `post` model: 81987 ```javascript 81988 // GET /api/posts/1 81989 { 81990 "data": { 81991 "id": 1, 81992 "type: "api::v1::post" 81993 } 81994 } 81995 ``` 81996 By overwriting `modelNameFromPayloadType` you can specify that the 81997 `posr` model should be used: 81998 ```app/serializers/application.js 81999 import DS from "ember-data"; 82000 export default DS.JSONAPISerializer.extend({ 82001 modelNameFromPayloadType(payloadType) { 82002 return payloadType.replace('api::v1::', ''); 82003 } 82004 }); 82005 ``` 82006 By default the modelName for a model is its singularized name in dasherized 82007 form. Usually, Ember Data can use the correct inflection to do this for 82008 you. Most of the time, you won't need to override 82009 `modelNameFromPayloadType` for this purpose. 82010 Also take a look at 82011 [payloadTypeFromModelName](#method_payloadTypeFromModelName) to customize 82012 how the type of a record should be serialized. 82013 @method modelNameFromPayloadType 82014 @public 82015 @param {String} payloadType type from payload 82016 @return {String} modelName 82017 */ 82018 modelNameFromPayloadType: function modelNameFromPayloadType(type) { 82019 return (0, _emberInflector.singularize)((0, _emberDataPrivateSystemNormalizeModelName['default'])(type)); 82020 }, 82021 82022 /** 82023 `payloadTypeFromModelName` can be used to change the mapping for the type in 82024 the payload, taken from the model name. 82025 Say your API namespaces the type of a model and expects the following 82026 payload when you update the `post` model: 82027 ```javascript 82028 // POST /api/posts/1 82029 { 82030 "data": { 82031 "id": 1, 82032 "type": "api::v1::post" 82033 } 82034 } 82035 ``` 82036 By overwriting `payloadTypeFromModelName` you can specify that the 82037 namespaces model name for the `post` should be used: 82038 ```app/serializers/application.js 82039 import DS from "ember-data"; 82040 export default JSONAPISerializer.extend({ 82041 payloadTypeFromModelName(modelName) { 82042 return "api::v1::" + modelName; 82043 } 82044 }); 82045 ``` 82046 By default the payload type is the pluralized model name. Usually, Ember 82047 Data can use the correct inflection to do this for you. Most of the time, 82048 you won't need to override `payloadTypeFromModelName` for this purpose. 82049 Also take a look at 82050 [modelNameFromPayloadType](#method_modelNameFromPayloadType) to customize 82051 how the model name from should be mapped from the payload. 82052 @method payloadTypeFromModelName 82053 @public 82054 @param {String} modelname modelName from the record 82055 @return {String} payloadType 82056 */ 82057 payloadTypeFromModelName: function payloadTypeFromModelName(modelName) { 82058 return (0, _emberInflector.pluralize)(modelName); 82059 }, 82060 82061 _hasCustomModelNameFromPayloadKey: function _hasCustomModelNameFromPayloadKey() { 82062 return this.modelNameFromPayloadKey !== JSONAPISerializer.prototype.modelNameFromPayloadKey; 82063 }, 82064 82065 _hasCustomPayloadKeyFromModelName: function _hasCustomPayloadKeyFromModelName() { 82066 return this.payloadKeyFromModelName !== JSONAPISerializer.prototype.payloadKeyFromModelName; 82067 } 82068 82069 }); 82070 } 82071 82072 (0, _emberDataPrivateDebug.runInDebug)(function () { 82073 JSONAPISerializer.reopen({ 82074 willMergeMixin: function willMergeMixin(props) { 82075 (0, _emberDataPrivateDebug.warn)('The JSONAPISerializer does not work with the EmbeddedRecordsMixin because the JSON API spec does not describe how to format embedded resources.', !props.isEmbeddedRecordsMixin, {
82076 id: 'ds.serializer.embedded-records-mixin-not-supported' 82077 }); 82078 }, 82079 warnMessageForUndefinedType: function warnMessageForUndefinedType() { 82080 return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; 82081 }, 82082 warnMessageNoModelForType: function warnMessageNoModelForType(modelName, originalType, usedLookup) { 82083 return 'Encountered a resource object with type "' + originalType + '", but no model was found for model name "' + modelName + '" (resolved model name using \'' + this.constructor.toString() + '.' + usedLookup + '("' + originalType + '")).'; 82084 } 82085 }); 82086 }); 82087 82088 exports['default'] = JSONAPISerializer; 82089}); 82090define('ember-data/serializers/json', ['exports', 'ember', 'ember-data/-private/debug', 'ember-data/serializer', 'ember-data/-private/system/coerce-id', 'ember-data/-private/system/normalize-model-name', 'ember-data/-private/utils', 'ember-data/-private/features', 'ember-data/adapters/errors'], function (exports, _ember, _emberDataPrivateDebug, _emberDataSerializer, _emberDataPrivateSystemCoerceId, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateUtils, _emberDataPrivateFeatures, _emberDataAdaptersErrors) { 82091 'use strict'; 82092 82093 function _toConsumableArray(arr) { 82094 if (Array.isArray(arr)) { 82095 for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];return arr2; 82096 } else { 82097 return Array.from(arr); 82098 } 82099 } 82100 82101 var get = _ember['default'].get; 82102 var isNone = _ember['default'].isNone; 82103 var assign = _ember['default'].assign || _ember['default'].merge; 82104 82105 /** 82106 Ember Data 2.0 Serializer: 82107 82108 In Ember Data a Serializer is used to serialize and deserialize 82109 records when they are transferred in and out of an external source. 82110 This process involves normalizing property names, transforming 82111 attribute values and serializing relationships. 82112 82113 By default, Ember Data uses and recommends the `JSONAPISerializer`. 82114 82115 `JSONSerializer` is useful for simpler or legacy backends that may 82116 not support the http://jsonapi.org/ spec. 82117 82118 For example, given the following `User` model and JSON payload: 82119 82120 ```app/models/user.js 82121 import DS from 'ember-data'; 82122 82123 export default DS.Model.extend({ 82124 friends: DS.hasMany('user'), 82125 house: DS.belongsTo('location'), 82126 82127 name: DS.attr('string') 82128 }); 82129 ``` 82130 82131 ```js 82132 { 82133 id: 1, 82134 name: 'Sebastian', 82135 friends: [3, 4], 82136 links: { 82137 house: '/houses/lefkada' 82138 } 82139 } 82140 ``` 82141 82142 `JSONSerializer` will normalize the JSON payload to the JSON API format that the 82143 Ember Data store expects. 82144 82145 You can customize how JSONSerializer processes its payload by passing options in 82146 the `attrs` hash or by subclassing the `JSONSerializer` and overriding hooks: 82147 82148 - To customize how a single record is normalized, use the `normalize` hook. 82149 - To customize how `JSONSerializer` normalizes the whole server response, use the 82150 `normalizeResponse` hook. 82151 - To customize how `JSONSerializer` normalizes a specific response from the server, 82152 use one of the many specific `normalizeResponse` hooks. 82153 - To customize how `JSONSerializer` normalizes your id, attributes or relationships, 82154 use the `extractId`, `extractAttributes` and `extractRelationships` hooks. 82155 82156 The `JSONSerializer` normalization process follows these steps: 82157 82158 - `normalizeResponse` - entry method to the serializer. 82159 - `normalizeCreateRecordResponse` - a `normalizeResponse` for a specific operation is called. 82160 - `normalizeSingleResponse`|`normalizeArrayResponse` - for methods like `createRecord` we expect 82161 a single record back, while for methods like `findAll` we expect multiple methods back. 82162 - `normalize` - `normalizeArray` iterates and calls `normalize` for each of its records while `normalizeSingle` 82163 calls it once. This is the method you most likely want to subclass. 82164 - `extractId` | `extractAttributes` | `extractRelationships` - `normalize` delegates to these methods to 82165 turn the record payload into the JSON API format. 82166 82167 @class JSONSerializer 82168 @namespace DS 82169 @extends DS.Serializer 82170 */ 82171 var JSONSerializer = _emberDataSerializer['default'].extend({ 82172 82173 /** 82174 The `primaryKey` is used when serializing and deserializing 82175 data. Ember Data always uses the `id` property to store the id of
82176 the record. The external source may not always follow this 82177 convention. In these cases it is useful to override the 82178 `primaryKey` property to match the `primaryKey` of your external 82179 store. 82180 Example 82181 ```app/serializers/application.js 82182 import DS from 'ember-data'; 82183 export default DS.JSONSerializer.extend({ 82184 primaryKey: '_id' 82185 }); 82186 ``` 82187 @property primaryKey 82188 @type {String} 82189 @default 'id' 82190 */ 82191 primaryKey: 'id', 82192 82193 /** 82194 The `attrs` object can be used to declare a simple mapping between 82195 property names on `DS.Model` records and payload keys in the 82196 serialized JSON object representing the record. An object with the 82197 property `key` can also be used to designate the attribute's key on 82198 the response payload. 82199 Example 82200 ```app/models/person.js 82201 import DS from 'ember-data'; 82202 export default DS.Model.extend({ 82203 firstName: DS.attr('string'), 82204 lastName: DS.attr('string'), 82205 occupation: DS.attr('string'), 82206 admin: DS.attr('boolean') 82207 }); 82208 ``` 82209 ```app/serializers/person.js 82210 import DS from 'ember-data'; 82211 export default DS.JSONSerializer.extend({ 82212 attrs: { 82213 admin: 'is_admin', 82214 occupation: { key: 'career' } 82215 } 82216 }); 82217 ``` 82218 You can also remove attributes by setting the `serialize` key to 82219 `false` in your mapping object. 82220 Example 82221 ```app/serializers/person.js 82222 import DS from 'ember-data'; 82223 export default DS.JSONSerializer.extend({ 82224 attrs: { 82225 admin: { serialize: false }, 82226 occupation: { key: 'career' } 82227 } 82228 }); 82229 ``` 82230 When serialized: 82231 ```javascript 82232 { 82233 "firstName": "Harry", 82234 "lastName": "Houdini", 82235 "career": "magician" 82236 } 82237 ``` 82238 Note that the `admin` is now not included in the payload. 82239 @property attrs 82240 @type {Object} 82241 */ 82242 mergedProperties: ['attrs'], 82243 82244 /** 82245 Given a subclass of `DS.Model` and a JSON object this method will 82246 iterate through each attribute of the `DS.Model` and invoke the 82247 `DS.Transform#deserialize` method on the matching property of the 82248 JSON object. This method is typically called after the 82249 serializer's `normalize` method. 82250 @method applyTransforms 82251 @private 82252 @param {DS.Model} typeClass 82253 @param {Object} data The data to transform 82254 @return {Object} data The transformed data object 82255 */ 82256 applyTransforms: function applyTransforms(typeClass, data) { 82257 var _this = this; 82258 82259 var attributes = get(typeClass, 'attributes'); 82260 82261 typeClass.eachTransformedAttribute(function (key, typeClass) { 82262 if (data[key] === undefined) { 82263 return; 82264 } 82265 82266 var transform = _this.transformFor(typeClass); 82267 var transformMeta = attributes.get(key); 82268 data[key] = transform.deserialize(data[key], transformMeta.options); 82269 }); 82270 82271 return data; 82272 }, 82273 82274 /** 82275 The `normalizeResponse` method is used to normalize a payload from the 82276 server to a JSON-API Document. 82277 http://jsonapi.org/format/#document-structure 82278 This method delegates to a more specific normalize method based on 82279 the `requestType`. 82280 To override this method with a custom one, make sure to call 82281 `return this._super(store, primaryModelClass, payload, id, requestType)` with your 82282 pre-processed data. 82283 Here's an example of using `normalizeResponse` manually: 82284 ```javascript 82285 socket.on('message', function(message) { 82286 var data = message.data; 82287 var modelClass = store.modelFor(data.modelName); 82288 var serializer = store.serializerFor(data.modelName); 82289 var normalized = serializer.normalizeSingleResponse(store, modelClass, data, data.id); 82290 store.push(normalized); 82291 }); 82292 ``` 82293 @since 1.13.0 82294 @method normalizeResponse 82295 @param {DS.Store} store 82296 @param {DS.Model} primaryModelClass 82297 @param {Object} payload 82298 @param {String|Number} id 82299 @param {String} requestType 82300 @return {Object} JSON-API Document 82301 */ 82302 normalizeResponse: function normalizeResponse(store, primaryModelClass, payload, id, requestType) { 82303 switch (requestType) { 82304 case 'findRecord': 82305 return this.normalizeFindRecordResponse.apply(this, arguments); 82306 case 'queryRecord': 82307 return this.normalizeQueryRecordResponse.apply(this, arguments); 82308 case 'findAll': 82309 return this.normalizeFindAllResponse.apply(this, arguments); 82310 case 'findBelongsTo': 82311 return this.normalizeFindBelongsToResponse.apply(this, arguments); 82312 case 'findHasMany': 82313 return this.normalizeFindHasManyResponse.apply(this, arguments); 82314 case 'findMany': 82315 return this.normalizeFindManyResponse.apply(this, arguments); 82316 case 'query': 82317 return this.normalizeQueryResponse.apply(this, arguments); 82318 case 'createRecord': 82319 return this.normalizeCreateRecordResponse.apply(this, arguments); 82320 case 'deleteRecord': 82321 return this.normalizeDeleteRecordResponse.apply(this, arguments); 82322 case 'updateRecord': 82323 return this.normalizeUpdateRecordResponse.apply(this, arguments); 82324 } 82325 }, 82326 82327 /** 82328 @since 1.13.0 82329 @method normalizeFindRecordResponse 82330 @param {DS.Store} store 82331 @param {DS.Model} primaryModelClass 82332 @param {Object} payload 82333 @param {String|Number} id 82334 @param {String} requestType 82335 @return {Object} JSON-API Document 82336 */ 82337 normalizeFindRecordResponse: function normalizeFindRecordResponse(store, primaryModelClass, payload, id, requestType) { 82338 return this.normalizeSingleResponse.apply(this, arguments); 82339 }, 82340 82341 /** 82342 @since 1.13.0 82343 @method normalizeQueryRecordResponse 82344 @param {DS.Store} store 82345 @param {DS.Model} primaryModelClass 82346 @param {Object} payload 82347 @param {String|Number} id 82348 @param {String} requestType 82349 @return {Object} JSON-API Document 82350 */ 82351 normalizeQueryRecordResponse: function normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { 82352 return this.normalizeSingleResponse.apply(this, arguments); 82353 }, 82354 82355 /** 82356 @since 1.13.0 82357 @method normalizeFindAllResponse 82358 @param {DS.Store} store 82359 @param {DS.Model} primaryModelClass 82360 @param {Object} payload 82361 @param {String|Number} id 82362 @param {String} requestType 82363 @return {Object} JSON-API Document 82364 */ 82365 normalizeFindAllResponse: function normalizeFindAllResponse(store, primaryModelClass, payload, id, requestType) { 82366 return this.normalizeArrayResponse.apply(this, arguments); 82367 }, 82368 82369 /** 82370 @since 1.13.0 82371 @method normalizeFindBelongsToResponse 82372 @param {DS.Store} store 82373 @param {DS.Model} primaryModelClass 82374 @param {Object} payload 82375 @param {String|Number} id 82376 @param {String} requestType 82377 @return {Object} JSON-API Document 82378 */ 82379 normalizeFindBelongsToResponse: function normalizeFindBelongsToResponse(store, primaryModelClass, payload, id, requestType) { 82380 return this.normalizeSingleResponse.apply(this, arguments); 82381 }, 82382 82383 /** 82384 @since 1.13.0 82385 @method normalizeFindHasManyResponse 82386 @param {DS.Store} store 82387 @param {DS.Model} primaryModelClass 82388 @param {Object} payload 82389 @param {String|Number} id 82390 @param {String} requestType 82391 @return {Object} JSON-API Document 82392 */ 82393 normalizeFindHasManyResponse: function normalizeFindHasManyResponse(store, primaryModelClass, payload, id, requestType) { 82394 return this.normalizeArrayResponse.apply(this, arguments); 82395 }, 82396 82397 /** 82398 @since 1.13.0 82399 @method normalizeFindManyResponse 82400 @param {DS.Store} store 82401 @param {DS.Model} primaryModelClass 82402 @param {Object} payload 82403 @param {String|Number} id 82404 @param {String} requestType 82405 @return {Object} JSON-API Document 82406 */ 82407 normalizeFindManyResponse: function normalizeFindManyResponse(store, primaryModelClass, payload, id, requestType) { 82408 return this.normalizeArrayResponse.apply(this, arguments); 82409 }, 82410 82411 /** 82412 @since 1.13.0 82413 @method normalizeQueryResponse 82414 @param {DS.Store} store 82415 @param {DS.Model} primaryModelClass 82416 @param {Object} payload 82417 @param {String|Number} id 82418 @param {String} requestType 82419 @return {Object} JSON-API Document 82420 */ 82421 normalizeQueryResponse: function normalizeQueryResponse(store, primaryModelClass, payload, id, requestType) { 82422 return this.normalizeArrayResponse.apply(this, arguments); 82423 }, 82424 82425 /** 82426 @since 1.13.0 82427 @method normalizeCreateRecordResponse 82428 @param {DS.Store} store 82429 @param {DS.Model} primaryModelClass 82430 @param {Object} payload 82431 @param {String|Number} id 82432 @param {String} requestType 82433 @return {Object} JSON-API Document 82434 */ 82435 normalizeCreateRecordResponse: function normalizeCreateRecordResponse(store, primaryModelClass, payload, id, requestType) { 82436 return this.normalizeSaveResponse.apply(this, arguments); 82437 }, 82438 82439 /** 82440 @since 1.13.0 82441 @method normalizeDeleteRecordResponse 82442 @param {DS.Store} store 82443 @param {DS.Model} primaryModelClass 82444 @param {Object} payload 82445 @param {String|Number} id 82446 @param {String} requestType 82447 @return {Object} JSON-API Document 82448 */ 82449 normalizeDeleteRecordResponse: function normalizeDeleteRecordResponse(store, primaryModelClass, payload, id, requestType) { 82450 return this.normalizeSaveResponse.apply(this, arguments); 82451 }, 82452 82453 /** 82454 @since 1.13.0 82455 @method normalizeUpdateRecordResponse 82456 @param {DS.Store} store 82457 @param {DS.Model} primaryModelClass 82458 @param {Object} payload 82459 @param {String|Number} id 82460 @param {String} requestType 82461 @return {Object} JSON-API Document 82462 */ 82463 normalizeUpdateRecordResponse: function normalizeUpdateRecordResponse(store, primaryModelClass, payload, id, requestType) { 82464 return this.normalizeSaveResponse.apply(this, arguments); 82465 }, 82466 82467 /** 82468 @since 1.13.0 82469 @method normalizeSaveResponse 82470 @param {DS.Store} store 82471 @param {DS.Model} primaryModelClass 82472 @param {Object} payload 82473 @param {String|Number} id 82474 @param {String} requestType 82475 @return {Object} JSON-API Document 82476 */ 82477 normalizeSaveResponse: function normalizeSaveResponse(store, primaryModelClass, payload, id, requestType) { 82478 return this.normalizeSingleResponse.apply(this, arguments); 82479 }, 82480 82481 /** 82482 @since 1.13.0 82483 @method normalizeSingleResponse 82484 @param {DS.Store} store 82485 @param {DS.Model} primaryModelClass 82486 @param {Object} payload 82487 @param {String|Number} id 82488 @param {String} requestType 82489 @return {Object} JSON-API Document 82490 */ 82491 normalizeSingleResponse: function normalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { 82492 return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, true); 82493 }, 82494 82495 /** 82496 @since 1.13.0 82497 @method normalizeArrayResponse 82498 @param {DS.Store} store 82499 @param {DS.Model} primaryModelClass 82500 @param {Object} payload 82501 @param {String|Number} id 82502 @param {String} requestType 82503 @return {Object} JSON-API Document 82504 */ 82505 normalizeArrayResponse: function normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { 82506 return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, false); 82507 }, 82508 82509 /** 82510 @method _normalizeResponse 82511 @param {DS.Store} store 82512 @param {DS.Model} primaryModelClass 82513 @param {Object} payload 82514 @param {String|Number} id 82515 @param {String} requestType 82516 @param {Boolean} isSingle 82517 @return {Object} JSON-API Document 82518 @private 82519 */ 82520 _normalizeResponse: function _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { 82521 var documentHash = { 82522 data: null, 82523 included: [] 82524 }; 82525 82526 var meta = this.extractMeta(store, primaryModelClass, payload); 82527 if (meta) { 82528 (0, _emberDataPrivateDebug.assert)('The `meta` returned from `extractMeta` has to be an object, not "' + _ember['default'].typeOf(meta) + '".', _ember['default'].typeOf(meta) === 'object'); 82529 documentHash.meta = meta; 82530 } 82531 82532 if (isSingle) {
82533 var _normalize = this.normalize(primaryModelClass, payload); 82534 82535 var data = _normalize.data; 82536 var included = _normalize.included; 82537 82538 documentHash.data = data; 82539 if (included) { 82540 documentHash.included = included; 82541 } 82542 } else { 82543 var ret = new Array(payload.length); 82544 for (var i = 0, l = payload.length; i < l; i++) { 82545 var item = payload[i]; 82546 82547 var _normalize2 = this.normalize(primaryModelClass, item); 82548 82549 var data = _normalize2.data; 82550 var included = _normalize2.included; 82551 82552 if (included) { 82553 var _documentHash$included; 82554 82555 (_documentHash$included = documentHash.included).push.apply(_documentHash$included, _toConsumableArray(included)); 82556 } 82557 ret[i] = data; 82558 } 82559 82560 documentHash.data = ret; 82561 } 82562 82563 return documentHash; 82564 }, 82565 82566 /** 82567 Normalizes a part of the JSON payload returned by 82568 the server. You should override this method, munge the hash 82569 and call super if you have generic normalization to do. 82570 It takes the type of the record that is being normalized 82571 (as a DS.Model class), the property where the hash was 82572 originally found, and the hash to normalize. 82573 You can use this method, for example, to normalize underscored keys to camelized 82574 or other general-purpose normalizations. 82575 Example 82576 ```app/serializers/application.js 82577 import DS from 'ember-data'; 82578 export default DS.JSONSerializer.extend({ 82579 normalize: function(typeClass, hash) { 82580 var fields = Ember.get(typeClass, 'fields'); 82581 fields.forEach(function(field) { 82582 var payloadField = Ember.String.underscore(field); 82583 if (field === payloadField) { return; } 82584 hash[field] = hash[payloadField]; 82585 delete hash[payloadField]; 82586 }); 82587 return this._super.apply(this, arguments); 82588 } 82589 }); 82590 ``` 82591 @method normalize 82592 @param {DS.Model} typeClass 82593 @param {Object} hash 82594 @return {Object} 82595 */ 82596 normalize: function normalize(modelClass, resourceHash) { 82597 var data = null; 82598 82599 if (resourceHash) { 82600 this.normalizeUsingDeclaredMapping(modelClass, resourceHash); 82601 if (_ember['default'].typeOf(resourceHash.links) === 'object') { 82602 this.normalizeUsingDeclaredMapping(modelClass, resourceHash.links); 82603 } 82604 82605 data = { 82606 id: this.extractId(modelClass, resourceHash), 82607 type: modelClass.modelName, 82608 attributes: this.extractAttributes(modelClass, resourceHash), 82609 relationships: this.extractRelationships(modelClass, resourceHash) 82610 }; 82611 82612 this.applyTransforms(modelClass, data.attributes); 82613 } 82614 82615 return { data: data }; 82616 }, 82617 82618 /** 82619 Returns the resource's ID. 82620 @method extractId 82621 @param {Object} modelClass 82622 @param {Object} resourceHash 82623 @return {String} 82624 */ 82625 extractId: function extractId(modelClass, resourceHash) { 82626 var primaryKey = get(this, 'primaryKey'); 82627 var id = resourceHash[primaryKey]; 82628 return (0, _emberDataPrivateSystemCoerceId['default'])(id); 82629 }, 82630 82631 /** 82632 Returns the resource's attributes formatted as a JSON-API "attributes object". 82633 http://jsonapi.org/format/#document-resource-object-attributes 82634 @method extractAttributes 82635 @param {Object} modelClass 82636 @param {Object} resourceHash 82637 @return {Object} 82638 */ 82639 extractAttributes: function extractAttributes(modelClass, resourceHash) { 82640 var _this2 = this; 82641 82642 var attributeKey; 82643 var attributes = {}; 82644 82645 modelClass.eachAttribute(function (key) { 82646 attributeKey = _this2.keyForAttribute(key, 'deserialize'); 82647 if (resourceHash[attributeKey] !== undefined) { 82648 attributes[key] = resourceHash[attributeKey]; 82649 } 82650 }); 82651 82652 return attributes; 82653 }, 82654 82655 /** 82656 Returns a relationship formatted as a JSON-API "relationship object". 82657 http://jsonapi.org/format/#document-resource-object-relationships 82658 @method extractRelationship 82659 @param {Object}
82659 relationshipModelName 82660 @param {Object} relationshipHash 82661 @return {Object} 82662 */ 82663 extractRelationship: function extractRelationship(relationshipModelName, relationshipHash) { 82664 if (_ember['default'].isNone(relationshipHash)) { 82665 return null; 82666 } 82667 /* 82668 When `relationshipHash` is an object it usually means that the relationship 82669 is polymorphic. It could however also be embedded resources that the 82670 EmbeddedRecordsMixin has be able to process. 82671 */ 82672 if (_ember['default'].typeOf(relationshipHash) === 'object') { 82673 if (relationshipHash.id) { 82674 relationshipHash.id = (0, _emberDataPrivateSystemCoerceId['default'])(relationshipHash.id); 82675 } 82676 82677 var modelClass = this.store.modelFor(relationshipModelName); 82678 if (relationshipHash.type && !(0, _emberDataPrivateUtils.modelHasAttributeOrRelationshipNamedType)(modelClass)) { 82679 82680 if (false) { 82681 var modelName = this.modelNameFromPayloadType(relationshipHash.type); 82682 var deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipHash.type); 82683 82684 if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { 82685 (0, _emberDataPrivateDebug.deprecate)("You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead", false, { 82686 id: 'ds.json-serializer.deprecated-type-for-polymorphic-relationship', 82687 until: '3.0.0' 82688 }); 82689 82690 modelName = deprecatedModelNameLookup; 82691 } 82692 82693 relationshipHash.type = modelName; 82694 } else { 82695 relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); 82696 } 82697 } 82698 return relationshipHash; 82699 } 82700 return { id: (0, _emberDataPrivateSystemCoerceId['default'])(relationshipHash), type: relationshipModelName }; 82701 }, 82702 82703 /** 82704 Returns a polymorphic relationship formatted as a JSON-API "relationship object". 82705 http://jsonapi.org/format/#document-resource-object-relationships 82706 `relationshipOptions` is a hash which contains more information about the 82707 polymorphic relationship which should be extracted: 82708 - `resourceHash` complete hash of the resource the relationship should be 82709 extracted from 82710 - `relationshipKey` key under which the value for the relationship is 82711 extracted from the resourceHash 82712 - `relationshipMeta` meta information about the relationship 82713 @method extractPolymorphicRelationship 82714 @param {Object} relationshipModelName 82715 @param {Object} relationshipHash 82716 @param {Object} relationshipOptions 82717 @return {Object} 82718 */ 82719 extractPolymorphicRelationship: function extractPolymorphicRelationship(relationshipModelName, relationshipHash, relationshipOptions) { 82720 return this.extractRelationship(relationshipModelName, relationshipHash); 82721 }, 82722 82723 /** 82724 Returns the resource's relationships formatted as a JSON-API "relationships object". 82725 http://jsonapi.org/format/#document-resource-object-relationships 82726 @method extractRelationships 82727 @param {Object} modelClass 82728 @param {Object} resourceHash 82729 @return {Object} 82730 */ 82731 extractRelationships: function extractRelationships(modelClass, resourceHash) { 82732 var _this3 = this; 82733 82734 var relationships = {}; 82735 82736 modelClass.eachRelationship(function (key, relationshipMeta) { 82737 var relationship = null; 82738 var relationshipKey = _this3.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); 82739 if (resourceHash[relationshipKey] !== undefined) { 82740 var data = null; 82741 var relationshipHash = resourceHash[relationshipKey]; 82742 if (relationshipMeta.kind === 'belongsTo') { 82743 if (relationshipMeta.options.polymorphic) { 82744 // extracting a polymorphic belongsTo may need more information 82745 // than the type and the hash (which might only be an id) for the 82746 // relationship, hence we pass the key, resource and 82747 // relationshipMeta too 82748 data = _this3.extractPolymorphicRelationship(relationshipMeta.type, relationshipHash, { key: key, resourceHash: resourceHash, relationshipMeta: relationshipMeta }); 82749 } else { 82750 data = _this3.extractRelationship(relationshipMeta.type, relationshipHash); 82751 } 82752 } else if (relationshipMeta.kind === 'hasMany') { 82753 if (!_ember['default'].isNone(relationshipHash)) { 82754 data = new Array(relationshipHash.length); 82755 for (var i = 0, l = relationshipHash.length; i < l; i++) { 82756 var item = relationshipHash[i]; 82757 data[i] = _this3.extractRelationship(relationshipMeta.type, item); 82758 } 82759 } 82760 } 82761 relationship = { data: data }; 82762 } 82763 82764 var linkKey = _this3.keyForLink(key, relationshipMeta.kind); 82765 if (resourceHash.links && resourceHash.links[linkKey] !== undefined) { 82766 var related = resourceHash.links[linkKey]; 82767 relationship = relationship || {}; 82768 relationship.links = { related: related }; 82769 } 82770
82771 if (relationship) { 82772 relationships[key] = relationship; 82773 } 82774 }); 82775 82776 return relationships; 82777 }, 82778 82779 /** 82780 @method modelNameFromPayloadKey 82781 @param {String} key 82782 @return {String} the model's modelName 82783 */ 82784 // TODO @deprecated Use modelNameFromPayloadType instead 82785 modelNameFromPayloadKey: function modelNameFromPayloadKey(key) { 82786 return (0, _emberDataPrivateSystemNormalizeModelName['default'])(key); 82787 }, 82788 82789 /** 82790 @method normalizeAttributes 82791 @private 82792 */ 82793 normalizeAttributes: function normalizeAttributes(typeClass, hash) { 82794 var _this4 = this; 82795 82796 var payloadKey; 82797 82798 if (this.keyForAttribute) { 82799 typeClass.eachAttribute(function (key) { 82800 payloadKey = _this4.keyForAttribute(key, 'deserialize'); 82801 if (key === payloadKey) { 82802 return; 82803 } 82804 if (hash[payloadKey] === undefined) { 82805 return; 82806 } 82807 82808 hash[key] = hash[payloadKey]; 82809 delete hash[payloadKey]; 82810 }); 82811 } 82812 }, 82813 82814 /** 82815 @method normalizeRelationships 82816 @private 82817 */ 82818 normalizeRelationships: function normalizeRelationships(typeClass, hash) { 82819 var _this5 = this; 82820 82821 var payloadKey; 82822 82823 if (this.keyForRelationship) { 82824 typeClass.eachRelationship(function (key, relationship) { 82825 payloadKey = _this5.keyForRelationship(key, relationship.kind, 'deserialize'); 82826 if (key === payloadKey) { 82827 return; 82828 } 82829 if (hash[payloadKey] === undefined) { 82830 return; 82831 } 82832 82833 hash[key] = hash[payloadKey]; 82834 delete hash[payloadKey]; 82835 }); 82836 } 82837 }, 82838 82839 /** 82840 @method normalizeUsingDeclaredMapping 82841 @private 82842 */ 82843 normalizeUsingDeclaredMapping: function normalizeUsingDeclaredMapping(modelClass, hash) { 82844 var attrs = get(this, 'attrs'); 82845 var normalizedKey, payloadKey, key; 82846 82847 if (attrs) { 82848 for (key in attrs) { 82849 normalizedKey = payloadKey = this._getMappedKey(key, modelClass); 82850 82851 if (hash[payloadKey] === undefined) { 82852 continue; 82853 } 82854 82855 if (get(modelClass, 'attributes').has(key)) { 82856 normalizedKey = this.keyForAttribute(key); 82857 } 82858 82859 if (get(modelClass, 'relationshipsByName').has(key)) { 82860 normalizedKey = this.keyForRelationship(key); 82861 } 82862 82863 if (payloadKey !== normalizedKey) { 82864 hash[normalizedKey] = hash[payloadKey]; 82865 delete hash[payloadKey]; 82866 } 82867 } 82868 } 82869 }, 82870 82871 /** 82872 Looks up the property key that was set by the custom `attr` mapping 82873 passed to the serializer. 82874 @method _getMappedKey 82875 @private 82876 @param {String} key 82877 @return {String} key 82878 */ 82879 _getMappedKey: function _getMappedKey(key, modelClass) { 82880 (0, _emberDataPrivateDebug.warn)('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { 82881 id: 'ds.serializer.no-mapped-attrs-key' 82882 }); 82883 82884 var attrs = get(this, 'attrs'); 82885 var mappedKey; 82886 if (attrs && attrs[key]) { 82887 mappedKey = attrs[key]; 82888 //We need to account for both the { title: 'post_title' } and 82889 //{ title: { key: 'post_title' }} forms 82890 if (mappedKey.key) { 82891 mappedKey = mappedKey.key; 82892 } 82893 if (typeof mappedKey === 'string') { 82894 key = mappedKey; 82895 } 82896 } 82897 82898 return key; 82899 }, 82900 82901 /** 82902 Check attrs.key.serialize property to inform if the `key` 82903 can be serialized 82904 @method _canSerialize 82905 @private 82906 @param {String} key 82907 @return {boolean} true if the key can be serialized 82908 */ 82909 _canSerialize: function _canSerialize(key) { 82910 var attrs = get(this, 'attrs'); 82911 82912 return !attrs || !attrs[key] || attrs[key].serialize !== false; 82913 }, 82914 82915 /** 82916 When attrs.key.serialize is set to true then 82917 it takes priority over the other checks and the related 82918 attribute/relationship will be serialized 82919 @method _mustSerialize 82920 @private 82921 @param {String} key 82922 @return {boolean} true if the key must be serialized 82923 */ 82924 _mustSerialize: function _mustSerialize(key) { 82925 var attrs = get(this, 'attrs'); 82926 82927 return attrs && attrs[key] && attrs[key].serialize === true; 82928 }, 82929 82930 /** 82931 Check if the given hasMany relationship should be serialized 82932 @method shouldSerializeHasMany 82933 @param {DS.Snapshot} snapshot 82934 @param {String} key 82935 @param {String} relationshipType 82936 @return {boolean} true if the hasMany relationship should be serialized 82937 */ 82938 82939 shouldSerializeHasMany: function shouldSerializeHasMany(snapshot, key, relationship
82939) { 82940 if (this._shouldSerializeHasMany !== JSONSerializer.prototype._shouldSerializeHasMany) { 82941 (0, _emberDataPrivateDebug.deprecate)('The private method _shouldSerializeHasMany has been promoted to the public API. Please remove the underscore to use the public shouldSerializeHasMany method.', false, { 82942 id: 'ds.serializer.private-should-serialize-has-many', 82943 until: '3.0.0' 82944 }); 82945 } 82946 82947 return this._shouldSerializeHasMany(snapshot, key, relationship); 82948 }, 82949 82950 /** 82951 Check if the given hasMany relationship should be serialized 82952 @method _shouldSerializeHasMany 82953 @private 82954 @param {DS.Snapshot} snapshot 82955 @param {String} key 82956 @param {String} relationshipType 82957 @return {boolean} true if the hasMany relationship should be serialized 82958 */ 82959 _shouldSerializeHasMany: function _shouldSerializeHasMany(snapshot, key, relationship) { 82960 var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); 82961 if (this._mustSerialize(key)) { 82962 return true; 82963 } 82964 return this._canSerialize(key) && (relationshipType === 'manyToNone' || relationshipType === 'manyToMany'); 82965 }, 82966 82967 // SERIALIZE 82968 /** 82969 Called when a record is saved in order to convert the 82970 record into JSON. 82971 By default, it creates a JSON object with a key for 82972 each attribute and belongsTo relationship. 82973 For example, consider this model: 82974 ```app/models/comment.js 82975 import DS from 'ember-data'; 82976 export default DS.Model.extend({ 82977 title: DS.attr(), 82978 body: DS.attr(), 82979 author: DS.belongsTo('user') 82980 }); 82981 ``` 82982 The default serialization would create a JSON object like: 82983 ```javascript 82984 { 82985 "title": "Rails is unagi", 82986 "body": "Rails? Omakase? O_O", 82987 "author": 12 82988 } 82989 ``` 82990 By default, attributes are passed through as-is, unless 82991 you specified an attribute type (`DS.attr('date')`). If 82992 you specify a transform, the JavaScript value will be 82993 serialized when inserted into the JSON hash. 82994 By default, belongs-to relationships are converted into 82995 IDs when inserted into the JSON hash. 82996 ## IDs 82997 `serialize` takes an options hash with a single option: 82998 `includeId`. If this option is `true`, `serialize` will, 82999 by default include the ID in the JSON object it builds. 83000 The adapter passes in `includeId: true` when serializing 83001 a record for `createRecord`, but not for `updateRecord`. 83002 ## Customization 83003 Your server may expect a different JSON format than the 83004 built-in serialization format. 83005 In that case, you can implement `serialize` yourself and 83006 return a JSON hash of your choosing. 83007 ```app/serializers/post.js 83008 import DS from 'ember-data'; 83009 export default DS.JSONSerializer.extend({ 83010 serialize: function(snapshot, options) { 83011 var json = { 83012 POST_TTL: snapshot.attr('title'), 83013 POST_BDY: snapshot.attr('body'), 83014 POST_CMS: snapshot.hasMany('comments', { ids: true }) 83015 } 83016 if (options.includeId) { 83017 json.POST_ID_ = snapshot.id; 83018 } 83019 return json; 83020 } 83021 }); 83022 ``` 83023 ## Customizing an App-Wide Serializer 83024 If you want to define a serializer for your entire 83025 application, you'll probably want to use `eachAttribute` 83026 and `eachRelationship` on the record. 83027 ```app/serializers/application.js 83028 import DS from 'ember-data'; 83029 export default DS.JSONSerializer.extend({ 83030 serialize: function(snapshot, options) { 83031 var json = {}; 83032 snapshot.eachAttribute(function(name) { 83033 json[serverAttributeName(name)] = snapshot.attr(name); 83034 }) 83035 snapshot.eachRelationship(function(name, relationship) { 83036 if (relationship.kind === 'hasMany') { 83037 json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); 83038 } 83039 }); 83040 if (options.includeId) { 83041 json.ID_ = snapshot.id; 83042 } 83043 return json; 83044 } 83045 }); 83046 function serverAttributeName(attribute) { 83047 return attribute.underscore().toUpperCase(); 83048 } 83049 function serverHasManyName(name) { 83050 return serverAttributeName(name.singularize()) + "_IDS"; 83051 } 83052 ``` 83053 This serializer will generate JSON that looks like this: 83054 ```javascript 83055 {
83056 "TITLE": "Rails is omakase", 83057 "BODY": "Yep. Omakase.", 83058 "COMMENT_IDS": [ 1, 2, 3 ] 83059 } 83060 ``` 83061 ## Tweaking the Default JSON 83062 If you just want to do some small tweaks on the default JSON, 83063 you can call super first and make the tweaks on the returned 83064 JSON. 83065 ```app/serializers/post.js 83066 import DS from 'ember-data'; 83067 export default DS.JSONSerializer.extend({ 83068 serialize: function(snapshot, options) { 83069 var json = this._super.apply(this, arguments); 83070 json.subject = json.title; 83071 delete json.title; 83072 return json; 83073 } 83074 }); 83075 ``` 83076 @method serialize 83077 @param {DS.Snapshot} snapshot 83078 @param {Object} options 83079 @return {Object} json 83080 */ 83081 serialize: function serialize(snapshot, options) { 83082 var _this6 = this; 83083 83084 var json = {}; 83085 83086 if (options && options.includeId) { 83087 var id = snapshot.id; 83088 83089 if (id) { 83090 json[get(this, 'primaryKey')] = id; 83091 } 83092 } 83093 83094 snapshot.eachAttribute(function (key, attribute) { 83095 _this6.serializeAttribute(snapshot, json, key, attribute); 83096 }); 83097 83098 snapshot.eachRelationship(function (key, relationship) { 83099 if (relationship.kind === 'belongsTo') { 83100 _this6.serializeBelongsTo(snapshot, json, relationship); 83101 } else if (relationship.kind === 'hasMany') { 83102 _this6.serializeHasMany(snapshot, json, relationship); 83103 } 83104 }); 83105 83106 return json; 83107 }, 83108 83109 /** 83110 You can use this method to customize how a serialized record is added to the complete 83111 JSON hash to be sent to the server. By default the JSON Serializer does not namespace 83112 the payload and just sends the raw serialized JSON object. 83113 If your server expects namespaced keys, you should consider using the RESTSerializer. 83114 Otherwise you can override this method to customize how the record is added to the hash. 83115 The hash property should be modified by reference. 83116 For example, your server may expect underscored root objects. 83117 ```app/serializers/application.js 83118 import DS from 'ember-data'; 83119 export default DS.RESTSerializer.extend({ 83120 serializeIntoHash: function(data, type, snapshot, options) { 83121 var root = Ember.String.decamelize(type.modelName); 83122 data[root] = this.serialize(snapshot, options); 83123 } 83124 }); 83125 ``` 83126 @method serializeIntoHash 83127 @param {Object} hash 83128 @param {DS.Model} typeClass 83129 @param {DS.Snapshot} snapshot 83130 @param {Object} options 83131 */ 83132 serializeIntoHash: function serializeIntoHash(hash, typeClass, snapshot, options) { 83133 assign(hash, this.serialize(snapshot, options)); 83134 }, 83135 83136 /** 83137 `serializeAttribute` can be used to customize how `DS.attr` 83138 properties are serialized 83139 For example if you wanted to ensure all your attributes were always 83140 serialized as properties on an `attributes` object you could 83141 write: 83142 ```app/serializers/application.js 83143 import DS from 'ember-data'; 83144 export default DS.JSONSerializer.extend({ 83145 serializeAttribute: function(snapshot, json, key, attributes) { 83146 json.attributes = json.attributes || {}; 83147 this._super(snapshot, json.attributes, key, attributes); 83148 } 83149 }); 83150 ``` 83151 @method serializeAttribute 83152 @param {DS.Snapshot} snapshot 83153 @param {Object} json 83154 @param {String} key 83155 @param {Object} attribute 83156 */ 83157 serializeAttribute: function serializeAttribute(snapshot, json, key, attribute) { 83158 var type = attribute.type; 83159 83160 if (this._canSerialize(key)) { 83161 var value = snapshot.attr(key); 83162 if (type) { 83163 var transform = this.transformFor(type); 83164 value = transform.serialize(value, attribute.options); 83165 } 83166 83167 // if provided, use the mapping provided by `attrs` in 83168 // the serializer 83169 var payloadKey = this._getMappedKey(key, snapshot.type); 83170 83171 if (payloadKey === key && this.keyForAttribute) { 83172 payloadKey = this.keyForAttribute(key, 'serialize'); 83173 } 83174 83175 json[payloadKey] = value; 83176 } 83177 }, 83178 83179 /** 83180 `serializeBelongsTo` can be used to customize how `DS.belongsTo` 83181 properties are serialized. 83182 Example 83183 ```app/serializers/post.js 83184 import DS from 'ember-data'; 83185 export default DS.JSONSerializer.extend({ 83186 serializeBelongsTo: function(snapshot, json, relationship
83186) { 83187 var key = relationship.key; 83188 var belongsTo = snapshot.belongsTo(key); 83189 key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key; 83190 json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.record.toJSON(); 83191 } 83192 }); 83193 ``` 83194 @method serializeBelongsTo 83195 @param {DS.Snapshot} snapshot 83196 @param {Object} json 83197 @param {Object} relationship 83198 */ 83199 serializeBelongsTo: function serializeBelongsTo(snapshot, json, relationship) { 83200 var key = relationship.key; 83201 83202 if (this._canSerialize(key)) { 83203 var belongsToId = snapshot.belongsTo(key, { id: true }); 83204 83205 // if provided, use the mapping provided by `attrs` in 83206 // the serializer 83207 var payloadKey = this._getMappedKey(key, snapshot.type); 83208 if (payloadKey === key && this.keyForRelationship) { 83209 payloadKey = this.keyForRelationship(key, "belongsTo", "serialize"); 83210 } 83211 83212 //Need to check whether the id is there for new&async records 83213 if (isNone(belongsToId)) { 83214 json[payloadKey] = null; 83215 } else { 83216 json[payloadKey] = belongsToId; 83217 } 83218 83219 if (relationship.options.polymorphic) { 83220 this.serializePolymorphicType(snapshot, json, relationship); 83221 } 83222 } 83223 }, 83224 83225 /** 83226 `serializeHasMany` can be used to customize how `DS.hasMany` 83227 properties are serialized. 83228 Example 83229 ```app/serializers/post.js 83230 import DS from 'ember-data'; 83231 export default DS.JSONSerializer.extend({ 83232 serializeHasMany: function(snapshot, json, relationship) { 83233 var key = relationship.key; 83234 if (key === 'comments') { 83235 return; 83236 } else { 83237 this._super.apply(this, arguments); 83238 } 83239 } 83240 }); 83241 ``` 83242 @method serializeHasMany 83243 @param {DS.Snapshot} snapshot 83244 @param {Object} json 83245 @param {Object} relationship 83246 */ 83247 serializeHasMany: function serializeHasMany(snapshot, json, relationship) { 83248 var key = relationship.key; 83249 var shouldSerializeHasMany = '_shouldSerializeHasMany'; 83250 if (false) { 83251 shouldSerializeHasMany = 'shouldSerializeHasMany'; 83252 } 83253 83254 if (this[shouldSerializeHasMany](snapshot, key, relationship)) { 83255 var hasMany = snapshot.hasMany(key, { ids: true }); 83256 if (hasMany !== undefined) { 83257 // if provided, use the mapping provided by `attrs` in 83258 // the serializer 83259 var payloadKey = this._getMappedKey(key, snapshot.type); 83260 if (payloadKey === key && this.keyForRelationship) { 83261 payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); 83262 } 83263 83264 json[payloadKey] = hasMany; 83265 // TODO support for polymorphic manyToNone and manyToMany relationships 83266 } 83267 } 83268 }, 83269 83270 /** 83271 You can use this method to customize how polymorphic objects are 83272 serialized. Objects are considered to be polymorphic if 83273 `{ polymorphic: true }` is pass as the second argument to the 83274 `DS.belongsTo` function. 83275 Example 83276 ```app/serializers/comment.js 83277 import DS from 'ember-data'; 83278 export default DS.JSONSerializer.extend({ 83279 serializePolymorphicType: function(snapshot, json, relationship) { 83280 var key = relationship.key, 83281 belongsTo = snapshot.belongsTo(key); 83282 key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; 83283 if (Ember.isNone(belongsTo)) { 83284 json[key + "_type"] = null; 83285 } else { 83286 json[key + "_type"] = belongsTo.modelName; 83287 } 83288 } 83289 }); 83290 ``` 83291 @method serializePolymorphicType 83292 @param {DS.Snapshot} snapshot 83293 @param {Object} json 83294 @param {Object} relationship 83295 */ 83296 serializePolymorphicType: _ember['default'].K, 83297 83298 /** 83299 `extractMeta` is used to deserialize any meta information in the 83300 adapter payload. By default Ember Data expects meta information to 83301 be located on the `meta` property of the payload object. 83302 Example 83303 ```app/serializers/post.js 83304 import DS from 'ember-data'; 83305 export default DS.JSONSerializer.extend({ 83306 extractMeta: function(store, typeClass, payload) { 83307 if (payload && payload.hasOwnProperty('_pagination')) { 83308 let meta = payload._pagination; 83309 delete payload._pagination; 83310 return meta; 83311 } 83312 } 83313 }); 83314 ``` 83315 @method extractMeta 83316 @param {DS.Store} store 83317 @param {DS.Model} modelClass 83318 @param {Object} payload 83319 */ 83320 extractMeta: function extractMeta(store, modelClass, payload) { 83321 if (payload && payload['meta'] !== undefined) { 83322 var meta = payload.meta; 83323 delete payload.meta; 83324 return meta; 83325 } 83326 }, 83327 83328 /** 83329 `extractErrors` is used to extract model errors when a call 83330 to `DS.Model#save` fails with an `InvalidError`. By default 83331 Ember Data expects error information to be located on the `errors` 83332 property of the payload object. 83333 This serializer expects this `errors` object to be an Array similar 83334 to the following, compliant with the JSON-API specification: 83335 ```js 83336 { 83337 "errors": [ 83338 { 83339 "detail": "This username is already taken!", 83340 "source": { 83341 "pointer": "data/attributes/username" 83342 } 83343 }, { 83344 "detail": "Doesn't look like a valid email.", 83345 "source": { 83346 "pointer": "data/attributes/email" 83347 } 83348 } 83349 ] 83350 } 83351 ``` 83352 The key `detail` provides a textual description of the problem. 83353 Alternatively, the key `title` can be used for the same purpose. 83354 The nested keys `source.pointer` detail which specific element
83355 of the request data was invalid. 83356 Note that JSON-API also allows for object-level errors to be placed 83357 in an object with pointer `data`, signifying that the problem 83358 cannot be traced to a specific attribute: 83359 ```javascript 83360 { 83361 "errors": [ 83362 { 83363 "detail": "Some generic non property error message", 83364 "source": { 83365 "pointer": "data" 83366 } 83367 } 83368 ] 83369 } 83370 ``` 83371 When turn into a `DS.Errors` object, you can read these errors 83372 through the property `base`: 83373 ```handlebars 83374 {{#each model.errors.base as |error|}} 83375 <div class="error"> 83376 {{error.message}} 83377 </div> 83378 {{/each}} 83379 ``` 83380 Example of alternative implementation, overriding the default 83381 behavior to deal with a different format of errors: 83382 ```app/serializers/post.js 83383 import DS from 'ember-data'; 83384 export default DS.JSONSerializer.extend({ 83385 extractErrors: function(store, typeClass, payload, id) { 83386 if (payload && typeof payload === 'object' && payload._problems) { 83387 payload = payload._problems; 83388 this.normalizeErrors(typeClass, payload); 83389 } 83390 return payload; 83391 } 83392 }); 83393 ``` 83394 @method extractErrors 83395 @param {DS.Store} store 83396 @param {DS.Model} typeClass 83397 @param {Object} payload 83398 @param {(String|Number)} id 83399 @return {Object} json The deserialized errors 83400 */ 83401 extractErrors: function extractErrors(store, typeClass, payload, id) { 83402 var _this7 = this; 83403 83404 if (payload && typeof payload === 'object' && payload.errors) { 83405 payload = (0, _emberDataAdaptersErrors.errorsArrayToHash)(payload.errors); 83406 83407 this.normalizeUsingDeclaredMapping(typeClass, payload); 83408 83409 typeClass.eachAttribute(function (name) { 83410 var key = _this7.keyForAttribute(name, 'deserialize'); 83411 if (key !== name && payload[key] !== undefined) { 83412 payload[name] = payload[key]; 83413 delete payload[key]; 83414 } 83415 }); 83416 83417 typeClass.eachRelationship(function (name) { 83418 var key = _this7.keyForRelationship(name, 'deserialize'); 83419 if (key !== name && payload[key] !== undefined) { 83420 payload[name] = payload[key]; 83421 delete payload[key]; 83422 } 83423 }); 83424 } 83425 83426 return payload; 83427 }, 83428 83429 /** 83430 `keyForAttribute` can be used to define rules for how to convert an 83431 attribute name in your model to a key in your JSON. 83432 Example 83433 ```app/serializers/application.js 83434 import DS from 'ember-data'; 83435 export default DS.RESTSerializer.extend({ 83436 keyForAttribute: function(attr, method) { 83437 return Ember.String.underscore(attr).toUpperCase(); 83438 } 83439 }); 83440 ``` 83441 @method keyForAttribute 83442 @param {String} key 83443 @param {String} method 83444 @return {String} normalized key 83445 */ 83446 keyForAttribute: function keyForAttribute(key, method) { 83447 return key; 83448 }, 83449 83450 /** 83451 `keyForRelationship` can be used to define a custom key when 83452 serializing and deserializing relationship properties. By default 83453 `JSONSerializer` does not provide an implementation of this method. 83454 Example 83455 ```app/serializers/post.js 83456 import DS from 'ember-data'; 83457 export default DS.JSONSerializer.extend({ 83458 keyForRelationship: function(key, relationship, method) { 83459 return 'rel_' + Ember.String.underscore(key); 83460 } 83461 }); 83462 ``` 83463 @method keyForRelationship 83464 @param {String} key 83465 @param {String} typeClass 83466 @param {String} method 83467 @return {String} normalized key 83468 */ 83469 keyForRelationship: function keyForRelationship(key, typeClass, method) { 83470 return key; 83471 }, 83472 83473 /** 83474 `keyForLink` can be used to define a custom key when deserializing link 83475 properties. 83476 @method keyForLink 83477 @param {String} key 83478 @param {String} kind `belongsTo` or `hasMany` 83479 @return {String} normalized key 83480 */ 83481 keyForLink: function keyForLink(key, kind) { 83482 return key; 83483 }, 83484 83485 // HELPERS 83486 83487 /** 83488 @method transformFor 83489 @private 83490 @param {String} attributeType 83491 @param {Boolean} skipAssertion 83492 @return {DS.Transform} transform 83493 */ 83494 transformFor: function transformFor(attributeType, skipAssertion) { 83495 var transform = (0, _emberDataPrivateUtils.getOwner)(this).lookup('transform:' + attributeType); 83496 83497 (0, _emberDataPrivateDebug.assert)("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); 83498 83499 return transform; 83500 } 83501 }); 83502 83503 if (false) { 83504 83505 JSONSerializer.reopen({ 83506 83507 /** 83508 @method modelNameFromPayloadType 83509 @public 83510 @param {String} type 83511 @return {String} the model's modelName 83512 */ 83513 modelNameFromPayloadType: function modelNameFromPayloadType(type) { 83514 return (0, _emberDataPrivateSystemNormalizeModelName['default'])(type); 83515 }, 83516 83517 _hasCustomModelNameFromPayloadKey: function _hasCustomModelNameFromPayloadKey() { 83518 return this.modelNameFromPayloadKey !== JSONSerializer.prototype.modelNameFromPayloadKey; 83519 } 83520 83521 }); 83522 } 83523 83524 exports['default'] = JSONSerializer; 83525}); 83526define("ember-data/serializers/rest", ["exports", "ember", "ember-data/-private/debug", "ember-data/serializers/json", "ember-data/-private/system/normalize-model-name", "ember-inflector", "ember-data/-private/system/coerce-id", "ember-data/-private/utils", "ember-data/-private/features"], function (exports, _ember, _emberDataPrivateDebug, _emberDataSerializersJson, _emberDataPrivateSystemNormalizeModelName, _emberInflector, _emberDataPrivateSystemCoerceId, _emberDataPrivateUtils, _emberDataPrivateFeatures) { 83527 "use strict"; 83528 83529 function _toConsumableArray(arr) { 83530 if (Array.isArray(arr)) { 83531 for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];return arr2; 83532 } else { 83533 return Array.from(arr); 83534 } 83535 } 83536 83537 /** 83538 @module ember-data 83539 */ 83540 83541 var camelize = _ember["default"].String.camelize; 83542 83543 /** 83544 Normally, applications will use the `RESTSerializer` by implementing 83545 the `normalize` method. 83546 83547 This allows you to do whatever kind of munging you need, and is 83548 especially useful if your server is inconsistent and you need to 83549 do munging differently for many different kinds of responses. 83550 83551 See the `normalize` documentation for more information. 83552 83553 ## Across the Board Normalization 83554 83555 There are also a number of hooks that you might find useful to define 83556 across-the-board rules for your payload. These rules will be useful 83557 if your server is consistent, or if you're building an adapter for
83558 an infrastructure service, like Firebase, and want to encode service 83559 conventions. 83560 83561 For example, if all of your keys are underscored and all-caps, but 83562 otherwise consistent with the names you use in your models, you 83563 can implement across-the-board rules for how to convert an attribute 83564 name in your model to a key in your JSON. 83565 83566 ```app/serializers/application.js 83567 import DS from 'ember-data'; 83568 83569 export default DS.RESTSerializer.extend({ 83570 keyForAttribute: function(attr, method) { 83571 return Ember.String.underscore(attr).toUpperCase(); 83572 } 83573 }); 83574 ``` 83575 83576 You can also implement `keyForRelationship`, which takes the name 83577 of the relationship as the first parameter, the kind of 83578 relationship (`hasMany` or `belongsTo`) as the second parameter, and 83579 the method (`serialize` or `deserialize`) as the third parameter. 83580 83581 @class RESTSerializer 83582 @namespace DS 83583 @extends DS.JSONSerializer 83584 */ 83585 var RESTSerializer = _emberDataSerializersJson["default"].extend({ 83586 83587 /** 83588 `keyForPolymorphicType` can be used to define a custom key when 83589 serializing and deserializing a polymorphic type. By default, the 83590 returned key is `${key}Type`. 83591 Example 83592 ```app/serializers/post.js 83593 import DS from 'ember-data'; 83594 export default DS.RESTSerializer.extend({ 83595 keyForPolymorphicType: function(key, relationship) { 83596 var relationshipKey = this.keyForRelationship(key); 83597 return 'type-' + relationshipKey; 83598 } 83599 }); 83600 ``` 83601 @method keyForPolymorphicType 83602 @param {String} key 83603 @param {String} typeClass 83604 @param {String} method 83605 @return {String} normalized key 83606 */ 83607 keyForPolymorphicType: function keyForPolymorphicType(key, typeClass, method) { 83608 var relationshipKey = this.keyForRelationship(key); 83609 83610 return relationshipKey + "Type"; 83611 }, 83612 83613 /** 83614 Normalizes a part of the JSON payload returned by 83615 the server. You should override this method, munge the hash 83616 and call super if you have generic normalization to do. 83617 It takes the type of the record that is being normalized 83618 (as a DS.Model class), the property where the hash was 83619 originally found, and the hash to normalize. 83620 For example, if you have a payload that looks like this: 83621 ```js 83622 { 83623 "post": { 83624 "id": 1, 83625 "title": "Rails is omakase", 83626 "comments": [ 1, 2 ] 83627 }, 83628 "comments": [{ 83629 "id": 1, 83630 "body": "FIRST" 83631 }, { 83632 "id": 2, 83633 "body": "Rails is unagi" 83634 }] 83635 } 83636 ``` 83637 The `normalize` method will be called three times: 83638 * With `App.Post`, `"posts"` and `{ id: 1, title: "Rails is omakase", ... }` 83639 * With `App.Comment`, `"comments"` and `{ id: 1, body: "FIRST" }` 83640 * With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }` 83641 You can use this method, for example, to normalize underscored keys to camelized 83642 or other general-purpose normalizations. You will only need to implement 83643 `normalize` and manipulate the payload as desired. 83644 For example, if the `IDs` under `"comments"` are provided as `_id` instead of 83645 `id`, you can specify how to normalize just the comments: 83646 ```app/serializers/post.js 83647 import DS from 'ember-data'; 83648 export default DS.RESTSerializer.extend({ 83649 normalize(model, hash, prop) { 83650 if (prop === 'comments') { 83651 hash.id = hash._id; 83652 delete hash._id; 83653 } 83654 return this._super(...arguments); 83655 } 83656 }); 83657 ``` 83658 On each call to the `normalize` method, the third parameter (`prop`) is always 83659 one of the keys that were in the original payload or in the result of another 83660 normalization as `normalizeResponse`. 83661 @method normalize 83662 @param {DS.Model} modelClass 83663 @param {Object} resourceHash 83664 @param {String} prop 83665 @return {Object} 83666 */ 83667 normalize: function normalize(modelClass, resourceHash, prop) { 83668 if (this.normalizeHash && this.normalizeHash[prop]) { 83669 (0, _emberDataPrivateDebug.deprecate)('`RESTSerializer.normalizeHash` has been deprecated. Please use `serializer.normalize` to modify the payload of single resources.', false, { 83670 id: 'ds.serializer.normalize-hash-deprecated', 83671 until: '3.0.0' 83672 }); 83673 this.normalizeHash[prop](resourceHash); 83674 } 83675 return this._super(modelClass, resourceHash); 83676 }, 83677 83678 /** 83679 Normalizes an array of resource payloads and returns a JSON-API Document 83680 with primary data and, if any, included data as `{ data, included }`. 83681 @method _normalizeArray 83682 @param {DS.Store} store 83683 @param {String} modelName 83684 @param {Object} arrayHash 83685 @param {String} prop 83686 @return {Object} 83687 @private 83688 */ 83689 _normalizeArray: function _normalizeArray(store, modelName, arrayHash, prop) { 83690 var _this = this; 83691 83692 var documentHash = { 83693 data: [], 83694 included: [] 83695 }; 83696 83697 var modelClass = store.modelFor(modelName); 83698 var serializer = store.serializerFor(modelName); 83699
83700 _ember["default"].makeArray(arrayHash).forEach(function (hash) { 83701 var _normalizePolymorphicRecord2 = _this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); 83702 83703 var data = _normalizePolymorphicRecord2.data; 83704 var included = _normalizePolymorphicRecord2.included; 83705 83706 documentHash.data.push(data); 83707 if (included) { 83708 var _documentHash$included; 83709 83710 (_documentHash$included = documentHash.included).push.apply(_documentHash$included, _toConsumableArray(included)); 83711 } 83712 }); 83713 83714 return documentHash; 83715 }, 83716 83717 _normalizePolymorphicRecord: function _normalizePolymorphicRecord(store, hash, prop, primaryModelClass, primarySerializer) { 83718 var serializer = primarySerializer; 83719 var modelClass = primaryModelClass; 83720 83721 var primaryHasTypeAttribute = (0, _emberDataPrivateUtils.modelHasAttributeOrRelationshipNamedType)(primaryModelClass); 83722 83723 if (!primaryHasTypeAttribute && hash.type) { 83724 // Support polymorphic records in async relationships 83725 var modelName = undefined; 83726 if (false) { 83727 modelName = this.modelNameFromPayloadType(hash.type); 83728 var deprecatedModelNameLookup = this.modelNameFromPayloadKey(hash.type); 83729 83730 if (modelName !== deprecatedModelNameLookup && !this._hasCustomModelNameFromPayloadType() && this._hasCustomModelNameFromPayloadKey()) { 83731 (0, _emberDataPrivateDebug.deprecate)("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This is has been deprecated in favor of modelNameFromPayloadType", false, { 83732 id: 'ds.rest-serializer.deprecated-model-name-for-polymorphic-type', 83733 until: '3.0.0' 83734 }); 83735 83736 modelName = deprecatedModelNameLookup; 83737 } 83738 } else { 83739 modelName = this.modelNameFromPayloadKey(hash.type); 83740 } 83741 83742 if (store._hasModelFor(modelName)) { 83743 serializer = store.serializerFor(modelName); 83744 modelClass = store.modelFor(modelName); 83745 } 83746 } 83747 83748 return serializer.normalize(modelClass, hash, prop); 83749 }, 83750 83751 /* 83752 @method _normalizeResponse 83753 @param {DS.Store} store 83754 @param {DS.Model} primaryModelClass 83755 @param {Object} payload 83756 @param {String|Number} id 83757 @param {String} requestType 83758 @param {Boolean} isSingle 83759 @return {Object} JSON-API Document 83760 @private 83761 */ 83762 _normalizeResponse: function _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { 83763 var documentHash = { 83764 data: null, 83765 included: [] 83766 }; 83767 83768 var meta = this.extractMeta(store, primaryModelClass, payload); 83769 if (meta) { 83770 (0, _emberDataPrivateDebug.assert)('The `meta` returned from `extractMeta` has to be an object, not "' + _ember["default"].typeOf(meta) + '".', _ember["default"].typeOf(meta) === 'object'); 83771 documentHash.meta = meta; 83772 } 83773 83774 var keys = Object.keys(payload); 83775 83776 for (var i = 0, _length = keys.length; i < _length; i++) { 83777 var prop = keys[i]; 83778 var modelName = prop; 83779 var forcedSecondary = false; 83780 83781 /* 83782 If you want to provide sideloaded records of the same type that the 83783 primary data you can do that by prefixing the key with `_`. 83784 Example 83785 ``` 83786 { 83787 users: [ 83788 { id: 1, title: 'Tom', manager: 3 }, 83789 { id: 2, title: 'Yehuda', manager: 3 } 83790 ], 83791 _users: [ 83792 { id: 3, title: 'Tomster' } 83793 ] 83794 } 83795 ``` 83796 This forces `_users` to be added to `included` instead of `data`. 83797 */ 83798 if (prop.charAt(0) === '_') { 83799 forcedSecondary = true; 83800 modelName = prop.substr(1); 83801 } 83802 83803 var typeName = this.modelNameFromPayloadKey(modelName); 83804 if (!store.modelFactoryFor(typeName)) { 83805 (0, _emberDataPrivateDebug.warn)(this.warnMessageNoModelForKey(modelName, typeName), false, { 83806 id: 'ds.serializer.model-for-key-missing' 83807 }); 83808 continue; 83809 } 83810 83811 var isPrimary = !forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass); 83812 var value = payload[prop]; 83813 83814 if (value === null) { 83815 continue; 83816 } 83817 83818 (0, _emberDataPrivateDebug.runInDebug)(function () { 83819 var isQueryRecordAnArray = requestType === 'queryRecord' && isPrimary && Array.isArray(value); 83820 var message = "The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record."; 83821 83822 (0, _emberDataPrivateDebug.deprecate)(message, !isQueryRecordAnArray, {
83823 id: 'ds.serializer.rest.queryRecord-array-response', 83824 until: '3.0' 83825 }); 83826 }); 83827 83828 /* 83829 Support primary data as an object instead of an array. 83830 Example 83831 ``` 83832 { 83833 user: { id: 1, title: 'Tom', manager: 3 } 83834 } 83835 ``` 83836 */ 83837 if (isPrimary && _ember["default"].typeOf(value) !== 'array') { 83838 var _normalizePolymorphicRecord3 = this._normalizePolymorphicRecord(store, value, prop, primaryModelClass, this); 83839 83840 var _data = _normalizePolymorphicRecord3.data; 83841 var _included = _normalizePolymorphicRecord3.included; 83842 83843 documentHash.data = _data; 83844 if (_included) { 83845 var _documentHash$included2; 83846 83847 (_documentHash$included2 = documentHash.included).push.apply(_documentHash$included2, _toConsumableArray(_included)); 83848 } 83849 continue; 83850 } 83851 83852 var _normalizeArray2 = this._normalizeArray(store, typeName, value, prop); 83853 83854 var data = _normalizeArray2.data; 83855 var included = _normalizeArray2.included; 83856 83857 if (included) { 83858 var _documentHash$included3; 83859 83860 (_documentHash$included3 = documentHash.included).push.apply(_documentHash$included3, _toConsumableArray(included)); 83861 } 83862 83863 if (isSingle) { 83864 data.forEach(function (resource) { 83865 83866 /* 83867 Figures out if this is the primary record or not. 83868 It's either: 83869 1. The record with the same ID as the original request 83870 2. If it's a newly created record without an ID, the first record 83871 in the array 83872 */ 83873 var isUpdatedRecord = isPrimary && (0, _emberDataPrivateSystemCoerceId["default"])(resource.id) === id; 83874 var isFirstCreatedRecord = isPrimary && !id && !documentHash.data; 83875 83876 if (isFirstCreatedRecord || isUpdatedRecord) { 83877 documentHash.data = resource; 83878 } else { 83879 documentHash.included.push(resource); 83880 } 83881 }); 83882 } else { 83883 if (isPrimary) { 83884 documentHash.data = data; 83885 } else { 83886 if (data) { 83887 var _documentHash$included4; 83888 83889 (_documentHash$included4 = documentHash.included).push.apply(_documentHash$included4, _toConsumableArray(data)); 83890 } 83891 } 83892 } 83893 } 83894 83895 return documentHash; 83896 }, 83897 83898 isPrimaryType: function isPrimaryType(store, typeName, primaryTypeClass) { 83899 var typeClass = store.modelFor(typeName); 83900 return typeClass.modelName === primaryTypeClass.modelName; 83901 }, 83902 83903 /** 83904 This method allows you to push a payload containing top-level 83905 collections of records organized per type. 83906 ```js 83907 { 83908 "posts": [{ 83909 "id": "1", 83910 "title": "Rails is omakase", 83911 "author", "1", 83912 "comments": [ "1" ] 83913 }], 83914 "comments": [{ 83915 "id": "1", 83916 "body": "FIRST" 83917 }], 83918 "users": [{ 83919 "id": "1", 83920 "name": "@d2h" 83921 }] 83922 } 83923 ``` 83924 It will first normalize the payload, so you can use this to push 83925 in data streaming in from your server structured the same way 83926 that fetches and saves are structured. 83927 @method pushPayload 83928 @param {DS.Store} store 83929 @param {Object} payload 83930 */ 83931 pushPayload: function pushPayload(store, payload) { 83932 var documentHash = { 83933 data: [], 83934 included: [] 83935 }; 83936 83937 for (var prop in payload) { 83938 var modelName = this.modelNameFromPayloadKey(prop); 83939 if (!store.modelFactoryFor(modelName)) { 83940 (0, _emberDataPrivateDebug.warn)(this.warnMessageNoModelForKey(prop, modelName), false, { 83941 id: 'ds.serializer.model-for-key-missing' 83942 }); 83943 continue; 83944 } 83945 var type = store.modelFor(modelName); 83946 var typeSerializer = store.serializerFor(type.modelName); 83947 83948 _ember["default"].makeArray(payload[prop]).forEach(function (hash) { 83949 var _typeSerializer$normalize = typeSerializer.normalize(type, hash, prop); 83950 83951 var data = _typeSerializer$normalize.data; 83952 var included = _typeSerializer$normalize.included; 83953 83954 documentHash.data.push(data); 83955 if (included) { 83956 var _documentHash$included5; 83957 83958 (_documentHash$included5 = documentHash.included).push.apply(_documentHash$included5, _toConsumableArray(included)); 83959 } 83960 }); 83961 } 83962 83963 if (false) { 83964 return store.push(documentHash); 83965 } else { 83966 store.push(documentHash); 83967 } 83968 }, 83969 83970 /** 83971 This method is used to convert each JSON root key in the payload 83972 into a modelName that it can use to look up the appropriate model for 83973 that part of the payload. 83974 For example, your server may send a model name that does not correspond with 83975 the name of the model in your app. Let's take a look at an example model, 83976 and an example payload: 83977 ```app/models/post.js 83978 import DS from 'ember-data'; 83979 export default DS.Model.extend({ 83980 }); 83981 ``` 83982 ```javascript 83983 { 83984 "blog/post": { 83985 "id": "1 83986 } 83987 } 83988 ``` 83989 Ember Data is going to normalize the payload's root key for the modelName. As a result, 83990 it will try to look up the "blog/post" model. Since we don't have a model called "blog/post" 83991 (or a file called app/models/blog/post.js in ember-cli), Ember Data will throw an error 83992 because it cannot find the "blog/post" model. 83993 Since we want to remove this namespace, we can define a serializer for the application that will 83994 remove "blog/" from the payload key whenver it's encountered by Ember Data: 83995 ```app/serializers/application.js 83996 import DS from 'ember-data'; 83997 export default DS.RESTSerializer.extend({ 83998 modelNameFromPayloadKey: function(payloadKey) { 83999 if (payloadKey === 'blog/post') { 84000 return this._super(payloadKey.replace('blog/', '')); 84001 } else { 84002 return this._super(payloadKey); 84003 } 84004 } 84005 }); 84006 ``` 84007 After refreshing, Ember Data will appropriately look up the "post" model. 84008 By default the modelName for a model is its 84009 name in dasherized form. This means that a payload key like "blogPost" would be 84010 normalized to "blog-post" when Ember Data looks up the model. Usually, Ember Data 84011 can use the correct inflection to do this for you. Most of the time, you won't 84012 need to override `modelNameFromPayloadKey` for this purpose. 84013 @method modelNameFromPayloadKey 84014 @param {String} key 84015 @return {String} the model's modelName 84016 */ 84017 modelNameFromPayloadKey: function modelNameFromPayloadKey(key) { 84018 return (0, _emberInflector.singularize)((0, _emberDataPrivateSystemNormalizeModelName["default"])(key)); 84019 }, 84020 84021 // SERIALIZE 84022 84023 /**
84024 Called when a record is saved in order to convert the 84025 record into JSON. 84026 By default, it creates a JSON object with a key for 84027 each attribute and belongsTo relationship. 84028 For example, consider this model: 84029 ```app/models/comment.js 84030 import DS from 'ember-data'; 84031 export default DS.Model.extend({ 84032 title: DS.attr(), 84033 body: DS.attr(), 84034 author: DS.belongsTo('user') 84035 }); 84036 ``` 84037 The default serialization would create a JSON object like: 84038 ```js 84039 { 84040 "title": "Rails is unagi", 84041 "body": "Rails? Omakase? O_O", 84042 "author": 12 84043 } 84044 ``` 84045 By default, attributes are passed through as-is, unless 84046 you specified an attribute type (`DS.attr('date')`). If 84047 you specify a transform, the JavaScript value will be 84048 serialized when inserted into the JSON hash. 84049 By default, belongs-to relationships are converted into 84050 IDs when inserted into the JSON hash. 84051 ## IDs 84052 `serialize` takes an options hash with a single option: 84053 `includeId`. If this option is `true`, `serialize` will, 84054 by default include the ID in the JSON object it builds. 84055 The adapter passes in `includeId: true` when serializing 84056 a record for `createRecord`, but not for `updateRecord`. 84057 ## Customization 84058 Your server may expect a different JSON format than the 84059 built-in serialization format. 84060 In that case, you can implement `serialize` yourself and 84061 return a JSON hash of your choosing. 84062 ```app/serializers/post.js 84063 import DS from 'ember-data'; 84064 export default DS.RESTSerializer.extend({ 84065 serialize: function(snapshot, options) { 84066 var json = { 84067 POST_TTL: snapshot.attr('title'), 84068 POST_BDY: snapshot.attr('body'), 84069 POST_CMS: snapshot.hasMany('comments', { ids: true }) 84070 } 84071 if (options.includeId) { 84072 json.POST_ID_ = snapshot.id; 84073 } 84074 return json; 84075 } 84076 }); 84077 ``` 84078 ## Customizing an App-Wide Serializer 84079 If you want to define a serializer for your entire 84080 application, you'll probably want to use `eachAttribute` 84081 and `eachRelationship` on the record. 84082 ```app/serializers/application.js 84083 import DS from 'ember-data'; 84084 export default DS.RESTSerializer.extend({ 84085 serialize: function(snapshot, options) { 84086 var json = {}; 84087 snapshot.eachAttribute(function(name) { 84088 json[serverAttributeName(name)] = snapshot.attr(name); 84089 }) 84090 snapshot.eachRelationship(function(name, relationship) { 84091 if (relationship.kind === 'hasMany') { 84092 json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); 84093 } 84094 }); 84095 if (options.includeId) { 84096 json.ID_ = snapshot.id; 84097 } 84098 return json; 84099 } 84100 }); 84101 function serverAttributeName(attribute) { 84102 return attribute.underscore().toUpperCase(); 84103 } 84104 function serverHasManyName(name) { 84105 return serverAttributeName(name.singularize()) + "_IDS"; 84106 } 84107 ``` 84108 This serializer will generate JSON that looks like this: 84109 ```js 84110 { 84111 "TITLE": "Rails is omakase", 84112 "BODY": "Yep. Omakase.", 84113 "COMMENT_IDS": [ 1, 2, 3 ] 84114 } 84115 ``` 84116 ## Tweaking the Default JSON 84117 If you just want to do some small tweaks on the default JSON, 84118 you can call super first and make the tweaks on the returned 84119 JSON. 84120 ```app/serializers/post.js 84121 import DS from 'ember-data'; 84122 export default DS.RESTSerializer.extend({ 84123 serialize: function(snapshot, options) { 84124 var json = this._super(snapshot, options); 84125 json.subject = json.title; 84126 delete json.title; 84127 return json; 84128 } 84129 }); 84130 ``` 84131 @method serialize 84132 @param {DS.Snapshot} snapshot 84133 @param {Object} options 84134 @return {Object} json 84135 */ 84136 serialize: function serialize(snapshot, options) { 84137 return this._super.apply(this, arguments); 84138 }, 84139 84140 /** 84141 You can use this method to customize the root keys serialized into the JSON. 84142 The hash property should be modified by reference (possibly using something like _.extend) 84143 By default the REST Serializer sends the modelName of a model, which is a camelized 84144 version of the name. 84145 For example, your server may expect underscored root objects. 84146 ```app/serializers/application.js 84147 import DS from 'ember-data'; 84148 export default DS.RESTSerializer.extend({ 84149 serializeIntoHash: function(data, type, record, options) { 84150 var root = Ember.String.decamelize(type.modelName); 84151 data[root] = this.serialize(record, options); 84152 } 84153 }); 84154 ``` 84155 @method serializeIntoHash 84156 @param {Object} hash 84157 @param {DS.Model} typeClass 84158 @param {DS.Snapshot} snapshot 84159 @param {Object} options 84160 */ 84161 serializeIntoHash: function serializeIntoHash(hash, typeClass, snapshot, options) { 84162 var normalizedRootKey = this.payloadKeyFromModelName(typeClass.modelName); 84163 hash[normalizedRootKey] = this.serialize(snapshot, options); 84164 }, 84165 84166 /** 84167 You can use `payloadKeyFromModelName` to override the root key for an outgoing 84168 request. By default, the RESTSerializer returns a camelized version of the 84169 model's name. 84170 For a model called TacoParty, its `modelName` would be the string `taco-party`. The RESTSerializer
84171 will send it to the server with `tacoParty` as the root key in the JSON payload: 84172 ```js 84173 { 84174 "tacoParty": { 84175 "id": "1", 84176 "location": "Matthew Beale's House" 84177 } 84178 } 84179 ``` 84180 For example, your server may expect dasherized root objects: 84181 ```app/serializers/application.js 84182 import DS from 'ember-data'; 84183 export default DS.RESTSerializer.extend({ 84184 payloadKeyFromModelName: function(modelName) { 84185 return Ember.String.dasherize(modelName); 84186 } 84187 }); 84188 ``` 84189 Given a `TacoParty` model, calling `save` on it would produce an outgoing 84190 request like: 84191 ```js 84192 { 84193 "taco-party": { 84194 "id": "1", 84195 "location": "Matthew Beale's House" 84196 } 84197 } 84198 ``` 84199 @method payloadKeyFromModelName 84200 @param {String} modelName 84201 @return {String} 84202 */ 84203 payloadKeyFromModelName: function payloadKeyFromModelName(modelName) { 84204 return camelize(modelName); 84205 }, 84206 84207 /** 84208 You can use this method to customize how polymorphic objects are serialized. 84209 By default the REST Serializer creates the key by appending `Type` to 84210 the attribute and value from the model's camelcased model name. 84211 @method serializePolymorphicType 84212 @param {DS.Snapshot} snapshot 84213 @param {Object} json 84214 @param {Object} relationship 84215 */ 84216 serializePolymorphicType: function serializePolymorphicType(snapshot, json, relationship) { 84217 var key = relationship.key; 84218 var belongsTo = snapshot.belongsTo(key); 84219 var typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); 84220 84221 // old way of getting the key for the polymorphic type 84222 key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; 84223 key = key + "Type"; 84224 84225 // The old way of serializing the type of a polymorphic record used 84226 // `keyForAttribute`, which is not correct. The next code checks if the old 84227 // way is used and if it differs from the new way of using 84228 // `keyForPolymorphicType`. If this is the case, a deprecation warning is 84229 // logged and the old way is restored (so nothing breaks). 84230 if (key !== typeKey && this.keyForPolymorphicType === RESTSerializer.prototype.keyForPolymorphicType) { 84231 (0, _emberDataPrivateDebug.deprecate)("The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead.", false, { 84232 id: 'ds.rest-serializer.deprecated-key-for-polymorphic-type', 84233 until: '3.0.0' 84234 }); 84235 84236 typeKey = key; 84237 } 84238 84239 if (_ember["default"].isNone(belongsTo)) { 84240 json[typeKey] = null; 84241 } else { 84242 if (false) { 84243 json[typeKey] = this.payloadTypeFromModelName(belongsTo.modelName); 84244 } else { 84245 json[typeKey] = camelize(belongsTo.modelName); 84246 } 84247 } 84248 }, 84249 84250 /** 84251 You can use this method to customize how a polymorphic relationship should 84252 be extracted. 84253 @method extractPolymorphicRelationship 84254 @param {Object} relationshipType 84255 @param {Object} relationshipHash 84256 @param {Object} relationshipOptions 84257 @return {Object} 84258 */ 84259 extractPolymorphicRelationship: function extractPolymorphicRelationship(relationshipType, relationshipHash, relationshipOptions) { 84260 var key = relationshipOptions.key; 84261 var resourceHash = relationshipOptions.resourceHash; 84262 var relationshipMeta = relationshipOptions.relationshipMeta; 84263 84264 // A polymorphic belongsTo relationship can be present in the payload 84265 // either in the form where the `id` and the `type` are given: 84266 // 84267 // { 84268 // message: { id: 1, type: 'post' } 84269 // } 84270 // 84271 // or by the `id` and a `<relationship>Type` attribute: 84272 // 84273 // { 84274 // message: 1, 84275 // messageType: 'post' 84276 // } 84277 // 84278 // The next code checks if the latter case is present and returns the 84279 // corresponding JSON-API representation. The former case is handled within 84280 // the base class JSONSerializer. 84281 var isPolymorphic = relationshipMeta.options.polymorphic; 84282 var typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); 84283 84284 if (isPolymorphic && resourceHash[typeProperty] !== undefined && typeof relationshipHash !== 'object') { 84285 84286 if (false) { 84287 84288 var payloadType = resourceHash[typeProperty]; 84289 var type = this.modelNameFromPayloadType(payloadType); 84290 var deprecatedTypeLookup = this.modelNameFromPayloadKey(payloadType); 84291 84292 if (payloadType !== deprecatedTypeLookup && !this._hasCustomModelNameFromPayloadType() && this._hasCustomModelNameFromPayloadKey()) { 84293 (0, _emberDataPrivateDebug.deprecate)("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated
84293in favor of modelNameFromPayloadType", false, { 84294 id: 'ds.rest-serializer.deprecated-model-name-for-polymorphic-type', 84295 until: '3.0.0' 84296 }); 84297 84298 type = deprecatedTypeLookup; 84299 } 84300 84301 return { 84302 id: relationshipHash, 84303 type: type 84304 }; 84305 } else { 84306 84307 var type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); 84308 return { 84309 id: relationshipHash, 84310 type: type 84311 }; 84312 } 84313 } 84314 84315 return this._super.apply(this, arguments); 84316 } 84317 }); 84318 84319 if (false) { 84320 84321 RESTSerializer.reopen({ 84322 84323 /** 84324 `modelNameFromPayloadType` can be used to change the mapping for a DS model 84325 name, taken from the value in the payload. 84326 Say your API namespaces the type of a model and returns the following 84327 payload for the `post` model, which has a polymorphic `user` relationship: 84328 ```javascript 84329 // GET /api/posts/1 84330 { 84331 "post": { 84332 "id": 1, 84333 "user": 1, 84334 "userType: "api::v1::administrator" 84335 } 84336 } 84337 ``` 84338 By overwriting `modelNameFromPayloadType` you can specify that the 84339 `administrator` model should be used: 84340 ```app/serializers/application.js 84341 import DS from "ember-data"; 84342 export default DS.RESTSerializer.extend({ 84343 modelNameFromPayloadType(payloadType) { 84344 return payloadType.replace('api::v1::', ''); 84345 } 84346 }); 84347 ``` 84348 By default the modelName for a model is its name in dasherized form. 84349 Usually, Ember Data can use the correct inflection to do this for you. Most 84350 of the time, you won't need to override `modelNameFromPayloadType` for this 84351 purpose. 84352 Also take a look at 84353 [payloadTypeFromModelName](#method_payloadTypeFromModelName) to customize 84354 how the type of a record should be serialized. 84355 @method modelNameFromPayloadType 84356 @public 84357 @param {String} payloadType type from payload 84358 @return {String} modelName 84359 */ 84360 modelNameFromPayloadType: function modelNameFromPayloadType(payloadType) { 84361 return (0, _emberInflector.singularize)((0, _emberDataPrivateSystemNormalizeModelName["default"])(payloadType)); 84362 }, 84363 84364 /** 84365 `payloadTypeFromModelName` can be used to change the mapping for the type in 84366 the payload, taken from the model name. 84367 Say your API namespaces the type of a model and expects the following 84368 payload when you update the `post` model, which has a polymorphic `user` 84369 relationship: 84370 ```javascript 84371 // POST /api/posts/1 84372 { 84373 "post": { 84374 "id": 1, 84375 "user": 1, 84376 "userType": "api::v1::administrator" 84377 } 84378 } 84379 ``` 84380 By overwriting `payloadTypeFromModelName` you can specify that the 84381 namespaces model name for the `administrator` should be used: 84382 ```app/serializers/application.js 84383 import DS from "ember-data"; 84384 export default DS.RESTSerializer.extend({ 84385 payloadTypeFromModelName(modelName) { 84386 return "api::v1::" + modelName; 84387 } 84388 }); 84389 ``` 84390 By default the payload type is the camelized model name. Usually, Ember 84391 Data can use the correct inflection to do this for you. Most of the time, 84392 you won't need to override `payloadTypeFromModelName` for this purpose. 84393 Also take a look at 84394 [modelNameFromPayloadType](#method_modelNameFromPayloadType) to customize 84395 how the model name from should be mapped from the payload. 84396 @method payloadTypeFromModelName 84397 @public 84398 @param {String} modelname modelName from the record 84399 @return {String} payloadType 84400 */ 84401 payloadTypeFromModelName: function payloadTypeFromModelName(modelName) { 84402 return camelize(modelName); 84403 }, 84404 84405 _hasCustomModelNameFromPayloadKey: function _hasCustomModelNameFromPayloadKey() { 84406 return this.modelNameFromPayloadKey !== RESTSerializer.prototype.modelNameFromPayloadKey; 84407 }, 84408 84409 _hasCustomModelNameFromPayloadType: function _hasCustomModelNameFromPayloadType() { 84410 return this.modelNameFromPayloadType !== RESTSerializer.prototype.modelNameFromPayloadType; 84411 }, 84412 84413 _hasCustomPayloadTypeFromModelName: function _hasCustomPayloadTypeFromModelName() { 84414 return this.payloadTypeFromModelName !== RESTSerializer.prototype.payloadTypeFromModelName; 84415 }, 84416 84417 _hasCustomPayloadKeyFromModelName: function _hasCustomPayloadKeyFromModelName() { 84418 return this.payloadKeyFromModelName !== RESTSerializer.prototype.payloadKeyFromModelName; 84419 } 84420 84421 }); 84422 } 84423 84424 (0, _emberDataPrivateDebug.runInDebug)(function () { 84425 RESTSerializer.reopen({ 84426 warnMessageNoModelForKey: function warnMessageNoModelForKey(prop, typeKey) { 84427 return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; 84428 } 84429 }); 84430 }); 84431 84432 exports["default"] = RESTSerializer; 84433}); 84434define('ember-data/setup-container', ['exports', 'ember-data/-private/initializer
84434s/store', 'ember-data/-private/initializers/transforms', 'ember-data/-private/initializers/store-injections', 'ember-data/-private/initializers/data-adapter'], function (exports, _emberDataPrivateInitializersStore, _emberDataPrivateInitializersTransforms, _emberDataPrivateInitializersStoreInjections, _emberDataPrivateInitializersDataAdapter) { 84435 'use strict'; 84436 84437 exports['default'] = setupContainer; 84438 84439 function setupContainer(application) { 84440 (0, _emberDataPrivateInitializersDataAdapter['default'])(application); 84441 (0, _emberDataPrivateInitializersTransforms['default'])(application); 84442 (0, _emberDataPrivateInitializersStoreInjections['default'])(application); 84443 (0, _emberDataPrivateInitializersStore['default'])(application); 84444 } 84445}); 84446define("ember-data/store", ["exports", "ember-data/-private/system/store"], function (exports, _emberDataPrivateSystemStore) { 84447 "use strict"; 84448 84449 exports["default"] = _emberDataPrivateSystemStore["default"]; 84450}); 84451define('ember-data/transform', ['exports', 'ember'], function (exports, _ember) { 84452 'use strict'; 84453 84454 /** 84455 The `DS.Transform` class is used to serialize and deserialize model 84456 attributes when they are saved or loaded from an 84457 adapter. Subclassing `DS.Transform` is useful for creating custom 84458 attributes. All subclasses of `DS.Transform` must implement a 84459 `serialize` and a `deserialize` method. 84460 84461 Example 84462 84463 ```app/transforms/temperature.js 84464 import DS from 'ember-data'; 84465 84466 // Converts centigrade in the JSON to fahrenheit in the app 84467 export default DS.Transform.extend({ 84468 deserialize: function(serialized) { 84469 return (serialized * 1.8) + 32; 84470 }, 84471 serialize: function(deserialized) { 84472 return (deserialized - 32) / 1.8; 84473 } 84474 }); 84475 ``` 84476 84477 Usage 84478 84479 ```app/models/requirement.js 84480 import DS from 'ember-data'; 84481 84482 export default DS.Model.extend({ 84483 name: DS.attr('string'), 84484 temperature: DS.attr('temperature') 84485 }); 84486 ``` 84487 84488 @class Transform 84489 @namespace DS 84490 */ 84491 exports['default'] = _ember['default'].Object.extend({ 84492 /** 84493 When given a deserialized value from a record attribute this 84494 method must return the serialized value. 84495 Example 84496 ```javascript 84497 serialize: function(deserialized, options) { 84498 return Ember.isEmpty(deserialized) ? null : Number(deserialized); 84499 } 84500 ``` 84501 @method serialize 84502 @param deserialized The deserialized value 84503 @param options hash of options passed to `DS.attr` 84504 @return The serialized value 84505 */ 84506 serialize: null, 84507 84508 /** 84509 When given a serialize value from a JSON object this method must 84510 return the deserialized value for the record attribute. 84511 Example 84512 ```javascript 84513 deserialize: function(serialized, options) { 84514 return empty(serialized) ? null : Number(serialized); 84515 } 84516 ``` 84517 @method deserialize 84518 @param serialized The serialized value 84519 @param options hash of options passed to `DS.attr` 84520 @return The deserialized value 84521 */ 84522 deserialize: null 84523 }); 84524}); 84525define("ember-data/version", ["exports"], function (exports) { 84526 "use strict"; 84527 84528 exports["default"] = "2.7.0"; 84529}); 84530define("ember-inflector/index", ["exports", "ember", "ember-inflector/lib/system", "ember-inflector/lib/ext/string"], function (exports, _ember, _emberInflectorLibSystem, _emberInflectorLibExtString) { 84531 /* global define, module */ 84532 84533 "use strict"; 84534 84535 _emberInflectorLibSystem.Inflector.defaultRules = _emberInflectorLibSystem.defaultRules; 84536 _ember["default"].Inflector = _emberInflectorLibSystem.Inflector; 84537 84538 _ember["default"].String.pluralize = _emberInflectorLibSystem.pluralize; 84539 _ember["default"].String.singularize = _emberInflectorLibSystem.singularize;exports["default"] = _emberInflectorLibSystem.Inflector; 84540 exports.pluralize = _emberInflectorLibSystem.pluralize; 84541 exports.singularize = _emberInflectorLibSystem.singularize; 84542 exports.defaultRules = _emberInflectorLibSystem.defaultRules; 84543 84544 if (typeof define !== 'undefined' && define.amd) { 84545 define('ember-inflector', ['exports'], function (__exports__) { 84546 __exports__['default'] = _emberInflectorLibSystem.Inflector; 84547 return _emberInflectorLibSystem.Inflector; 84548 }); 84549 } else if (typeof module !== 'undefined' && module['exports']) { 84550 module['exports'] = _emberInflectorLibSystem.Inflector; 84551 } 84552}); 84553define('ember-inflector/lib/ext/string', ['exports', 'ember', 'ember-inflector/lib/system/string'], function (exports, _ember, _emberInflectorLibSystemString) { 84554 'use strict'; 84555 84556 if (_ember['default'].EXTEND_PROTOTYPES === true || _ember['default'].EXTEND_PROTOTYPES.String) { 84557 /** 84558 See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}} 84559 @method pluralize 84560 @for String 84561 */ 84562 String.prototype.pluralize = function () { 84563 return (0, _emberInflectorLibSystemString.pluralize)(this); 84564 }; 84565 84566 /** 84567 See {{#crossLink "Ember.String/singularize"}}{{/crossLink}} 84568 @method singularize 84569 @for String 84570 */ 84571 String.prototype.singularize = function () { 84572 return (0, _emberInflectorLibSystemString.singularize)(this); 84573 }; 84574 } 84575}); 84576define('ember-inflector/lib/helpers/pluralize', ['exports', 'ember-inflector', 'ember-inflector/lib/utils/make-helper'], function (exports, _emberInflector, _emberInflectorLibUtilsMakeHelper) { 84577 'use strict'; 84578 84579 /** 84580 * 84581 * If you have Ember Inflector (such as if Ember Data is present), 84582 * pluralize a word. For example, turn "ox" into "oxen". 84583 * 84584 * Example: 84585 * 84586 * {{pluralize count myProperty}} 84587 * {{pluralize 1 "oxen"}} 84588 * {{pluralize myProperty}} 84589 * {{pluralize "ox"}} 84590 * 84591 * @for Ember.HTMLBars.helpers 84592 * @method pluralize 84593 * @param {Number|Property} [count] count of objects 84594 * @param {String|Property} word word to pluralize 84595 */ 84596 exports['default'] = (0, _emberInflectorLibUtilsMakeHelper['default'])(function (params) { 84597 var count = undefined, 84598 word = undefined; 84599 84600 if (params.length === 1) { 84601 word = params[0]; 84602 return (0, _emberInflector.pluralize)(word); 84603 } else { 84604 count = params[0]; 84605 word = params[1]; 84606 84607 if (parseFloat(count) !== 1) { 84608 word = (0, _emberInflector.pluralize)(word); 84609 } 84610 84611 return count + " " + word; 84612 } 84613 }); 84614}); 84615define('ember-inflector/lib/helpers/singularize', ['exports', 'ember-inflector', 'ember-inflector/lib/utils/make-helper'], function (exports, _emberInflector, _emberInflectorLibUtilsMakeHelper) { 84616 'use strict'; 84617 84618 /** 84619 * 84620 * If you have Ember Inflector (such as if Ember Data is present), 84621 * singularize a word. For example, turn "oxen" into "ox". 84622 * 84623 * Example: 84624 * 84625 * {{singularize myProperty}} 84626 * {{singularize "oxen"}} 84627 * 84628 * @for Ember.HTMLBars.helpers 84629 * @method singularize 84630 * @param {String|Property} word word to singularize 84631 */ 84632 exports['default'] = (0, _emberInflectorLibUtilsMakeHelper['default'])(function (params) { 84633 return (0, _emberInflector.singularize)(params[0]); 84634 }); 84635}); 84636define("ember-inflector/lib/system", ["exports", "ember-inflector/lib/system/inflector", "ember-inflector/lib/system/string", "ember-inflector/lib/system/inflections"], function (exports, _emberInflectorLibSystemInflector, _emberInflectorLibSystemString, _emberInflectorLibSystemInflections) { 84637 "use strict"; 84638 84639 _emberInflectorLibSystemInflector["default"].inflector = new _emberInflectorLibSystemInflector["default"](_emberInflectorLibSystemInflections["default"]); 84640 84641 exports.Inflector = _emberInflectorLibSystemInflector["default"]; 84642 exports.singularize = _emberInflectorLibSystemString.singularize; 84643 exports.pluralize = _emberInflectorLibSystemString.pluralize; 84644 exports.defaultRules = _emberInflectorLibSystemInflections["default"]; 84645}); 84646define('ember-inflector/lib/system/inflections', ['exports'], function (exports) { 84647 'use strict'; 84648 84649 exports['default'] = { 84650 plurals: [[/$/, 's'], [/s$/i, 's'], [/^(ax|test)is$/i, '$1es'], [/(octop|vir)us$/i, '$1i'], [/(octop|vir)i$/i, '$1i'], [/(alias|status|bonus)$/i, '$1es'], [/(bu)s$/i, '$1ses'], [/(buffal|tomat)o$/i, '$1oes'], [/([ti])um$/i, '$1a'], [/([ti])a$/i, '$1a'], [/sis$/i, 'ses'], [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'], [/(hive)$/i, '$1s'], [/([^aeiouy]|qu)y$/i, '$1ies'], [/(x|ch|ss|sh)$/i, '$1es'], [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'], [/^(m|l)ouse$/i, '$1ice'], [/^(m|l)ice$/i, '$1ice'], [/^(ox)$/i, '$1en'], [/^(oxen)$/i, '$1'], [/(quiz)$/i, '$1zes']], 84651 84652 singular: [[/s$/i, ''], [/(ss)$/i, '$1'], [/(n)ews$/i, '$1ews'], [/([ti])a$/i, '$1um'], [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'], [/(^anal
84652y)(sis|ses)$/i, '$1sis'], [/([^f])ves$/i, '$1fe'], [/(hive)s$/i, '$1'], [/(tive)s$/i, '$1'], [/([lr])ves$/i, '$1f'], [/([^aeiouy]|qu)ies$/i, '$1y'], [/(s)eries$/i, '$1eries'], [/(m)ovies$/i, '$1ovie'], [/(x|ch|ss|sh)es$/i, '$1'], [/^(m|l)ice$/i, '$1ouse'], [/(bus)(es)?$/i, '$1'], [/(o)es$/i, '$1'], [/(shoe)s$/i, '$1'], [/(cris|test)(is|es)$/i, '$1is'], [/^(a)x[ie]s$/i, '$1xis'], [/(octop|vir)(us|i)$/i, '$1us'], [/(alias|status|bonus)(es)?$/i, '$1'], [/^(ox)en/i, '$1'], [/(vert|ind)ices$/i, '$1ex'], [/(matr)ices$/i, '$1ix'], [/(quiz)zes$/i, '$1'], [/(database)s$/i, '$1']], 84653 84654 irregularPairs: [['person', 'people'], ['man', 'men'], ['child', 'children'], ['sex', 'sexes'], ['move', 'moves'], ['cow', 'kine'], ['zombie', 'zombies']], 84655 84656 uncountable: ['equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep', 'jeans', 'police'] 84657 }; 84658}); 84659define('ember-inflector/lib/system/inflector', ['exports', 'ember'], function (exports, _ember) { 84660 'use strict'; 84661 84662 var capitalize = _ember['default'].String.capitalize; 84663 84664 var BLANK_REGEX = /^\s*$/; 84665 var LAST_WORD_DASHED_REGEX = /([\w/-]+[_/\s-])([a-z\d]+$)/; 84666 var LAST_WORD_CAMELIZED_REGEX = /([\w/\s-]+)([A-Z][a-z\d]*$)/; 84667 var CAMELIZED_REGEX = /[A-Z][a-z\d]*$/; 84668 84669 function loadUncountable(rules, uncountable) { 84670 for (var i = 0, length = uncountable.length; i < length; i++) { 84671 rules.uncountable[uncountable[i].toLowerCase()] = true; 84672 } 84673 } 84674 84675 function loadIrregular(rules, irregularPairs) { 84676 var pair; 84677 84678 for (var i = 0, length = irregularPairs.length; i < length; i++) { 84679 pair = irregularPairs[i]; 84680 84681 //pluralizing 84682 rules.irregular[pair[0].toLowerCase()] = pair[1]; 84683 rules.irregular[pair[1].toLowerCase()] = pair[1]; 84684 84685 //singularizing 84686 rules.irregularInverse[pair[1].toLowerCase()] = pair[0]; 84687 rules.irregularInverse[pair[0].toLowerCase()] = pair[0]; 84688 } 84689 } 84690 84691 /** 84692 Inflector.Ember provides a mechanism for supplying inflection rules for your 84693 application. Ember includes a default set of inflection rules, and provides an 84694 API for providing additional rules. 84695 84696 Examples: 84697 84698 Creating an inflector with no rules. 84699 84700 ```js 84701 var inflector = new Ember.Inflector(); 84702 ``` 84703 84704 Creating an inflector with the default ember ruleset. 84705 84706 ```js 84707 var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); 84708 84709 inflector.pluralize('cow'); //=> 'kine' 84710 inflector.singularize('kine'); //=> 'cow' 84711 ``` 84712 84713 Creating an inflector and adding rules later. 84714 84715 ```javascript 84716 var inflector = Ember.Inflector.inflector; 84717 84718 inflector.pluralize('advice'); // => 'advices' 84719 inflector.uncountable('advice'); 84720 inflector.pluralize('advice'); // => 'advice' 84721 84722 inflector.pluralize('formula'); // => 'formulas' 84723 inflector.irregular('formula', 'formulae'); 84724 inflector.pluralize('formula'); // => 'formulae' 84725 84726 // you would not need to add these as they are the default rules 84727 inflector.plural(/$/, 's'); 84728 inflector.singular(/s$/i, ''); 84729 ``` 84730 84731 Creating an inflector with a nondefault ruleset. 84732 84733 ```javascript 84734 var rules = { 84735 plurals: [ /$/, 's' ], 84736 singular: [ /\s$/, '' ], 84737 irregularPairs: [ 84738 [ 'cow', 'kine' ] 84739 ], 84740 uncountable: [ 'fish' ] 84741 }; 84742 84743 var inflector = new Ember.Inflector(rules); 84744 ``` 84745 84746 @class Inflector 84747 @namespace Ember 84748 */ 84749 function Inflector(ruleSet) { 84750 ruleSet = ruleSet || {}; 84751 ruleSet.uncountable = ruleSet.uncountable || makeDictionary(); 84752 ruleSet.irregularPairs = ruleSet.irregularPairs || makeDictionary(); 84753 84754 var rules = this.rules = { 84755 plurals: ruleSet.plurals || [], 84756 singular: ruleSet.singular || [], 84757 irregular: makeDictionary(), 84758 irregularInverse: makeDictionary(), 84759 uncountable: makeDictionary() 84760 }; 84761 84762 loadUncountable(rules, ruleSet.uncountable); 84763 loadIrregular(rules, ruleSet.irregularPairs); 84764 84765 this.enableCache(); 84766 } 84767 84768 if (!Object.create && !Object.create(null).hasOwnProperty) { 84769 throw new Error("This browser does not support Object.create(null), please polyfil with es5-sham: http://git.io/yBU2rg"); 84770 } 84771 84772 function makeDictionary() { 84773 var cache = Object.create(null); 84774 cache['_dict'] = null; 84775 delete cache['_dict']; 84776 return cache; 84777 } 84778 84779 Inflector.prototype = { 84780 /** 84781 @public 84782 As inflections can be costly, and commonly the same subset of words are repeatedly 84783 inflected an optional cache is provided. 84784 @method enableCache 84785 */ 84786 enableCache: function enableCache() { 84787 this.purgeCache(); 84788 84789 this.singularize = function (word) { 84790 this._cacheUsed = true; 84791 return this._sCache[word] || (this._sCache[word] = this._singularize(word)); 84792 }; 84793 84794 this.pluralize = function (word) { 84795 this._cacheUsed = true; 84796 return this._pCache[word] || (this._pCache[word] = this._pluralize(word)); 84797 }; 84798 }, 84799 84800 /** 84801 @public 84802 @method purgedCache 84803 */ 84804 purgeCache: function purgeCache() { 84805 this._cacheUsed = false;
84806 this._sCache = makeDictionary(); 84807 this._pCache = makeDictionary(); 84808 }, 84809 84810 /** 84811 @public 84812 disable caching 84813 @method disableCache; 84814 */ 84815 disableCache: function disableCache() { 84816 this._sCache = null; 84817 this._pCache = null; 84818 this.singularize = function (word) { 84819 return this._singularize(word); 84820 }; 84821 84822 this.pluralize = function (word) { 84823 return this._pluralize(word); 84824 }; 84825 }, 84826 84827 /** 84828 @method plural 84829 @param {RegExp} regex 84830 @param {String} string 84831 */ 84832 plural: function plural(regex, string) { 84833 if (this._cacheUsed) { 84834 this.purgeCache(); 84835 } 84836 this.rules.plurals.push([regex, string.toLowerCase()]); 84837 }, 84838 84839 /** 84840 @method singular 84841 @param {RegExp} regex 84842 @param {String} string 84843 */ 84844 singular: function singular(regex, string) { 84845 if (this._cacheUsed) { 84846 this.purgeCache(); 84847 } 84848 this.rules.singular.push([regex, string.toLowerCase()]); 84849 }, 84850 84851 /** 84852 @method uncountable 84853 @param {String} regex 84854 */ 84855 uncountable: function uncountable(string) { 84856 if (this._cacheUsed) { 84857 this.purgeCache(); 84858 } 84859 loadUncountable(this.rules, [string.toLowerCase()]); 84860 }, 84861 84862 /** 84863 @method irregular 84864 @param {String} singular 84865 @param {String} plural 84866 */ 84867 irregular: function irregular(singular, plural) { 84868 if (this._cacheUsed) { 84869 this.purgeCache(); 84870 } 84871 loadIrregular(this.rules, [[singular, plural]]); 84872 }, 84873 84874 /** 84875 @method pluralize 84876 @param {String} word 84877 */ 84878 pluralize: function pluralize(word) { 84879 return this._pluralize(word); 84880 }, 84881 84882 _pluralize: function _pluralize(word) { 84883 return this.inflect(word, this.rules.plurals, this.rules.irregular); 84884 }, 84885 /** 84886 @method singularize 84887 @param {String} word 84888 */ 84889 singularize: function singularize(word) { 84890 return this._singularize(word); 84891 }, 84892 84893 _singularize: function _singularize(word) { 84894 return this.inflect(word, this.rules.singular, this.rules.irregularInverse); 84895 }, 84896 84897 /** 84898 @protected 84899 @method inflect 84900 @param {String} word 84901 @param {Object} typeRules 84902 @param {Object} irregular 84903 */ 84904 inflect: function inflect(word, typeRules, irregular) { 84905 var inflection, substitution, result, lowercase, wordSplit, firstPhrase, lastWord, isBlank, isCamelized, rule, isUncountable; 84906 84907 isBlank = !word || BLANK_REGEX.test(word); 84908 84909 isCamelized = CAMELIZED_REGEX.test(word); 84910 firstPhrase = ""; 84911 84912 if (isBlank) { 84913 return word; 84914 } 84915 84916 lowercase = word.toLowerCase(); 84917 wordSplit = LAST_WORD_DASHED_REGEX.exec(word) || LAST_WORD_CAMELIZED_REGEX.exec(word); 84918 84919 if (wordSplit) { 84920 firstPhrase = wordSplit[1]; 84921 lastWord = wordSplit[2].toLowerCase(); 84922 } 84923 84924 isUncountable = this.rules.uncountable[lowercase] || this.rules.uncountable[lastWord]; 84925 84926 if (isUncountable) { 84927 return word; 84928 } 84929 84930 for (rule in irregular) { 84931 if (lowercase.match(rule + "$")) { 84932 substitution = irregular[rule]; 84933 84934 if (isCamelized && irregular[lastWord]) { 84935 substitution = capitalize(substitution); 84936 rule = capitalize(rule); 84937 } 84938 84939 return word.replace(new RegExp(rule, 'i'), substitution); 84940 } 84941 } 84942 84943 for (var i = typeRules.length, min = 0; i > min; i--) { 84944 inflection = typeRules[i - 1]; 84945 rule = inflection[0]; 84946 84947 if (rule.test(word)) { 84948 break; 84949 } 84950 } 84951 84952 inflection = inflection || []; 84953 84954 rule = inflection[0]; 84955 substitution = inflection[1]; 84956 84957 result = word.replace(rule, substitution); 84958 84959 return result; 84960 } 84961 }; 84962 84963 exports['default'] = Inflector; 84964}); 84965define('ember-inflector/lib/system/string', ['exports', 'ember-inflector/lib/system/inflector'], function (exports, _emberInflectorLibSystemInflector) { 84966 'use strict'; 84967 84968 function pluralize(word) { 84969 return _emberInflectorLibSystemInflector['default'].inflector.pluralize(word); 84970 } 84971 84972 function singularize(word) { 84973 return _emberInflectorLibSystemInflector['default'].inflector.singularize(word); 84974 } 84975 84976 exports.pluralize = pluralize; 84977 exports.singularize = singularize; 84978}); 84979define('ember-inflector/lib/utils/make-helper', ['exports', 'ember'], function (exports, _ember) { 84980 'use strict'; 84981 84982 exports['default'] = makeHelper; 84983 84984 function makeHelper(helperFunction) { 84985 if (_ember['default'].Helper) { 84986 return _ember['default'].Helper.helper(helperFunction); 84987 } 84988 if (_ember['default'].HTMLBars) { 84989 return _ember['default'].HTMLBars.makeBoundHelper(helperFunction); 84990 } 84991 return _ember['default'].Handlebars.makeBoundHelper(helperFunction); 84992 } 84993});
84994define('ember-load-initializers/index', ['exports', 'ember'], function (exports, _ember) { 84995 'use strict'; 84996 84997 exports['default'] = function (app, prefix) { 84998 var regex = new RegExp('^' + prefix + '\/((?:instance-)?initializers)\/'); 84999 var getKeys = Object.keys || _ember['default'].keys; 85000 85001 getKeys(requirejs._eak_seen).map(function (moduleName) { 85002 return { 85003 moduleName: moduleName, 85004 matches: regex.exec(moduleName) 85005 }; 85006 }).filter(function (dep) { 85007 return dep.matches && dep.matches.length === 2; 85008 }).forEach(function (dep) { 85009 var moduleName = dep.moduleName; 85010 85011 var module = require(moduleName, null, null, true); 85012 if (!module) { 85013 throw new Error(moduleName + ' must export an initializer.'); 85014 } 85015 85016 var initializerType = _ember['default'].String.camelize(dep.matches[1].substring(0, dep.matches[1].length - 1)); 85017 var initializer = module['default']; 85018 if (!initializer.name) { 85019 var initializerName = moduleName.match(/[^\/]+\/?$/)[0]; 85020 initializer.name = initializerName; 85021 } 85022 85023 if (app[initializerType]) { 85024 app[initializerType](initializer); 85025 } 85026 }); 85027 }; 85028}); 85029define('ember-resolver/container-debug-adapter', ['exports', 'ember', 'ember-resolver/utils/module-registry'], function (exports, _ember, _emberResolverUtilsModuleRegistry) { 85030 'use strict'; 85031 85032 var ContainerDebugAdapter = _ember['default'].ContainerDebugAdapter; 85033 85034 var ModulesContainerDebugAdapter = null; 85035 85036 function getPod(type, key, prefix) { 85037 var match = key.match(new RegExp('^/?' + prefix + '/(.+)/' + type + '$')); 85038 if (match) { 85039 return match[1]; 85040 } 85041 } 85042 85043 // Support Ember < 1.5-beta.4 85044 // TODO: Remove this after 1.5.0 is released 85045 if (typeof ContainerDebugAdapter !== 'undefined') { 85046 85047 /* 85048 * This module defines a subclass of Ember.ContainerDebugAdapter that adds two 85049 * important features: 85050 * 85051 * 1) is able provide injections to classes that implement `extend` 85052 * (as is typical with Ember). 85053 */ 85054 85055 ModulesContainerDebugAdapter = ContainerDebugAdapter.extend({ 85056 _moduleRegistry: null, 85057 85058 init: function init() { 85059 this._super.apply(this, arguments); 85060 85061 if (!this._moduleRegistry) { 85062 this._moduleRegistry = new _emberResolverUtilsModuleRegistry['default'](); 85063 } 85064 }, 85065 85066 /** 85067 The container of the application being debugged. 85068 This property will be injected 85069 on creation. 85070 @property container 85071 @default null 85072 */ 85073 85074 /** 85075 The resolver instance of the application 85076 being debugged. This property will be injected 85077 on creation. 85078 @property resolver 85079 @default null 85080 */ 85081 85082 /** 85083 Returns true if it is possible to catalog a list of available 85084 classes in the resolver for a given type. 85085 @method canCatalogEntriesByType 85086 @param {string} type The type. e.g. "model", "controller", "route" 85087 @return {boolean} whether a list is available for this type. 85088 */ 85089 canCatalogEntriesByType: function canCatalogEntriesByType() /* type */{ 85090 return true; 85091 }, 85092 85093 /** 85094 Returns the available classes a given type. 85095 @method catalogEntriesByType 85096 @param {string} type The type. e.g. "model", "controller", "route" 85097 @return {Array} An array of classes. 85098 */ 85099 catalogEntriesByType: function catalogEntriesByType(type) { 85100 var moduleNames = this._moduleRegistry.moduleNames(); 85101 var types = _ember['default'].A(); 85102 85103 var prefix = this.namespace.modulePrefix; 85104 85105 for (var i = 0, l = moduleNames.length; i < l; i++) { 85106 var key = moduleNames[i]; 85107 85108 if (key.indexOf(type) !== -1) { 85109 // Check if it's a pod module 85110 var name = getPod(type, key, this.namespace.podModulePrefix || prefix); 85111 if (!name) { 85112 // Not pod 85113 name = key.split(type + 's/').pop(); 85114 85115 // Support for different prefix (such as ember-cli addons). 85116 // Uncomment the code below when 85117 // https://github.com/ember-cli/ember-resolver/pull/80 is merged. 85118 85119 //var match = key.match('^/?(.+)/' + type); 85120 //if (match && match[1] !== prefix) { 85121 // Different prefix such as an addon 85122 //name = match[1] + '@' + name; 85123 //} 85124 } 85125 types.addObject(name); 85126 } 85127 } 85128 return types; 85129 } 85130 }); 85131 } 85132 85133 exports['default'] = ModulesContainerDebugAdapter; 85134}); 85135define('ember-resolver/index', ['exports', 'ember-resolver/resolver'], function (exports, _emberResolverResolver) { 85136 'use strict'; 85137 85138 Object.defineProperty(exports, 'default', { 85139 enumerable: true, 85140 get: function get() { 85141 return _emberResolverResolver['default']; 85142 } 85143 }); 85144}); 85145define('ember-resolver/resolver', ['exports', 'ember', 'ember-resolver/utils/module-registry', 'ember-resolver/utils/class-factory', 'ember-resolver/utils/make-dictionary'], function (exports, _ember, _emberResolverUtilsModuleRegistry, _emberResolverUtilsClassFactory, _emberResolverUtilsMakeDictionary) { 85146 /*globals require */ 85147 85148 'use strict'; 85149 85150 /* 85151 * This module defines a subclass of Ember.DefaultResolver that adds two 85152 * important features: 85153 * 85154 * 1) The resolver makes the container aware of es6 modules via the AMD 85155 * output. The loader's _moduleEntries is consulted so that classes can be 85156 * resolved directly via the module loader, without needing a manual 85157 * `import`. 85158 * 2) is able to provide injections to classes that implement `extend` 85159 * (as is typical with Ember). 85160 */ 85161 85162 var _Ember$String = _ember['default'].String; 85163 var underscore = _Ember$String.underscore; 85164 var classify = _Ember$String.classify; 85165 var get = _ember['default'].get; 85166 var DefaultResolver = _ember['default'].DefaultResolver; 85167 85168 function parseName(fullName) { 85169 /*jshint validthis:true */ 85170 85171 if (fullName.parsedName === true) { 85172 return fullName; 85173 } 85174 85175 var prefix, type, name; 85176 var fullNameParts = fullName.split('@'); 85177 85178 // HTMLBars uses helper:@content-helper which collides 85179 // with ember-cli namespace detection. 85180 // This will be removed in a future release of HTMLBars. 85181 if (fullName !== 'helper:@content-helper' && fullNameParts.length === 2) { 85182 var prefixParts = fullNameParts[0].split(':'); 85183 85184 if (prefixParts.length === 2) { 85185 prefix = prefixParts[1]; 85186 type = prefixParts[0]; 85187 name = fullNameParts[1]; 85188 } else { 85189 var nameParts = fullNameParts[1].split(':'); 85190 85191 prefix = fullNameParts[0]; 85192 type = nameParts[0]; 85193 name = nameParts[1]; 85194 } 85195 } else { 85196 fullNameParts = fullName.split(':'); 85197 type = fullNameParts[0]; 85198 name = fullNameParts[1]; 85199 } 85200 85201 var fullNameWithoutType = name; 85202 var namespace = get(this, 'namespace'); 85203 var root = namespace; 85204 85205 return { 85206 parsedName: true, 85207 fullName: fullName, 85208 prefix: prefix || this.prefix({ type: type }), 85209 type: type, 85210 fullNameWithoutType: fullNameWithoutType, 85211 name: name, 85212 root: root, 85213 resolveMethodName: "resolve" + classify(type) 85214 }; 85215 } 85216 85217 function resolveOther(parsedName) { 85218 /*jshint validthis:true */ 85219 85220 _ember['default'].assert('`modulePrefix` must be defined', this.namespace.modulePrefix); 85221 85222 var normalizedModuleName = this.findModuleName(parsedName); 85223 85224 if (normalizedModuleName) { 85225 var defaultExport = this._extractDefaultExport(normalizedModuleName, parsedName); 85226 85227 if (defaultExport === undefined) { 85228 throw new Error(" Expected to find: '" + parsedName.fullName + "' within '" + normalizedModuleName + "' but got 'undefined'. Did you forget to `export default` within '" + normalizedModuleName + "'?"); 85229 } 85230 85231 if (this.shouldWrapInClassFactory(defaultExport, parsedName)) { 85232 defaultExport = (0, _emberResolverUtilsClassFactory['default'])(defaultExport); 85233 } 85234 85235 return defaultExport; 85236 } else { 85237 return this._super(parsedName); 85238 } 85239 } 85240 85241 // Ember.DefaultResolver docs: 85242 // https://github.com/emberjs/ember.js/blob/master/packages/ember-application/lib/system/resolver.js 85243 var Resolver = DefaultResolver.extend({ 85244 resolveOther: resolveOther, 85245 parseName: parseName, 85246 resolveTemplate: resolveOther, 85247 pluralizedTypes: null, 85248 moduleRegistry: null, 85249 85250 makeToString: function makeToString(factory, fullName) { 85251 return '' + this.namespace.modulePrefix + '@' + fullName + ':'; 85252 }, 85253 85254 shouldWrapInClassFactory: function shouldWrapInClassFactory() /* module, parsedName */{ 85255 return false;
85256 }, 85257 85258 init: function init() { 85259 this._super(); 85260 this.moduleBasedResolver = true; 85261 85262 if (!this._moduleRegistry) { 85263 this._moduleRegistry = new _emberResolverUtilsModuleRegistry['default'](); 85264 } 85265 85266 this._normalizeCache = (0, _emberResolverUtilsMakeDictionary['default'])(); 85267 85268 this.pluralizedTypes = this.pluralizedTypes || (0, _emberResolverUtilsMakeDictionary['default'])(); 85269 85270 if (!this.pluralizedTypes.config) { 85271 this.pluralizedTypes.config = 'config'; 85272 } 85273 85274 this._deprecatedPodModulePrefix = false; 85275 }, 85276 85277 normalize: function normalize(fullName) { 85278 return this._normalizeCache[fullName] || (this._normalizeCache[fullName] = this._normalize(fullName)); 85279 }, 85280 85281 _normalize: function _normalize(fullName) { 85282 // replace `.` with `/` in order to make nested controllers work in the following cases 85283 // 1. `needs: ['posts/post']` 85284 // 2. `{{render "posts/post"}}` 85285 // 3. `this.render('posts/post')` from Route 85286 var split = fullName.split(':'); 85287 if (split.length > 1) { 85288 return split[0] + ':' + _ember['default'].String.dasherize(split[1].replace(/\./g, '/')); 85289 } else { 85290 return fullName; 85291 } 85292 }, 85293 85294 pluralize: function pluralize(type) { 85295 return this.pluralizedTypes[type] || (this.pluralizedTypes[type] = type + 's'); 85296 }, 85297 85298 podBasedLookupWithPrefix: function podBasedLookupWithPrefix(podPrefix, parsedName) { 85299 var fullNameWithoutType = parsedName.fullNameWithoutType; 85300 85301 if (parsedName.type === 'template') { 85302 fullNameWithoutType = fullNameWithoutType.replace(/^components\//, ''); 85303 } 85304 85305 return podPrefix + '/' + fullNameWithoutType + '/' + parsedName.type; 85306 }, 85307 85308 podBasedModuleName: function podBasedModuleName(parsedName) { 85309 var podPrefix = this.namespace.podModulePrefix || this.namespace.modulePrefix; 85310 85311 return this.podBasedLookupWithPrefix(podPrefix, parsedName); 85312 }, 85313 85314 podBasedComponentsInSubdir: function podBasedComponentsInSubdir(parsedName) { 85315 var podPrefix = this.namespace.podModulePrefix || this.namespace.modulePrefix; 85316 podPrefix = podPrefix + '/components'; 85317 85318 if (parsedName.type === 'component' || parsedName.fullNameWithoutType.match(/^components/)) { 85319 return this.podBasedLookupWithPrefix(podPrefix, parsedName); 85320 } 85321 }, 85322 85323 mainModuleName: function mainModuleName(parsedName) { 85324 // if router:main or adapter:main look for a module with just the type first 85325 var tmpModuleName = parsedName.prefix + '/' + parsedName.type; 85326 85327 if (parsedName.fullNameWithoutType === 'main') { 85328 return tmpModuleName; 85329 } 85330 }, 85331 85332 defaultModuleName: function defaultModuleName(parsedName) { 85333 return parsedName.prefix + '/' + this.pluralize(parsedName.type) + '/' + parsedName.fullNameWithoutType; 85334 }, 85335 85336 prefix: function prefix(parsedName) { 85337 var tmpPrefix = this.namespace.modulePrefix; 85338 85339 if (this.namespace[parsedName.type + 'Prefix']) { 85340 tmpPrefix = this.namespace[parsedName.type + 'Prefix']; 85341 } 85342 85343 return tmpPrefix; 85344 }, 85345 85346 /** 85347 A listing of functions to test for moduleName's based on the provided 85348 `parsedName`. This allows easy customization of additional module based 85349 lookup patterns. 85350 @property moduleNameLookupPatterns 85351 @returns {Ember.Array} 85352 */ 85353 moduleNameLookupPatterns: _ember['default'].computed(function () { 85354 return [this.podBasedModuleName, this.podBasedComponentsInSubdir, this.mainModuleName, this.defaultModuleName]; 85355 }), 85356 85357 findModuleName: function findModuleName(parsedName, loggingDisabled) { 85358 var moduleNameLookupPatterns = this.get('moduleNameLookupPatterns'); 85359 var moduleName; 85360 85361 for (var index = 0, _length = moduleNameLookupPatterns.length; index < _length; index++) { 85362 var item = moduleNameLookupPatterns[index]; 85363 85364 var tmpModuleName = item.call(this, parsedName); 85365 85366 // allow treat all dashed and all underscored as the same thing 85367 // supports components with dashes and other stuff with underscores. 85368 if (tmpModuleName) { 85369 tmpModuleName = this.chooseModuleName(tmpModuleName); 85370 } 85371 85372 if (tmpModuleName && this._moduleRegistry.has(tmpModuleName)) { 85373 moduleName = tmpModuleName; 85374 } 85375 85376 if (!loggingDisabled) { 85377 this._logLookup(moduleName, parsedName, tmpModuleName); 85378 } 85379 85380 if (moduleName) { 85381 return moduleName; 85382 } 85383 } 85384 }, 85385 85386 chooseModuleName: function chooseModuleName(moduleName) { 85387 var underscoredModuleName = underscore(moduleName); 85388 85389 if (moduleName !== underscoredModuleName && this._moduleRegistry.has(moduleName) && this._moduleRegistry.has(underscoredModuleName)) { 85390 throw new TypeError("Ambiguous module names: `" + moduleName + "` and `" + underscoredModuleName + "`"); 85391 } 85392 85393 if (this._moduleRegistry.has(moduleName)) { 85394 return moduleName; 85395 } else if (this._moduleRegistry.has(underscoredModuleName)) { 85396 return underscoredModuleName; 85397 } else { 85398 // workaround for dasherized partials: 85399 // something/something/-something => something/something/_something 85400 var partializedModuleName = moduleName.replace(/\/-([^\/]*)$/, '/_$1'); 85401 85402 if (this._moduleRegistry.has(partializedModuleName)) { 85403 _ember['default'].deprecate('Modules should not contain underscores. ' + 'Attempted to lookup "' + moduleName + '" which ' + 'was not found. Please rename "' + partializedModuleName + '" ' + 'to "' + moduleName + '" instead.', false); 85404 85405 return partializedModuleName; 85406 } else { 85407 return moduleName; 85408 } 85409 } 85410 }, 85411 85412 // used by Ember.DefaultResolver.prototype._logLookup 85413 lookupDescription: function lookupDescription(fullName) { 85414 var parsedName = this.parseName(fullName); 85415 85416 var moduleName = this.findModuleName(parsedName, true); 85417 85418 return moduleName; 85419 }, 85420 85421 // only needed until 1.6.0-beta.2 can be required 85422 _logLookup: function _logLookup(found, parsedName, description) { 85423 if (!_ember['default'].ENV.LOG_MODULE_RESOLVER && !parsedName.root.LOG_RESOLVER) { 85424 return; 85425 } 85426 85427 var symbol, padding; 85428 85429 if (found) { 85430 symbol = '[â]'; 85431 } else { 85432 symbol = '[ ]'; 85433 } 85434 85435 if (parsedName.fullName.length > 60) { 85436 padding = '.'; 85437 } else { 85438 padding = new Array(60 - parsedName.fullName.length).join('.'); 85439 } 85440 85441 if (!description) { 85442 description = this.lookupDescription(parsedName); 85443 } 85444 85445 _ember['default'].Logger.info(symbol, parsedName.fullName, padding, description); 85446 }, 85447 85448 knownForType: function knownForType(type) { 85449 var moduleKeys = this._moduleRegistry.moduleNames(); 85450 85451 var items = (0, _emberResolverUtilsMakeDictionary['default'])(); 85452 for (var index = 0, length = moduleKeys.length; index < length; index++) { 85453 var moduleName = moduleKeys[index]; 85454 var fullname = this.translateToContainerFullname(type, moduleName); 85455 85456 if (fullname) { 85457 items[fullname] = true; 85458 } 85459 } 85460 85461 return items; 85462 }, 85463 85464 translateToContainerFullname: function translateToContainerFullname(type, moduleName) { 85465 var prefix = this.prefix({ type: type }); 85466 85467 // Note: using string manipulation here rather than regexes for better performance. 85468 // pod modules 85469 // '^' + prefix + '/(.+)/' + type + '$' 85470 var podPrefix = prefix + '/'; 85471 var podSuffix = '/' + type; 85472 var start = moduleName.indexOf(podPrefix); 85473 var end = moduleName.indexOf(podSuffix); 85474 85475 if (start === 0 && end === moduleName.length - podSuffix.length && moduleName.length > podPrefix.length + podSuffix.length) { 85476 return type + ':' + moduleName.slice(start + podPrefix.length, end); 85477 } 85478 85479 // non-pod modules 85480 // '^' + prefix + '/' + pluralizedType + '/(.+)$' 85481 var pluralizedType = this.pluralize(type); 85482 var nonPodPrefix = prefix + '/' + pluralizedType + '/'; 85483 85484 if (moduleName.indexOf(nonPodPrefix) === 0 && moduleName.length > nonPodPrefix.length) { 85485 return type + ':' + moduleName.slice(nonPodPrefix.length); 85486 } 85487 }, 85488 85489 _extractDefaultExport: function _extractDefaultExport(normalizedModuleName) { 85490 var module = require(normalizedModuleName, null, null, true /* force sync */); 85491 85492 if (module && module['default']) { 85493 module = module['default']; 85494 } 85495 85496 return module; 85497 } 85498 }); 85499 85500 Resolver.reopenClass({ 85501 moduleBasedResolver: true 85502 }); 85503 85504 exports['default'] = Resolver; 85505}); 85506define('ember-resolver/utils/class-factory', ['exports'], function (exports) { 85507 'use strict'; 85508 85509 exports['default'] = classFactory; 85510 85511 function classFactory(klass) { 85512 return { 85513 create: function create(injections) { 85514 if (typeof klass.extend === 'function') { 85515 return klass.extend(injections); 85516 } else { 85517 return klass; 85518 } 85519 } 85520 }; 85521 } 85522}); 85523define("ember-resolver/utils/create", ["exports", "ember"], function (exports, _ember) { 85524 "use strict"; 85525 85526 var create = Object.create || _ember["default"].create; 85527 if (!(create && !create(null).hasOwnProperty)) { 85528 throw new Error("This browser does not support Object.create(null), please polyfil with es5-sham: http://git.io/yBU2rg"); 85529 } 85530 85531 exports["default"] = create; 85532}); 85533define('ember-resolver/utils/make-dictionary', ['exports', 'ember-resolver/utils/create'], function (exports, _emberResolverUtilsCreate) { 85534 'use strict'; 85535 85536 exports['default'] = makeDictionary; 85537 85538 function makeDictionary() { 85539 var cache = (0, _emberResolverUtilsCreate['default'])(null); 85540 cache['_dict'] = null; 85541 delete cache['_dict']; 85542 return cache; 85543 } 85544}); 85545define('ember-resolver/utils/module-registry', ['exports', 'ember'], function (exports, _ember) { 85546 /*globals requirejs, require */ 85547 85548 'use strict'; 85549 85550 if (typeof requirejs.entries === 'undefined') { 85551 requirejs.entries = requirejs._eak_seen; 85552 } 85553 85554 function ModuleRegistry(entries) { 85555 this._entries = entries || requirejs.entries; 85556 } 85557 85558 ModuleRegistry.prototype.moduleNames = function ModuleRegistry_moduleNames() { 85559 return (Object.keys || _ember['default'].keys)(this._entries); 85560 }; 85561 85562 ModuleRegistry.prototype.has = function ModuleRegistry_has(moduleName) { 85563 return moduleName in this._entries; 85564 }; 85565 85566 ModuleRegistry.prototype.get = function ModuleRegistry_get(moduleName) { 85567 var exportName = arguments.length <= 1 || arguments[1] === undefined ? 'default' : arguments[1]; 85568 85569 var module = require(moduleName); 85570 return module && module[exportName]; 85571 }; 85572 85573 exports['default'] = ModuleRegistry; 85574}); 85575define('ember-youtube/components/ember-youtube', ['exports', 'ember'], function (exports, _ember) { 85576 /* global YT, window */ 85577 'use strict'; 85578 85579 var computed = _ember['default'].computed; 85580 var debug = _ember['default'].debug; 85581 var observer = _ember['default'].observer; 85582 var on = _ember['default'].on; 85583 var run = _ember['default'].run; 85584 var RSVP = _ember['default'].RSVP; 85585 var $ = _ember['default'].$; 85586 85587 exports['default'] = _ember['default'].Component.extend({ 85588 classNames: ['EmberYoutube'], 85589 ytid: null, 85590 player: null, 85591 playerState: 'loading', 85592 showDebug: false, 85593 showControls: false, 85594 showProgress: false, 85595 lazyload: false, 85596 showExtras: computed.or('showControls', 'showProgress', 'showDebug'), 85597 85598 // YouTube's embedded player can take a number of optional parameters. 85599 // https://developers.google.com/youtube/player_parameters#Parameters 85600 // https://developers.google.com/youtube/youtube_player_demo 85601 playerVars: {}, 85602 85603 startSeconds: undefined, 85604 endSeconds: undefined, 85605 suggestedQuality: undefined, 85606 height: 360, 85607 width: 270, 85608 85609 // from YT.PlayerState 85610 stateNames: { 85611 '-1': 'ready', // READY 85612 0: 'ended', // YT.Player.ENDED 85613 1: 'playing', // YT.PlayerState.PLAYING 85614 2: 'paused', // YT.PlayerState.PAUSED 85615 3: 'buffering', // YT.PlayerState.BUFFERING 85616 5: 'queued' // YT.PlayerState.CUED 85617 }, 85618 85619 // Expose the component to the outside world. 85620 _register: on('init', function () { 85621 var _this = this; 85622 85623 var delegate = this.get('delegate'); 85624 var delegateAs = this.get('delegate-as'); 85625 run.schedule('afterRender', function () { 85626 if (!delegate) { 85627 return; 85628 } 85629 delegate.set(delegateAs || 'emberYoutubePlayer', _this); 85630 }); 85631 }), 85632 85633 didInsertElement: function didInsertElement() { 85634 this._super.apply(this, arguments); 85635 if (this.get('lazyload') && !this.get('ytid')) { 85636 // If "lazyload" is enabled and we don't have an ID,
85637 // we can defer loading and creating the player. As soon as an `ytid` is available it'll run the `loadVideo` observer. 85638 return; 85639 } 85640 this.loadAndCreatePlayer(); 85641 }, 85642 85643 loadAndCreatePlayer: function loadAndCreatePlayer() { 85644 var _this2 = this; 85645 85646 var promise = new RSVP.Promise(function (resolve, reject) { 85647 _this2.loadYouTubeApi().then(function () { 85648 _this2.createPlayer().then(function (player) { 85649 if (!player) { 85650 reject(); 85651 } 85652 _this2.setProperties({ 85653 player: player, 85654 playerState: 'ready' 85655 }); 85656 _this2.loadVideo(); 85657 resolve(); 85658 }); 85659 }); 85660 }); 85661 // The `wait` helper waits for this run loop, 85662 // but not the above promise, which is what i want. 85663 if (_ember['default'].testing) { 85664 run.later(function () {}, 5000); 85665 } 85666 return promise; 85667 }, 85668 85669 // A promise that is resolved when window.onYouTubeIframeAPIReady is called. 85670 // The promise is resolved with a reference to window.YT object. 85671 loadYouTubeApi: function loadYouTubeApi() { 85672 return new RSVP.Promise(function (resolve) { 85673 var previous = undefined; 85674 previous = window.onYouTubeIframeAPIReady; 85675 85676 // The API will call this function when page has finished downloading 85677 // the JavaScript for the player API. 85678 window.onYouTubeIframeAPIReady = function () { 85679 if (previous) { 85680 previous(); 85681 } 85682 resolve(window.YT); 85683 }; 85684 85685 if (window.YT && window.YT.loaded) { 85686 // If already loaded, make sure not to load the script again. 85687 resolve(window.YT); 85688 } else { 85689 $.getScript('https://www.youtube.com/iframe_api'); 85690 } 85691 }); 85692 }, 85693 85694 // A promise that is immediately resolved with a YouTube player object. 85695 createPlayer: function createPlayer() { 85696 var _this3 = this; 85697 85698 var playerVars = this.get('playerVars'); 85699 var width = this.get('width'); 85700 var height = this.get('height'); 85701 // const iframe = this.element.querySelector('#EmberYoutube-player'); 85702 var iframe = this.$('#EmberYoutube-player'); 85703 var player = undefined; 85704 return new RSVP.Promise(function (resolve) { 85705 if (!iframe) { 85706 // reject(`Couldn't find the iframe element to create a YouTube player`); 85707 resolve(false); 85708 } 85709 player = new YT.Player(iframe.get(0), { 85710 width: width, 85711 height: height, 85712 playerVars: playerVars, 85713 events: { 85714 onReady: function onReady() { 85715 resolve(player); 85716 }, 85717 onStateChange: _this3.onPlayerStateChange.bind(_this3), 85718 onError: _this3.onPlayerError.bind(_this3) 85719 } 85720 }); 85721 }); 85722 }, 85723 85724 // Gets called by the YouTube player. 85725 onPlayerStateChange: function onPlayerStateChange(event) { 85726 // Set a readable state name 85727 var state = this.get('stateNames.' + event.data.toString()); 85728 this.set('playerState', state); 85729 if (this.get('showDebug')) { 85730 debug(state); 85731 } 85732 // send actions outside 85733 this.sendAction(state); 85734 // send actions inside 85735 this.send(state); 85736 }, 85737 85738 // Gets called by the YouTube player. 85739 onPlayerError: function onPlayerError(event) { 85740 var errorCode = event.data; 85741 this.set('playerState', 'error'); 85742 debug('error' + errorCode); 85743 // Send the event to the controller 85744 this.sendAction('error', errorCode); 85745 // switch(errorCode) { 85746 // case 2: 85747 // debug('Invalid parameter'); 85748 // break; 85749 // case 100: 85750 // debug('Not found/private'); 85751 // this.send('playNext'); 85752 // break; 85753 // case 101: 85754 // case 150: 85755 // debug('Embed not allowed'); 85756 // this.send('playNext'); 85757 // break; 85758 // default: 85759 // break; 85760 // } 85761 }, 85762 85763 // Returns a boolean that indicates playback status 85764 // by looking at the player state. 85765 isPlaying: computed('playerState', { 85766 get: function get() { 85767 var player = this.get('player'); 85768 if (!player || this.get('playerState') === 'loading') { 85769 return false; 85770 } 85771 return player.getPlayerState() === 1; 85772 }, 85773 set: function set(name, paused) { 85774 var player = this.get('player'); 85775 // Stop without player or when loading. 85776 if (!player || this.get('playerState') === 'loading') { 85777 return; 85778 } 85779 if (paused) { 85780 this.send('play'); 85781 } else { 85782 this.send('pause'); 85783 } 85784 } 85785 }), 85786 85787 // Load (and plays) a video every time ytid changes. 85788 loadVideo: observer('ytid', function () { 85789 var _this4 = this; 85790 85791 var player = this.get('player'); 85792 var videoId = this.get('ytid'); 85793 var startSeconds = this.get('startSeconds'); 85794 var endSeconds = this.get('endSeconds'); 85795 var suggestedQuality = this.get('suggestedQuality'); 85796 // Make sure we have access to the functions we need otherwise the player might die. 85797 if (!videoId || !player || !player.loadVideoById || !player.cueVideoById) { 85798 this.loadAndCreatePlayer().then(function () { 85799 _this4.loadVideo(); 85800 }); 85801 return; 85802 } 85803 // Set parameters for the video to be played. 85804 var options = { 85805 videoId: videoId, 85806 startSeconds: startSeconds, 85807 endSeconds: endSeconds, 85808 suggestedQuality: suggestedQuality 85809 }; 85810 // Check mute status and set it. 85811 this.set('isMuted', player.isMuted()); 85812 // Either load or cue depending on `autoplay`. 85813 if (this.playerVars.autoplay) { 85814 player.loadVideoById(options); 85815 } else { 85816 player.cueVideoById(options); 85817 } 85818 }), 85819 85820 volume: computed({ 85821 get: function get() { 85822 return this.get('player').getVolume(); 85823 },
85824 set: function set(name, volume) { 85825 var player = this.get('player'); 85826 // Clamp between 0 and 100 85827 if (volume > 100) { 85828 volume = 100; 85829 } else if (volume < 0) { 85830 volume = 0; 85831 } 85832 if (player) { 85833 player.setVolume(volume); 85834 } 85835 } 85836 }), 85837 85838 startTimer: function startTimer() { 85839 var player = this.get('player'); 85840 var interval = 1000; 85841 // set initial times 85842 this.setProperties({ 85843 currentTime: player.getCurrentTime(), 85844 duration: player.getDuration() 85845 }); 85846 // stop any previously started timer we forgot to clear 85847 this.stopTimer(); 85848 // every second update current time 85849 var timer = window.setInterval((function () { 85850 this.set('currentTime', player.getCurrentTime()); 85851 }).bind(this), interval); 85852 // save the timer so we can stop it later 85853 this.set('timer', timer); 85854 }, 85855 85856 stopTimer: function stopTimer() { 85857 window.clearInterval(this.get('timer')); 85858 }, 85859 85860 // avoids 'undefined' value for the <progress> element. 85861 currentTimeValue: computed('currentTime', function () { 85862 var time = this.get('currentTime'); 85863 return time ? time : 0; 85864 }), 85865 85866 // avoids 'undefined' value for the <progress> element. 85867 durationValue: computed('duration', function () { 85868 var duration = this.get('duration'); 85869 return duration ? duration : 0; 85870 }), 85871 85872 // OK, this is stupid but couldn't access the "event" inside 85873 // an ember action so here's a manual click handler instead. 85874 progressBarClick: on('didInsertElement', function () { 85875 var self = this; 85876 this.$().on('click', 'progress', function (event) { 85877 // get the x position of the click inside our progress el 85878 var x = event.pageX - _ember['default'].$(this).position().left; 85879 // convert it to a value relative to the duration (max) 85880 var clickedValue = x * this.max / this.offsetWidth; 85881 // 250 = 0.25 seconds into player 85882 self.send('seekTo', clickedValue); 85883 }); 85884 }), 85885 85886 // clean up when element will be destroyed. 85887 willDestroyElement: function willDestroyElement() { 85888 // clear the timer 85889 this.stopTimer(); 85890 // destroy video player 85891 var player = this.get('player'); 85892 if (player) { 85893 player.destroy(); 85894 this.set('player', null); 85895 } 85896 }, 85897 85898 actions: { 85899 play: function play() { 85900 if (this.get('player')) { 85901 this.get('player').playVideo(); 85902 } 85903 }, 85904 pause: function pause() { 85905 if (this.get('player')) { 85906 this.get('player').pauseVideo(); 85907 } 85908 }, 85909 togglePlay: function togglePlay() { 85910 this.toggleProperty('isPlaying'); 85911 }, 85912 mute: function mute() { 85913 if (this.get('player')) { 85914 this.get('player').mute(); 85915 this.set('isMuted', true); 85916 } 85917 }, 85918 unMute: function unMute() { 85919 if (this.get('player')) { 85920 this.get('player').unMute(); 85921 this.set('isMuted', false); 85922 } 85923 }, 85924 toggleVolume: function toggleVolume() { 85925 if (this.get('player').isMuted()) { 85926 this.send('unMute'); 85927 } else { 85928 this.send('mute'); 85929 } 85930 }, 85931 seekTo: function seekTo(seconds) { 85932 if (this.get('player')) { 85933 this.get('player').seekTo(seconds); 85934 } 85935 }, 85936 // youtube events 85937 ready: function ready() {}, 85938 ended: function ended() {}, 85939 playing: function playing() { 85940 this.startTimer(); 85941 }, 85942 paused: function paused() { 85943 this.stopTimer(); 85944 }, 85945 buffering: function buffering() {}, 85946 queued: function queued() {} 85947 } 85948 }); 85949}); 85950;/* jshint ignore:start */ 85951 85952 85953 85954/* jshint ignore:end */ 85955//# sourceMappingURL=vendor.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.