1var optimizeCb = function(func, context, argCount) { 2 if (context === void 0) return func; 3 switch (argCount == null ? 3 : argCount) { 4 case 1: return function(value) { 5 return func.call(context, value); 6 }; 7 case 2: return function(value, other) { 8 return func.call(context, value, other); 9 }; 10 case 3: return function(value, index, collection) { 11 return func.call(context, value, index, collection); 12 }; 13 case 4: return function(accumulator, value, index, collection) { 14 return func.call(context, accumulator, value, index, collection); 15 }; 16 } 17 return function() { 18 return func.apply(context, arguments); 19 }; 20}; 21var cb = function(value, context, argCount) { 22 if (value == null) return _.identity; 23 if (_.isFunction(value)) return optimizeCb(value, context, argCount); 24 if (_.isObject(value)) return _.matcher(value); 25 return _.property(value); 26}; 27 28_.mixin({ 29 mapObject: function(obj, iteratee, context) { 30 iteratee = cb(iteratee, context); 31 var keys = _.keys(obj), 32 length = keys.length, 33 results = {}, 34 currentKey; 35 for (var index = 0; index < length; index++) { 36 currentKey = keys[index]; 37 results[currentKey] = iteratee(obj[currentKey], currentKey, obj); 38 } 39 return results; 40 } 41}) 42 43_.noop = function(){} 44void function ( root, factory ) { 45 46 // Set up Backbone appropriately for the environment. Start with AMD. 47 if ( typeof define === 'function' && define.amd ) { 48 define([ 'underscore', 'backbone', 'exports' ], function ( _, Backbone, exports ) { 49 // Export global even in AMD case in case this script is loaded with 50 // others that may still expect a global Backbone. 51 root.B = factory(root, exports, _, Backbone); 52 }); 53 54 // Next for Node.js or CommonJS. 55 } else if ( typeof exports !== 'undefined' ) { 56 var _ = require('underscore'); 57 var Backbone = require('backbone'); 58 factory(root, exports, _, Backbone); 59 60 // Finally, as a browser global. 61 } else { 62 root.B = factory(root, root.B || {}, root._, root.Backbone); 63 } 64 65}(this, function ( root, B, _, Backbone ) { 66 67 var Model, Collection, Compute; 68 var BackboneModel = Backbone.Model; 69 var BackboneCollection = Backbone.Collection; 70 71 /* --- Compute --- */ 72 Compute = B.Compute = function () { 73 74 function Compute ( deps, options ) { 75 if ( !(this instanceof Compute) ) 76 return new Compute(deps, options); 77 if ( _.isArray(deps) && _.isFunction(options) ) 78 options = { deps: deps, get: options } 79 else if ( _.isFunction(deps) ) 80 options = _.defaults({ get: deps }, options) 81 else 82 options = (deps || {}); 83 84 _.defaults(this, options, { 85 deps: [], 86 init: function () { 87 return null; 88 }, 89 get: function ( value ) { 90 return value; 91 }, 92 set: function ( value ) { 93 return value; 94 } 95 }) 96 } 97 98 return Compute 99 }() 100 101 /* --- Model --- */ 102 Model = B.Model = function () { 103 104 function Model ( attrs, options ) { 105 if ( !(this instanceof Model) ) { 106 if (isPrototypeOf(attrs, Model)) 107 return attrs.create.apply(attrs, _(arguments).slice(1)); 108 return Model.create.apply(Model, arguments); 109 } 110 _.extend(this, _.pick(options, '_parent', '_relatedKey')) 111 _.each(this.computes, this._registerComputeValue, this) 112 Object.defineProperties(this, { 113 'root': { 114 get: function () { 115 var root = this; 116 var parent = this.collection || this._parent; 117 while ( parent ) { 118 root = parent; 119 parent = parent.collection || parent._parent; 120 } 121 return root; 122 } 123 } 124 }); 125 BackboneModel.apply(this, arguments); 126 } 127 128 Model.prototype.__proto__ = BackboneModel.prototype; 129 130 var useMatchAll = typeof String.prototype.matchAll == 'function' 131 132 // prototypes 133 _.extend(Model.prototype, { 134 135 relations: {}, 136 computes: {}, 137 defaults: {}, 138 139 /* 140 * Use String.matchAll() on newer browsers 141 * otherwise use Regex.exec() for older browsers 142 * */ 143 get: useMatchAll ? 144 function( key ) { 145 var value = this; 146 var regex = /(\w+)(?:\[([0-9]+)\])?/g; 147 var m = key.matchAll(regex) 148 var done = false 149 while (!done) { 150 var result = m.next() 151 if (result.done == false) { 152 var match = result.value 153 value = value instanceof BackboneModel ? getComputedValue(value, match[ 1 ]) : 154 typeof value == 'object' ? value[ match[ 1 ] ] : undefined; 155 if ( match[ 2 ] ) 156 value = value instanceof BackboneCollection ? value.at(match[ 2 ]) : value[ match[ 2 ] ]; 157 } else { 158 done = true 159 } 160 } 161 return value; 162 } : 163 function ( key ) { 164 var value = this; 165 var regex = /(\w+)(?:\[([0-9]+)\])?/g; 166 var match; 167 while (match = regex.exec(key)) { 168 value = value instanceof BackboneModel ? getComputedValue(value, match[ 1 ]) : 169 typeof value == 'object' ? value[ match[ 1 ] ] : undefined; 170 if ( match[ 2 ] ) { 171 value = value instanceof BackboneCollection ? value.at(match[ 2 ]) : value[ match[ 2 ] ]; 172 } 173 } 174 return value; 175 }, 176 177 // 178 // Borrowed from "Backbone Nested Models" by "Bret Little" 179 // 180 setRelation: function ( attr, val, options ) { 181 var relation = this.attributes[ attr ], 182 id = this.idAttribute || "id", 183 modelToSet, modelsToAdd = [], modelsToRemove = []; 184 185 if ( options.unset && relation ) delete relation.parent; 186 187 if ( this.relations && _.has(this.relations, attr) ) { 188 189 // If the relation already exists, we don't want to replace it, rather 190 // update the data within it whether it is a collection or model 191 if ( relation && relation instanceof Collection ) { 192 193 // If the val that is being set is already a collection, use the models 194 // within the collection. 195 if ( val instanceof Collection || val instanceof Array ) { 196 val = val.models || val; 197 modelsToAdd = _.clone(val); 198 199 relation.each(function ( model, i ) { 200
201 // If the model does not have an "id" skip logic to detect if it already 202 // exists and simply add it to the collection 203 if ( typeof model[ id ] == 'undefined' ) return; 204 205 // If the incoming model also exists within the existing collection, 206 // call set on that model. If it doesn't exist in the incoming array, 207 // then add it to a list that will be removed. 208 var rModel = _.find(val, function ( _model ) { 209 return _model[ id ] === model[ id ]; 210 }); 211 212 if ( rModel ) { 213 model.set(rModel.toJSON ? rModel.toJSON() : rModel); 214 215 // Remove the model from the incoming list because all remaining models 216 // will be added to the relation 217 modelsToAdd.splice(i, 1); 218 } else { 219 modelsToRemove.push(model); 220 } 221 222 }); 223 224 _.each(modelsToRemove, function ( model ) { 225 relation.remove(model); 226 }); 227 228 relation.add(modelsToAdd); 229 230 } else { 231 232 // The incoming val that is being set is not an array or collection, then it represents 233 // a single model. Go through each of the models in the existing relation and remove 234 // all models that aren't the same as this one (by id). If it is the same, call set on that 235 // model. 236 237 relation.each(function ( model ) { 238 if ( val[ id ] === model[ id ] ) { 239 model.set(val); 240 } else { 241 relation.remove(model); 242 } 243 }); 244 } 245 246 return relation; 247 } 248 249 if ( val instanceof Model ) { 250 val = val.toJSON() 251 } 252 253 if ( relation && relation instanceof Model ) { 254 relation.set(val); 255 return relation; 256 } 257 258 options._parent = this; 259 options._relatedKey = attr; 260 261 val = new this.relations[ attr ](val, options); 262 val.parent = this; 263 } 264 265 return val; 266 }, 267 set: function ( key, val, options ) { 268 if ( typeof key == 'object' ) { 269 options = val; 270 return this._set(key, options) 271 } 272 if ( typeof key == 'string' ) { 273 if ( !key.match(/[.\[]/) ) 274 return this._set(key, val, options) 275 var regex = /(\w+)(?:\[([0-9]+)\])?/; 276 var keys = key.split('.'); 277 var setAttr = keys.pop().match(regex); 278 var getAttr = keys.join('.'); 279 if ( !setAttr[ 2 ] ) { 280 var setter = this.get(getAttr); 281 if ( setter instanceof BackboneModel ) 282 setter.set(setAttr[ 1 ], val, options); 283 else if ( typeof setter === 'object' ) 284 setter[ setAttr[ 1 ] ] = val; 285 return this; 286 } 287 var collection = this.get(getAttr + '.' + setAttr[ 1 ]); 288 if ( collection instanceof BackboneCollection ) 289 collection.at(parseInt(setAttr[ 2 ])).set(val, options) 290 else if ( typeof setter === 'object' ) 291 collection[ parseInt(setAttr[ 2 ]) ] = val; 292 return this; 293 } 294 }, 295 _set: function ( key, val, options ) { 296 var attr, attrs, unset, changes, silent, changing, prev, current; 297 if ( key == null ) return this; 298 299 // Handle both `"key", value` and `{key: value}` -style arguments. 300 if ( typeof key === 'object' ) { 301 attrs = key; 302 options = val; 303 } else { 304 (attrs = {})[ key ] = val; 305 } 306 307 options || (options = {}); 308 309 // Run validation. 310 if ( !this._validate(attrs, options) ) return false; 311 312 // Extract attributes and options. 313 unset = options.unset; 314 silent = options.silent; 315 changes = []; 316 changing = this._changing; 317 this._changing = true; 318 319 if ( !changing ) { 320 this._previousAttributes = _.clone(this.attributes); 321 this.changed = {}; 322 } 323 current = this.attributes, prev = this._previousAttributes; 324 325 // Check for changes of `id`. 326 if ( this.idAttribute in attrs ) this.id = attrs[ this.idAttribute ]; 327 328 // For each `set` attribute, update or delete the current value. 329 for ( attr in attrs ) { 330 if ( this.computes[ attr ] ) { 331 val = attrs[ attr ] 332 val = this.computes[ attr ].set.call(this, val, options); 333 } 334 else { 335 val = attrs[ attr ]; 336 // Inject in the relational lookup 337 val = this.setRelation(attr, val, options); 338 } 339 340 if ( !_.isEqual(current[ attr ], val) ) changes.push(attr); 341 if ( !_.isEqual(prev[ attr ], val) ) { 342 this.changed[ attr ] = val; 343 } else { 344 delete this.changed[ attr ]; 345 } 346 unset ? delete current[ attr ] : current[ attr ] = val; 347 } 348 349 // Trigger all relevant attribute changes. 350 if ( !silent ) { 351 if ( changes.length ) this._pending = true; 352 for ( var i = 0, l = changes.length; i < l; i++ ) { 353 this.trigger('change:' + changes[ i ], this, current[ changes[ i ] ], options); 354 } 355 } 356 357 if ( changing ) return this; 358 if ( !silent ) { 359 while ( this._pending ) { 360 this._pending = false;
361 this.trigger('change', this, options); 362 this._triggerParentChange(options); 363 } 364 } 365 this._pending = false; 366 this._changing = false; 367 return this; 368 }, 369 clone: function ( options ) { 370 return new this.constructor(this.toJSON()); 371 }, 372 clear: function ( options ) { 373 var attrs = {}; 374 for ( var key in this.attributes ) { 375 if ( this.attributes[ key ] instanceof BackboneModel ) 376 this.attributes[ key ].clear(options); 377 else if ( this.attributes[ key ] instanceof BackboneCollection ) 378 this.attributes[ key ].invoke('clear', options), 379 this.attributes[ key ].reset([]); 380 else 381 attrs[ key ] = void 0; 382 } 383 return this.set(attrs, _.extend({}, options, { unset: true })); 384 }, 385 toJSON2: function ( options ) { 386 var attrs = _.clone(this.attributes); 387 attrs.__proto__ = null; 388 389 _.each(this.relations, function ( rel, key ) { 390 if ( _.has(attrs, key) ) { 391 attrs[ key ] = attrs[ key ].toJSON(); 392 } else { 393 attrs[ key ] = (new rel()).toJSON(); 394 } 395 }); 396 397 return attrs; 398 }, 399 toJSON: function () { 400 var attr, obj = Object.create(null, {}); 401 for ( var key in this.attributes ) { 402 attr = this.attributes[ key ]; 403 if ( attr instanceof BackboneModel || attr instanceof BackboneCollection ) 404 attr = attr.toJSON(); 405 if (this.computes.hasOwnProperty(key)) 406 continue; 407 if ( _.isObject(attr) ) 408 attr = _.clone(attr); 409 obj[ key ] = attr; 410 } 411 return obj; 412 }, 413 toCompactJSON: function () { 414 var attr, obj = Object.create(null, {}); 415 for ( var key in this.attributes ) { 416 if ( this.attributes.hasOwnProperty(key) ) { 417 attr = this.attributes[ key ]; 418 if ( attr instanceof Model || attr instanceof Collection ) 419 attr = attr.toCompactJSON(); 420 else if ( attr instanceof BackboneModel || attr instanceof BackboneCollection ) 421 attr = attr.toJSON(); 422 423 //if (attr instanceof Compute) 424 if (this.computes.hasOwnProperty(key)) 425 continue; 426 if ( _.isEqual(attr, this.defaults[ key ])) 427 continue; 428 429 obj[ key ] = attr; 430 } 431 } 432 return obj; 433 }, 434 _triggerParentChange: function ( options ) { 435 var parent = this._parent; 436 if ( !parent ) return; 437 438 parent.changed = {}; 439 _.extend(options, { chained: true }) 440 441 // Loop through every changed attribute 442 for ( var key in this.changed ) { 443 444 // Trigger "change:this.attr" 445 parent.changed[ this._relatedKey + '.' + key ] = this.changed[ key ]; 446 parent.trigger('change:' + this._relatedKey + '.' + key, parent, this.changed[ key ], options); 447 } 448 //parent.changed[ this._relatedKey ] = this; 449 parent.changed[ this._relatedKey ] = undefined; 450 451 parent.trigger('change:' + this._relatedKey, parent, this, options); 452 parent.trigger('change', parent, options); 453 parent._triggerParentChange(options); 454 }, 455 _registerComputeValue: function ( compute, attr ) { 456 _.each(compute.deps, function ( depAttr ) { 457 this.on('change:' + depAttr, function ( model, value, options ) { 458 var value = model.get(depAttr); 459 if ( value instanceof BackboneModel || value instanceof Collection ) { 460 model.changed[ attr ] = undefined; 461 _.each(value.changed, function ( subValue, subAttr ) { 462 model.changed[ subAttr ] = subValue; 463 model.trigger('change:' + attr + '.' + subAttr, model, subValue, options) 464 }) 465 } 466 else { 467 model.changed[ attr ] = value; 468 } 469 model.trigger('change:' + attr, model, value, options) 470 model.trigger('change', model, options) 471 }) 472 }, this) 473 }, 474 alias: function ( model ) { 475 for ( var attr in model.attributes ) { 476 if ( model.attributes[ attr ] instanceof BackboneModel ) { 477 if ( !this.attributes.hasOwnProperty(attr) || !(this.attributes[ attr ] instanceof BackboneModel) || !(this.attributes[ attr ] instanceof BackboneCollection) ) { 478 this.attributes[ attr ] = new Model(this.attributes[ attr ], { _parent: this, _relatedKey: attr }); 479 } 480 this.attributes[ attr ].alias(model.attributes[ attr ]) 481 } 482 } 483 this._alias = model; 484 this.attributes.__proto__ = model.attributes; 485 this.defaults = _.extend({}, model.defaults, this.defaults); 486 this.relations = _.extend({}, model.relations, this.relations); 487 this.computes = _.extend({}, model.computes, this.computes); 488 //this.on('change', function () { 489 // _.each(this.changed, function ( val, attr ) { 490 // console.log('check target attr',model.has(attr)) 491 // model.has(attr) || model.set(attr, val) 492 // }) 493 //}) 494 return this; 495 } 496 }) 497 // statics 498 _.extend(Model, { 499 create: function ( attrs, protos, statics ) { 500 501 var protos = protos || {}; 502 var statics = statics || {}; 503 var defaults = _.extend( {}, this.prototype.defaults, protos.defaults, attrs ); 504 var relations = _.extend( {}, this.prototype.relations, protos.relations ); 505 var computes = _.extend( {}, this.prototype.computes, protos.computes ); 506 for ( var attr in attrs ) { 507 if ( isPrototypeOf(attrs[ attr ], BackboneModel) ) { 508 relations[ attr ] = attrs[ attr ]; 509 defaults[ attr ] = {}; 510 } 511 else if ( isPrototypeOf(attrs[ attr ], BackboneCollection) ) { 512 relations[ attr ] = attrs[ attr ]; 513 defaults[ attr ] = []; 514 } 515 else if ( attrs[ attr ] instanceof Compute ) { 516 computes[ attr ] = attrs[ attr ]; 517 delete defaults[ attr ]; 518 } 519 } 520 return this.extend( 521 _.extend({}, protos, {
522 defaults: defaults, 523 relations: relations, 524 computes: computes 525 }), 526 _.extend({}, statics, { 527 create: Model.create, 528 extend: Model.extend, 529 define: Model.define, 530 }) 531 ); 532 }, 533 extend: function () { 534 return BackboneModel.extend.apply(this, arguments) 535 } 536 }) 537 538 Model.define = Model.create; 539 540 return Model 541 }(); 542 543 /* --- Collection --- */ 544 Collection = B.Collection = function () { 545 546 function Collection ( models, options ) { 547 if ( !(this instanceof Collection) ) { 548 if (isPrototypeOf(models, Collection)) 549 return models.create.apply(models, _(arguments).slice(1)); 550 return Collection.create.apply(Collection, arguments); 551 } 552 _.extend(this, _.pick(options, '_parent', '_relatedKey')) 553 this.on('change', this._triggerParentChange) 554 this.on('add', this._triggerParentChange) 555 this.on('remove', this._triggerParentChange) 556 BackboneCollection.apply(this, arguments) 557 } 558 559 Collection.prototype.__proto__ = BackboneCollection.prototype; 560 561 // prototypes 562 _.extend(Collection.prototype, { 563 564 model: Model, 565 566 _triggerParentChange: function ( model, options ) { 567 var parent = this._parent; 568 if ( !parent ) return; 569 570 // If this change event is triggered by one of its child model 571 if ( model && model.collection ) { 572 573 var modelIndex = model.collection.indexOf(model); 574 575 parent.changed = {}; 576 _.extend(options, { chained: true }) 577 578 // Loop through every changed attributes of this model 579 for ( var key in model.changed ) { 580 581 // Trigger "change:collection[n].child" 582 parent.changed[ this._relatedKey + '[' + modelIndex + '].' + key ] = model.changed[ key ]; 583 parent.trigger('change:' + this._relatedKey + '[' + modelIndex + '].' + key, parent, model.changed[ key ], options); 584 585 // Trigger "change:collection.child" 586 parent.changed[ this._relatedKey + '.' + key ] = model.changed[ key ]; 587 parent.trigger('change:' + this._relatedKey + '.' + key, parent, model.changed[ key ], options); 588 } 589 590 // Trigger "change:collection" 591 //parent.changed[ this._relatedKey ] = this; 592 parent.changed[ this._relatedKey ] = undefined; 593 parent.trigger('change:' + this._relatedKey, parent, options); 594 parent._triggerParentChange(options); 595 } 596 597 // Finally trigger "change" 598 parent.trigger('change', parent, options); 599 }, 600 resetRelations: function ( options ) { 601 _.each(this.models, function ( model ) { 602 _.each(model.relations, function ( rel, key ) { 603 if ( model.get(key) instanceof BackboneCollection ) { 604 model.get(key).trigger('reset', model, options); 605 } 606 }); 607 }) 608 }, 609 reset: function ( models, options ) { 610 options || (options = {}); 611 for ( var i = 0, l = this.models.length; i < l; i++ ) { 612 this._removeReference(this.models[ i ]); 613 } 614 options.previousModels = this.models; 615 this._reset(); 616 this.add(models, _.extend({ silent: true }, options)); 617 if ( !options.silent ) { 618 this.trigger('reset', this, options); 619 this.resetRelations(options); 620 } 621 return this; 622 }, 623 comparator: function ( model ) { 624 return model.get('index'); 625 }, 626 toCompactJSON: function () { 627 var models = _(this.models).map(function ( model ) { 628 return model instanceof BackboneModel ? model.toCompactJSON() : model.toJSON(); 629 }); 630 models.__proto__ = null; 631 return models; 632 }, 633 _prepareModel: function( attrs, options ) { 634 if (attrs instanceof Model) 635 return attrs; 636 options = options ? _.clone(options) : {}; 637 options.collection = this; 638 639 var modelClass = this.model; 640 if (attrs._rel && this.relations[attrs._rel]) 641 modelClass = this.relations[attrs._rel]; 642 var model = new modelClass(attrs, options); 643 if (!model.validationError) return model; 644 this.trigger('invalid', this, model.validationError, options); 645 return false; 646 } 647 }) 648 // statics 649 _.extend(Collection, { 650 create: function ( models, protos, statics ) { 651 var statics = _.extend({}, statics, { 652 create: Collection.create, 653 extend: Collection.extend, 654 define: Collection.define, 655 }); 656 if ( _.isArray(models) || isPrototypeOf(models, Model)) 657 return Collection.extend(_.extend({}, protos, {
658 model: _.isArray(models) ? models[ 0 ] : models 659 }), statics); 660 661 else if ( _.isObject(models)) 662 return Collection.extend(_.extend({}, protos, { 663 relations: models 664 }), statics); 665 else 666 return Collection.extend( protos, statics ); 667 }, 668 extend: function () { 669 return BackboneCollection.extend.apply(this, arguments) 670 } 671 }) 672 673 Collection.define = Collection.create; 674 675 return Collection 676 }() 677 678 /* --- Utils --- */ 679 function getComputedValue ( model, key ) { 680 if ( model.computes && model.computes[ key ] ) { 681 var compute = model.computes[ key ]; 682 var deps = _(compute.deps).map(function ( dep ) { 683 return getComputedValue(model, dep); 684 }) 685 // console.log('computed value', compute.get.apply(model, deps)) 686 return compute.get.apply(model, deps); 687 } 688 return model.attributes[ key ]; 689 } 690 691 function setPrototypeOf( child, prototype ) { 692 if (_.isFunction(Object.setPrototypeOf)) 693 Object.setPrototypeOf(child.prototype || child, prototype); 694 else 695 (child.prototype || child).__proto__ = prototype; 696 return child 697 } 698 699 function isPrototypeOf( child, parent ) { 700 if ( !child || !parent ) 701 return false; 702 var result = false;
703 var proto = child.prototype; 704 while ( proto ) { 705 if ( proto == parent.prototype ) { 706 result = true; 707 break; 708 } 709 proto = proto.__proto__; 710 } 711 return result; 712 } 713 714 return B; 715});
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.