Commit d6c38b45 authored by Pascal Hartig's avatar Pascal Hartig

Ember: Upgrade to 1.6.0

parent 5a53ef13
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
"todomvc-common": "~0.1.4", "todomvc-common": "~0.1.4",
"jquery": "~2.1.0", "jquery": "~2.1.0",
"handlebars": "~1.3.0", "handlebars": "~1.3.0",
"ember": "~1.5.0", "ember": "~1.6.0",
"ember-data": "1.0.0-beta.7", "ember-data": "1.0.0-beta.7",
"ember-localstorage-adapter": "latest" "ember-localstorage-adapter": "latest"
} }
......
/*global Ember*/ /*global Ember*/
/*global DS*/ /*global DS*/
'use strict'; (function () {
'use strict';
DS.LSSerializer = DS.JSONSerializer.extend({ DS.LSSerializer = DS.JSONSerializer.extend({
serializeHasMany: function(record, json, relationship) { serializeHasMany: function(record, json, relationship) {
var key = relationship.key, var key = relationship.key,
relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship); relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (relationshipType === 'manyToNone' || if (relationshipType === 'manyToNone' ||
relationshipType === 'manyToMany' || relationshipType === 'manyToMany' ||
relationshipType === 'manyToOne') { relationshipType === 'manyToOne') {
json[key] = record.get(key).mapBy('id'); json[key] = record.get(key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany relationships // TODO support for polymorphic manyToNone and manyToMany relationships
} }
}, },
extractSingle: function(store, type, payload) {
if (payload && payload._embedded) {
for (var relation in payload._embedded) {
var typeName = Ember.String.singularize(relation),
embeddedPayload = payload._embedded[relation];
if (embeddedPayload) { /**
if (Ember.isArray(embeddedPayload)) { * Extracts whatever was returned from the adapter.
store.pushMany(typeName, embeddedPayload); *
} else { * If the adapter returns relationships in an embedded way, such as follows:
store.push(typeName, embeddedPayload); *
* ```js
* {
* "id": 1,
* "title": "Rails Rambo",
*
* "_embedded": {
* "comment": [{
* "id": 1,
* "comment_title": "FIRST"
* }, {
* "id": 2,
* "comment_title": "Rails is unagi"
* }]
* }
* }
*
* this method will create separated JSON for each resource and then push
* them individually to the Store.
*
* In the end, only the main resource will remain, containing the ids of its
* relationships. Given the relations are already in the Store, we will
* return a JSON with the main resource alone. The Store will sort out the
* associations by itself.
*
* @method extractSingle
* @private
* @param {DS.Store} store the returned store
* @param {DS.Model} type the type/model
* @param {Object} payload returned JSON
*/
extractSingle: function(store, type, payload) {
if (payload && payload._embedded) {
for (var relation in payload._embedded) {
var relType = type.typeForRelationship(relation);
var typeName = relType.typeKey,
embeddedPayload = payload._embedded[relation];
if (embeddedPayload) {
if (Ember.isArray(embeddedPayload)) {
store.pushMany(typeName, embeddedPayload);
} else {
store.push(typeName, embeddedPayload);
}
} }
} }
}
delete payload._embedded;
}
return this.normalize(type, payload);
}
}); delete payload._embedded;
}
DS.LSAdapter = DS.Adapter.extend(Ember.Evented, {
/**
This is the main entry point into finding records. The first parameter to
this method is the model's name as a string.
@method find return this.normalize(type, payload);
@param {DS.Model} type },
@param {Object|String|Integer|null} id
*/
find: function(store, type, id, opts) {
var adapter = this;
var allowRecursive = true;
var namespace = this._namespaceForType(type);
/** /**
* In the case where there are relationships, this method is called again * This is exactly the same as extractSingle, but used in an array.
* for each relation. Given the relations have references to the main
* object, we use allowRecursive to avoid going further into infinite
* recursiveness.
* *
* Concept from ember-indexdb-adapter * @method extractSingle
* @private
* @param {DS.Store} store the returned store
* @param {DS.Model} type the type/model
* @param {Array} payload returned JSONs
*/ */
if (opts && typeof opts.allowRecursive !== 'undefined') { extractArray: function(store, type, payload) {
allowRecursive = opts.allowRecursive; var serializer = this;
return payload.map(function(record) {
var extracted = serializer.extractSingle(store, type, record);
return serializer.normalize(type, record);
});
} }
return new Ember.RSVP.Promise(function(resolve, reject) { });
var record = Ember.A(namespace.records[id]);
if (allowRecursive && record) { DS.LSAdapter = DS.Adapter.extend(Ember.Evented, {
adapter.loadRelationships(type, record).then(function(finalRecord) { /**
resolve(finalRecord); This is the main entry point into finding records. The first parameter to
}); this method is the model's name as a string.
} else {
if (!record) { @method find
@param {DS.Model} type
@param {Object|String|Integer|null} id
*/
find: function(store, type, id, opts) {
var adapter = this;
var allowRecursive = true;
var namespace = this._namespaceForType(type);
/**
* In the case where there are relationships, this method is called again
* for each relation. Given the relations have references to the main
* object, we use allowRecursive to avoid going further into infinite
* recursiveness.
*
* Concept from ember-indexdb-adapter
*/
if (opts && typeof opts.allowRecursive !== 'undefined') {
allowRecursive = opts.allowRecursive;
}
return new Ember.RSVP.Promise(function(resolve, reject) {
var record = Ember.A(namespace.records[id]);
if (!record || !record.hasOwnProperty('id')) {
store.dematerializeRecord(store.typeMapFor(type).idToRecord[id]);
reject(); reject();
return;
}
if (allowRecursive) {
adapter.loadRelationships(type, record).then(function(finalRecord) {
resolve(finalRecord);
});
} else { } else {
resolve(record); resolve(record);
} }
} });
}); },
resolve(record);
},
findMany: function (store, type, ids) { findMany: function (store, type, ids) {
var adapter = this; var adapter = this;
var namespace = this._namespaceForType(type); var namespace = this._namespaceForType(type);
return new Ember.RSVP.Promise(function(resolve, reject) { return new Ember.RSVP.Promise(function(resolve, reject) {
var results = []; var results = [];
for (var i = 0; i < ids.length; i++) { for (var i = 0; i < ids.length; i++) {
results.push(Ember.copy(namespace.records[ids[i]])); results.push(Ember.copy(namespace.records[ids[i]]));
} }
resolve(results); resolve(results);
}); }).then(function(records) {
}, if (records.get('length')) {
return adapter.loadRelationshipsForMany(type, records);
// Supports queries that look like this:
//
// {
// <property to query>: <value or regex (for strings) to match>,
// ...
// }
//
// Every property added to the query is an "AND" query, not "OR"
//
// Example:
//
// match records with "complete: true" and the name "foo" or "bar"
//
// { complete: true, name: /foo|bar/ }
findQuery: function (store, type, query, recordArray) {
var namespace = this._namespaceForType(type),
results = this.query(namespace.records, query);
return Ember.RSVP.resolve(results);
},
query: function (records, query) {
var results = [],
id, record, property, test, push;
for (id in records) {
record = records[id];
for (property in query) {
test = query[property];
push = false;
if (Object.prototype.toString.call(test) === '[object RegExp]') {
push = test.test(record[property]);
} else { } else {
push = record[property] === test; return records;
}
});
},
// Supports queries that look like this:
//
// {
// <property to query>: <value or regex (for strings) to match>,
// ...
// }
//
// Every property added to the query is an "AND" query, not "OR"
//
// Example:
//
// match records with "complete: true" and the name "foo" or "bar"
//
// { complete: true, name: /foo|bar/ }
findQuery: function (store, type, query, recordArray) {
var namespace = this._namespaceForType(type),
results = this.query(namespace.records, query);
if (results.get('length')) {
results = this.loadRelationshipsForMany(type, results);
return Ember.RSVP.resolve(results);
} else {
return Ember.RSVP.reject();
}
},
query: function (records, query) {
var results = [],
id, record, property, test, push;
for (id in records) {
record = records[id];
for (property in query) {
test = query[property];
push = false;
if (Object.prototype.toString.call(test) === '[object RegExp]') {
push = test.test(record[property]);
} else {
push = record[property] === test;
}
}
if (push) {
results.push(record);
} }
} }
if (push) { return results;
results.push(record); },
findAll: function (store, type) {
var namespace = this._namespaceForType(type),
results = [];
for (var id in namespace.records) {
results.push(Ember.copy(namespace.records[id]));
} }
} return Ember.RSVP.resolve(results);
return results; },
},
findAll: function (store, type) { createRecord: function (store, type, record) {
var namespace = this._namespaceForType(type), var namespaceRecords = this._namespaceForType(type),
results = []; recordHash = record.serialize({includeId: true});
for (var id in namespace.records) { namespaceRecords.records[recordHash.id] = recordHash;
results.push(Ember.copy(namespace.records[id]));
}
return Ember.RSVP.resolve(results);
},
createRecord: function (store, type, record) {
var namespaceRecords = this._namespaceForType(type),
recordHash = record.serialize({includeId: true});
namespaceRecords.records[recordHash.id] = recordHash;
this.persistData(type, namespaceRecords);
return Ember.RSVP.resolve();
},
updateRecord: function (store, type, record) {
var namespaceRecords = this._namespaceForType(type),
id = record.get('id');
namespaceRecords.records[id] = record.serialize({ includeId: true });
this.persistData(type, namespaceRecords);
return Ember.RSVP.resolve();
},
deleteRecord: function (store, type, record) {
var namespaceRecords = this._namespaceForType(type),
id = record.get('id');
delete namespaceRecords.records[id];
this.persistData(type, namespaceRecords);
return Ember.RSVP.resolve();
},
generateIdForRecord: function () {
return Math.random().toString(32).slice(2).substr(0, 5);
},
// private
adapterNamespace: function () {
return this.namespace || 'DS.LSAdapter';
},
loadData: function () {
var storage = localStorage.getItem(this.adapterNamespace());
return storage ? JSON.parse(storage) : {};
},
persistData: function(type, data) {
var modelNamespace = this.modelNamespace(type),
localStorageData = this.loadData();
localStorageData[modelNamespace] = data;
localStorage.setItem(this.adapterNamespace(), JSON.stringify(localStorageData));
},
_namespaceForType: function (type) {
var namespace = this.modelNamespace(type),
storage = localStorage.getItem(this.adapterNamespace());
return storage ? JSON.parse(storage)[namespace] || {records: {}} : {records: {}};
},
modelNamespace: function(type) {
return type.url || type.toString();
},
/**
* This takes a record, then analyzes the model relationships and replaces
* ids with the actual values.
*
* Stolen from ember-indexdb-adapter
*
* Consider the following JSON is entered:
*
* ```js
* {
* "id": 1,
* "title": "Rails Rambo",
* "comments": [1, 2]
* }
*
* This will return:
*
* ```js
* {
* "id": 1,
* "title": "Rails Rambo",
* "comments": [1, 2]
*
* "_embedded": {
* "comment": [{
* "_id": 1,
* "comment_title": "FIRST"
* }, {
* "_id": 2,
* "comment_title": "Rails is unagi"
* }]
* }
* }
*
* This way, whenever a resource returned, its relationships will be also
* returned.
*
* @method loadRelationships
* @private
* @param {DS.Model} type
* @param {Object} record
*/
loadRelationships: function(type, record) {
var adapter = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
var resultJSON = {},
typeKey = type.typeKey,
relationshipNames, relationships,
relationshipPromises = [];
relationshipNames = Ember.get(type, 'relationshipNames');
relationships = relationshipNames.belongsTo;
relationships = relationships.concat(relationshipNames.hasMany);
relationships.forEach(function(relationName) {
var relationModel = type.typeForRelationship(relationName),
relationEmbeddedId = record[relationName],
relationProp = adapter.relationshipProperties(type, relationName),
relationType = relationProp.kind,
/**
* This is the relationship field.
*/
promise, embedPromise;
var opts = {allowRecursive: false};
/** this.persistData(type, namespaceRecords);
* embeddedIds are ids of relations that are included in the main return Ember.RSVP.resolve();
* payload, such as: },
*
* { updateRecord: function (store, type, record) {
* cart: { var namespaceRecords = this._namespaceForType(type),
* id: "s85fb", id = record.get('id');
* customer: "rld9u"
* } namespaceRecords.records[id] = record.serialize({ includeId: true });
* }
* this.persistData(type, namespaceRecords);
* In this case, cart belongsTo customer and its id is present in the return Ember.RSVP.resolve();
* main payload. We find each of these records and add them to _embedded. },
*/
if (relationEmbeddedId) { deleteRecord: function (store, type, record) {
if (relationType == 'belongsTo' || relationType == 'hasOne') { var namespaceRecords = this._namespaceForType(type),
promise = adapter.find(null, relationModel, relationEmbeddedId, opts) id = record.get('id');
} else if (relationType == 'hasMany') {
promise = adapter.findMany(null, relationModel, relationEmbeddedId, opts) delete namespaceRecords.records[id];
}
this.persistData(type, namespaceRecords);
return Ember.RSVP.resolve();
},
generateIdForRecord: function () {
return Math.random().toString(32).slice(2).substr(0, 5);
},
// private
adapterNamespace: function () {
return this.get('namespace') || 'DS.LSAdapter';
},
loadData: function () {
var storage = localStorage.getItem(this.adapterNamespace());
return storage ? JSON.parse(storage) : {};
},
persistData: function(type, data) {
var modelNamespace = this.modelNamespace(type),
localStorageData = this.loadData();
localStorageData[modelNamespace] = data;
localStorage.setItem(this.adapterNamespace(), JSON.stringify(localStorageData));
},
_namespaceForType: function (type) {
var namespace = this.modelNamespace(type),
storage = localStorage.getItem(this.adapterNamespace());
return storage ? JSON.parse(storage)[namespace] || {records: {}} : {records: {}};
},
embedPromise = new Ember.RSVP.Promise(function(resolve, reject) { modelNamespace: function(type) {
promise.then(function(relationRecord) { return type.url || type.typeKey;
var finalPayload = adapter.addEmbeddedPayload(record, relationName, relationRecord) },
resolve(finalPayload);
/**
* This takes a record, then analyzes the model relationships and replaces
* ids with the actual values.
*
* Stolen from ember-indexdb-adapter
*
* Consider the following JSON is entered:
*
* ```js
* {
* "id": 1,
* "title": "Rails Rambo",
* "comments": [1, 2]
* }
*
* This will return:
*
* ```js
* {
* "id": 1,
* "title": "Rails Rambo",
* "comments": [1, 2]
*
* "_embedded": {
* "comment": [{
* "_id": 1,
* "comment_title": "FIRST"
* }, {
* "_id": 2,
* "comment_title": "Rails is unagi"
* }]
* }
* }
*
* This way, whenever a resource returned, its relationships will be also
* returned.
*
* @method loadRelationships
* @private
* @param {DS.Model} type
* @param {Object} record
*/
loadRelationships: function(type, record) {
var adapter = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
var resultJSON = {},
typeKey = type.typeKey,
relationshipNames, relationships,
relationshipPromises = [];
relationshipNames = Ember.get(type, 'relationshipNames');
relationships = relationshipNames.belongsTo;
relationships = relationships.concat(relationshipNames.hasMany);
relationships.forEach(function(relationName) {
var relationModel = type.typeForRelationship(relationName),
relationEmbeddedId = record[relationName],
relationProp = adapter.relationshipProperties(type, relationName),
relationType = relationProp.kind,
/**
* This is the relationship field.
*/
promise, embedPromise;
var opts = {allowRecursive: false};
/**
* embeddedIds are ids of relations that are included in the main
* payload, such as:
*
* {
* cart: {
* id: "s85fb",
* customer: "rld9u"
* }
* }
*
* In this case, cart belongsTo customer and its id is present in the
* main payload. We find each of these records and add them to _embedded.
*/
if (relationEmbeddedId) {
if (relationType == 'belongsTo' || relationType == 'hasOne') {
promise = adapter.find(null, relationModel, relationEmbeddedId, opts)
} else if (relationType == 'hasMany') {
promise = adapter.findMany(null, relationModel, relationEmbeddedId, opts)
}
embedPromise = new Ember.RSVP.Promise(function(resolve, reject) {
promise.then(function(relationRecord) {
var finalPayload = adapter.addEmbeddedPayload(record, relationName, relationRecord)
resolve(finalPayload);
});
}); });
});
relationshipPromises.push(embedPromise); relationshipPromises.push(embedPromise);
} }
}); });
Ember.RSVP.all(relationshipPromises).then(function() { Ember.RSVP.all(relationshipPromises).then(function() {
resolve(record); resolve(record);
});
}); });
}); },
},
/**
/** * Given the following payload,
* Given the following payload, *
* * {
* { * cart: {
* cart: { * id: "1",
* id: "1", * customer: "2"
* customer: "2" * }
* } * }
* } *
* * With `relationshipName` being `customer` and `relationshipRecord`
* With `relationshipName` being `customer` and `relationshipRecord` *
* * {id: "2", name: "Rambo"}
* {id: "2", name: "Rambo"} *
* * This method returns the following payload:
* This method returns the following payload: *
* * {
* { * cart: {
* cart: { * id: "1",
* id: "1", * customer: "2"
* customer: "2" * },
* }, * _embedded: {
* _embedded: { * customer: {
* customer: { * id: "2",
* id: "2", * name: "Rambo"
* name: "Rambo" * }
* } * }
* } * }
* } *
* * which is then treated by the serializer later.
* which is then treated by the serializer later. *
* * @method addEmbeddedPayload
* @method addEmbeddedPayload * @private
* @private * @param {Object} payload
* @param {Object} payload * @param {String} relationshipName
* @param {String} relationshipName * @param {Object} relationshipRecord
* @param {Object} relationshipRecord */
*/ addEmbeddedPayload: function(payload, relationshipName, relationshipRecord) {
addEmbeddedPayload: function(payload, relationshipName, relationshipRecord) { var objectHasId = (relationshipRecord && relationshipRecord.id),
var objectHasId = (relationshipRecord && relationshipRecord.id), arrayHasIds = (relationshipRecord.length && relationshipRecord.everyBy("id")),
arrayHasIds = (relationshipRecord.length && relationshipRecord.everyBy("id")), isValidRelationship = (objectHasId || arrayHasIds);
isValidRelationship = (objectHasId || arrayHasIds);
if (isValidRelationship) {
if (isValidRelationship) { if (!payload['_embedded']) {
if (!payload['_embedded']) { payload['_embedded'] = {}
payload['_embedded'] = {} }
payload['_embedded'][relationshipName] = relationshipRecord;
if (relationshipRecord.length) {
payload[relationshipName] = relationshipRecord.mapBy('id');
} else {
payload[relationshipName] = relationshipRecord.id;
}
} }
payload['_embedded'][relationshipName] = relationshipRecord; if (this.isArray(payload[relationshipName])) {
if (relationshipRecord.length) { payload[relationshipName] = payload[relationshipName].filter(function(id) {
payload[relationshipName] = relationshipRecord.mapBy('id'); return id;
} else { });
payload[relationshipName] = relationshipRecord.id;
} }
}
if (this.isArray(payload[relationshipName])) { return payload;
payload[relationshipName] = payload[relationshipName].filter(function(id) { },
return id;
});
}
return payload; isArray: function(value) {
}, return Object.prototype.toString.call(value) === '[object Array]';
},
/**
* Same as `loadRelationships`, but for an array of records.
*
* @method loadRelationshipsForMany
* @private
* @param {DS.Model} type
* @param {Object} recordsArray
*/
loadRelationshipsForMany: function(type, recordsArray) {
var adapter = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
var recordsWithRelationships = [],
recordsToBeLoaded = [],
promises = [];
isArray: function(value) { /**
return Object.prototype.toString.call(value) === '[object Array]'; * Some times Ember puts some stuff in arrays. We want to clean it so
}, * we know exactly what to iterate over.
*/
for (var i in recordsArray) {
if (recordsArray.hasOwnProperty(i)) {
recordsToBeLoaded.push(recordsArray[i]);
}
}
var loadNextRecord = function(record) {
/**
* Removes the first item from recordsToBeLoaded
*/
recordsToBeLoaded = recordsToBeLoaded.slice(1);
/** var promise = adapter.loadRelationships(type, record);
*
* @method relationshipProperties promise.then(function(recordWithRelationships) {
* @private recordsWithRelationships.push(recordWithRelationships);
* @param {DS.Model} type
* @param {String} relationName if (recordsToBeLoaded[0]) {
*/ loadNextRecord(recordsToBeLoaded[0]);
relationshipProperties: function(type, relationName) { } else {
var relationships = Ember.get(type, 'relationshipsByName'); resolve(recordsWithRelationships);
if (relationName) { }
return relationships.get(relationName); });
} else { }
return relationships;
/**
* We start by the first record
*/
loadNextRecord(recordsToBeLoaded[0]);
});
},
/**
*
* @method relationshipProperties
* @private
* @param {DS.Model} type
* @param {String} relationName
*/
relationshipProperties: function(type, relationName) {
var relationships = Ember.get(type, 'relationshipsByName');
if (relationName) {
return relationships.get(relationName);
} else {
return relationships;
}
} }
} });
}); }());
This source diff could not be displayed because it is too large. You can view the blob instead.
/*! /*!
* jQuery JavaScript Library v2.1.0 * jQuery JavaScript Library v2.1.1
* http://jquery.com/ * http://jquery.com/
* *
* Includes Sizzle.js * Includes Sizzle.js
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Released under the MIT license * Released under the MIT license
* http://jquery.org/license * http://jquery.org/license
* *
* Date: 2014-01-23T21:10Z * Date: 2014-05-01T17:11Z
*/ */
(function( global, factory ) { (function( global, factory ) {
...@@ -59,8 +59,6 @@ var toString = class2type.toString; ...@@ -59,8 +59,6 @@ var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty; var hasOwn = class2type.hasOwnProperty;
var trim = "".trim;
var support = {}; var support = {};
...@@ -69,7 +67,7 @@ var ...@@ -69,7 +67,7 @@ var
// Use the correct document accordingly with window argument (sandbox) // Use the correct document accordingly with window argument (sandbox)
document = window.document, document = window.document,
version = "2.1.0", version = "2.1.1",
// Define a local copy of jQuery // Define a local copy of jQuery
jQuery = function( selector, context ) { jQuery = function( selector, context ) {
...@@ -78,6 +76,10 @@ var ...@@ -78,6 +76,10 @@ var
return new jQuery.fn.init( selector, context ); return new jQuery.fn.init( selector, context );
}, },
// Support: Android<4.1
// Make sure we trim BOM and NBSP
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
// Matches dashed string for camelizing // Matches dashed string for camelizing
rmsPrefix = /^-ms-/, rmsPrefix = /^-ms-/,
rdashAlpha = /-([\da-z])/gi, rdashAlpha = /-([\da-z])/gi,
...@@ -108,10 +110,10 @@ jQuery.fn = jQuery.prototype = { ...@@ -108,10 +110,10 @@ jQuery.fn = jQuery.prototype = {
get: function( num ) { get: function( num ) {
return num != null ? return num != null ?
// Return a 'clean' array // Return just the one element from the set
( num < 0 ? this[ num + this.length ] : this[ num ] ) : ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
// Return just the object // Return all the elements in a clean array
slice.call( this ); slice.call( this );
}, },
...@@ -267,7 +269,7 @@ jQuery.extend({ ...@@ -267,7 +269,7 @@ jQuery.extend({
// parseFloat NaNs numeric-cast false positives (null|true|false|"") // parseFloat NaNs numeric-cast false positives (null|true|false|"")
// ...but misinterprets leading-number strings, particularly hex literals ("0x...") // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
// subtraction forces infinities to NaN // subtraction forces infinities to NaN
return obj - parseFloat( obj ) >= 0; return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
}, },
isPlainObject: function( obj ) { isPlainObject: function( obj ) {
...@@ -279,16 +281,8 @@ jQuery.extend({ ...@@ -279,16 +281,8 @@ jQuery.extend({
return false; return false;
} }
// Support: Firefox <20 if ( obj.constructor &&
// The try/catch suppresses exceptions thrown when attempting to access !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
// the "constructor" property of certain host objects, ie. |window.location|
// https://bugzilla.mozilla.org/show_bug.cgi?id=814622
try {
if ( obj.constructor &&
!hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
return false;
}
} catch ( e ) {
return false; return false;
} }
...@@ -398,8 +392,11 @@ jQuery.extend({ ...@@ -398,8 +392,11 @@ jQuery.extend({
return obj; return obj;
}, },
// Support: Android<4.1
trim: function( text ) { trim: function( text ) {
return text == null ? "" : trim.call( text ); return text == null ?
"" :
( text + "" ).replace( rtrim, "" );
}, },
// results is for internal usage only // results is for internal usage only
...@@ -551,14 +548,14 @@ function isArraylike( obj ) { ...@@ -551,14 +548,14 @@ function isArraylike( obj ) {
} }
var Sizzle = var Sizzle =
/*! /*!
* Sizzle CSS Selector Engine v1.10.16 * Sizzle CSS Selector Engine v1.10.19
* http://sizzlejs.com/ * http://sizzlejs.com/
* *
* Copyright 2013 jQuery Foundation, Inc. and other contributors * Copyright 2013 jQuery Foundation, Inc. and other contributors
* Released under the MIT license * Released under the MIT license
* http://jquery.org/license * http://jquery.org/license
* *
* Date: 2014-01-13 * Date: 2014-04-18
*/ */
(function( window ) { (function( window ) {
...@@ -567,7 +564,9 @@ var i, ...@@ -567,7 +564,9 @@ var i,
Expr, Expr,
getText, getText,
isXML, isXML,
tokenize,
compile, compile,
select,
outermostContext, outermostContext,
sortInput, sortInput,
hasDuplicate, hasDuplicate,
...@@ -634,17 +633,23 @@ var i, ...@@ -634,17 +633,23 @@ var i,
// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
identifier = characterEncoding.replace( "w", "w#" ), identifier = characterEncoding.replace( "w", "w#" ),
// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
"*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", // Operator (capture 2)
"*([*^$|!~]?=)" + whitespace +
// Prefer arguments quoted, // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
// then not containing pseudos/brackets, "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
// then attribute selectors/non-parenthetical expressions, "*\\]",
// then anything else
// These preferences are here to reduce the number of selectors pseudos = ":(" + characterEncoding + ")(?:\\((" +
// needing tokenize in the PSEUDO preFilter // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", // 1. quoted (capture 3; capture 4 or capture 5)
"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
// 2. simple (capture 6)
"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
// 3. anything else (capture 2)
".*" +
")\\)|)",
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
...@@ -689,7 +694,7 @@ var i, ...@@ -689,7 +694,7 @@ var i,
funescape = function( _, escaped, escapedWhitespace ) { funescape = function( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000; var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint // NaN means non-codepoint
// Support: Firefox // Support: Firefox<24
// Workaround erroneous numeric interpretation of +"0x" // Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ? return high !== high || escapedWhitespace ?
escaped : escaped :
...@@ -1085,7 +1090,7 @@ setDocument = Sizzle.setDocument = function( node ) { ...@@ -1085,7 +1090,7 @@ setDocument = Sizzle.setDocument = function( node ) {
var m = context.getElementById( id ); var m = context.getElementById( id );
// Check parentNode to catch when Blackberry 4.6 returns // Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963 // nodes that are no longer in the document #6963
return m && m.parentNode ? [m] : []; return m && m.parentNode ? [ m ] : [];
} }
}; };
Expr.filter["ID"] = function( id ) { Expr.filter["ID"] = function( id ) {
...@@ -1165,11 +1170,13 @@ setDocument = Sizzle.setDocument = function( node ) { ...@@ -1165,11 +1170,13 @@ setDocument = Sizzle.setDocument = function( node ) {
// setting a boolean content attribute, // setting a boolean content attribute,
// since its presence should be enough // since its presence should be enough
// http://bugs.jquery.com/ticket/12359 // http://bugs.jquery.com/ticket/12359
div.innerHTML = "<select t=''><option selected=''></option></select>"; div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
// Support: IE8, Opera 10-12 // Support: IE8, Opera 11-12.16
// Nothing should be selected when empty strings follow ^= or $= or *= // Nothing should be selected when empty strings follow ^= or $= or *=
if ( div.querySelectorAll("[t^='']").length ) { // The test attribute must be unknown in Opera but "safe" for WinRT
// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
if ( div.querySelectorAll("[msallowclip^='']").length ) {
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
} }
...@@ -1212,7 +1219,8 @@ setDocument = Sizzle.setDocument = function( node ) { ...@@ -1212,7 +1219,8 @@ setDocument = Sizzle.setDocument = function( node ) {
}); });
} }
if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector || if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
docElem.webkitMatchesSelector ||
docElem.mozMatchesSelector || docElem.mozMatchesSelector ||
docElem.oMatchesSelector || docElem.oMatchesSelector ||
docElem.msMatchesSelector) )) ) { docElem.msMatchesSelector) )) ) {
...@@ -1393,7 +1401,7 @@ Sizzle.matchesSelector = function( elem, expr ) { ...@@ -1393,7 +1401,7 @@ Sizzle.matchesSelector = function( elem, expr ) {
} catch(e) {} } catch(e) {}
} }
return Sizzle( expr, document, null, [elem] ).length > 0; return Sizzle( expr, document, null, [ elem ] ).length > 0;
}; };
Sizzle.contains = function( context, elem ) { Sizzle.contains = function( context, elem ) {
...@@ -1522,7 +1530,7 @@ Expr = Sizzle.selectors = { ...@@ -1522,7 +1530,7 @@ Expr = Sizzle.selectors = {
match[1] = match[1].replace( runescape, funescape ); match[1] = match[1].replace( runescape, funescape );
// Move the given value to match[3] whether quoted or unquoted // Move the given value to match[3] whether quoted or unquoted
match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
if ( match[2] === "~=" ) { if ( match[2] === "~=" ) {
match[3] = " " + match[3] + " "; match[3] = " " + match[3] + " ";
...@@ -1565,15 +1573,15 @@ Expr = Sizzle.selectors = { ...@@ -1565,15 +1573,15 @@ Expr = Sizzle.selectors = {
"PSEUDO": function( match ) { "PSEUDO": function( match ) {
var excess, var excess,
unquoted = !match[5] && match[2]; unquoted = !match[6] && match[2];
if ( matchExpr["CHILD"].test( match[0] ) ) { if ( matchExpr["CHILD"].test( match[0] ) ) {
return null; return null;
} }
// Accept quoted arguments as-is // Accept quoted arguments as-is
if ( match[3] && match[4] !== undefined ) { if ( match[3] ) {
match[2] = match[4]; match[2] = match[4] || match[5] || "";
// Strip excess characters from unquoted arguments // Strip excess characters from unquoted arguments
} else if ( unquoted && rpseudo.test( unquoted ) && } else if ( unquoted && rpseudo.test( unquoted ) &&
...@@ -1978,7 +1986,7 @@ function setFilters() {} ...@@ -1978,7 +1986,7 @@ function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos; setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters(); Expr.setFilters = new setFilters();
function tokenize( selector, parseOnly ) { tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
var matched, match, tokens, type, var matched, match, tokens, type,
soFar, groups, preFilters, soFar, groups, preFilters,
cached = tokenCache[ selector + " " ]; cached = tokenCache[ selector + " " ];
...@@ -2043,7 +2051,7 @@ function tokenize( selector, parseOnly ) { ...@@ -2043,7 +2051,7 @@ function tokenize( selector, parseOnly ) {
Sizzle.error( selector ) : Sizzle.error( selector ) :
// Cache the tokens // Cache the tokens
tokenCache( selector, groups ).slice( 0 ); tokenCache( selector, groups ).slice( 0 );
} };
function toSelector( tokens ) { function toSelector( tokens ) {
var i = 0, var i = 0,
...@@ -2122,6 +2130,15 @@ function elementMatcher( matchers ) { ...@@ -2122,6 +2130,15 @@ function elementMatcher( matchers ) {
matchers[0]; matchers[0];
} }
function multipleContexts( selector, contexts, results ) {
var i = 0,
len = contexts.length;
for ( ; i < len; i++ ) {
Sizzle( selector, contexts[i], results );
}
return results;
}
function condense( unmatched, map, filter, context, xml ) { function condense( unmatched, map, filter, context, xml ) {
var elem, var elem,
newUnmatched = [], newUnmatched = [],
...@@ -2390,7 +2407,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) { ...@@ -2390,7 +2407,7 @@ function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
superMatcher; superMatcher;
} }
compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
var i, var i,
setMatchers = [], setMatchers = [],
elementMatchers = [], elementMatchers = [],
...@@ -2398,12 +2415,12 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { ...@@ -2398,12 +2415,12 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
if ( !cached ) { if ( !cached ) {
// Generate a function of recursive functions that can be used to check each element // Generate a function of recursive functions that can be used to check each element
if ( !group ) { if ( !match ) {
group = tokenize( selector ); match = tokenize( selector );
} }
i = group.length; i = match.length;
while ( i-- ) { while ( i-- ) {
cached = matcherFromTokens( group[i] ); cached = matcherFromTokens( match[i] );
if ( cached[ expando ] ) { if ( cached[ expando ] ) {
setMatchers.push( cached ); setMatchers.push( cached );
} else { } else {
...@@ -2413,74 +2430,83 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { ...@@ -2413,74 +2430,83 @@ compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
// Cache the compiled function // Cache the compiled function
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
// Save selector and tokenization
cached.selector = selector;
} }
return cached; return cached;
}; };
function multipleContexts( selector, contexts, results ) { /**
var i = 0, * A low-level selection function that works with Sizzle's compiled
len = contexts.length; * selector functions
for ( ; i < len; i++ ) { * @param {String|Function} selector A selector or a pre-compiled
Sizzle( selector, contexts[i], results ); * selector function built with Sizzle.compile
} * @param {Element} context
return results; * @param {Array} [results]
} * @param {Array} [seed] A set of elements to match against
*/
function select( selector, context, results, seed ) { select = Sizzle.select = function( selector, context, results, seed ) {
var i, tokens, token, type, find, var i, tokens, token, type, find,
match = tokenize( selector ); compiled = typeof selector === "function" && selector,
match = !seed && tokenize( (selector = compiled.selector || selector) );
results = results || [];
if ( !seed ) { // Try to minimize operations if there is no seed and only one group
// Try to minimize operations if there is only one group if ( match.length === 1 ) {
if ( match.length === 1 ) {
// Take a shortcut and set the context if the root selector is an ID // Take a shortcut and set the context if the root selector is an ID
tokens = match[0] = match[0].slice( 0 ); tokens = match[0] = match[0].slice( 0 );
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
support.getById && context.nodeType === 9 && documentIsHTML && support.getById && context.nodeType === 9 && documentIsHTML &&
Expr.relative[ tokens[1].type ] ) { Expr.relative[ tokens[1].type ] ) {
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
if ( !context ) { if ( !context ) {
return results; return results;
}
selector = selector.slice( tokens.shift().value.length ); // Precompiled matchers will still verify ancestry, so step up a level
} else if ( compiled ) {
context = context.parentNode;
} }
// Fetch a seed set for right-to-left matching selector = selector.slice( tokens.shift().value.length );
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; }
while ( i-- ) {
token = tokens[i];
// Abort if we hit a combinator // Fetch a seed set for right-to-left matching
if ( Expr.relative[ (type = token.type) ] ) { i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
break; while ( i-- ) {
} token = tokens[i];
if ( (find = Expr.find[ type ]) ) {
// Search, expanding context for leading sibling combinators
if ( (seed = find(
token.matches[0].replace( runescape, funescape ),
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
)) ) {
// If seed is empty or no tokens remain, we can return early
tokens.splice( i, 1 );
selector = seed.length && toSelector( tokens );
if ( !selector ) {
push.apply( results, seed );
return results;
}
break; // Abort if we hit a combinator
if ( Expr.relative[ (type = token.type) ] ) {
break;
}
if ( (find = Expr.find[ type ]) ) {
// Search, expanding context for leading sibling combinators
if ( (seed = find(
token.matches[0].replace( runescape, funescape ),
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
)) ) {
// If seed is empty or no tokens remain, we can return early
tokens.splice( i, 1 );
selector = seed.length && toSelector( tokens );
if ( !selector ) {
push.apply( results, seed );
return results;
} }
break;
} }
} }
} }
} }
// Compile and execute a filtering function // Compile and execute a filtering function if one is not provided
// Provide `match` to avoid retokenization if we modified the selector above // Provide `match` to avoid retokenization if we modified the selector above
compile( selector, match )( ( compiled || compile( selector, match ) )(
seed, seed,
context, context,
!documentIsHTML, !documentIsHTML,
...@@ -2488,7 +2514,7 @@ function select( selector, context, results, seed ) { ...@@ -2488,7 +2514,7 @@ function select( selector, context, results, seed ) {
rsibling.test( selector ) && testContext( context.parentNode ) || context rsibling.test( selector ) && testContext( context.parentNode ) || context
); );
return results; return results;
} };
// One-time assignments // One-time assignments
...@@ -3365,8 +3391,9 @@ jQuery.extend({ ...@@ -3365,8 +3391,9 @@ jQuery.extend({
readyList.resolveWith( document, [ jQuery ] ); readyList.resolveWith( document, [ jQuery ] );
// Trigger any bound ready events // Trigger any bound ready events
if ( jQuery.fn.trigger ) { if ( jQuery.fn.triggerHandler ) {
jQuery( document ).trigger("ready").off("ready"); jQuery( document ).triggerHandler( "ready" );
jQuery( document ).off( "ready" );
} }
} }
}); });
...@@ -3738,11 +3765,15 @@ jQuery.fn.extend({ ...@@ -3738,11 +3765,15 @@ jQuery.fn.extend({
if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) { if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
i = attrs.length; i = attrs.length;
while ( i-- ) { while ( i-- ) {
name = attrs[ i ].name;
if ( name.indexOf( "data-" ) === 0 ) { // Support: IE11+
name = jQuery.camelCase( name.slice(5) ); // The attrs elements can be null (#14894)
dataAttr( elem, name, data[ name ] ); if ( attrs[ i ] ) {
name = attrs[ i ].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = jQuery.camelCase( name.slice(5) );
dataAttr( elem, name, data[ name ] );
}
} }
} }
data_priv.set( elem, "hasDataAttrs", true ); data_priv.set( elem, "hasDataAttrs", true );
...@@ -3972,10 +4003,17 @@ var rcheckableType = (/^(?:checkbox|radio)$/i); ...@@ -3972,10 +4003,17 @@ var rcheckableType = (/^(?:checkbox|radio)$/i);
(function() { (function() {
var fragment = document.createDocumentFragment(), var fragment = document.createDocumentFragment(),
div = fragment.appendChild( document.createElement( "div" ) ); div = fragment.appendChild( document.createElement( "div" ) ),
input = document.createElement( "input" );
// #11217 - WebKit loses check when the name is after the checked attribute // #11217 - WebKit loses check when the name is after the checked attribute
div.innerHTML = "<input type='radio' checked='checked' name='t'/>"; // Support: Windows Web Apps (WWA)
// `name` and `type` need .setAttribute for WWA
input.setAttribute( "type", "radio" );
input.setAttribute( "checked", "checked" );
input.setAttribute( "name", "t" );
div.appendChild( input );
// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
// old WebKit doesn't clone checked state correctly in fragments // old WebKit doesn't clone checked state correctly in fragments
...@@ -3995,7 +4033,7 @@ support.focusinBubbles = "onfocusin" in window; ...@@ -3995,7 +4033,7 @@ support.focusinBubbles = "onfocusin" in window;
var var
rkeyEvent = /^key/, rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|contextmenu)|click/, rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
...@@ -4564,7 +4602,7 @@ jQuery.event = { ...@@ -4564,7 +4602,7 @@ jQuery.event = {
// Support: Firefox 20+ // Support: Firefox 20+
// Firefox doesn't alert if the returnValue field is not set. // Firefox doesn't alert if the returnValue field is not set.
if ( event.result !== undefined ) { if ( event.result !== undefined && event.originalEvent ) {
event.originalEvent.returnValue = event.result; event.originalEvent.returnValue = event.result;
} }
} }
...@@ -4615,9 +4653,9 @@ jQuery.Event = function( src, props ) { ...@@ -4615,9 +4653,9 @@ jQuery.Event = function( src, props ) {
// Events bubbling up the document may have been marked as prevented // Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value. // by a handler lower down the tree; reflect the correct value.
this.isDefaultPrevented = src.defaultPrevented || this.isDefaultPrevented = src.defaultPrevented ||
// Support: Android < 4.0
src.defaultPrevented === undefined && src.defaultPrevented === undefined &&
src.getPreventDefault && src.getPreventDefault() ? // Support: Android < 4.0
src.returnValue === false ?
returnTrue : returnTrue :
returnFalse; returnFalse;
...@@ -4664,7 +4702,14 @@ jQuery.Event.prototype = { ...@@ -4664,7 +4702,14 @@ jQuery.Event.prototype = {
} }
}, },
stopImmediatePropagation: function() { stopImmediatePropagation: function() {
var e = this.originalEvent;
this.isImmediatePropagationStopped = returnTrue; this.isImmediatePropagationStopped = returnTrue;
if ( e && e.stopImmediatePropagation ) {
e.stopImmediatePropagation();
}
this.stopPropagation(); this.stopPropagation();
} }
}; };
...@@ -4673,7 +4718,9 @@ jQuery.Event.prototype = { ...@@ -4673,7 +4718,9 @@ jQuery.Event.prototype = {
// Support: Chrome 15+ // Support: Chrome 15+
jQuery.each({ jQuery.each({
mouseenter: "mouseover", mouseenter: "mouseover",
mouseleave: "mouseout" mouseleave: "mouseout",
pointerenter: "pointerover",
pointerleave: "pointerout"
}, function( orig, fix ) { }, function( orig, fix ) {
jQuery.event.special[ orig ] = { jQuery.event.special[ orig ] = {
delegateType: fix, delegateType: fix,
...@@ -5098,7 +5145,7 @@ jQuery.extend({ ...@@ -5098,7 +5145,7 @@ jQuery.extend({
}, },
cleanData: function( elems ) { cleanData: function( elems ) {
var data, elem, events, type, key, j, var data, elem, type, key,
special = jQuery.event.special, special = jQuery.event.special,
i = 0; i = 0;
...@@ -5107,9 +5154,8 @@ jQuery.extend({ ...@@ -5107,9 +5154,8 @@ jQuery.extend({
key = elem[ data_priv.expando ]; key = elem[ data_priv.expando ];
if ( key && (data = data_priv.cache[ key ]) ) { if ( key && (data = data_priv.cache[ key ]) ) {
events = Object.keys( data.events || {} ); if ( data.events ) {
if ( events.length ) { for ( type in data.events ) {
for ( j = 0; (type = events[j]) !== undefined; j++ ) {
if ( special[ type ] ) { if ( special[ type ] ) {
jQuery.event.remove( elem, type ); jQuery.event.remove( elem, type );
...@@ -5412,14 +5458,15 @@ var iframe, ...@@ -5412,14 +5458,15 @@ var iframe,
*/ */
// Called only from within defaultDisplay // Called only from within defaultDisplay
function actualDisplay( name, doc ) { function actualDisplay( name, doc ) {
var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), var style,
elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
// getDefaultComputedStyle might be reliably used only on attached element // getDefaultComputedStyle might be reliably used only on attached element
display = window.getDefaultComputedStyle ? display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
// Use of this method is a temporary fix (more like optmization) until something better comes along, // Use of this method is a temporary fix (more like optmization) until something better comes along,
// since it was removed from specification and supported only in FF // since it was removed from specification and supported only in FF
window.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], "display" ); style.display : jQuery.css( elem[ 0 ], "display" );
// We don't have any data stored on the element, // We don't have any data stored on the element,
// so use "detach" method as fast way to get rid of the element // so use "detach" method as fast way to get rid of the element
...@@ -5542,28 +5589,32 @@ function addGetHookIf( conditionFn, hookFn ) { ...@@ -5542,28 +5589,32 @@ function addGetHookIf( conditionFn, hookFn ) {
(function() { (function() {
var pixelPositionVal, boxSizingReliableVal, var pixelPositionVal, boxSizingReliableVal,
// Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
divReset = "padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;" +
"-moz-box-sizing:content-box;box-sizing:content-box",
docElem = document.documentElement, docElem = document.documentElement,
container = document.createElement( "div" ), container = document.createElement( "div" ),
div = document.createElement( "div" ); div = document.createElement( "div" );
if ( !div.style ) {
return;
}
div.style.backgroundClip = "content-box"; div.style.backgroundClip = "content-box";
div.cloneNode( true ).style.backgroundClip = ""; div.cloneNode( true ).style.backgroundClip = "";
support.clearCloneStyle = div.style.backgroundClip === "content-box"; support.clearCloneStyle = div.style.backgroundClip === "content-box";
container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;" + container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
"margin-top:1px"; "position:absolute";
container.appendChild( div ); container.appendChild( div );
// Executing both pixelPosition & boxSizingReliable tests require only one layout // Executing both pixelPosition & boxSizingReliable tests require only one layout
// so they're executed at the same time to save the second computation. // so they're executed at the same time to save the second computation.
function computePixelPositionAndBoxSizingReliable() { function computePixelPositionAndBoxSizingReliable() {
// Support: Firefox, Android 2.3 (Prefixed box-sizing versions). div.style.cssText =
div.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" + // Support: Firefox<29, Android 2.3
"box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;" + // Vendor-prefix box-sizing
"position:absolute;top:1%"; "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
"box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
"border:1px;padding:1px;width:4px;position:absolute";
div.innerHTML = "";
docElem.appendChild( container ); docElem.appendChild( container );
var divStyle = window.getComputedStyle( div, null ); var divStyle = window.getComputedStyle( div, null );
...@@ -5573,9 +5624,10 @@ function addGetHookIf( conditionFn, hookFn ) { ...@@ -5573,9 +5624,10 @@ function addGetHookIf( conditionFn, hookFn ) {
docElem.removeChild( container ); docElem.removeChild( container );
} }
// Use window.getComputedStyle because jsdom on node.js will break without it. // Support: node.js jsdom
// Don't assume that getComputedStyle is a property of the global object
if ( window.getComputedStyle ) { if ( window.getComputedStyle ) {
jQuery.extend(support, { jQuery.extend( support, {
pixelPosition: function() { pixelPosition: function() {
// This test is executed only once but we still do memoizing // This test is executed only once but we still do memoizing
// since we can use the boxSizingReliable pre-computing. // since we can use the boxSizingReliable pre-computing.
...@@ -5597,7 +5649,13 @@ function addGetHookIf( conditionFn, hookFn ) { ...@@ -5597,7 +5649,13 @@ function addGetHookIf( conditionFn, hookFn ) {
// This support function is only executed once so no memoizing is needed. // This support function is only executed once so no memoizing is needed.
var ret, var ret,
marginDiv = div.appendChild( document.createElement( "div" ) ); marginDiv = div.appendChild( document.createElement( "div" ) );
marginDiv.style.cssText = div.style.cssText = divReset;
// Reset CSS: box-sizing; display; margin; border; padding
marginDiv.style.cssText = div.style.cssText =
// Support: Firefox<29, Android 2.3
// Vendor-prefix box-sizing
"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
marginDiv.style.marginRight = marginDiv.style.width = "0"; marginDiv.style.marginRight = marginDiv.style.width = "0";
div.style.width = "1px"; div.style.width = "1px";
docElem.appendChild( container ); docElem.appendChild( container );
...@@ -5606,9 +5664,6 @@ function addGetHookIf( conditionFn, hookFn ) { ...@@ -5606,9 +5664,6 @@ function addGetHookIf( conditionFn, hookFn ) {
docElem.removeChild( container ); docElem.removeChild( container );
// Clean up the div for other support tests.
div.innerHTML = "";
return ret; return ret;
} }
}); });
...@@ -5647,8 +5702,8 @@ var ...@@ -5647,8 +5702,8 @@ var
cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = { cssNormalTransform = {
letterSpacing: 0, letterSpacing: "0",
fontWeight: 400 fontWeight: "400"
}, },
cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
...@@ -5795,13 +5850,10 @@ function showHide( elements, show ) { ...@@ -5795,13 +5850,10 @@ function showHide( elements, show ) {
values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) ); values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
} }
} else { } else {
hidden = isHidden( elem );
if ( !values[ index ] ) { if ( display !== "none" || !hidden ) {
hidden = isHidden( elem ); data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
if ( display && display !== "none" || !hidden ) {
data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
}
} }
} }
} }
...@@ -5840,6 +5892,8 @@ jQuery.extend({ ...@@ -5840,6 +5892,8 @@ jQuery.extend({
cssNumber: { cssNumber: {
"columnCount": true, "columnCount": true,
"fillOpacity": true, "fillOpacity": true,
"flexGrow": true,
"flexShrink": true,
"fontWeight": true, "fontWeight": true,
"lineHeight": true, "lineHeight": true,
"opacity": true, "opacity": true,
...@@ -5904,9 +5958,6 @@ jQuery.extend({ ...@@ -5904,9 +5958,6 @@ jQuery.extend({
// If a hook was provided, use that value, otherwise just set the specified value // If a hook was provided, use that value, otherwise just set the specified value
if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
// Support: Chrome, Safari
// Setting style to blank string required to delete "style: x !important;"
style[ name ] = "";
style[ name ] = value; style[ name ] = value;
} }
...@@ -5962,7 +6013,7 @@ jQuery.each([ "height", "width" ], function( i, name ) { ...@@ -5962,7 +6013,7 @@ jQuery.each([ "height", "width" ], function( i, name ) {
if ( computed ) { if ( computed ) {
// certain elements can have dimension info if we invisibly show them // certain elements can have dimension info if we invisibly show them
// however, it must have a current display style that would benefit from this // however, it must have a current display style that would benefit from this
return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ? return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
jQuery.swap( elem, cssShow, function() { jQuery.swap( elem, cssShow, function() {
return getWidthOrHeight( elem, name, extra ); return getWidthOrHeight( elem, name, extra );
}) : }) :
...@@ -6283,7 +6334,7 @@ function createTween( value, prop, animation ) { ...@@ -6283,7 +6334,7 @@ function createTween( value, prop, animation ) {
function defaultPrefilter( elem, props, opts ) { function defaultPrefilter( elem, props, opts ) {
/* jshint validthis: true */ /* jshint validthis: true */
var prop, value, toggle, tween, hooks, oldfire, display, var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
anim = this, anim = this,
orig = {}, orig = {},
style = elem.style, style = elem.style,
...@@ -6327,13 +6378,12 @@ function defaultPrefilter( elem, props, opts ) { ...@@ -6327,13 +6378,12 @@ function defaultPrefilter( elem, props, opts ) {
// Set display property to inline-block for height/width // Set display property to inline-block for height/width
// animations on inline elements that are having width/height animated // animations on inline elements that are having width/height animated
display = jQuery.css( elem, "display" ); display = jQuery.css( elem, "display" );
// Get default display if display is currently "none"
if ( display === "none" ) {
display = defaultDisplay( elem.nodeName );
}
if ( display === "inline" &&
jQuery.css( elem, "float" ) === "none" ) {
// Test default display if display is currently "none"
checkDisplay = display === "none" ?
data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
style.display = "inline-block"; style.display = "inline-block";
} }
} }
...@@ -6363,6 +6413,10 @@ function defaultPrefilter( elem, props, opts ) { ...@@ -6363,6 +6413,10 @@ function defaultPrefilter( elem, props, opts ) {
} }
} }
orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
// Any non-fx value stops us from restoring the original display value
} else {
display = undefined;
} }
} }
...@@ -6405,6 +6459,10 @@ function defaultPrefilter( elem, props, opts ) { ...@@ -6405,6 +6459,10 @@ function defaultPrefilter( elem, props, opts ) {
} }
} }
} }
// If this is a noop like .hide().hide(), restore an overwritten display value
} else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
style.display = display;
} }
} }
...@@ -7297,6 +7355,16 @@ jQuery.fn.extend({ ...@@ -7297,6 +7355,16 @@ jQuery.fn.extend({
jQuery.extend({ jQuery.extend({
valHooks: { valHooks: {
option: {
get: function( elem ) {
var val = jQuery.find.attr( elem, "value" );
return val != null ?
val :
// Support: IE10-11+
// option.text throws exceptions (#14686, #14858)
jQuery.trim( jQuery.text( elem ) );
}
},
select: { select: {
get: function( elem ) { get: function( elem ) {
var value, option, var value, option,
...@@ -7343,7 +7411,7 @@ jQuery.extend({ ...@@ -7343,7 +7411,7 @@ jQuery.extend({
while ( i-- ) { while ( i-- ) {
option = options[ i ]; option = options[ i ];
if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) { if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
optionSet = true; optionSet = true;
} }
} }
...@@ -8550,10 +8618,15 @@ jQuery.ajaxTransport(function( options ) { ...@@ -8550,10 +8618,15 @@ jQuery.ajaxTransport(function( options ) {
// Create the abort callback // Create the abort callback
callback = xhrCallbacks[ id ] = callback("abort"); callback = xhrCallbacks[ id ] = callback("abort");
// Do send the request try {
// This may raise an exception which is actually // Do send the request (this may raise an exception)
// handled in jQuery.ajax (so no try/catch here) xhr.send( options.hasContent && options.data || null );
xhr.send( options.hasContent && options.data || null ); } catch ( e ) {
// #14683: Only rethrow if this hasn't been notified as an error yet
if ( callback ) {
throw e;
}
}
}, },
abort: function() { abort: function() {
...@@ -8760,7 +8833,7 @@ jQuery.fn.load = function( url, params, callback ) { ...@@ -8760,7 +8833,7 @@ jQuery.fn.load = function( url, params, callback ) {
off = url.indexOf(" "); off = url.indexOf(" ");
if ( off >= 0 ) { if ( off >= 0 ) {
selector = url.slice( off ); selector = jQuery.trim( url.slice( off ) );
url = url.slice( 0, off ); url = url.slice( 0, off );
} }
...@@ -9068,6 +9141,12 @@ jQuery.fn.andSelf = jQuery.fn.addBack; ...@@ -9068,6 +9141,12 @@ jQuery.fn.andSelf = jQuery.fn.addBack;
// derived from file names, and jQuery is normally delivered in a lowercase // derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants // file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work. // to call noConflict to hide this version of jQuery, it will work.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
if ( typeof define === "function" && define.amd ) { if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() { define( "jquery", [], function() {
return jQuery; return jQuery;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment