# HG changeset patch
# User rougeronj
# Date 1421921780 -3600
# Node ID c0034b35c44e744d98bcf932e900590f1fa9966c
# Parent 9fcb0e0991ed67959b3d094100e15dc9492d26fd
merge + gulp + correction of superposition category-text
diff -r 9fcb0e0991ed -r c0034b35c44e annot-server/static/js/app.js
--- a/annot-server/static/js/app.js Thu Jan 22 10:30:36 2015 +0100
+++ b/annot-server/static/js/app.js Thu Jan 22 11:16:20 2015 +0100
@@ -219,7 +219,7 @@
user : $scope.username
};
sock.send(JSON.stringify(new_annot));
- if(context.logging===true){
+ if(context.logging===true){
log('Sent: ' + JSON.stringify(new_annot));
}
if(typeof c==='undefined'){
diff -r 9fcb0e0991ed -r c0034b35c44e annot-server/static/js/lib.js
--- a/annot-server/static/js/lib.js Thu Jan 22 10:30:36 2015 +0100
+++ b/annot-server/static/js/lib.js Thu Jan 22 11:16:20 2015 +0100
@@ -1,5 +1,5 @@
/*!
- * jQuery JavaScript Library v2.1.1
+ * jQuery JavaScript Library v2.1.3
* http://jquery.com/
*
* Includes Sizzle.js
@@ -9,19 +9,19 @@
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-05-01T17:11Z
+ * Date: 2014-12-18T15:11Z
*/
(function( global, factory ) {
if ( typeof module === "object" && typeof module.exports === "object" ) {
- // For CommonJS and CommonJS-like environments where a proper window is present,
- // execute the factory and get jQuery
- // For environments that do not inherently posses a window with a document
- // (such as Node.js), expose a jQuery-making factory as module.exports
- // This accentuates the need for the creation of a real window
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
- // See ticket #14549 for more info
+ // See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
@@ -37,10 +37,10 @@
// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
-// Can't do this because several apps including ASP.NET trace
+// Support: Firefox 18+
+// Can't be in strict mode, several libs including ASP.NET trace
// the stack via arguments.caller.callee and Firefox dies if
// you try to trace through "use strict" call chains. (#13335)
-// Support: Firefox 18+
//
var arr = [];
@@ -67,7 +67,7 @@
// Use the correct document accordingly with window argument (sandbox)
document = window.document,
- version = "2.1.1",
+ version = "2.1.3",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
@@ -185,7 +185,7 @@
if ( typeof target === "boolean" ) {
deep = target;
- // skip the boolean and the target
+ // Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
@@ -195,7 +195,7 @@
target = {};
}
- // extend jQuery itself if only one argument is passed
+ // Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
@@ -252,9 +252,6 @@
noop: function() {},
- // See test/unit/core.js for details concerning isFunction.
- // Since version 1.3, DOM methods and functions like alert
- // aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
return jQuery.type(obj) === "function";
},
@@ -269,7 +266,8 @@
// parseFloat NaNs numeric-cast false positives (null|true|false|"")
// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
// subtraction forces infinities to NaN
- return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
+ // adding 1 corrects loss of precision from parseFloat (#15100)
+ return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
},
isPlainObject: function( obj ) {
@@ -303,7 +301,7 @@
if ( obj == null ) {
return obj + "";
}
- // Support: Android < 4.0, iOS < 6 (functionish RegExp)
+ // Support: Android<4.0, iOS<6 (functionish RegExp)
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call(obj) ] || "object" :
typeof obj;
@@ -333,6 +331,7 @@
},
// Convert dashed to camelCase; used by the css and data modules
+ // Support: IE9-11+
// Microsoft forgot to hump their vendor prefix (#9572)
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
@@ -548,14 +547,14 @@
}
var Sizzle =
/*!
- * Sizzle CSS Selector Engine v1.10.19
+ * Sizzle CSS Selector Engine v2.2.0-pre
* http://sizzlejs.com/
*
- * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-04-18
+ * Date: 2014-12-16
*/
(function( window ) {
@@ -582,7 +581,7 @@
contains,
// Instance-specific data
- expando = "sizzle" + -(new Date()),
+ expando = "sizzle" + 1 * new Date(),
preferredDoc = window.document,
dirruns = 0,
done = 0,
@@ -597,7 +596,6 @@
},
// General-purpose constants
- strundefined = typeof undefined,
MAX_NEGATIVE = 1 << 31,
// Instance methods
@@ -607,12 +605,13 @@
push_native = arr.push,
push = arr.push,
slice = arr.slice,
- // Use a stripped-down indexOf if we can't use a native one
- indexOf = arr.indexOf || function( elem ) {
+ // Use a stripped-down indexOf as it's faster than native
+ // http://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
var i = 0,
- len = this.length;
+ len = list.length;
for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
+ if ( list[i] === elem ) {
return i;
}
}
@@ -652,6 +651,7 @@
")\\)|)",
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
@@ -703,6 +703,14 @@
String.fromCharCode( high + 0x10000 ) :
// Supplemental Plane codepoint (surrogate pair)
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
};
// Optimize for push.apply( _, NodeList )
@@ -745,19 +753,18 @@
context = context || document;
results = results || [];
-
- if ( !selector || typeof selector !== "string" ) {
+ nodeType = context.nodeType;
+
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
return results;
}
- if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- if ( documentIsHTML && !seed ) {
-
- // Shortcuts
- if ( (match = rquickExpr.exec( selector )) ) {
+ if ( !seed && documentIsHTML ) {
+
+ // Try to shortcut find operations when possible (e.g., not under DocumentFragment)
+ if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
// Speed-up: Sizzle("#ID")
if ( (m = match[1]) ) {
if ( nodeType === 9 ) {
@@ -789,7 +796,7 @@
return results;
// Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+ } else if ( (m = match[3]) && support.getElementsByClassName ) {
push.apply( results, context.getElementsByClassName( m ) );
return results;
}
@@ -799,7 +806,7 @@
if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
nid = old = expando;
newContext = context;
- newSelector = nodeType === 9 && selector;
+ newSelector = nodeType !== 1 && selector;
// qSA works strangely on Element-rooted queries
// We can work around this by specifying an extra ID on the root
@@ -986,7 +993,7 @@
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
*/
function testContext( context ) {
- return context && typeof context.getElementsByTagName !== strundefined && context;
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
}
// Expose support vars for convenience
@@ -1010,9 +1017,8 @@
* @returns {Object} Returns the current document
*/
setDocument = Sizzle.setDocument = function( node ) {
- var hasCompare,
- doc = node ? node.ownerDocument || node : preferredDoc,
- parent = doc.defaultView;
+ var hasCompare, parent,
+ doc = node ? node.ownerDocument || node : preferredDoc;
// If no document and documentElement is available, return
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
@@ -1022,9 +1028,7 @@
// Set our document
document = doc;
docElem = doc.documentElement;
-
- // Support tests
- documentIsHTML = !isXML( doc );
+ parent = doc.defaultView;
// Support: IE>8
// If iframe document is assigned to "document" variable and if iframe has been reloaded,
@@ -1033,21 +1037,22 @@
if ( parent && parent !== parent.top ) {
// IE11 does not have attachEvent, so all must suffer
if ( parent.addEventListener ) {
- parent.addEventListener( "unload", function() {
- setDocument();
- }, false );
+ parent.addEventListener( "unload", unloadHandler, false );
} else if ( parent.attachEvent ) {
- parent.attachEvent( "onunload", function() {
- setDocument();
- });
- }
- }
+ parent.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ /* Support tests
+ ---------------------------------------------------------------------- */
+ documentIsHTML = !isXML( doc );
/* Attributes
---------------------------------------------------------------------- */
// Support: IE<8
- // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
support.attributes = assert(function( div ) {
div.className = "i";
return !div.getAttribute("className");
@@ -1062,17 +1067,8 @@
return !div.getElementsByTagName("*").length;
});
- // Check if getElementsByClassName can be trusted
- support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
- div.innerHTML = "
";
-
- // Support: Safari<4
- // Catch class over-caching
- div.firstChild.className = "i";
- // Support: Opera<10
- // Catch gEBCN failure to find non-leading classes
- return div.getElementsByClassName("i").length === 2;
- });
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( doc.getElementsByClassName );
// Support: IE<10
// Check if getElementById returns elements by name
@@ -1086,7 +1082,7 @@
// ID find and filter
if ( support.getById ) {
Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var m = context.getElementById( id );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
@@ -1107,7 +1103,7 @@
Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
return node && node.value === attrId;
};
};
@@ -1116,14 +1112,20 @@
// Tag
Expr.find["TAG"] = support.getElementsByTagName ?
function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
}
} :
+
function( tag, context ) {
var elem,
tmp = [],
i = 0,
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
results = context.getElementsByTagName( tag );
// Filter out possible comments
@@ -1141,7 +1143,7 @@
// Class
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
- if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ if ( documentIsHTML ) {
return context.getElementsByClassName( className );
}
};
@@ -1170,13 +1172,15 @@
// setting a boolean content attribute,
// since its presence should be enough
// http://bugs.jquery.com/ticket/12359
- div.innerHTML = "";
+ docElem.appendChild( div ).innerHTML = "" +
+ "";
// Support: IE8, Opera 11-12.16
// Nothing should be selected when empty strings follow ^= or $= or *=
// 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 ) {
+ if ( div.querySelectorAll("[msallowcapture^='']").length ) {
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
}
@@ -1186,12 +1190,24 @@
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
}
+ // Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+
+ if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push("~=");
+ }
+
// Webkit/Opera - :checked should return selected option elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
// IE8 throws error here and will not see later tests
if ( !div.querySelectorAll(":checked").length ) {
rbuggyQSA.push(":checked");
}
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibing-combinator selector` fails
+ if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push(".#.+[+~]");
+ }
});
assert(function( div ) {
@@ -1308,7 +1324,7 @@
// Maintain original order
return sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
}
@@ -1335,7 +1351,7 @@
aup ? -1 :
bup ? 1 :
sortInput ?
- ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
// If the nodes are siblings, we can do a quick check
@@ -1398,7 +1414,7 @@
elem.document && elem.document.nodeType !== 11 ) {
return ret;
}
- } catch(e) {}
+ } catch (e) {}
}
return Sizzle( expr, document, null, [ elem ] ).length > 0;
@@ -1617,7 +1633,7 @@
return pattern ||
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
classCache( className, function( elem ) {
- return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
});
},
@@ -1639,7 +1655,7 @@
operator === "^=" ? check && result.indexOf( check ) === 0 :
operator === "*=" ? check && result.indexOf( check ) > -1 :
operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
false;
};
@@ -1759,7 +1775,7 @@
matched = fn( seed, argument ),
i = matched.length;
while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
+ idx = indexOf( seed, matched[i] );
seed[ idx ] = !( matches[ idx ] = matched[i] );
}
}) :
@@ -1798,6 +1814,8 @@
function( elem, context, xml ) {
input[0] = elem;
matcher( input, null, xml, results );
+ // Don't keep the element (issue #299)
+ input[0] = null;
return !results.pop();
};
}),
@@ -1809,6 +1827,7 @@
}),
"contains": markFunction(function( text ) {
+ text = text.replace( runescape, funescape );
return function( elem ) {
return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
};
@@ -2230,7 +2249,7 @@
i = matcherOut.length;
while ( i-- ) {
if ( (elem = matcherOut[i]) &&
- (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+ (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
seed[temp] = !(results[temp] = elem);
}
@@ -2265,13 +2284,16 @@
return elem === checkContext;
}, implicitRelative, true ),
matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
+ return indexOf( checkContext, elem ) > -1;
}, implicitRelative, true ),
matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
(checkContext = context).nodeType ?
matchContext( elem, context, xml ) :
matchAnyContext( elem, context, xml ) );
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
} ];
for ( ; i < len; i++ ) {
@@ -2521,7 +2543,7 @@
// Sort stability
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
-// Support: Chrome<14
+// Support: Chrome 14-35+
// Always assume duplicates if they aren't passed to the comparison function
support.detectDuplicates = !!hasDuplicate;
@@ -2730,7 +2752,7 @@
if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
- // scripts is true for back-compat
+ // Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge( this, jQuery.parseHTML(
match[1],
@@ -2758,8 +2780,8 @@
} else {
elem = document.getElementById( match[2] );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
+ // Support: Blackberry 4.6
+ // gEBID returns nodes no longer in the document (#6963)
if ( elem && elem.parentNode ) {
// Inject the element directly into the jQuery object
this.length = 1;
@@ -2812,7 +2834,7 @@
var rparentsprev = /^(?:parents|prev(?:Until|All))/,
- // methods guaranteed to produce a unique set when starting from a unique set
+ // Methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
children: true,
contents: true,
@@ -2892,8 +2914,7 @@
return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
},
- // Determine the position of an element within
- // the matched set of elements
+ // Determine the position of an element within the set
index: function( elem ) {
// No argument, return index in parent
@@ -2901,7 +2922,7 @@
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
- // index in selector
+ // Index in selector
if ( typeof elem === "string" ) {
return indexOf.call( jQuery( elem ), this[ 0 ] );
}
@@ -3317,7 +3338,7 @@
progressValues, progressContexts, resolveContexts;
- // add listeners to Deferred subordinates; treat others as resolved
+ // Add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
@@ -3334,7 +3355,7 @@
}
}
- // if we're not waiting on anything, resolve the master
+ // If we're not waiting on anything, resolve the master
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
@@ -3413,7 +3434,7 @@
readyList = jQuery.Deferred();
// Catch cases where $(document).ready() is called after the browser event has already occurred.
- // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // We once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
@@ -3507,7 +3528,7 @@
function Data() {
- // Support: Android < 4,
+ // Support: Android<4,
// Old WebKit does not have Object.preventExtensions/freeze method,
// return new empty object instead with no [[set]] accessor
Object.defineProperty( this.cache = {}, 0, {
@@ -3516,7 +3537,7 @@
}
});
- this.expando = jQuery.expando + Math.random();
+ this.expando = jQuery.expando + Data.uid++;
}
Data.uid = 1;
@@ -3544,7 +3565,7 @@
descriptor[ this.expando ] = { value: unlock };
Object.defineProperties( owner, descriptor );
- // Support: Android < 4
+ // Support: Android<4
// Fallback to a less secure definition
} catch ( e ) {
descriptor[ this.expando ] = unlock;
@@ -3684,17 +3705,16 @@
-/*
- Implementation Summary
-
- 1. Enforce API surface and semantic compatibility with 1.9.x branch
- 2. Improve the module's maintainability by reducing the storage
- paths to a single mechanism.
- 3. Use the same single mechanism to support "private" and "user" data.
- 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
- 5. Avoid exposing implementation details on user objects (eg. expando properties)
- 6. Provide a clear path for implementation upgrade to WeakMap in 2014
-*/
+// Implementation Summary
+//
+// 1. Enforce API surface and semantic compatibility with 1.9.x branch
+// 2. Improve the module's maintainability by reducing the storage
+// paths to a single mechanism.
+// 3. Use the same single mechanism to support "private" and "user" data.
+// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+// 5. Avoid exposing implementation details on user objects (eg. expando properties)
+// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
+
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
rmultiDash = /([A-Z])/g;
@@ -3899,7 +3919,7 @@
queue.unshift( "inprogress" );
}
- // clear up the last queue stop function
+ // Clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next, hooks );
}
@@ -3909,7 +3929,7 @@
}
},
- // not intended for public consumption - generates a queueHooks object, or returns the current one
+ // Not public - generate a queueHooks object, or return the current one
_queueHooks: function( elem, type ) {
var key = type + "queueHooks";
return data_priv.get( elem, key ) || data_priv.access( elem, key, {
@@ -3939,7 +3959,7 @@
this.each(function() {
var queue = jQuery.queue( this, type, data );
- // ensure a hooks for this queue
+ // Ensure a hooks for this queue
jQuery._queueHooks( this, type );
if ( type === "fx" && queue[0] !== "inprogress" ) {
@@ -4006,21 +4026,22 @@
div = fragment.appendChild( document.createElement( "div" ) ),
input = document.createElement( "input" );
- // #11217 - WebKit loses check when the name is after the checked attribute
+ // Support: Safari<=5.1
+ // Check state lost if the name is set (#11217)
// Support: Windows Web Apps (WWA)
- // `name` and `type` need .setAttribute for WWA
+ // `name` and `type` must use .setAttribute for WWA (#14901)
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
- // old WebKit doesn't clone checked state correctly in fragments
+ // Support: Safari<=5.1, Android<4.2
+ // Older WebKit doesn't clone checked state correctly in fragments
support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+ // Support: IE<=11+
// Make sure textarea (and checkbox) defaultValue is properly cloned
- // Support: IE9-IE11+
div.innerHTML = "";
support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
})();
@@ -4398,8 +4419,8 @@
j = 0;
while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
- // Triggered event must either 1) have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ // Triggered event must either 1) have no namespace, or 2) have namespace(s)
+ // a subset or equal to those in the bound event (both can have no namespace).
if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
event.handleObj = handleObj;
@@ -4549,7 +4570,7 @@
event.target = document;
}
- // Support: Safari 6.0+, Chrome < 28
+ // Support: Safari 6.0+, Chrome<28
// Target should not be a text node (#504, #13143)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
@@ -4654,7 +4675,7 @@
// by a handler lower down the tree; reflect the correct value.
this.isDefaultPrevented = src.defaultPrevented ||
src.defaultPrevented === undefined &&
- // Support: Android < 4.0
+ // Support: Android<4.0
src.returnValue === false ?
returnTrue :
returnFalse;
@@ -4744,8 +4765,8 @@
};
});
+// Support: Firefox, Chrome, Safari
// Create "bubbling" focus and blur events
-// Support: Firefox, Chrome, Safari
if ( !support.focusinBubbles ) {
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
@@ -4898,7 +4919,7 @@
// We have to close these tags to support XHTML (#13200)
wrapMap = {
- // Support: IE 9
+ // Support: IE9
option: [ 1, "" ],
thead: [ 1, "
", "
" ],
@@ -4909,7 +4930,7 @@
_default: [ 0, "", "" ]
};
-// Support: IE 9
+// Support: IE9
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
@@ -4999,7 +5020,7 @@
ret;
}
-// Support: IE >= 9
+// Fix IE bugs, see support tests
function fixInput( src, dest ) {
var nodeName = dest.nodeName.toLowerCase();
@@ -5019,8 +5040,7 @@
clone = elem.cloneNode( true ),
inPage = jQuery.contains( elem.ownerDocument, elem );
- // Support: IE >= 9
- // Fix Cloning issues
+ // Fix IE cloning issues
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
!jQuery.isXMLDoc( elem ) ) {
@@ -5071,8 +5091,8 @@
// Add nodes directly
if ( jQuery.type( elem ) === "object" ) {
- // Support: QtWebKit
- // jQuery.merge because push.apply(_, arraylike) throws
+ // Support: QtWebKit, PhantomJS
+ // push.apply(_, arraylike) throws on ancient WebKit
jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
// Convert non-html into a text node
@@ -5094,15 +5114,14 @@
tmp = tmp.lastChild;
}
- // Support: QtWebKit
- // jQuery.merge because push.apply(_, arraylike) throws
+ // Support: QtWebKit, PhantomJS
+ // push.apply(_, arraylike) throws on ancient WebKit
jQuery.merge( nodes, tmp.childNodes );
// Remember the top-level container
tmp = fragment.firstChild;
- // Fixes #12346
- // Support: Webkit, IE
+ // Ensure the created nodes are orphaned (#12392)
tmp.textContent = "";
}
}
@@ -5464,7 +5483,7 @@
// getDefaultComputedStyle might be reliably used only on attached element
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 optimization) until something better comes along,
// since it was removed from specification and supported only in FF
style.display : jQuery.css( elem[ 0 ], "display" );
@@ -5514,7 +5533,14 @@
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
var getStyles = function( elem ) {
- return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+ // Support: IE<=11+, Firefox<=30+ (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ if ( elem.ownerDocument.defaultView.opener ) {
+ return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+ }
+
+ return window.getComputedStyle( elem, null );
};
@@ -5526,7 +5552,7 @@
computed = computed || getStyles( elem );
// Support: IE9
- // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ // getPropertyValue is only needed for .css('filter') (#12537)
if ( computed ) {
ret = computed.getPropertyValue( name ) || computed[ name ];
}
@@ -5572,15 +5598,13 @@
return {
get: function() {
if ( conditionFn() ) {
- // Hook not needed (or it's not possible to use it due to missing dependency),
- // remove it.
- // Since there are no other hooks for marginRight, remove the whole object.
+ // Hook not needed (or it's not possible to use it due
+ // to missing dependency), remove it.
delete this.get;
return;
}
// Hook needed; redefine it so that the support test is not executed again.
-
return (this.get = hookFn).apply( this, arguments );
}
};
@@ -5597,6 +5621,8 @@
return;
}
+ // Support: IE9-11+
+ // Style of cloned element affects source element cloned (#8908)
div.style.backgroundClip = "content-box";
div.cloneNode( true ).style.backgroundClip = "";
support.clearCloneStyle = div.style.backgroundClip === "content-box";
@@ -5629,6 +5655,7 @@
if ( window.getComputedStyle ) {
jQuery.extend( support, {
pixelPosition: function() {
+
// This test is executed only once but we still do memoizing
// since we can use the boxSizingReliable pre-computing.
// No need to check if the test was already performed, though.
@@ -5642,6 +5669,7 @@
return boxSizingReliableVal;
},
reliableMarginRight: function() {
+
// Support: Android 2.3
// Check if div with explicit width and no margin-right incorrectly
// gets computed margin-right based on width of container. (#3333)
@@ -5663,6 +5691,7 @@
ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
docElem.removeChild( container );
+ div.removeChild( marginDiv );
return ret;
}
@@ -5694,8 +5723,8 @@
var
- // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
- // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ // Swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
@@ -5708,15 +5737,15 @@
cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
-// return a css property mapped to a potentially vendor prefixed property
+// Return a css property mapped to a potentially vendor prefixed property
function vendorPropName( style, name ) {
- // shortcut for names that are not vendor prefixed
+ // Shortcut for names that are not vendor prefixed
if ( name in style ) {
return name;
}
- // check for vendor prefixed names
+ // Check for vendor prefixed names
var capName = name[0].toUpperCase() + name.slice(1),
origName = name,
i = cssPrefixes.length;
@@ -5749,7 +5778,7 @@
val = 0;
for ( ; i < 4; i += 2 ) {
- // both box models exclude margin, so add it if we want it
+ // Both box models exclude margin, so add it if we want it
if ( extra === "margin" ) {
val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
}
@@ -5760,15 +5789,15 @@
val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
}
- // at this point, extra isn't border nor margin, so remove border
+ // At this point, extra isn't border nor margin, so remove border
if ( extra !== "margin" ) {
val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
} else {
- // at this point, extra isn't content, so add padding
+ // At this point, extra isn't content, so add padding
val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
- // at this point, extra isn't content nor padding, so add border
+ // At this point, extra isn't content nor padding, so add border
if ( extra !== "padding" ) {
val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
@@ -5786,7 +5815,7 @@
styles = getStyles( elem ),
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
- // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // Some non-html elements return undefined for offsetWidth, so check for null/undefined
// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
if ( val <= 0 || val == null ) {
@@ -5801,7 +5830,7 @@
return val;
}
- // we need the check for style in case a browser which returns unreliable values
+ // Check for style in case a browser which returns unreliable values
// for getComputedStyle silently falls back to the reliable elem.style
valueIsBorderBox = isBorderBox &&
( support.boxSizingReliable() || val === elem.style[ name ] );
@@ -5810,7 +5839,7 @@
val = parseFloat( val ) || 0;
}
- // use the active box-sizing model to add/subtract irrelevant styles
+ // Use the active box-sizing model to add/subtract irrelevant styles
return ( val +
augmentWidthOrHeight(
elem,
@@ -5874,12 +5903,14 @@
}
jQuery.extend({
+
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
cssHooks: {
opacity: {
get: function( elem, computed ) {
if ( computed ) {
+
// We should always get a number back from opacity
var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
@@ -5907,12 +5938,12 @@
// Add in properties whose names you wish to fix before
// setting or getting the value
cssProps: {
- // normalize float css property
"float": "cssFloat"
},
// Get and set the style property on a DOM Node
style: function( elem, name, value, extra ) {
+
// Don't set styles on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
return;
@@ -5925,33 +5956,32 @@
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
- // gets hook for the prefixed version
- // followed by the unprefixed version
+ // Gets hook for the prefixed version, then unprefixed version
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// Check if we're setting a value
if ( value !== undefined ) {
type = typeof value;
- // convert relative number strings (+= or -=) to relative numbers. #7345
+ // Convert "+=" or "-=" to relative numbers (#7345)
if ( type === "string" && (ret = rrelNum.exec( value )) ) {
value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
// Fixes bug #9237
type = "number";
}
- // Make sure that null and NaN values aren't set. See: #7116
+ // Make sure that null and NaN values aren't set (#7116)
if ( value == null || value !== value ) {
return;
}
- // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ // If a number, add 'px' to the (except for certain CSS properties)
if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
value += "px";
}
- // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
- // but it would mean to define eight (for every problematic property) identical functions
+ // Support: IE9-11+
+ // background-* props affect original clone's values
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
style[ name ] = "inherit";
}
@@ -5979,8 +6009,7 @@
// Make sure that we're working with the right name
name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
- // gets hook for the prefixed version
- // followed by the unprefixed version
+ // Try prefixed name followed by the unprefixed name
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// If a hook was provided get the computed value from there
@@ -5993,12 +6022,12 @@
val = curCSS( elem, name, styles );
}
- //convert "normal" to computed value
+ // Convert "normal" to computed value
if ( val === "normal" && name in cssNormalTransform ) {
val = cssNormalTransform[ name ];
}
- // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ // Make numeric if forced or a qualifier was provided and val looks numeric
if ( extra === "" || extra ) {
num = parseFloat( val );
return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
@@ -6011,8 +6040,9 @@
jQuery.cssHooks[ name ] = {
get: function( elem, computed, extra ) {
if ( computed ) {
- // certain elements can have dimension info if we invisibly show them
- // however, it must have a current display style that would benefit from this
+
+ // Certain elements can have dimension info if we invisibly show them
+ // but it must have a current display style that would benefit
return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
jQuery.swap( elem, cssShow, function() {
return getWidthOrHeight( elem, name, extra );
@@ -6040,8 +6070,6 @@
jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
function( elem, computed ) {
if ( computed ) {
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- // Work around by temporarily setting element display to inline-block
return jQuery.swap( elem, { "display": "inline-block" },
curCSS, [ elem, "marginRight" ] );
}
@@ -6059,7 +6087,7 @@
var i = 0,
expanded = {},
- // assumes a single number if not a string
+ // Assumes a single number if not a string
parts = typeof value === "string" ? value.split(" ") : [ value ];
for ( ; i < 4; i++ ) {
@@ -6182,17 +6210,18 @@
return tween.elem[ tween.prop ];
}
- // passing an empty string as a 3rd parameter to .css will automatically
- // attempt a parseFloat and fallback to a string if the parse fails
- // so, simple values such as "10px" are parsed to Float.
- // complex values such as "rotate(1rad)" are returned as is.
+ // Passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails.
+ // Simple values such as "10px" are parsed to Float;
+ // complex values such as "rotate(1rad)" are returned as-is.
result = jQuery.css( tween.elem, tween.prop, "" );
// Empty strings, null, undefined and "auto" are converted to 0.
return !result || result === "auto" ? 0 : result;
},
set: function( tween ) {
- // use step hook for back compat - use cssHook if its there - use .style if its
- // available and use plain properties where available
+ // Use step hook for back compat.
+ // Use cssHook if its there.
+ // Use .style if available and use plain properties where available.
if ( jQuery.fx.step[ tween.prop ] ) {
jQuery.fx.step[ tween.prop ]( tween );
} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
@@ -6206,7 +6235,6 @@
// Support: IE9
// Panic based approach to setting things on disconnected nodes
-
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
set: function( tween ) {
if ( tween.elem.nodeType && tween.elem.parentNode ) {
@@ -6262,16 +6290,16 @@
start = +target || 1;
do {
- // If previous iteration zeroed out, double until we get *something*
- // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ // If previous iteration zeroed out, double until we get *something*.
+ // Use string for doubling so we don't accidentally see scale as unchanged below
scale = scale || ".5";
// Adjust and apply
start = start / scale;
jQuery.style( tween.elem, prop, start + unit );
- // Update scale, tolerating zero or NaN from tween.cur()
- // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ // Update scale, tolerating zero or NaN from tween.cur(),
+ // break the loop if scale is unchanged or perfect, or if we've just had enough
} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
}
@@ -6303,8 +6331,8 @@
i = 0,
attrs = { height: type };
- // if we include width, step value is 1 to do all cssExpand values,
- // if we don't include width, step value is 2 to skip over Left and Right
+ // If we include width, step value is 1 to do all cssExpand values,
+ // otherwise step value is 2 to skip over Left and Right
includeWidth = includeWidth ? 1 : 0;
for ( ; i < 4 ; i += 2 - includeWidth ) {
which = cssExpand[ i ];
@@ -6326,7 +6354,7 @@
for ( ; index < length; index++ ) {
if ( (tween = collection[ index ].call( animation, prop, value )) ) {
- // we're done with this property
+ // We're done with this property
return tween;
}
}
@@ -6341,7 +6369,7 @@
hidden = elem.nodeType && isHidden( elem ),
dataShow = data_priv.get( elem, "fxshow" );
- // handle queue: false promises
+ // Handle queue: false promises
if ( !opts.queue ) {
hooks = jQuery._queueHooks( elem, "fx" );
if ( hooks.unqueued == null ) {
@@ -6356,8 +6384,7 @@
hooks.unqueued++;
anim.always(function() {
- // doing this makes sure that the complete handler will be called
- // before this completes
+ // Ensure the complete handler is called before this completes
anim.always(function() {
hooks.unqueued--;
if ( !jQuery.queue( elem, "fx" ).length ) {
@@ -6367,7 +6394,7 @@
});
}
- // height/width overflow pass
+ // Height/width overflow pass
if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
// Make sure that nothing sneaks out
// Record all 3 overflow attributes because IE9-10 do not
@@ -6429,7 +6456,7 @@
dataShow = data_priv.access( elem, "fxshow", {} );
}
- // store state if its toggle - enables .stop().toggle() to "reverse"
+ // Store state if its toggle - enables .stop().toggle() to "reverse"
if ( toggle ) {
dataShow.hidden = !hidden;
}
@@ -6489,8 +6516,8 @@
value = hooks.expand( value );
delete props[ name ];
- // not quite $.extend, this wont overwrite keys already present.
- // also - reusing 'index' from above because we have the correct "name"
+ // Not quite $.extend, this won't overwrite existing keys.
+ // Reusing 'index' because we have the correct "name"
for ( index in value ) {
if ( !( index in props ) ) {
props[ index ] = value[ index ];
@@ -6509,7 +6536,7 @@
index = 0,
length = animationPrefilters.length,
deferred = jQuery.Deferred().always( function() {
- // don't match elem in the :animated selector
+ // Don't match elem in the :animated selector
delete tick.elem;
}),
tick = function() {
@@ -6518,7 +6545,8 @@
}
var currentTime = fxNow || createFxNow(),
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
- // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ // Support: Android 2.3
+ // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
temp = remaining / animation.duration || 0,
percent = 1 - temp,
index = 0,
@@ -6554,7 +6582,7 @@
},
stop: function( gotoEnd ) {
var index = 0,
- // if we are going to the end, we want to run all the tweens
+ // If we are going to the end, we want to run all the tweens
// otherwise we skip this part
length = gotoEnd ? animation.tweens.length : 0;
if ( stopped ) {
@@ -6565,8 +6593,7 @@
animation.tweens[ index ].run( 1 );
}
- // resolve when we played the last frame
- // otherwise, reject
+ // Resolve when we played the last frame; otherwise, reject
if ( gotoEnd ) {
deferred.resolveWith( elem, [ animation, gotoEnd ] );
} else {
@@ -6648,7 +6675,7 @@
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
- // normalize opt.queue - true/undefined/null -> "fx"
+ // Normalize opt.queue - true/undefined/null -> "fx"
if ( opt.queue == null || opt.queue === true ) {
opt.queue = "fx";
}
@@ -6672,10 +6699,10 @@
jQuery.fn.extend({
fadeTo: function( speed, to, easing, callback ) {
- // show any hidden elements after setting opacity to 0
+ // Show any hidden elements after setting opacity to 0
return this.filter( isHidden ).css( "opacity", 0 ).show()
- // animate to the value specified
+ // Animate to the value specified
.end().animate({ opacity: to }, speed, easing, callback );
},
animate: function( prop, speed, easing, callback ) {
@@ -6738,9 +6765,9 @@
}
}
- // start the next in the queue if the last step wasn't forced
- // timers currently will call their complete callbacks, which will dequeue
- // but only if they were gotoEnd
+ // Start the next in the queue if the last step wasn't forced.
+ // Timers currently will call their complete callbacks, which
+ // will dequeue but only if they were gotoEnd.
if ( dequeue || !gotoEnd ) {
jQuery.dequeue( this, type );
}
@@ -6758,17 +6785,17 @@
timers = jQuery.timers,
length = queue ? queue.length : 0;
- // enable finishing flag on private data
+ // Enable finishing flag on private data
data.finish = true;
- // empty the queue first
+ // Empty the queue first
jQuery.queue( this, type, [] );
if ( hooks && hooks.stop ) {
hooks.stop.call( this, true );
}
- // look for any active animations, and finish them
+ // Look for any active animations, and finish them
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
timers[ index ].anim.stop( true );
@@ -6776,14 +6803,14 @@
}
}
- // look for any animations in the old queue and finish them
+ // Look for any animations in the old queue and finish them
for ( index = 0; index < length; index++ ) {
if ( queue[ index ] && queue[ index ].finish ) {
queue[ index ].finish.call( this );
}
}
- // turn off finishing flag
+ // Turn off finishing flag
delete data.finish;
});
}
@@ -6886,21 +6913,21 @@
input.type = "checkbox";
- // Support: iOS 5.1, Android 4.x, Android 2.3
- // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
+ // Support: iOS<=5.1, Android<=4.2+
+ // Default value for a checkbox should be "on"
support.checkOn = input.value !== "";
- // Must access the parent to make an option select properly
- // Support: IE9, IE10
+ // Support: IE<=11+
+ // Must access selectedIndex to make default options select
support.optSelected = opt.selected;
- // Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as disabled)
+ // Support: Android<=2.3
+ // Options inside disabled selects are incorrectly marked as disabled
select.disabled = true;
support.optDisabled = !opt.disabled;
- // Check if an input maintains its value after becoming a radio
- // Support: IE9, IE10
+ // Support: IE<=11+
+ // An input loses its value after becoming a radio
input = document.createElement( "input" );
input.value = "t";
input.type = "radio";
@@ -6997,8 +7024,6 @@
set: function( elem, value ) {
if ( !support.radioValue && value === "radio" &&
jQuery.nodeName( elem, "input" ) ) {
- // Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to default in case type is set after value during creation
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
@@ -7068,7 +7093,7 @@
var ret, hooks, notxml,
nType = elem.nodeType;
- // don't get/set properties on text, comment and attribute nodes
+ // Don't get/set properties on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
return;
}
@@ -7104,8 +7129,6 @@
}
});
-// Support: IE9+
-// Selectedness for an option in an optgroup can be inaccurate
if ( !support.optSelected ) {
jQuery.propHooks.selected = {
get: function( elem ) {
@@ -7213,7 +7236,7 @@
}
}
- // only assign if different to avoid unneeded rendering.
+ // Only assign if different to avoid unneeded rendering.
finalValue = value ? jQuery.trim( cur ) : "";
if ( elem.className !== finalValue ) {
elem.className = finalValue;
@@ -7240,14 +7263,14 @@
return this.each(function() {
if ( type === "string" ) {
- // toggle individual class names
+ // Toggle individual class names
var className,
i = 0,
self = jQuery( this ),
classNames = value.match( rnotwhite ) || [];
while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
+ // Check each className given, space separated list
if ( self.hasClass( className ) ) {
self.removeClass( className );
} else {
@@ -7262,7 +7285,7 @@
data_priv.set( this, "__className__", this.className );
}
- // If the element has a class name or if we're passed "false",
+ // If the element has a class name or if we're passed `false`,
// then remove the whole classname (if there was one, the above saved it).
// Otherwise bring back whatever was previously saved (if anything),
// falling back to the empty string if nothing was stored.
@@ -7306,9 +7329,9 @@
ret = elem.value;
return typeof ret === "string" ?
- // handle most common string cases
+ // Handle most common string cases
ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
+ // Handle cases where value is null/undef or number
ret == null ? "" : ret;
}
@@ -7416,7 +7439,7 @@
}
}
- // force browsers to behave consistently when non-matching value is set
+ // Force browsers to behave consistently when non-matching value is set
if ( !optionSet ) {
elem.selectedIndex = -1;
}
@@ -7437,8 +7460,6 @@
};
if ( !support.checkOn ) {
jQuery.valHooks[ this ].get = function( elem ) {
- // Support: Webkit
- // "" is returned instead of "on" if a value isn't specified
return elem.getAttribute("value") === null ? "on" : elem.value;
};
}
@@ -7520,10 +7541,6 @@
var
- // Document location
- ajaxLocParts,
- ajaxLocation,
-
rhash = /#.*$/,
rts = /([?&])_=[^&]*/,
rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
@@ -7552,22 +7569,13 @@
transports = {},
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
- allTypes = "*/".concat("*");
-
-// #8138, IE may throw an exception when accessing
-// a field from window.location if document.domain has been set
-try {
- ajaxLocation = location.href;
-} catch( e ) {
- // Use the href attribute of an A element
- // since IE will modify it given document.location
- ajaxLocation = document.createElement( "a" );
- ajaxLocation.href = "";
- ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+ allTypes = "*/".concat( "*" ),
+
+ // Document location
+ ajaxLocation = window.location.href,
+
+ // Segment location into parts
+ ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {
@@ -8046,7 +8054,8 @@
}
// We can fire global events as of now if asked to
- fireGlobals = s.global;
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && s.global;
// Watch for a new set of requests
if ( fireGlobals && jQuery.active++ === 0 ) {
@@ -8119,7 +8128,7 @@
return jqXHR.abort();
}
- // aborting is no longer a cancellation
+ // Aborting is no longer a cancellation
strAbort = "abort";
// Install callbacks on deferreds
@@ -8231,8 +8240,7 @@
isSuccess = !error;
}
} else {
- // We extract error from statusText
- // then normalize statusText and status for non-aborts
+ // Extract error from statusText and normalize for non-aborts
error = statusText;
if ( status || !statusText ) {
statusText = "error";
@@ -8288,7 +8296,7 @@
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
- // shift arguments if data argument was omitted
+ // Shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
@@ -8305,13 +8313,6 @@
};
});
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
- jQuery.fn[ type ] = function( fn ) {
- return this.on( type, fn );
- };
-});
-
jQuery._evalUrl = function( url ) {
return jQuery.ajax({
@@ -8529,8 +8530,9 @@
// Support: IE9
// Open requests must be manually aborted on unload (#5280)
-if ( window.ActiveXObject ) {
- jQuery( window ).on( "unload", function() {
+// See https://support.microsoft.com/kb/2856746 for more info
+if ( window.attachEvent ) {
+ window.attachEvent( "onunload", function() {
for ( var key in xhrCallbacks ) {
xhrCallbacks[ key ]();
}
@@ -8883,6 +8885,16 @@
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+});
+
+
+
+
jQuery.expr.filters.animated = function( elem ) {
return jQuery.grep(jQuery.timers, function( fn ) {
return elem === fn.elem;
@@ -8919,7 +8931,8 @@
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
- // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ // Need to be able to calculate position if either
+ // top or left is auto and position is either absolute or fixed
if ( calculatePosition ) {
curPosition = curElem.position();
curTop = curPosition.top;
@@ -8976,8 +8989,8 @@
return box;
}
+ // Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error
- // BlackBerry 5, iOS 3 (original iPhone)
if ( typeof elem.getBoundingClientRect !== strundefined ) {
box = elem.getBoundingClientRect();
}
@@ -8999,7 +9012,7 @@
// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
if ( jQuery.css( elem, "position" ) === "fixed" ) {
- // We assume that getBoundingClientRect is available when computed position is fixed
+ // Assume getBoundingClientRect is there when computed position is fixed
offset = elem.getBoundingClientRect();
} else {
@@ -9062,16 +9075,18 @@
};
});
+// Support: Safari<7+, Chrome<37+
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
-// getComputedStyle returns percent when specified for top/left/bottom/right
-// rather than make the css module depend on the offset module, we just check for it here
+// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
jQuery.each( [ "top", "left" ], function( i, prop ) {
jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
function( elem, computed ) {
if ( computed ) {
computed = curCSS( elem, prop );
- // if curCSS returns percentage, fallback to offset
+ // If curCSS returns percentage, fallback to offset
return rnumnonpx.test( computed ) ?
jQuery( elem ).position()[ prop ] + "px" :
computed;
@@ -9084,7 +9099,7 @@
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
- // margin is only for outerHeight, outerWidth
+ // Margin is only for outerHeight, outerWidth
jQuery.fn[ funcName ] = function( margin, value ) {
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
@@ -9175,8 +9190,8 @@
return jQuery;
};
-// Expose jQuery and $ identifiers, even in
-// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
if ( typeof noGlobal === strundefined ) {
window.jQuery = window.$ = jQuery;
@@ -9190,7 +9205,7 @@
}));
/**
- * @license AngularJS v1.3.0-rc.5
+ * @license AngularJS v1.3.8
* (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
*/
@@ -9228,45 +9243,28 @@
function minErr(module, ErrorConstructor) {
ErrorConstructor = ErrorConstructor || Error;
- return function () {
+ return function() {
var code = arguments[0],
prefix = '[' + (module ? module + ':' : '') + code + '] ',
template = arguments[1],
templateArgs = arguments,
- stringify = function (obj) {
- if (typeof obj === 'function') {
- return obj.toString().replace(/ \{[\s\S]*$/, '');
- } else if (typeof obj === 'undefined') {
- return 'undefined';
- } else if (typeof obj !== 'string') {
- return JSON.stringify(obj);
- }
- return obj;
- },
+
message, i;
- message = prefix + template.replace(/\{\d+\}/g, function (match) {
+ message = prefix + template.replace(/\{\d+\}/g, function(match) {
var index = +match.slice(1, -1), arg;
if (index + 2 < templateArgs.length) {
- arg = templateArgs[index + 2];
- if (typeof arg === 'function') {
- return arg.toString().replace(/ ?\{[\s\S]*$/, '');
- } else if (typeof arg === 'undefined') {
- return 'undefined';
- } else if (typeof arg !== 'string') {
- return toJson(arg);
- }
- return arg;
+ return toDebugString(templateArgs[index + 2]);
}
return match;
});
- message = message + '\nhttp://errors.angularjs.org/1.3.0-rc.5/' +
+ message = message + '\nhttp://errors.angularjs.org/1.3.8/' +
(module ? module + '/' : '') + code;
for (i = 2; i < arguments.length; i++) {
- message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
- encodeURIComponent(stringify(arguments[i]));
+ message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
+ encodeURIComponent(toDebugString(arguments[i]));
}
return new ErrorConstructor(message);
};
@@ -9317,16 +9315,16 @@
isWindow: true,
isScope: true,
isFile: true,
+ isFormData: true,
isBlob: true,
isBoolean: true,
isPromiseLike: true,
trim: true,
+ escapeForRegexp: true,
isElement: true,
makeMap: true,
- size: true,
includes: true,
arrayRemove: true,
- isLeafNode: true,
copy: true,
shallowCopy: true,
equals: true,
@@ -9396,7 +9394,7 @@
* @param {string} string String to be converted to lowercase.
* @returns {string} Lowercased string.
*/
-var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
+var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
@@ -9409,7 +9407,7 @@
* @param {string} string String to be converted to uppercase.
* @returns {string} Uppercased string.
*/
-var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
+var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
var manualLowercase = function(s) {
@@ -9435,8 +9433,8 @@
}
-var /** holds major version number for IE or NaN for real browsers */
- msie,
+var
+ msie, // holds major version number for IE, or NaN if UA is not IE.
jqLite, // delay binding since jQuery could be loaded after us.
jQuery, // delay binding
slice = [].slice,
@@ -9493,6 +9491,11 @@
* It is worth noting that `.forEach` does not iterate over inherited properties because it filters
* using the `hasOwnProperty` method.
*
+ * Unlike ES262's
+ * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
+ * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
+ * return the value provided.
+ *
```js
var values = {name: 'misko', gender: 'male'};
var log = [];
@@ -9540,18 +9543,12 @@
}
function sortedKeys(obj) {
- var keys = [];
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- keys.push(key);
- }
- }
- return keys.sort();
+ return Object.keys(obj).sort();
}
function forEachSorted(obj, iterator, context) {
var keys = sortedKeys(obj);
- for ( var i = 0; i < keys.length; i++) {
+ for (var i = 0; i < keys.length; i++) {
iterator.call(context, obj[keys[i]], keys[i]);
}
return keys;
@@ -9604,7 +9601,9 @@
*
* @description
* Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
- * to `dst`. You can specify multiple `src` objects.
+ * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
+ * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
+ * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy).
*
* @param {Object} dst Destination object.
* @param {...Object} src Source object(s).
@@ -9634,7 +9633,7 @@
function inherit(parent, extra) {
- return extend(new (extend(function() {}, {prototype:parent}))(), extra);
+ return extend(Object.create(parent), extra);
}
/**
@@ -9672,6 +9671,8 @@
return (transformationFn || angular.identity)(value);
};
```
+ * @param {*} value to be returned.
+ * @returns {*} the value passed in.
*/
function identity($) {return $;}
identity.$inject = [];
@@ -9691,7 +9692,7 @@
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is undefined.
*/
-function isUndefined(value){return typeof value === 'undefined';}
+function isUndefined(value) {return typeof value === 'undefined';}
/**
@@ -9706,7 +9707,7 @@
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is defined.
*/
-function isDefined(value){return typeof value !== 'undefined';}
+function isDefined(value) {return typeof value !== 'undefined';}
/**
@@ -9722,7 +9723,7 @@
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Object` but not `null`.
*/
-function isObject(value){
+function isObject(value) {
// http://jsperf.com/isobject4
return value !== null && typeof value === 'object';
}
@@ -9740,7 +9741,7 @@
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `String`.
*/
-function isString(value){return typeof value === 'string';}
+function isString(value) {return typeof value === 'string';}
/**
@@ -9755,7 +9756,7 @@
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Number`.
*/
-function isNumber(value){return typeof value === 'number';}
+function isNumber(value) {return typeof value === 'number';}
/**
@@ -9801,7 +9802,7 @@
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Function`.
*/
-function isFunction(value){return typeof value === 'function';}
+function isFunction(value) {return typeof value === 'function';}
/**
@@ -9838,6 +9839,11 @@
}
+function isFormData(obj) {
+ return toString.call(obj) === '[object FormData]';
+}
+
+
function isBlob(obj) {
return toString.call(obj) === '[object Blob]';
}
@@ -9857,6 +9863,14 @@
return isString(value) ? value.trim() : value;
};
+// Copied from:
+// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
+// Prereq: s is a string.
+var escapeForRegexp = function(s) {
+ return s.replace(/([-()\[\]{}+?*.$\^|,:#=0)
+ if (index >= 0)
array.splice(index, 1);
return value;
}
-function isLeafNode (node) {
- if (node) {
- switch (nodeName_(node)) {
- case "option":
- case "pre":
- case "title":
- return true;
- }
- }
- return false;
-}
-
/**
* @ngdoc function
* @name angular.copy
@@ -9953,7 +9927,7 @@
* Creates a deep copy of `source`, which should be an object or an array.
*
* * If no destination is supplied, a copy of the object or array is created.
- * * If a destination is provided, all of its elements (for array) or properties (for objects)
+ * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
* are deleted and then all elements/properties from the source are copied to it.
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
* * If `source` is identical to 'destination' an exception will be thrown.
@@ -10040,7 +10014,7 @@
var result;
if (isArray(source)) {
destination.length = 0;
- for ( var i = 0; i < source.length; i++) {
+ for (var i = 0; i < source.length; i++) {
result = copy(source[i], null, stackSource, stackDest);
if (isObject(source[i])) {
stackSource.push(source[i]);
@@ -10057,8 +10031,8 @@
delete destination[key];
});
}
- for ( var key in source) {
- if(source.hasOwnProperty(key)) {
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) {
result = copy(source[key], null, stackSource, stackDest);
if (isObject(source[key])) {
stackSource.push(source[key]);
@@ -10139,7 +10113,7 @@
if (isArray(o1)) {
if (!isArray(o2)) return false;
if ((length = o1.length) == o2.length) {
- for(key=0; key').append(element).html();
try {
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
elemHtml.
match(/^(<[^>]+>)/)[1].
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
- } catch(e) {
+ } catch (e) {
return lowercase(elemHtml);
}
@@ -10332,7 +10310,7 @@
function tryDecodeURIComponent(value) {
try {
return decodeURIComponent(value);
- } catch(e) {
+ } catch (e) {
// Ignore any invalid uri component
}
}
@@ -10345,14 +10323,14 @@
function parseKeyValue(/**string*/keyValue) {
var obj = {}, key_value, key;
forEach((keyValue || "").split('&'), function(keyValue) {
- if ( keyValue ) {
+ if (keyValue) {
key_value = keyValue.replace(/\+/g,'%20').split('=');
key = tryDecodeURIComponent(key_value[0]);
- if ( isDefined(key) ) {
+ if (isDefined(key)) {
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
if (!hasOwnProperty.call(obj, key)) {
obj[key] = val;
- } else if(isArray(obj[key])) {
+ } else if (isArray(obj[key])) {
obj[key].push(val);
} else {
obj[key] = [obj[key],val];
@@ -10425,7 +10403,7 @@
function getNgAttribute(element, ngAttr) {
var attr, i, ii = ngAttrPrefixes.length;
element = jqLite(element);
- for (i=0; i
@@ -10635,8 +10613,8 @@
* @param {Object=} config an object for defining configuration options for the application. The
* following keys are supported:
*
- * - `strictDi`: disable automatic function annotation for the application. This is meant to
- * assist in finding bugs which break minified code.
+ * * `strictDi` - disable automatic function annotation for the application. This is meant to
+ * assist in finding bugs which break minified code. Defaults to `false`.
*
* @returns {auto.$injector} Returns the newly created injector for this app.
*/
@@ -10728,7 +10706,12 @@
* @param {DOMElement} element DOM element which is the root of angular application.
*/
function getTestability(rootElement) {
- return angular.element(rootElement).injector().get('$$testability');
+ var injector = angular.element(rootElement).injector();
+ if (!injector) {
+ throw ngMinErr('test',
+ 'no injector found for element argument to getTestability');
+ }
+ return injector.get('$$testability');
}
var SNAKE_CASE_REGEXP = /[A-Z]/g;
@@ -11115,7 +11098,7 @@
* })
* ```
*
- * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
+ * See {@link ng.$animateProvider#register $animateProvider.register()} and
* {@link ngAnimate ngAnimate module} for more information.
*/
animation: invokeLater('$animateProvider', 'register'),
@@ -11165,7 +11148,7 @@
* @description
* Use this method to register work which needs to be performed on module loading.
* For more about how to configure services, see
- * {@link providers#providers_provider-recipe Provider Recipe}.
+ * {@link providers#provider-recipe Provider Recipe}.
*/
config: config,
@@ -11189,7 +11172,7 @@
config(configFn);
}
- return moduleInstance;
+ return moduleInstance;
/**
* @param {string} provider
@@ -11210,6 +11193,34 @@
}
+/* global: toDebugString: true */
+
+function serializeObject(obj) {
+ var seen = [];
+
+ return JSON.stringify(obj, function(key, val) {
+ val = toJsonReplacer(key, val);
+ if (isObject(val)) {
+
+ if (seen.indexOf(val) >= 0) return '<>';
+
+ seen.push(val);
+ }
+ return val;
+ });
+}
+
+function toDebugString(obj) {
+ if (typeof obj === 'function') {
+ return obj.toString().replace(/ \{[\s\S]*$/, '');
+ } else if (typeof obj === 'undefined') {
+ return 'undefined';
+ } else if (typeof obj !== 'string') {
+ return serializeObject(obj);
+ }
+ return obj;
+}
+
/* global angularModule: true,
version: true,
@@ -11293,7 +11304,8 @@
$TimeoutProvider,
$$RAFProvider,
$$AsyncCallbackProvider,
- $WindowProvider
+ $WindowProvider,
+ $$jqLiteProvider
*/
@@ -11312,15 +11324,15 @@
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.3.0-rc.5', // all of these placeholder strings will be replaced by grunt's
+ full: '1.3.8', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
minor: 3,
- dot: 0,
- codeName: 'impossible-choreography'
-};
-
-
-function publishExternalAPI(angular){
+ dot: 8,
+ codeName: 'prophetic-narwhal'
+};
+
+
+function publishExternalAPI(angular) {
extend(angular, {
'bootstrap': bootstrap,
'copy': copy,
@@ -11446,7 +11458,8 @@
$timeout: $TimeoutProvider,
$window: $WindowProvider,
$$rAF: $$RAFProvider,
- $$asyncCallback : $$AsyncCallbackProvider
+ $$asyncCallback: $$AsyncCallbackProvider,
+ $$jqLite: $$jqLiteProvider
});
}
]);
@@ -11491,12 +11504,12 @@
* - [`addClass()`](http://api.jquery.com/addClass/)
* - [`after()`](http://api.jquery.com/after/)
* - [`append()`](http://api.jquery.com/append/)
- * - [`attr()`](http://api.jquery.com/attr/)
+ * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
* - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
* - [`clone()`](http://api.jquery.com/clone/)
* - [`contents()`](http://api.jquery.com/contents/)
- * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()`
+ * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`
* - [`data()`](http://api.jquery.com/data/)
* - [`detach()`](http://api.jquery.com/detach/)
* - [`empty()`](http://api.jquery.com/empty/)
@@ -11539,10 +11552,12 @@
* `'ngModel'`).
* - `injector()` - retrieves the injector of the current element or its parent.
* - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
- * element or its parent.
+ * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
+ * be enabled.
* - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
* current element. This getter should be used only on elements that contain a directive which starts a new isolate
* scope. Calling `scope()` on this element always returns the original non-isolate scope.
+ * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
* - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
* parent element is reached.
*
@@ -11574,7 +11589,7 @@
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
-var MOUSE_EVENT_MAP= { mouseleave : "mouseout", mouseenter : "mouseover"};
+var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
var jqLiteMinErr = minErr('jqLite');
/**
@@ -11703,7 +11718,7 @@
return element.cloneNode(true);
}
-function jqLiteDealoc(element, onlyDescendants){
+function jqLiteDealoc(element, onlyDescendants) {
if (!onlyDescendants) jqLiteRemoveData(element);
if (element.querySelectorAll) {
@@ -11726,18 +11741,22 @@
if (!type) {
for (type in events) {
if (type !== '$destroy') {
- removeEventListenerFn(element, type, events[type]);
+ removeEventListenerFn(element, type, handle);
}
delete events[type];
}
} else {
forEach(type.split(' '), function(type) {
- if (isUndefined(fn)) {
- removeEventListenerFn(element, type, events[type]);
- delete events[type];
- } else {
- arrayRemove(events[type] || [], fn);
- }
+ if (isDefined(fn)) {
+ var listenerFns = events[type];
+ arrayRemove(listenerFns || [], fn);
+ if (listenerFns && listenerFns.length > 0) {
+ return;
+ }
+ }
+
+ removeEventListenerFn(element, type, handle);
+ delete events[type];
});
}
}
@@ -11806,7 +11825,7 @@
function jqLiteHasClass(element, selector) {
if (!element.getAttribute) return false;
return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
- indexOf( " " + selector + " " ) > -1);
+ indexOf(" " + selector + " ") > -1);
}
function jqLiteRemoveClass(element, cssClasses) {
@@ -11865,13 +11884,13 @@
function jqLiteController(element, name) {
- return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
+ return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
}
function jqLiteInheritedData(element, name, value) {
// if element is the document object work with the html element instead
// this makes $(document).scope() possible
- if(element.nodeType == NODE_TYPE_DOCUMENT) {
+ if (element.nodeType == NODE_TYPE_DOCUMENT) {
element = element.documentElement;
}
var names = isArray(name) ? name : [name];
@@ -11901,6 +11920,20 @@
if (parent) parent.removeChild(element);
}
+
+function jqLiteDocumentLoaded(action, win) {
+ win = win || window;
+ if (win.document.readyState === 'complete') {
+ // Force the action to be run async for consistent behaviour
+ // from the action's point of view
+ // i.e. it will definitely not be in a $apply
+ win.setTimeout(action);
+ } else {
+ // No need to unbind this handler as load is only ever called once
+ jqLite(win).on('load', action);
+ }
+}
+
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
@@ -11915,7 +11948,7 @@
}
// check if document is already loaded
- if (document.readyState === 'complete'){
+ if (document.readyState === 'complete') {
setTimeout(trigger);
} else {
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
@@ -11923,12 +11956,11 @@
// jshint -W064
JQLite(window).on('load', trigger); // fallback to window.onload for others
// jshint +W064
- this.on('DOMContentLoaded', trigger);
}
},
toString: function() {
var value = [];
- forEach(this, function(e){ value.push('' + e);});
+ forEach(this, function(e) { value.push('' + e);});
return '[' + value.join(', ') + ']';
},
@@ -11956,11 +11988,11 @@
BOOLEAN_ELEMENTS[value] = true;
});
var ALIASED_ATTR = {
- 'ngMinlength' : 'minlength',
- 'ngMaxlength' : 'maxlength',
- 'ngMin' : 'min',
- 'ngMax' : 'max',
- 'ngPattern' : 'pattern'
+ 'ngMinlength': 'minlength',
+ 'ngMaxlength': 'maxlength',
+ 'ngMin': 'min',
+ 'ngMax': 'max',
+ 'ngPattern': 'pattern'
};
function getBooleanAttrName(element, name) {
@@ -12019,7 +12051,7 @@
}
},
- attr: function(element, name, value){
+ attr: function(element, name, value) {
var lowercasedName = lowercase(name);
if (BOOLEAN_ATTR[lowercasedName]) {
if (isDefined(value)) {
@@ -12032,7 +12064,7 @@
}
} else {
return (element[name] ||
- (element.attributes.getNamedItem(name)|| noop).specified)
+ (element.attributes.getNamedItem(name) || noop).specified)
? lowercasedName
: undefined;
}
@@ -12072,7 +12104,7 @@
if (isUndefined(value)) {
if (element.multiple && nodeName_(element) === 'select') {
var result = [];
- forEach(element.options, function (option) {
+ forEach(element.options, function(option) {
if (option.selected) {
result.push(option.value || option.text);
}
@@ -12093,7 +12125,7 @@
},
empty: jqLiteEmpty
-}, function(fn, name){
+}, function(fn, name) {
/**
* Properties: writes return selection, reads return first value
*/
@@ -12145,7 +12177,7 @@
});
function createEventHandler(element, events) {
- var eventHandler = function (event, type) {
+ var eventHandler = function(event, type) {
// jQuery specific api
event.isDefaultPrevented = function() {
return event.defaultPrevented;
@@ -12201,7 +12233,7 @@
forEach({
removeData: jqLiteRemoveData,
- on: function jqLiteOn(element, type, fn, unsupported){
+ on: function jqLiteOn(element, type, fn, unsupported) {
if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
// Do not add event handlers to non-elements because they will not be cleaned up.
@@ -12237,7 +12269,7 @@
var target = this, related = event.relatedTarget;
// For mousenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !target.contains(related)) ){
+ if (!related || (related !== target && !target.contains(related))) {
handle(event, type);
}
});
@@ -12271,7 +12303,7 @@
replaceWith: function(element, replaceNode) {
var index, parent = element.parentNode;
jqLiteDealoc(element);
- forEach(new JQLite(replaceNode), function(node){
+ forEach(new JQLite(replaceNode), function(node) {
if (index) {
parent.insertBefore(node, index.nextSibling);
} else {
@@ -12283,7 +12315,7 @@
children: function(element) {
var children = [];
- forEach(element.childNodes, function(element){
+ forEach(element.childNodes, function(element) {
if (element.nodeType === NODE_TYPE_ELEMENT)
children.push(element);
});
@@ -12309,7 +12341,7 @@
prepend: function(element, node) {
if (element.nodeType === NODE_TYPE_ELEMENT) {
var index = element.firstChild;
- forEach(new JQLite(node), function(child){
+ forEach(new JQLite(node), function(child) {
element.insertBefore(child, index);
});
}
@@ -12346,7 +12378,7 @@
toggleClass: function(element, selector, condition) {
if (selector) {
- forEach(selector.split(' '), function(className){
+ forEach(selector.split(' '), function(className) {
var classCondition = condition;
if (isUndefined(classCondition)) {
classCondition = !jqLiteHasClass(element, className);
@@ -12411,14 +12443,14 @@
});
}
}
-}, function(fn, name){
+}, function(fn, name) {
/**
* chaining functions
*/
JQLite.prototype[name] = function(arg1, arg2, arg3) {
var value;
- for(var i = 0, ii = this.length; i < ii; i++) {
+ for (var i = 0, ii = this.length; i < ii; i++) {
if (isUndefined(value)) {
value = fn(this[i], arg1, arg2, arg3);
if (isDefined(value)) {
@@ -12437,6 +12469,27 @@
JQLite.prototype.unbind = JQLite.prototype.off;
});
+
+// Provider for private $$jqLite service
+function $$jqLiteProvider() {
+ this.$get = function $$jqLite() {
+ return extend(JQLite, {
+ hasClass: function(node, classes) {
+ if (node.attr) node = node[0];
+ return jqLiteHasClass(node, classes);
+ },
+ addClass: function(node, classes) {
+ if (node.attr) node = node[0];
+ return jqLiteAddClass(node, classes);
+ },
+ removeClass: function(node, classes) {
+ if (node.attr) node = node[0];
+ return jqLiteRemoveClass(node, classes);
+ }
+ });
+ };
+}
+
/**
* Computes a hash of an 'obj'.
* Hash of a:
@@ -12520,10 +12573,11 @@
* Creates an injector object that can be used for retrieving services as well as for
* dependency injection (see {@link guide/di dependency injection}).
*
-
* @param {Array.} modules A list of module functions or their aliases. See
- * {@link angular.module}. The `ng` module must be explicitly added.
- * @returns {function()} Injector object. See {@link auto.$injector $injector}.
+ * {@link angular.module}. The `ng` module must be explicitly added.
+ * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
+ * disallows argument name annotation inference.
+ * @returns {injector} Injector object. See {@link auto.$injector $injector}.
*
* @example
* Typical usage
@@ -12668,8 +12722,10 @@
* ## Inference
*
* In JavaScript calling `toString()` on a function returns the function definition. The definition
- * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
- * minification, and obfuscation tools since these tools change the argument names.
+ * can then be parsed and the function arguments can be extracted. This method of discovering
+ * annotations is disallowed when the injector is in strict mode.
+ * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
+ * argument names.
*
* ## `$inject` Annotation
* By adding an `$inject` property onto a function the injection parameters can be specified.
@@ -12686,6 +12742,7 @@
* Return an instance of the service.
*
* @param {string} name The name of the instance to retrieve.
+ * @param {string} caller An optional string to provide the origin of the function call for error messages.
* @return {*} The instance.
*/
@@ -12754,6 +12811,8 @@
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
* ```
*
+ * You can disallow this method by using strict injection mode.
+ *
* This method does not work with code minification / obfuscation. For this reason the following
* annotation strategies are supported.
*
@@ -12806,6 +12865,8 @@
* @param {Function|Array.} fn Function for which dependent service names need to
* be retrieved as described above.
*
+ * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
+ *
* @returns {Array.} The names of the services which the function requires.
*/
@@ -13132,14 +13193,17 @@
}
},
providerInjector = (providerCache.$injector =
- createInternalInjector(providerCache, function() {
+ createInternalInjector(providerCache, function(serviceName, caller) {
+ if (angular.isString(caller)) {
+ path.push(caller);
+ }
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
- createInternalInjector(instanceCache, function(servicename) {
- var provider = providerInjector.get(servicename + providerSuffix);
- return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
+ createInternalInjector(instanceCache, function(serviceName, caller) {
+ var provider = providerInjector.get(serviceName + providerSuffix, caller);
+ return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
@@ -13174,7 +13238,7 @@
function enforceReturnValue(name, factory) {
return function enforcedReturnValue() {
- var result = instanceInjector.invoke(factory);
+ var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
}
@@ -13215,7 +13279,7 @@
////////////////////////////////////
// Module Loading
////////////////////////////////////
- function loadModules(modulesToLoad){
+ function loadModules(modulesToLoad) {
var runBlocks = [], moduleFn;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
@@ -13223,7 +13287,7 @@
function runInvokeQueue(queue) {
var i, ii;
- for(i = 0, ii = queue.length; i < ii; i++) {
+ for (i = 0, ii = queue.length; i < ii; i++) {
var invokeArgs = queue[i],
provider = providerInjector.get(invokeArgs[0]);
@@ -13269,7 +13333,7 @@
function createInternalInjector(cache, factory) {
- function getService(serviceName) {
+ function getService(serviceName, caller) {
if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
@@ -13280,7 +13344,7 @@
try {
path.unshift(serviceName);
cache[serviceName] = INSTANTIATING;
- return cache[serviceName] = factory(serviceName);
+ return cache[serviceName] = factory(serviceName, caller);
} catch (err) {
if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName];
@@ -13303,7 +13367,7 @@
length, i,
key;
- for(i = 0, length = $inject.length; i < length; i++) {
+ for (i = 0, length = $inject.length; i < length; i++) {
key = $inject[i];
if (typeof key !== 'string') {
throw $injectorMinErr('itkn',
@@ -13312,7 +13376,7 @@
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
- : getService(key)
+ : getService(key, serviceName)
);
}
if (isArray(fn)) {
@@ -13325,14 +13389,11 @@
}
function instantiate(Type, locals, serviceName) {
- var Constructor = function() {},
- instance, returnedValue;
-
// Check if Type is annotated and use just the given function at n-1 as parameter
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
- Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
- instance = new Constructor();
- returnedValue = invoke(Type, instance, locals, serviceName);
+ // Object creation: http://jsperf.com/create-constructor/2
+ var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype);
+ var returnedValue = invoke(Type, instance, locals, serviceName);
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
@@ -13352,93 +13413,251 @@
createInjector.$$annotate = annotate;
/**
- * @ngdoc service
- * @name $anchorScroll
- * @kind function
- * @requires $window
- * @requires $location
- * @requires $rootScope
- *
- * @description
- * When called, it checks current value of `$location.hash()` and scrolls to the related element,
- * according to rules specified in
- * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
- *
- * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
- * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
- *
- * @example
-
-
-
-
-
- angular.module('anchorScrollExample', [])
- .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
- function ($scope, $location, $anchorScroll) {
- $scope.gotoBottom = function() {
- // set the location.hash to the id of
- // the element you wish to scroll to.
- $location.hash('bottom');
-
- // call $anchorScroll()
- $anchorScroll();
- };
- }]);
-
-
- #scrollArea {
- height: 350px;
- overflow: auto;
- }
-
- #bottom {
- display: block;
- margin-top: 2000px;
- }
-
-
+ * @ngdoc provider
+ * @name $anchorScrollProvider
+ *
+ * @description
+ * Use `$anchorScrollProvider` to disable automatic scrolling whenever
+ * {@link ng.$location#hash $location.hash()} changes.
*/
function $AnchorScrollProvider() {
var autoScrollingEnabled = true;
+ /**
+ * @ngdoc method
+ * @name $anchorScrollProvider#disableAutoScrolling
+ *
+ * @description
+ * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
+ * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
+ * Use this method to disable automatic scrolling.
+ *
+ * If automatic scrolling is disabled, one must explicitly call
+ * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
+ * current hash.
+ */
this.disableAutoScrolling = function() {
autoScrollingEnabled = false;
};
+ /**
+ * @ngdoc service
+ * @name $anchorScroll
+ * @kind function
+ * @requires $window
+ * @requires $location
+ * @requires $rootScope
+ *
+ * @description
+ * When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
+ * scrolls to the related element, according to the rules specified in the
+ * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
+ *
+ * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
+ * match any anchor whenever it changes. This can be disabled by calling
+ * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
+ *
+ * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
+ * vertical scroll-offset (either fixed or dynamic).
+ *
+ * @property {(number|function|jqLite)} yOffset
+ * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
+ * positioned elements at the top of the page, such as navbars, headers etc.
+ *
+ * `yOffset` can be specified in various ways:
+ * - **number**: A fixed number of pixels to be used as offset.
+ * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
+ * a number representing the offset (in pixels).
+ * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
+ * the top of the page to the element's bottom will be used as offset.
+ * **Note**: The element will be taken into account only as long as its `position` is set to
+ * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
+ * their height and/or positioning according to the viewport's size.
+ *
+ *
+ *
+ * In order for `yOffset` to work properly, scrolling should take place on the document's root and
+ * not some child element.
+ *
+
+
+ angular.module('anchorScrollOffsetExample', [])
+ .run(['$anchorScroll', function($anchorScroll) {
+ $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
+ }])
+ .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
+ function ($anchorScroll, $location, $scope) {
+ $scope.gotoAnchor = function(x) {
+ var newHash = 'anchor' + x;
+ if ($location.hash() !== newHash) {
+ // set the $location.hash to `newHash` and
+ // $anchorScroll will automatically scroll to it
+ $location.hash('anchor' + x);
+ } else {
+ // call $anchorScroll() explicitly,
+ // since $location.hash hasn't changed
+ $anchorScroll();
+ }
+ };
+ }
+ ]);
+
+
+ body {
+ padding-top: 50px;
+ }
+
+ .anchor {
+ border: 2px dashed DarkOrchid;
+ padding: 10px 10px 200px 10px;
+ }
+
+ .fixed-header {
+ background-color: rgba(0, 0, 0, 0.2);
+ height: 50px;
+ position: fixed;
+ top: 0; left: 0; right: 0;
+ }
+
+ .fixed-header > a {
+ display: inline-block;
+ margin: 5px 15px;
+ }
+
+
+ */
this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
var document = $window.document;
- // helper function to get first anchor from a NodeList
- // can't use filter.filter, as it accepts only instances of Array
- // and IE can't convert NodeList to an array using [].slice
- // TODO(vojta): use filter if we change it to accept lists as well
+ // Helper function to get first anchor from a NodeList
+ // (using `Array#some()` instead of `angular#forEach()` since it's more performant
+ // and working in all supported browsers.)
function getFirstAnchor(list) {
var result = null;
- forEach(list, function(element) {
- if (!result && nodeName_(element) === 'a') result = element;
+ Array.prototype.some.call(list, function(element) {
+ if (nodeName_(element) === 'a') {
+ result = element;
+ return true;
+ }
});
return result;
}
+ function getYOffset() {
+
+ var offset = scroll.yOffset;
+
+ if (isFunction(offset)) {
+ offset = offset();
+ } else if (isElement(offset)) {
+ var elem = offset[0];
+ var style = $window.getComputedStyle(elem);
+ if (style.position !== 'fixed') {
+ offset = 0;
+ } else {
+ offset = elem.getBoundingClientRect().bottom;
+ }
+ } else if (!isNumber(offset)) {
+ offset = 0;
+ }
+
+ return offset;
+ }
+
+ function scrollTo(elem) {
+ if (elem) {
+ elem.scrollIntoView();
+
+ var offset = getYOffset();
+
+ if (offset) {
+ // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
+ // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
+ // top of the viewport.
+ //
+ // IF the number of pixels from the top of `elem` to the end of the page's content is less
+ // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
+ // way down the page.
+ //
+ // This is often the case for elements near the bottom of the page.
+ //
+ // In such cases we do not need to scroll the whole `offset` up, just the difference between
+ // the top of the element and the offset, which is enough to align the top of `elem` at the
+ // desired position.
+ var elemTop = elem.getBoundingClientRect().top;
+ $window.scrollBy(0, elemTop - offset);
+ }
+ } else {
+ $window.scrollTo(0, 0);
+ }
+ }
+
function scroll() {
var hash = $location.hash(), elm;
// empty hash, scroll to the top of the page
- if (!hash) $window.scrollTo(0, 0);
+ if (!hash) scrollTo(null);
// element with given id
- else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
+ else if ((elm = document.getElementById(hash))) scrollTo(elm);
// first anchor with given name :-D
- else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
+ else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
// no element and hash == 'top', scroll to the top of the page
- else if (hash === 'top') $window.scrollTo(0, 0);
+ else if (hash === 'top') scrollTo(null);
}
// does not scroll when user clicks on anchor link that is currently on
@@ -13449,7 +13668,9 @@
// skip the initial scroll if $location.hash is empty
if (newVal === oldVal && newVal === '') return;
- $rootScope.$evalAsync(scroll);
+ jqLiteDocumentLoaded(function() {
+ $rootScope.$evalAsync(scroll);
+ });
});
}
@@ -13532,7 +13753,7 @@
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
*/
this.classNameFilter = function(expression) {
- if(arguments.length === 1) {
+ if (arguments.length === 1) {
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
}
return this.$$classNameFilter;
@@ -13557,7 +13778,7 @@
return defer.promise;
}
- function resolveElementClasses(element, cache) {
+ function resolveElementClasses(element, classes) {
var toAdd = [], toRemove = [];
var hasClasses = createMap();
@@ -13565,7 +13786,7 @@
hasClasses[className] = true;
});
- forEach(cache.classes, function(status, className) {
+ forEach(classes, function(status, className) {
var hasClass = hasClasses[className];
// If the most recent class manipulation (via $animate) was to remove the class, and the
@@ -13579,7 +13800,8 @@
}
});
- return (toAdd.length + toRemove.length) > 0 && [toAdd.length && toAdd, toRemove.length && toRemove];
+ return (toAdd.length + toRemove.length) > 0 &&
+ [toAdd.length ? toAdd : null, toRemove.length ? toRemove : null];
}
function cachedClassManipulation(cache, classes, op) {
@@ -13601,6 +13823,13 @@
return currentDefer.promise;
}
+ function applyStyles(element, options) {
+ if (angular.isObject(options)) {
+ var styles = extend(options.from || {}, options.to || {});
+ element.css(styles);
+ }
+ }
+
/**
*
* @ngdoc service
@@ -13619,6 +13848,10 @@
* page}.
*/
return {
+ animate: function(element, from, to) {
+ applyStyles(element, { from: from, to: to });
+ return asyncPromise();
+ },
/**
*
@@ -13633,9 +13866,11 @@
* a child (if the after element is not present)
* @param {DOMElement} after the sibling element which will append the element
* after itself
+ * @param {object=} options an optional collection of styles that will be applied to the element.
* @return {Promise} the animation callback promise
*/
- enter : function(element, parent, after) {
+ enter: function(element, parent, after, options) {
+ applyStyles(element, options);
after ? after.after(element)
: parent.prepend(element);
return asyncPromise();
@@ -13649,9 +13884,10 @@
* @description Removes the element from the DOM. When the function is called a promise
* is returned that will be resolved at a later time.
* @param {DOMElement} element the element which will be removed from the DOM
+ * @param {object=} options an optional collection of options that will be applied to the element.
* @return {Promise} the animation callback promise
*/
- leave : function(element) {
+ leave: function(element, options) {
element.remove();
return asyncPromise();
},
@@ -13671,12 +13907,13 @@
* inserted into (if the after element is not present)
* @param {DOMElement} after the sibling element where the element will be
* positioned next to
+ * @param {object=} options an optional collection of options that will be applied to the element.
* @return {Promise} the animation callback promise
*/
- move : function(element, parent, after) {
+ move: function(element, parent, after, options) {
// Do not remove element before insert. Removing will cause data associated with the
// element to be dropped. Insert will implicitly do the remove.
- return this.enter(element, parent, after);
+ return this.enter(element, parent, after, options);
},
/**
@@ -13689,20 +13926,23 @@
* @param {DOMElement} element the element which will have the className value
* added to it
* @param {string} className the CSS class which will be added to the element
+ * @param {object=} options an optional collection of options that will be applied to the element.
* @return {Promise} the animation callback promise
*/
- addClass : function(element, className) {
- return this.setClass(element, className, []);
+ addClass: function(element, className, options) {
+ return this.setClass(element, className, [], options);
},
- $$addClassImmediately : function addClassImmediately(element, className) {
+ $$addClassImmediately: function(element, className, options) {
element = jqLite(element);
className = !isString(className)
? (isArray(className) ? className.join(' ') : '')
: className;
- forEach(element, function (element) {
+ forEach(element, function(element) {
jqLiteAddClass(element, className);
});
+ applyStyles(element, options);
+ return asyncPromise();
},
/**
@@ -13715,20 +13955,22 @@
* @param {DOMElement} element the element which will have the className value
* removed from it
* @param {string} className the CSS class which will be removed from the element
+ * @param {object=} options an optional collection of options that will be applied to the element.
* @return {Promise} the animation callback promise
*/
- removeClass : function(element, className) {
- return this.setClass(element, [], className);
+ removeClass: function(element, className, options) {
+ return this.setClass(element, [], className, options);
},
- $$removeClassImmediately : function removeClassImmediately(element, className) {
+ $$removeClassImmediately: function(element, className, options) {
element = jqLite(element);
className = !isString(className)
? (isArray(className) ? className.join(' ') : '')
: className;
- forEach(element, function (element) {
+ forEach(element, function(element) {
jqLiteRemoveClass(element, className);
});
+ applyStyles(element, options);
return asyncPromise();
},
@@ -13743,28 +13985,24 @@
* removed from it
* @param {string} add the CSS classes which will be added to the element
* @param {string} remove the CSS class which will be removed from the element
+ * @param {object=} options an optional collection of options that will be applied to the element.
* @return {Promise} the animation callback promise
*/
- setClass : function(element, add, remove, runSynchronously) {
+ setClass: function(element, add, remove, options) {
var self = this;
var STORAGE_KEY = '$$animateClasses';
var createdCache = false;
element = jqLite(element);
- if (runSynchronously) {
- // TODO(@caitp/@matsko): Remove undocumented `runSynchronously` parameter, and always
- // perform DOM manipulation asynchronously or in postDigest.
- self.$$addClassImmediately(element, add);
- self.$$removeClassImmediately(element, remove);
- return asyncPromise();
- }
-
var cache = element.data(STORAGE_KEY);
if (!cache) {
cache = {
- classes: {}
+ classes: {},
+ options: options
};
createdCache = true;
+ } else if (options && cache.options) {
+ cache.options = angular.extend(cache.options || {}, options);
}
var classes = cache.classes;
@@ -13779,11 +14017,14 @@
var cache = element.data(STORAGE_KEY);
element.removeData(STORAGE_KEY);
- var classes = cache && resolveElementClasses(element, cache);
-
- if (classes) {
- if (classes[0]) self.$$addClassImmediately(element, classes[0]);
- if (classes[1]) self.$$removeClassImmediately(element, classes[1]);
+ // in the event that the element is removed before postDigest
+ // is run then the cache will be undefined and there will be
+ // no need anymore to add or remove and of the element classes
+ if (cache) {
+ var classes = resolveElementClasses(element, cache.classes);
+ if (classes) {
+ self.$$setClassImmediately(element, classes[0], classes[1], cache.options);
+ }
}
done();
@@ -13794,13 +14035,20 @@
return cache.promise;
},
- enabled : noop,
- cancel : noop
+ $$setClassImmediately: function(element, add, remove, options) {
+ add && this.$$addClassImmediately(element, add);
+ remove && this.$$removeClassImmediately(element, remove);
+ applyStyles(element, options);
+ return asyncPromise();
+ },
+
+ enabled: noop,
+ cancel: noop
};
}];
}];
-function $$AsyncCallbackProvider(){
+function $$AsyncCallbackProvider() {
this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
return $$rAF.supported
? function(fn) { return $$rAF(fn); }
@@ -13830,8 +14078,7 @@
/**
* @param {object} window The global window object.
* @param {object} document jQuery wrapped document.
- * @param {function()} XHR XMLHttpRequest constructor.
- * @param {object} $log console.log or an object with the same interface.
+ * @param {object} $log window.console or an object with the same interface.
* @param {object} $sniffer $sniffer service
*/
function Browser(window, document, $log, $sniffer) {
@@ -13862,7 +14109,7 @@
} finally {
outstandingRequestCount--;
if (outstandingRequestCount === 0) {
- while(outstandingRequestCallbacks.length) {
+ while (outstandingRequestCallbacks.length) {
try {
outstandingRequestCallbacks.pop()();
} catch (e) {
@@ -13873,6 +14120,11 @@
}
}
+ function getHash(url) {
+ var index = url.indexOf('#');
+ return index === -1 ? '' : url.substr(index + 1);
+ }
+
/**
* @private
* Note: this method is used only by scenario runner
@@ -13883,7 +14135,7 @@
// force browser to execute all pollFns - this is needed so that cookies and other pollers fire
// at some deterministic time in respect to the test runner's actions. Leaving things up to the
// regular poller would result in flaky tests.
- forEach(pollFns, function(pollFn){ pollFn(); });
+ forEach(pollFns, function(pollFn) { pollFn(); });
if (outstandingRequestCount === 0) {
callback();
@@ -13925,7 +14177,7 @@
*/
function startPoller(interval, setTimeout) {
(function check() {
- forEach(pollFns, function(pollFn){ pollFn(); });
+ forEach(pollFns, function(pollFn) { pollFn(); });
pollTimeout = setTimeout(check, interval);
})();
}
@@ -13934,11 +14186,14 @@
// URL API
//////////////////////////////////////////////////////////////
- var lastBrowserUrl = location.href,
- lastHistoryState = history.state,
+ var cachedState, lastHistoryState,
+ lastBrowserUrl = location.href,
baseElement = document.find('base'),
reloadLocation = null;
+ cacheState();
+ lastHistoryState = cachedState;
+
/**
* @name $browser#url
*
@@ -13973,29 +14228,36 @@
// setter
if (url) {
+ var sameState = lastHistoryState === state;
+
// Don't change anything if previous and current URLs and states match. This also prevents
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
// See https://github.com/angular/angular.js/commit/ffb2701
- if (lastBrowserUrl === url && (!$sniffer.history || history.state === state)) {
- return;
+ if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
+ return self;
}
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
lastBrowserUrl = url;
+ lastHistoryState = state;
// Don't use history API if only the hash changed
// due to a bug in IE10/IE11 which leads
// to not firing a `hashchange` nor `popstate` event
// in some cases (see #9143).
- if ($sniffer.history && (!sameBase || history.state !== state)) {
+ if ($sniffer.history && (!sameBase || !sameState)) {
history[replace ? 'replaceState' : 'pushState'](state, '', url);
- lastHistoryState = history.state;
+ cacheState();
+ // Do the assignment again so that those two variables are referentially identical.
+ lastHistoryState = cachedState;
} else {
if (!sameBase) {
reloadLocation = url;
}
if (replace) {
location.replace(url);
+ } else if (!sameBase) {
+ location.href = url;
} else {
- location.href = url;
+ location.hash = getHash(url);
}
}
return self;
@@ -14019,20 +14281,40 @@
* @returns {object} state
*/
self.state = function() {
- return isUndefined(history.state) ? null : history.state;
+ return cachedState;
};
var urlChangeListeners = [],
urlChangeInit = false;
+ function cacheStateAndFireUrlChange() {
+ cacheState();
+ fireUrlChange();
+ }
+
+ // This variable should be used *only* inside the cacheState function.
+ var lastCachedState = null;
+ function cacheState() {
+ // This should be the only place in $browser where `history.state` is read.
+ cachedState = window.history.state;
+ cachedState = isUndefined(cachedState) ? null : cachedState;
+
+ // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
+ if (equals(cachedState, lastCachedState)) {
+ cachedState = lastCachedState;
+ }
+ lastCachedState = cachedState;
+ }
+
function fireUrlChange() {
- if (lastBrowserUrl === self.url() && lastHistoryState === history.state) {
+ if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
return;
}
lastBrowserUrl = self.url();
+ lastHistoryState = cachedState;
forEach(urlChangeListeners, function(listener) {
- listener(self.url(), history.state);
+ listener(self.url(), cachedState);
});
}
@@ -14065,9 +14347,9 @@
// changed by push/replaceState
// html5 history api - popstate event
- if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
+ if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
// hashchange event
- jqLite(window).on('hashchange', fireUrlChange);
+ jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
urlChangeInit = true;
}
@@ -14108,6 +14390,14 @@
var lastCookieString = '';
var cookiePath = self.baseHref();
+ function safeDecodeURIComponent(str) {
+ try {
+ return decodeURIComponent(str);
+ } catch (e) {
+ return str;
+ }
+ }
+
/**
* @name $browser#cookies
*
@@ -14145,8 +14435,8 @@
// - 20 cookies per unique domain
// - 4096 bytes per cookie
if (cookieLength > 4096) {
- $log.warn("Cookie '"+ name +
- "' possibly not set or overflowed because it was too large ("+
+ $log.warn("Cookie '" + name +
+ "' possibly not set or overflowed because it was too large (" +
cookieLength + " > 4096 bytes)!");
}
}
@@ -14161,12 +14451,12 @@
cookie = cookieArray[i];
index = cookie.indexOf('=');
if (index > 0) { //ignore nameless cookies
- name = decodeURIComponent(cookie.substring(0, index));
+ name = safeDecodeURIComponent(cookie.substring(0, index));
// the first value that is seen for a cookie is the most
// specific one. values for the same cookie name that
// follow are for less specific paths.
if (lastCookies[name] === undefined) {
- lastCookies[name] = decodeURIComponent(cookie.substring(index + 1));
+ lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
}
}
}
@@ -14224,9 +14514,9 @@
}
-function $BrowserProvider(){
+function $BrowserProvider() {
this.$get = ['$window', '$log', '$sniffer', '$document',
- function( $window, $log, $sniffer, $document){
+ function($window, $log, $sniffer, $document) {
return new Browser($window, $document, $log, $sniffer);
}];
}
@@ -14600,7 +14890,8 @@
* ```
*
* **Note:** the `script` tag containing the template does not need to be included in the `head` of
- * the document, but it must be below the `ng-app` definition.
+ * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
+ * element with ng-app attribute), otherwise the template will be ignored.
*
* Adding via the $templateCache service:
*
@@ -14691,6 +14982,7 @@
* // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
* transclude: false,
* restrict: 'A',
+ * templateNamespace: 'html',
* scope: false,
* controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
* controllerAs: 'stringAlias',
@@ -14744,9 +15036,9 @@
* #### `multiElement`
* When this property is set to true, the HTML compiler will collect DOM nodes between
* nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
- * together as the directive elements. It is recomended that this feature be used on directives
- * which are not strictly behavioural (such as {@link api/ng.directive:ngClick ngClick}), and which
- * do not manipulate or replace child nodes (such as {@link api/ng.directive:ngInclude ngInclude}).
+ * together as the directive elements. It is recommended that this feature be used on directives
+ * which are not strictly behavioural (such as {@link ngClick}), and which
+ * do not manipulate or replace child nodes (such as {@link ngInclude}).
*
* #### `priority`
* When there are multiple directives defined on a single DOM element, sometimes it
@@ -14759,7 +15051,8 @@
* #### `terminal`
* If set to true then the current `priority` will be the last set of directives
* which will execute (any directives at the current priority will still execute
- * as the order of execution on same `priority` is undefined).
+ * as the order of execution on same `priority` is undefined). Note that expressions
+ * and other directives used in the directive's template will also be excluded from execution.
*
* #### `scope`
* **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
@@ -14792,7 +15085,9 @@
* value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
* in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
* scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
- * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
+ * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
+ * you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
+ * `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
*
* * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
* If no `attr` name is specified then the attribute name is assumed to be the same as the
@@ -14806,7 +15101,7 @@
*
*
* #### `bindToController`
- * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController` will
+ * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
* allow a component to have its properties bound to the controller, rather than to scope. When the controller
* is instantiated, the initial values of the isolate scope bindings are already available.
*
@@ -14906,7 +15201,7 @@
* You can specify `templateUrl` as a string representing the URL or as a function which takes two
* arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
* a string value representing the url. In either case, the template URL is passed through {@link
- * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
+ * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
*
*
* #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
@@ -14916,7 +15211,7 @@
* * `false` - the template will replace the contents of the directive's element.
*
* The replacement process migrates all of the attributes / classes from the old element to the new
- * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
+ * one. See the {@link guide/directive#template-expanding-directive
* Directives Guide} for an example.
*
* There are very few scenarios where element replacement is required for the application function,
@@ -15071,7 +15366,7 @@
* then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
* object that contains the compiled DOM, which is linked to the correct transclusion scope.
*
- * When you call a transclusion function you can pass in a **clone attach function**. This function is accepts
+ * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
* two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
* content and the `scope` is the newly created transclusion scope, to which the clone is bound.
*
@@ -15248,10 +15543,17 @@
*
*
* @param {string|DOMElement} element Element or HTML string to compile into a template function.
- * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
+ * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
+ *
+ *
+ * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
+ * e.g. will not use the right outer scope. Please pass the transclude function as a
+ * `parentBoundTranscludeFn` to the link function instead.
+ *
+ *
* @param {number} maxPriority only apply directives lower than given priority (Only effects the
* root element(s), not their children)
- * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
+ * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
* (a DOM element/tree) to a scope. Where:
*
* * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
@@ -15263,6 +15565,19 @@
* * `clonedElement` - is a clone of the original `element` passed into the compiler.
* * `scope` - is the current scope with which the linking function is working with.
*
+ * * `options` - An optional object hash with linking options. If `options` is provided, then the following
+ * keys may be used to control linking behavior:
+ *
+ * * `parentBoundTranscludeFn` - the transclude function made available to
+ * directives; if given, it will be passed through to the link functions of
+ * directives found in `element` during compilation.
+ * * `transcludeControllers` - an object hash with keys that map controller names
+ * to controller instances; if given, it will make the controllers
+ * available to directives.
+ * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
+ * the cloned elements; only needed for transcludes that are allowed to contain non html
+ * elements (e.g. SVG elements). See also the directive.controller property.
+ *
* Calling the linking function returns the element of the template. It is either the original
* element passed in, or the clone of the element if the `cloneAttachFn` is provided.
*
@@ -15308,8 +15623,8 @@
function $CompileProvider($provide, $$sanitizeUriProvider) {
var hasDirectives = {},
Suffix = 'Directive',
- COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
- CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
+ COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
+ CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
@@ -15319,7 +15634,7 @@
var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
function parseIsolateBindings(scope, directiveName) {
- var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
+ var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
var bindings = {};
@@ -15334,9 +15649,10 @@
}
bindings[scopeName] = {
- attrName: match[3] || scopeName,
- mode: match[1],
- optional: match[2] === '?'
+ mode: match[1][0],
+ collection: match[2] === '*',
+ optional: match[3] === '?',
+ attrName: match[4] || scopeName
};
});
@@ -15408,7 +15724,7 @@
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
* urls during a[href] sanitization.
*
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
+ * The sanitization is a security measure aimed at preventing XSS attacks via html links.
*
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
@@ -15475,14 +15791,14 @@
* * `ng-binding` CSS class
* * `$binding` data property containing an array of the binding expressions
*
- * You may want to use this in production for a significant performance boost. See
+ * You may want to disable this in production for a significant performance boost. See
* {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
*
* The default value is true.
*/
var debugInfoEnabled = true;
this.debugInfoEnabled = function(enabled) {
- if(isDefined(enabled)) {
+ if (isDefined(enabled)) {
debugInfoEnabled = enabled;
return this;
}
@@ -15512,6 +15828,21 @@
};
Attributes.prototype = {
+ /**
+ * @ngdoc method
+ * @name $compile.directive.Attributes#$normalize
+ * @kind function
+ *
+ * @description
+ * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
+ * `data-`) to its normalized, camelCase form.
+ *
+ * Also there is special case for Moz prefix starting with upper case letter.
+ *
+ * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
+ *
+ * @param {string} name Name to normalize
+ */
$normalize: directiveNormalize,
@@ -15526,8 +15857,8 @@
*
* @param {string} classVal The className value that will be added to the element
*/
- $addClass : function(classVal) {
- if(classVal && classVal.length > 0) {
+ $addClass: function(classVal) {
+ if (classVal && classVal.length > 0) {
$animate.addClass(this.$$element, classVal);
}
},
@@ -15543,8 +15874,8 @@
*
* @param {string} classVal The className value that will be removed from the element
*/
- $removeClass : function(classVal) {
- if(classVal && classVal.length > 0) {
+ $removeClass: function(classVal) {
+ if (classVal && classVal.length > 0) {
$animate.removeClass(this.$$element, classVal);
}
},
@@ -15561,7 +15892,7 @@
* @param {string} newClasses The current CSS className value
* @param {string} oldClasses The former CSS className value
*/
- $updateClass : function(newClasses, oldClasses) {
+ $updateClass: function(newClasses, oldClasses) {
var toAdd = tokenDifference(newClasses, oldClasses);
if (toAdd && toAdd.length) {
$animate.addClass(this.$$element, toAdd);
@@ -15591,13 +15922,12 @@
booleanKey = getBooleanAttrName(node, key),
aliasedKey = getAliasedAttrName(node, key),
observer = key,
- normalizedVal,
nodeName;
if (booleanKey) {
this.$$element.prop(key, value);
attrName = booleanKey;
- } else if(aliasedKey) {
+ } else if (aliasedKey) {
this[aliasedKey] = value;
observer = aliasedKey;
}
@@ -15635,22 +15965,22 @@
// for each tuples
var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
- for (var i=0; i
- forEach($compileNodes, function(node, index){
+ forEach($compileNodes, function(node, index) {
if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
$compileNodes[index] = jqLite(node).wrap('').parent()[0];
}
@@ -15781,8 +16111,22 @@
maxPriority, ignoreDirective, previousCompileContext);
compile.$$addScopeClass($compileNodes);
var namespace = null;
- return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement){
+ return function publicLinkFn(scope, cloneConnectFn, options) {
assertArg(scope, 'scope');
+
+ options = options || {};
+ var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
+ transcludeControllers = options.transcludeControllers,
+ futureParentElement = options.futureParentElement;
+
+ // When `parentBoundTranscludeFn` is passed, it is a
+ // `controllersBoundTransclude` function (it was previously passed
+ // as `transclude` to directive.link) so we must unwrap it to get
+ // its `boundTranscludeFn`
+ if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
+ parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
+ }
+
if (!namespace) {
namespace = detectNamespaceForChildElements(futureParentElement);
}
@@ -15824,7 +16168,7 @@
if (!node) {
return 'html';
} else {
- return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg': 'html';
+ return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
}
}
@@ -15906,7 +16250,7 @@
stableNodeList = nodeList;
}
- for(i = 0, ii = linkFns.length; i < ii;) {
+ for (i = 0, ii = linkFns.length; i < ii;) {
node = stableNodeList[linkFns[i++]];
nodeLinkFn = linkFns[i++];
childLinkFn = linkFns[i++];
@@ -15919,7 +16263,7 @@
childScope = scope;
}
- if ( nodeLinkFn.transcludeOnThisElement ) {
+ if (nodeLinkFn.transcludeOnThisElement) {
childBoundTranscludeFn = createBoundTranscludeFn(
scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
nodeLinkFn.elementTranscludeOnThisElement);
@@ -15952,7 +16296,11 @@
transcludedScope.$$transcluded = true;
}
- return transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn, futureParentElement);
+ return transcludeFn(transcludedScope, cloneFn, {
+ parentBoundTranscludeFn: previousBoundTranscludeFn,
+ transcludeControllers: controllers,
+ futureParentElement: futureParentElement
+ });
};
return boundTranscludeFn;
@@ -15974,7 +16322,7 @@
match,
className;
- switch(nodeType) {
+ switch (nodeType) {
case NODE_TYPE_ELEMENT: /* Element */
// use the node name:
addDirective(directives,
@@ -15993,7 +16341,10 @@
// support ngAttr attribute binding
ngAttrName = directiveNormalize(name);
if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
- name = snake_case(ngAttrName.substr(6), '-');
+ name = name.replace(PREFIX_REGEXP, '')
+ .substr(8).replace(/_(.)/g, function(match, letter) {
+ return letter.toUpperCase();
+ });
}
var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
@@ -16066,7 +16417,6 @@
var nodes = [];
var depth = 0;
if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
- var startNode = node;
do {
if (!node) {
throw $compileMinErr('uterdir',
@@ -16150,7 +16500,7 @@
directiveValue;
// executes all directives on the current element
- for(var i = 0, ii = directives.length; i < ii; i++) {
+ for (var i = 0, ii = directives.length; i < ii; i++) {
directive = directives[i];
var attrStart = directive.$$start;
var attrEnd = directive.$$end;
@@ -16394,7 +16744,7 @@
"Controller '{0}', required by directive '{1}', can't be found!",
require, directiveName);
}
- return value;
+ return value || null;
} else if (isArray(require)) {
value = [];
forEach(require, function(require) {
@@ -16421,7 +16771,13 @@
isolateScope = scope.$new(true);
}
- transcludeFn = boundTranscludeFn && controllersBoundTransclude;
+ if (boundTranscludeFn) {
+ // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
+ // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
+ transcludeFn = controllersBoundTransclude;
+ transcludeFn.$$boundTransclude = boundTranscludeFn;
+ }
+
if (controllerDirectives) {
// TODO: merge `controllers` and `elementControllers` into single object.
controllers = {};
@@ -16456,8 +16812,6 @@
}
if (newIsolateScopeDirective) {
- var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
-
compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
templateDirective === newIsolateScopeDirective.$$originalDirective)));
compile.$$addScopeClass($element, true);
@@ -16483,7 +16837,7 @@
isolateBindingContext[scopeName] = value;
});
attrs.$$observers[attrName].$$scope = scope;
- if( attrs[attrName] ) {
+ if (attrs[attrName]) {
// If the attribute has been provided then we trigger an interpolation to ensure
// the value is there for use in the link fn
isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
@@ -16498,7 +16852,7 @@
if (parentGet.literal) {
compare = equals;
} else {
- compare = function(a,b) { return a === b || (a !== a && b !== b); };
+ compare = function(a, b) { return a === b || (a !== a && b !== b); };
}
parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest
@@ -16522,7 +16876,12 @@
return lastValue = parentValue;
};
parentValueWatch.$stateful = true;
- var unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
+ var unwatch;
+ if (definition.collection) {
+ unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
+ } else {
+ unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
+ }
isolateScope.$on('$destroy', unwatch);
break;
@@ -16543,7 +16902,7 @@
}
// PRELINKING
- for(i = 0, ii = preLinkFns.length; i < ii; i++) {
+ for (i = 0, ii = preLinkFns.length; i < ii; i++) {
linkFn = preLinkFns[i];
invokeLinkFn(linkFn,
linkFn.isolateScope ? isolateScope : scope,
@@ -16564,7 +16923,7 @@
childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
// POSTLINKING
- for(i = postLinkFns.length - 1; i >= 0; i--) {
+ for (i = postLinkFns.length - 1; i >= 0; i--) {
linkFn = postLinkFns[i];
invokeLinkFn(linkFn,
linkFn.isolateScope ? isolateScope : scope,
@@ -16624,11 +16983,11 @@
if (name === ignoreDirective) return null;
var match = null;
if (hasDirectives.hasOwnProperty(name)) {
- for(var directive, directives = $injector.get(name + Suffix),
- i = 0, ii = directives.length; i directive.priority) &&
+ if ((maxPriority === undefined || maxPriority > directive.priority) &&
directive.restrict.indexOf(location) != -1) {
if (startAttrName) {
directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
@@ -16636,7 +16995,7 @@
tDirectives.push(directive);
match = directive;
}
- } catch(e) { $exceptionHandler(e); }
+ } catch (e) { $exceptionHandler(e); }
}
}
return match;
@@ -16653,8 +17012,8 @@
*/
function directiveIsMultiElement(name) {
if (hasDirectives.hasOwnProperty(name)) {
- for(var directive, directives = $injector.get(name + Suffix),
- i = 0, ii = directives.length; i'+template+''+type+'>';
+ wrapper.innerHTML = '<' + type + '>' + template + '' + type + '>';
return wrapper.childNodes[0].childNodes;
default:
return template;
@@ -16897,7 +17256,10 @@
function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
- var interpolateFn = $interpolate(value, true);
+ var trustedContext = getTrustedContext(node, name);
+ allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
+
+ var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
// no interpolation found -> ignore
if (!interpolateFn) return;
@@ -16922,16 +17284,16 @@
"ng- versions (such as ng-click instead of onclick) instead.");
}
- // If the attribute was removed, then we are done
- if (!attr[name]) {
- return;
+ // If the attribute has changed since last $interpolate()ed
+ var newValue = attr[name];
+ if (newValue !== value) {
+ // we need to interpolate again since the attribute value has been updated
+ // (e.g. by another directive's compile function)
+ // ensure unset/empty values make interpolateFn falsy
+ interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
+ value = newValue;
}
- // we need to interpolate again, in case the attribute value has been updated
- // (e.g. by another directive's compile function)
- interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name),
- ALL_OR_NOTHING_ATTRS[name] || allOrNothing);
-
// if attribute was updated so that there is no interpolation going on we don't want to
// register any observers
if (!interpolateFn) return;
@@ -16950,7 +17312,7 @@
//skip animations when the first digest occurs (when
//both the new and the old values are the same) since
//the CSS classes are the non-interpolated values
- if(name === 'class' && newValue != oldValue) {
+ if (name === 'class' && newValue != oldValue) {
attr.$updateClass(newValue, oldValue);
} else {
attr.$set(name, newValue);
@@ -16980,7 +17342,7 @@
i, ii;
if ($rootElement) {
- for(i = 0, ii = $rootElement.length; i < ii; i++) {
+ for (i = 0, ii = $rootElement.length; i < ii; i++) {
if ($rootElement[i] == firstElementToRemove) {
$rootElement[i++] = newNode;
for (var j = i, j2 = j + removeCount - 1,
@@ -17055,23 +17417,16 @@
function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
try {
linkFn(scope, $element, attrs, controllers, transcludeFn);
- } catch(e) {
+ } catch (e) {
$exceptionHandler(e, startingTag($element));
}
}
}];
}
-var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
+var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
/**
* Converts all accepted directives format into proper directive name.
- * All of these will become 'myDirective':
- * my:Directive
- * my-directive
- * x-my-directive
- * data-my:directive
- *
- * Also there is special case for Moz prefix starting with upper case letter.
* @param name Name to normalize
*/
function directiveNormalize(name) {
@@ -17128,7 +17483,7 @@
/* NodeList */ nodeList,
/* Element */ rootElement,
/* function(Function) */ boundTranscludeFn
-){}
+) {}
function directiveLinkingFn(
/* nodesetLinkingFn */ nodesetLinkingFn,
@@ -17136,7 +17491,7 @@
/* Node */ node,
/* Element */ rootElement,
/* function(Function) */ boundTranscludeFn
-){}
+) {}
function tokenDifference(str1, str2) {
var values = '',
@@ -17144,10 +17499,10 @@
tokens2 = str2.split(/\s+/);
outer:
- for(var i = 0; i < tokens1.length; i++) {
+ for (var i = 0; i < tokens1.length; i++) {
var token = tokens1[i];
- for(var j = 0; j < tokens2.length; j++) {
- if(token == tokens2[j]) continue outer;
+ for (var j = 0; j < tokens2.length; j++) {
+ if (token == tokens2[j]) continue outer;
}
values += (values.length > 0 ? ' ' : '') + token;
}
@@ -17230,6 +17585,10 @@
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
* `window` object (not recommended)
*
+ * The string can use the `controller as property` syntax, where the controller instance is published
+ * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
+ * to work correctly.
+ *
* @param {Object} locals Injection locals for Controller.
* @return {Object} Instance of given controller.
*
@@ -17253,7 +17612,7 @@
identifier = ident;
}
- if(isString(expression)) {
+ if (isString(expression)) {
match = expression.match(CNTRL_REG),
constructor = match[1],
identifier = identifier || match[3];
@@ -17275,10 +17634,10 @@
//
// This feature is not intended for use by applications, and is thus not documented
// publicly.
- var Constructor = function() {};
- Constructor.prototype = (isArray(expression) ?
+ // Object creation: http://jsperf.com/create-constructor/2
+ var controllerPrototype = (isArray(expression) ?
expression[expression.length - 1] : expression).prototype;
- instance = new Constructor();
+ instance = Object.create(controllerPrototype);
if (identifier) {
addIdentifier(locals, identifier, instance, constructor || expression.name);
@@ -17339,8 +17698,8 @@
*/
-function $DocumentProvider(){
- this.$get = ['$window', function(window){
+function $DocumentProvider() {
+ this.$get = ['$window', function(window) {
return jqLite(window.document);
}];
}
@@ -17361,8 +17720,8 @@
* ## Example:
*
* ```js
- * angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
- * return function (exception, cause) {
+ * angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
+ * return function(exception, cause) {
* exception.message += ' (caused by "' + cause + '")';
* throw exception;
* };
@@ -17372,6 +17731,14 @@
* This example will override the normal action of `$exceptionHandler`, to make angular
* exceptions fail hard when they happen, instead of just logging to the console.
*
+ *
+ * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
+ * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
+ * (unless executed during a digest).
+ *
+ * If you wish, you can manually delegate exceptions, e.g.
+ * `try { ... } catch(e) { $exceptionHandler(e); }`
+ *
* @param {Error} exception Exception associated with the error.
* @param {string=} cause optional information about the context in which
* the error was thrown.
@@ -17385,6 +17752,36 @@
}];
}
+var APPLICATION_JSON = 'application/json';
+var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
+var JSON_START = /^\[|^\{(?!\{)/;
+var JSON_ENDS = {
+ '[': /]$/,
+ '{': /}$/
+};
+var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
+
+function defaultHttpResponseTransform(data, headers) {
+ if (isString(data)) {
+ // Strip json vulnerability protection prefix and trim whitespace
+ var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
+
+ if (tempData) {
+ var contentType = headers('Content-Type');
+ if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
+ data = fromJson(tempData);
+ }
+ }
+ }
+
+ return data;
+}
+
+function isJsonLike(str) {
+ var jsonStart = str.match(JSON_START);
+ return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
+}
+
/**
* Parse headers into key value object
*
@@ -17392,7 +17789,7 @@
* @returns {Object} Parsed headers as key value object
*/
function parseHeaders(headers) {
- var parsed = {}, key, val, i;
+ var parsed = createMap(), key, val, i;
if (!headers) return parsed;
@@ -17429,7 +17826,11 @@
if (!headersObj) headersObj = parseHeaders(headers);
if (name) {
- return headersObj[lowercase(name)] || null;
+ var value = headersObj[lowercase(name)];
+ if (value === void 0) {
+ value = null;
+ }
+ return value;
}
return headersObj;
@@ -17443,16 +17844,17 @@
* This function is used for both request and response transforming
*
* @param {*} data Data to transform.
- * @param {function(string=)} headers Http headers getter fn.
+ * @param {function(string=)} headers HTTP headers getter fn.
+ * @param {number} status HTTP status code of the response.
* @param {(Function|Array.)} fns Function or an array of functions.
* @returns {*} Transformed data.
*/
-function transformData(data, headers, fns) {
+function transformData(data, headers, status, fns) {
if (isFunction(fns))
- return fns(data, headers);
+ return fns(data, headers, status);
forEach(fns, function(fn) {
- data = fn(data, headers);
+ data = fn(data, headers, status);
});
return data;
@@ -17471,12 +17873,6 @@
* Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
* */
function $HttpProvider() {
- var JSON_START = /^\s*(\[|\{[^\{])/,
- JSON_END = /[\}\]]\s*$/,
- PROTECTION_PREFIX = /^\)\]\}',?\n/,
- APPLICATION_JSON = 'application/json',
- CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
-
/**
* @ngdoc property
* @name $httpProvider#defaults
@@ -17484,6 +17880,11 @@
*
* Object containing default values for all {@link ng.$http $http} requests.
*
+ * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
+ * that will provide the cache for all requests who set their `cache` property to `true`.
+ * If you set the `default.cache = false` then only requests that specify their own custom
+ * cache object will be cached. See {@link $http#caching $http Caching} for more information.
+ *
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
* Defaults value is `'XSRF-TOKEN'`.
*
@@ -17497,25 +17898,15 @@
* - **`defaults.headers.post`**
* - **`defaults.headers.put`**
* - **`defaults.headers.patch`**
+ *
**/
var defaults = this.defaults = {
// transform incoming response data
- transformResponse: [function defaultHttpResponseTransform(data, headers) {
- if (isString(data)) {
- // strip json vulnerability protection prefix
- data = data.replace(PROTECTION_PREFIX, '');
- var contentType = headers('Content-Type');
- if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
- (JSON_START.test(data) && JSON_END.test(data))) {
- data = fromJson(data);
- }
- }
- return data;
- }],
+ transformResponse: [defaultHttpResponseTransform],
// transform outgoing request data
transformRequest: [function(d) {
- return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
+ return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
}],
// default headers
@@ -17539,7 +17930,7 @@
* @description
*
* Configure $http service to combine processing of multiple http responses received at around
- * the same time via {@link ng.$rootScope#applyAsync $rootScope.$applyAsync}. This can result in
+ * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
* significant performance improvement for bigger applications that make many HTTP requests
* concurrently (common during application bootstrap).
*
@@ -17561,9 +17952,18 @@
};
/**
- * Are ordered by request, i.e. they are applied in the same order as the
+ * @ngdoc property
+ * @name $httpProvider#interceptors
+ * @description
+ *
+ * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
+ * pre-processing of request or postprocessing of responses.
+ *
+ * These service factories are ordered by request, i.e. they are applied in the same order as the
* array, on request, but reverse order, on response.
- */
+ *
+ * {@link ng.$http#interceptors Interceptors detailed info}
+ **/
var interceptorFactories = this.interceptors = [];
this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
@@ -17615,7 +18015,8 @@
* with two $http specific methods: `success` and `error`.
*
* ```js
- * $http({method: 'GET', url: '/someUrl'}).
+ * // Simple GET request example :
+ * $http.get('/someUrl').
* success(function(data, status, headers, config) {
* // this callback will be called asynchronously
* // when the response is available
@@ -17626,6 +18027,20 @@
* });
* ```
*
+ * ```js
+ * // Simple POST request example (passing data) :
+ * $http.post('/someUrl', {msg:'hello word!'}).
+ * success(function(data, status, headers, config) {
+ * // this callback will be called asynchronously
+ * // when the response is available
+ * }).
+ * error(function(data, status, headers, config) {
+ * // called asynchronously if an error occurs
+ * // or server returns response with an error status.
+ * });
+ * ```
+ *
+ *
* Since the returned value of calling the $http function is a `promise`, you can also use
* the `then` method to register callbacks, and these callbacks will receive a single argument –
* an object representing the response. See the API signature and type info below for more
@@ -17698,12 +18113,27 @@
* In addition, you can supply a `headers` property in the config object passed when
* calling `$http(config)`, which overrides the defaults without changing them globally.
*
+ * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
+ * Use the `headers` property, setting the desired header to `undefined`. For example:
+ *
+ * ```js
+ * var req = {
+ * method: 'POST',
+ * url: 'http://example.com',
+ * headers: {
+ * 'Content-Type': undefined
+ * },
+ * data: { test: 'test' },
+ * }
+ *
+ * $http(req).success(function(){...}).error(function(){...});
+ * ```
*
* ## Transforming Requests and Responses
*
* Both requests and responses can be transformed using transformation functions: `transformRequest`
* and `transformResponse`. These properties can be a single function that returns
- * the transformed value (`{function(data, headersGetter)`) or an array of such transformation functions,
+ * the transformed value (`{function(data, headersGetter, status)`) or an array of such transformation functions,
* which allows you to `push` or `unshift` a new transformation function into the transformation chain.
*
* ### Default Transformations
@@ -17778,7 +18208,7 @@
*
* You can change the default cache to a new object (built with
* {@link ng.$cacheFactory `$cacheFactory`}) by updating the
- * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
+ * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
* their `cache` property to `true` will now use this cache object.
*
* If you set the default cache to `false` then only requests that specify their own custom
@@ -17944,12 +18374,14 @@
* `{function(data, headersGetter)|Array.}` –
* transform function or an array of such functions. The transform function takes the http
* request body and headers and returns its transformed (typically serialized) version.
- * See {@link #overriding-the-default-transformations-per-request Overriding the Default Transformations}
+ * See {@link ng.$http#overriding-the-default-transformations-per-request
+ * Overriding the Default Transformations}
* - **transformResponse** –
- * `{function(data, headersGetter)|Array.}` –
+ * `{function(data, headersGetter, status)|Array.}` –
* transform function or an array of such functions. The transform function takes the http
- * response body and headers and returns its transformed (typically deserialized) version.
- * See {@link #overriding-the-default-transformations-per-request Overriding the Default Transformations}
+ * response body, headers and status and returns its transformed (typically deserialized) version.
+ * See {@link ng.$http#overriding-the-default-transformations-per-request
+ * Overriding the Default Transformations}
* - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
* GET request, otherwise if a cache instance built with
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
@@ -18070,20 +18502,23 @@
*/
function $http(requestConfig) {
- var config = {
+
+ if (!angular.isObject(requestConfig)) {
+ throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
+ }
+
+ var config = extend({
method: 'get',
transformRequest: defaults.transformRequest,
transformResponse: defaults.transformResponse
- };
- var headers = mergeHeaders(requestConfig);
-
- extend(config, requestConfig);
- config.headers = headers;
+ }, requestConfig);
+
+ config.headers = mergeHeaders(requestConfig);
config.method = uppercase(config.method);
var serverRequest = function(config) {
- headers = config.headers;
- var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
+ var headers = config.headers;
+ var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
// strip content-type if data is undefined
if (isUndefined(reqData)) {
@@ -18099,7 +18534,7 @@
}
// send request
- return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
+ return sendReq(config, reqData).then(transformResponse, transformResponse);
};
var chain = [serverRequest, undefined];
@@ -18115,7 +18550,7 @@
}
});
- while(chain.length) {
+ while (chain.length) {
var thenFn = chain.shift();
var rejectFn = chain.shift();
@@ -18140,14 +18575,34 @@
function transformResponse(response) {
// make a copy since the response must be cacheable
- var resp = extend({}, response, {
- data: transformData(response.data, response.headers, config.transformResponse)
- });
+ var resp = extend({}, response);
+ if (!response.data) {
+ resp.data = response.data;
+ } else {
+ resp.data = transformData(response.data, response.headers, response.status, config.transformResponse);
+ }
return (isSuccess(response.status))
? resp
: $q.reject(resp);
}
+ function executeHeaderFns(headers) {
+ var headerContent, processedHeaders = {};
+
+ forEach(headers, function(headerFn, header) {
+ if (isFunction(headerFn)) {
+ headerContent = headerFn();
+ if (headerContent != null) {
+ processedHeaders[header] = headerContent;
+ }
+ } else {
+ processedHeaders[header] = headerFn;
+ }
+ });
+
+ return processedHeaders;
+ }
+
function mergeHeaders(config) {
var defHeaders = defaults.headers,
reqHeaders = extend({}, config.headers),
@@ -18170,23 +18625,7 @@
}
// execute if header value is a function for merged headers
- execHeaders(reqHeaders);
- return reqHeaders;
-
- function execHeaders(headers) {
- var headerContent;
-
- forEach(headers, function(headerFn, header) {
- if (isFunction(headerFn)) {
- headerContent = headerFn();
- if (headerContent != null) {
- headers[header] = headerContent;
- } else {
- delete headers[header];
- }
- }
- });
- }
+ return executeHeaderFns(reqHeaders);
}
}
@@ -18329,11 +18768,12 @@
* !!! ACCESSES CLOSURE VARS:
* $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
*/
- function sendReq(config, reqData, reqHeaders) {
+ function sendReq(config, reqData) {
var deferred = $q.defer(),
promise = deferred.promise,
cache,
cachedResp,
+ reqHeaders = config.headers,
url = buildUrl(config.url, config.params);
$http.pendingRequests.push(config);
@@ -18352,8 +18792,7 @@
if (isDefined(cachedResp)) {
if (isPromiseLike(cachedResp)) {
// cached request has already been sent, but there is no response yet
- cachedResp.then(removePendingReq, removePendingReq);
- return cachedResp;
+ cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
} else {
// serving from cache
if (isArray(cachedResp)) {
@@ -18427,10 +18866,13 @@
status: status,
headers: headersGetter(headers),
config: config,
- statusText : statusText
- });
- }
-
+ statusText: statusText
+ });
+ }
+
+ function resolvePromiseWithResult(result) {
+ resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
+ }
function removePendingReq() {
var idx = $http.pendingRequests.indexOf(config);
@@ -18448,7 +18890,7 @@
forEach(value, function(v) {
if (isObject(v)) {
- if (isDate(v)){
+ if (isDate(v)) {
v = v.toISOString();
} else {
v = toJson(v);
@@ -18458,7 +18900,7 @@
encodeUriQuery(v));
});
});
- if(parts.length > 0) {
+ if (parts.length > 0) {
url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
}
return url;
@@ -18545,7 +18987,7 @@
statusText);
};
- var requestError = function () {
+ var requestError = function() {
// The response is always empty
// See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
completeRequest(callback, -1, null, null, '');
@@ -18592,7 +19034,9 @@
function completeRequest(callback, status, response, headersString, statusText) {
// cancel timeout and subsequent timeout promise resolution
- timeoutId && $browserDefer.cancel(timeoutId);
+ if (timeoutId !== undefined) {
+ $browserDefer.cancel(timeoutId);
+ }
jsonpDone = xhr = null;
callback(status, response, headersString, statusText);
@@ -18687,7 +19131,7 @@
* @param {string=} value new value to set the starting symbol to.
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
*/
- this.startSymbol = function(value){
+ this.startSymbol = function(value) {
if (value) {
startSymbol = value;
return this;
@@ -18705,7 +19149,7 @@
* @param {string=} value new value to set the ending symbol to.
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
*/
- this.endSymbol = function(value){
+ this.endSymbol = function(value) {
if (value) {
endSymbol = value;
return this;
@@ -18831,9 +19275,9 @@
concat = [],
expressionPositions = [];
- while(index < textLength) {
- if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
- ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
+ while (index < textLength) {
+ if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
+ ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
if (index !== startIndex) {
concat.push(unescapeText(text.substring(index, startIndex)));
}
@@ -18867,34 +19311,31 @@
if (!mustHaveExpression || expressions.length) {
var compute = function(values) {
- for(var i = 0, ii = expressions.length; i < ii; i++) {
+ for (var i = 0, ii = expressions.length; i < ii; i++) {
if (allOrNothing && isUndefined(values[i])) return;
concat[expressionPositions[i]] = values[i];
}
return concat.join('');
};
- var getValue = function (value) {
+ var getValue = function(value) {
return trustedContext ?
$sce.getTrusted(trustedContext, value) :
$sce.valueOf(value);
};
- var stringify = function (value) {
+ var stringify = function(value) {
if (value == null) { // null || undefined
return '';
}
switch (typeof value) {
- case 'string': {
+ case 'string':
break;
- }
- case 'number': {
+ case 'number':
value = '' + value;
break;
- }
- default: {
+ default:
value = toJson(value);
- }
}
return value;
@@ -18911,7 +19352,7 @@
}
return compute(values);
- } catch(err) {
+ } catch (err) {
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
err.toString());
$exceptionHandler(newErr);
@@ -18921,7 +19362,7 @@
// all of these properties are undocumented for now
exp: text, //just for compatibility with regular watchers created via $watch
expressions: expressions,
- $$watchDelegate: function (scope, listener, objectEquality) {
+ $$watchDelegate: function(scope, listener, objectEquality) {
var lastValue;
return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
var currValue = compute(values);
@@ -18941,8 +19382,9 @@
function parseStringifyInterceptor(value) {
try {
- return stringify(getValue(value));
- } catch(err) {
+ value = getValue(value);
+ return allOrNothing && !isDefined(value) ? value : stringify(value);
+ } catch (err) {
var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
err.toString());
$exceptionHandler(newErr);
@@ -19042,33 +19484,33 @@
* // Don't start a new fight if we are already fighting
* if ( angular.isDefined(stop) ) return;
*
- * stop = $interval(function() {
- * if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
- * $scope.blood_1 = $scope.blood_1 - 3;
- * $scope.blood_2 = $scope.blood_2 - 4;
- * } else {
- * $scope.stopFight();
- * }
- * }, 100);
- * };
+ * stop = $interval(function() {
+ * if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
+ * $scope.blood_1 = $scope.blood_1 - 3;
+ * $scope.blood_2 = $scope.blood_2 - 4;
+ * } else {
+ * $scope.stopFight();
+ * }
+ * }, 100);
+ * };
*
- * $scope.stopFight = function() {
- * if (angular.isDefined(stop)) {
- * $interval.cancel(stop);
- * stop = undefined;
- * }
- * };
+ * $scope.stopFight = function() {
+ * if (angular.isDefined(stop)) {
+ * $interval.cancel(stop);
+ * stop = undefined;
+ * }
+ * };
*
- * $scope.resetFight = function() {
- * $scope.blood_1 = 100;
- * $scope.blood_2 = 120;
- * };
+ * $scope.resetFight = function() {
+ * $scope.blood_1 = 100;
+ * $scope.blood_2 = 120;
+ * };
*
- * $scope.$on('$destroy', function() {
- * // Make sure that the interval is destroyed too
- * $scope.stopFight();
- * });
- * }])
+ * $scope.$on('$destroy', function() {
+ * // Make sure that the interval is destroyed too
+ * $scope.stopFight();
+ * });
+ * }])
* // Register the 'myCurrentTime' directive factory method.
* // We inject $interval and dateFilter service since the factory method is DI.
* .directive('myCurrentTime', ['$interval', 'dateFilter',
@@ -19181,7 +19623,7 @@
*
* * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
*/
-function $LocaleProvider(){
+function $LocaleProvider() {
this.$get = function() {
return {
id: 'en-us',
@@ -19224,7 +19666,7 @@
SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
AMPMS: ['AM','PM'],
medium: 'MMM d, y h:mm:ss a',
- short: 'M/d/yy h:mm a',
+ 'short': 'M/d/yy h:mm a',
fullDate: 'EEEE, MMMM d, y',
longDate: 'MMMM d, y',
mediumDate: 'MMM d, y',
@@ -19265,8 +19707,8 @@
return segments.join('/');
}
-function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
- var parsedUrl = urlResolve(absoluteUrl, appBase);
+function parseAbsoluteUrl(absoluteUrl, locationObj) {
+ var parsedUrl = urlResolve(absoluteUrl);
locationObj.$$protocol = parsedUrl.protocol;
locationObj.$$host = parsedUrl.hostname;
@@ -19274,12 +19716,12 @@
}
-function parseAppUrl(relativeUrl, locationObj, appBase) {
+function parseAppUrl(relativeUrl, locationObj) {
var prefixed = (relativeUrl.charAt(0) !== '/');
if (prefixed) {
relativeUrl = '/' + relativeUrl;
}
- var match = urlResolve(relativeUrl, appBase);
+ var match = urlResolve(relativeUrl);
locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
match.pathname.substring(1) : match.pathname);
locationObj.$$search = parseKeyValue(match.search);
@@ -19311,6 +19753,10 @@
return index == -1 ? url : url.substr(0, index);
}
+function trimEmptyHash(url) {
+ return url.replace(/(#.+)|#$/, '$1');
+}
+
function stripFile(url) {
return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
@@ -19334,12 +19780,12 @@
this.$$html5 = true;
basePrefix = basePrefix || '';
var appBaseNoFile = stripFile(appBase);
- parseAbsoluteUrl(appBase, this, appBase);
+ parseAbsoluteUrl(appBase, this);
/**
* Parse given html5 (regular) url string into properties
- * @param {string} newAbsoluteUrl HTML5 url
+ * @param {string} url HTML5 url
* @private
*/
this.$$parse = function(url) {
@@ -19349,7 +19795,7 @@
appBaseNoFile);
}
- parseAppUrl(pathUrl, this, appBase);
+ parseAppUrl(pathUrl, this);
if (!this.$$path) {
this.$$path = '/';
@@ -19380,14 +19826,14 @@
var appUrl, prevAppUrl;
var rewrittenUrl;
- if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
+ if ((appUrl = beginsWith(appBase, url)) !== undefined) {
prevAppUrl = appUrl;
- if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
+ if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
} else {
rewrittenUrl = appBase + prevAppUrl;
}
- } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
+ } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
rewrittenUrl = appBaseNoFile + appUrl;
} else if (appBaseNoFile == url + '/') {
rewrittenUrl = appBaseNoFile;
@@ -19412,7 +19858,7 @@
function LocationHashbangUrl(appBase, hashPrefix) {
var appBaseNoFile = stripFile(appBase);
- parseAbsoluteUrl(appBase, this, appBase);
+ parseAbsoluteUrl(appBase, this);
/**
@@ -19422,17 +19868,26 @@
*/
this.$$parse = function(url) {
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
- var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
- ? beginsWith(hashPrefix, withoutBaseUrl)
- : (this.$$html5)
- ? withoutBaseUrl
- : '';
-
- if (!isString(withoutHashUrl)) {
- throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
- hashPrefix);
- }
- parseAppUrl(withoutHashUrl, this, appBase);
+ var withoutHashUrl;
+
+ if (withoutBaseUrl.charAt(0) === '#') {
+
+ // The rest of the url starts with a hash so we have
+ // got either a hashbang path or a plain hash fragment
+ withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
+ if (isUndefined(withoutHashUrl)) {
+ // There was no hashbang prefix so we just have a hash fragment
+ withoutHashUrl = withoutBaseUrl;
+ }
+
+ } else {
+ // There was no hashbang path nor hash fragment:
+ // If we are in HTML5 mode we use what is left as the path;
+ // Otherwise we ignore what is left
+ withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
+ }
+
+ parseAppUrl(withoutHashUrl, this);
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
@@ -19449,7 +19904,7 @@
* Inside of Angular, we're always using pathnames that
* do not include drive names for routing.
*/
- function removeWindowsDriveName (path, url, base) {
+ function removeWindowsDriveName(path, url, base) {
/*
Matches paths for file protocol on windows,
such as /C:/foo/bar, and captures only /foo/bar.
@@ -19486,7 +19941,7 @@
};
this.$$parseLinkUrl = function(url, relHref) {
- if(stripHash(appBase) == stripHash(url)) {
+ if (stripHash(appBase) == stripHash(url)) {
this.$$parse(url);
return true;
}
@@ -19521,11 +19976,11 @@
var rewrittenUrl;
var appUrl;
- if ( appBase == stripHash(url) ) {
+ if (appBase == stripHash(url)) {
rewrittenUrl = url;
- } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
+ } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
rewrittenUrl = appBase + hashPrefix + appUrl;
- } else if ( appBaseNoFile === url + '/') {
+ } else if (appBaseNoFile === url + '/') {
rewrittenUrl = appBaseNoFile;
}
if (rewrittenUrl) {
@@ -19570,6 +20025,13 @@
* Return full url representation with all segments encoded according to rules specified in
* [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var absUrl = $location.absUrl();
+ * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
+ * ```
+ *
* @return {string} full url
*/
absUrl: locationGetter('$$absUrl'),
@@ -19585,6 +20047,13 @@
*
* Change path, search and hash, when called with parameter and return `$location`.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var url = $location.url();
+ * // => "/some/path?foo=bar&baz=xoxo"
+ * ```
+ *
* @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
* @return {string} url
*/
@@ -19593,8 +20062,8 @@
return this.$$url;
var match = PATH_MATCH.exec(url);
- if (match[1]) this.path(decodeURIComponent(match[1]));
- if (match[2] || match[1]) this.search(match[3] || '');
+ if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
+ if (match[2] || match[1] || url === '') this.search(match[3] || '');
this.hash(match[5] || '');
return this;
@@ -19609,6 +20078,13 @@
*
* Return protocol of current url.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var protocol = $location.protocol();
+ * // => "http"
+ * ```
+ *
* @return {string} protocol of current url
*/
protocol: locationGetter('$$protocol'),
@@ -19622,6 +20098,13 @@
*
* Return host of current url.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var host = $location.host();
+ * // => "example.com"
+ * ```
+ *
* @return {string} host of current url.
*/
host: locationGetter('$$host'),
@@ -19635,6 +20118,13 @@
*
* Return port of current url.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var port = $location.port();
+ * // => 80
+ * ```
+ *
* @return {Number} port
*/
port: locationGetter('$$port'),
@@ -19653,6 +20143,13 @@
* Note: Path should always begin with forward slash (/), this method will add the forward slash
* if it is missing.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
+ * var path = $location.path();
+ * // => "/some/path"
+ * ```
+ *
* @param {(string|number)=} path New path
* @return {string} path
*/
@@ -19678,10 +20175,9 @@
* var searchObject = $location.search();
* // => {foo: 'bar', baz: 'xoxo'}
*
- *
* // set foo to 'yipee'
* $location.search('foo', 'yipee');
- * // => $location
+ * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
* ```
*
* @param {string|Object.|Object.>} search New search params - string or
@@ -19716,6 +20212,7 @@
search = search.toString();
this.$$search = parseKeyValue(search);
} else if (isObject(search)) {
+ search = copy(search, {});
// remove object undefined or null properties
forEach(search, function(value, key) {
if (value == null) delete search[key];
@@ -19750,6 +20247,13 @@
*
* Change hash fragment when called with parameter and return `$location`.
*
+ *
+ * ```js
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
+ * var hash = $location.hash();
+ * // => "hashValue"
+ * ```
+ *
* @param {(string|number)=} hash New hash fragment
* @return {string} hash
*/
@@ -19771,7 +20275,7 @@
}
};
-forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function (Location) {
+forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
Location.prototype = Object.create(locationPrototype);
/**
@@ -19863,7 +20367,7 @@
* @description
* Use the `$locationProvider` to configure how the application deep linking paths are stored.
*/
-function $LocationProvider(){
+function $LocationProvider() {
var hashPrefix = '',
html5Mode = {
enabled: false,
@@ -19901,8 +20405,8 @@
* whether or not a tag is required to be present. If `enabled` and `requireBase` are
* true, and a base tag is not present, an error will be thrown when `$location` is injected.
* See the {@link guide/$location $location guide for more information}
- * - **rewriteLinks** - `{boolean}` - (default: `false`) When html5Mode is enabled, disables
- * url rewriting for relative linksTurns off url rewriting for relative links.
+ * - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
+ * enables/disables url rewriting for relative links.
*
* @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
*/
@@ -19913,7 +20417,7 @@
} else if (isObject(mode)) {
if (isBoolean(mode.enabled)) {
- html5Mode.enabled = mode.enabled;
+ html5Mode.enabled = mode.enabled;
}
if (isBoolean(mode.requireBase)) {
@@ -19921,7 +20425,7 @@
}
if (isBoolean(mode.rewriteLinks)) {
- html5Mode.rewriteLinks = mode.rewriteLinks;
+ html5Mode.rewriteLinks = mode.rewriteLinks;
}
return this;
@@ -19940,7 +20444,7 @@
* This change can be prevented by calling
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
* details about event object. Upon successful change
- * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
+ * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
*
* The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
* the browser supports the HTML5 History API.
@@ -19969,8 +20473,8 @@
* @param {string=} oldState History state object that was before it was changed.
*/
- this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
- function( $rootScope, $browser, $sniffer, $rootElement) {
+ this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
+ function($rootScope, $browser, $sniffer, $rootElement, $window) {
var $location,
LocationMode,
baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
@@ -20052,7 +20556,7 @@
if ($location.absUrl() != $browser.url()) {
$rootScope.$apply();
// hack to work around FF6 bug 684208 when scenario runner clicks on links
- window.angular['ff-684208-preventDefault'] = true;
+ $window.angular['ff-684208-preventDefault'] = true;
}
}
}
@@ -20071,11 +20575,19 @@
$rootScope.$evalAsync(function() {
var oldUrl = $location.absUrl();
var oldState = $location.$$state;
+ var defaultPrevented;
$location.$$parse(newUrl);
$location.$$state = newState;
- if ($rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
- newState, oldState).defaultPrevented) {
+
+ defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
+ newState, oldState).defaultPrevented;
+
+ // if the location was changed by a `$locationChangeStart` handler then stop
+ // processing this location change
+ if ($location.absUrl() !== newUrl) return;
+
+ if (defaultPrevented) {
$location.$$parse(oldUrl);
$location.$$state = oldState;
setBrowserUrlWithFallback(oldUrl, false, oldState);
@@ -20089,22 +20601,33 @@
// update browser
$rootScope.$watch(function $locationWatch() {
- var oldUrl = $browser.url();
+ var oldUrl = trimEmptyHash($browser.url());
+ var newUrl = trimEmptyHash($location.absUrl());
var oldState = $browser.state();
var currentReplace = $location.$$replace;
-
- if (initializing || oldUrl !== $location.absUrl() ||
- ($location.$$html5 && $sniffer.history && oldState !== $location.$$state)) {
+ var urlOrStateChanged = oldUrl !== newUrl ||
+ ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
+
+ if (initializing || urlOrStateChanged) {
initializing = false;
$rootScope.$evalAsync(function() {
- if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl,
- $location.$$state, oldState).defaultPrevented) {
+ var newUrl = $location.absUrl();
+ var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
+ $location.$$state, oldState).defaultPrevented;
+
+ // if the location was changed by a `$locationChangeStart` handler then stop
+ // processing this location change
+ if ($location.absUrl() !== newUrl) return;
+
+ if (defaultPrevented) {
$location.$$parse(oldUrl);
$location.$$state = oldState;
} else {
- setBrowserUrlWithFallback($location.absUrl(), currentReplace,
- oldState === $location.$$state ? null : $location.$$state);
+ if (urlOrStateChanged) {
+ setBrowserUrlWithFallback(newUrl, currentReplace,
+ oldState === $location.$$state ? null : $location.$$state);
+ }
afterLocationChange(oldUrl, oldState);
}
});
@@ -20168,7 +20691,7 @@
* @description
* Use the `$logProvider` to configure how the application logs messages
*/
-function $LogProvider(){
+function $LogProvider() {
var debug = true,
self = this;
@@ -20188,7 +20711,7 @@
}
};
- this.$get = ['$window', function($window){
+ this.$get = ['$window', function($window) {
return {
/**
* @ngdoc method
@@ -20233,7 +20756,7 @@
* @description
* Write a debug message
*/
- debug: (function () {
+ debug: (function() {
var fn = consoleLog('debug');
return function() {
@@ -20292,7 +20815,7 @@
// Sandboxing Angular Expressions
// ------------------------------
// Angular expressions are generally considered safe because these expressions only have direct
-// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
+// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
// obtaining a reference to native JS functions such as the Function constructor.
//
// As an example, consider the following Angular expression:
@@ -20301,7 +20824,7 @@
//
// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
// against the expression language, but not to prevent exploits that were enabled by exposing
-// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
+// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
// practice and therefore we are not even trying to protect against interaction with an object
// explicitly exposed in this way.
//
@@ -20309,6 +20832,8 @@
// window or some DOM object that has a reference to window is published onto a Scope.
// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
// native objects.
+//
+// See https://docs.angularjs.org/guide/security
function ensureSafeMemberName(name, fullExpression) {
@@ -20317,7 +20842,7 @@
|| name === "__proto__") {
throw $parseMinErr('isecfld',
'Attempting to access a disallowed field in Angular expressions! '
- +'Expression: {0}', fullExpression);
+ + 'Expression: {0}', fullExpression);
}
return name;
}
@@ -20386,8 +20911,7 @@
//Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
var OPERATORS = extend(createMap(), {
- /* jshint bitwise : false */
- '+':function(self, locals, a,b){
+ '+':function(self, locals, a, b) {
a=a(self, locals); b=b(self, locals);
if (isDefined(a)) {
if (isDefined(b)) {
@@ -20395,33 +20919,30 @@
}
return a;
}
- return isDefined(b)?b:undefined;},
- '-':function(self, locals, a,b){
+ return isDefined(b) ? b : undefined;},
+ '-':function(self, locals, a, b) {
a=a(self, locals); b=b(self, locals);
- return (isDefined(a)?a:0)-(isDefined(b)?b:0);
+ return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
},
- '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
- '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
- '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
- '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
- '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
- '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
- '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
- '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
- '<':function(self, locals, a,b){return a(self, locals)':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
- '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
- '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
- '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
- '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
- '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
- '!':function(self, locals, a){return !a(self, locals);},
+ '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);},
+ '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);},
+ '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);},
+ '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);},
+ '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);},
+ '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);},
+ '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);},
+ '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);},
+ '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);},
+ '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);},
+ '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);},
+ '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);},
+ '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);},
+ '!':function(self, locals, a) {return !a(self, locals);},
//Tokenized as operators but parsed as assignment/filters
'=':true,
'|':true
});
-/* jshint bitwise: true */
var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
@@ -20431,54 +20952,41 @@
/**
* @constructor
*/
-var Lexer = function (options) {
+var Lexer = function(options) {
this.options = options;
};
Lexer.prototype = {
constructor: Lexer,
- lex: function (text) {
+ lex: function(text) {
this.text = text;
this.index = 0;
- this.ch = undefined;
this.tokens = [];
while (this.index < this.text.length) {
- this.ch = this.text.charAt(this.index);
- if (this.is('"\'')) {
- this.readString(this.ch);
- } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
+ var ch = this.text.charAt(this.index);
+ if (ch === '"' || ch === "'") {
+ this.readString(ch);
+ } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
this.readNumber();
- } else if (this.isIdent(this.ch)) {
+ } else if (this.isIdent(ch)) {
this.readIdent();
- } else if (this.is('(){}[].,;:?')) {
- this.tokens.push({
- index: this.index,
- text: this.ch
- });
- this.index++;
- } else if (this.isWhitespace(this.ch)) {
+ } else if (this.is(ch, '(){}[].,;:?')) {
+ this.tokens.push({index: this.index, text: ch});
this.index++;
- } else {
- var ch2 = this.ch + this.peek();
+ } else if (this.isWhitespace(ch)) {
+ this.index++;
+ } else {
+ var ch2 = ch + this.peek();
var ch3 = ch2 + this.peek(2);
- var fn = OPERATORS[this.ch];
- var fn2 = OPERATORS[ch2];
- var fn3 = OPERATORS[ch3];
- if (fn3) {
- this.tokens.push({index: this.index, text: ch3, fn: fn3});
- this.index += 3;
- } else if (fn2) {
- this.tokens.push({index: this.index, text: ch2, fn: fn2});
- this.index += 2;
- } else if (fn) {
- this.tokens.push({
- index: this.index,
- text: this.ch,
- fn: fn
- });
- this.index += 1;
+ var op1 = OPERATORS[ch];
+ var op2 = OPERATORS[ch2];
+ var op3 = OPERATORS[ch3];
+ if (op1 || op2 || op3) {
+ var token = op3 ? ch3 : (op2 ? ch2 : ch);
+ this.tokens.push({index: this.index, text: token, operator: true});
+ this.index += token.length;
} else {
this.throwError('Unexpected next character ', this.index, this.index + 1);
}
@@ -20487,8 +20995,8 @@
return this.tokens;
},
- is: function(chars) {
- return chars.indexOf(this.ch) !== -1;
+ is: function(ch, chars) {
+ return chars.indexOf(ch) !== -1;
},
peek: function(i) {
@@ -20497,7 +21005,7 @@
},
isNumber: function(ch) {
- return ('0' <= ch && ch <= '9');
+ return ('0' <= ch && ch <= '9') && typeof ch === "string";
},
isWhitespace: function(ch) {
@@ -20550,79 +21058,28 @@
}
this.index++;
}
- number = 1 * number;
this.tokens.push({
index: start,
text: number,
constant: true,
- fn: function() { return number; }
+ value: Number(number)
});
},
readIdent: function() {
- var expression = this.text;
-
- var ident = '';
var start = this.index;
-
- var lastDot, peekIndex, methodName, ch;
-
while (this.index < this.text.length) {
- ch = this.text.charAt(this.index);
- if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
- if (ch === '.') lastDot = this.index;
- ident += ch;
- } else {
+ var ch = this.text.charAt(this.index);
+ if (!(this.isIdent(ch) || this.isNumber(ch))) {
break;
}
this.index++;
}
-
- //check if the identifier ends with . and if so move back one char
- if (lastDot && ident[ident.length - 1] === '.') {
- this.index--;
- ident = ident.slice(0, -1);
- lastDot = ident.lastIndexOf('.');
- if (lastDot === -1) {
- lastDot = undefined;
- }
- }
-
- //check if this is not a method invocation and if it is back out to last dot
- if (lastDot) {
- peekIndex = this.index;
- while (peekIndex < this.text.length) {
- ch = this.text.charAt(peekIndex);
- if (ch === '(') {
- methodName = ident.substr(lastDot - start + 1);
- ident = ident.substr(0, lastDot - start);
- this.index = peekIndex;
- break;
- }
- if (this.isWhitespace(ch)) {
- peekIndex++;
- } else {
- break;
- }
- }
- }
-
this.tokens.push({
index: start,
- text: ident,
- fn: CONSTANTS[ident] || getterFn(ident, this.options, expression)
- });
-
- if (methodName) {
- this.tokens.push({
- index: lastDot,
- text: '.'
- });
- this.tokens.push({
- index: lastDot + 1,
- text: methodName
- });
- }
+ text: this.text.slice(start, this.index),
+ identifier: true
+ });
},
readString: function(quote) {
@@ -20653,9 +21110,8 @@
this.tokens.push({
index: start,
text: rawString,
- string: string,
constant: true,
- fn: function() { return string; }
+ value: string
});
return;
} else {
@@ -20675,13 +21131,13 @@
/**
* @constructor
*/
-var Parser = function (lexer, $filter, options) {
+var Parser = function(lexer, $filter, options) {
this.lexer = lexer;
this.$filter = $filter;
this.options = options;
};
-Parser.ZERO = extend(function () {
+Parser.ZERO = extend(function() {
return 0;
}, {
sharedGetter: true,
@@ -20691,7 +21147,7 @@
Parser.prototype = {
constructor: Parser,
- parse: function (text) {
+ parse: function(text) {
this.text = text;
this.tokens = this.lexer.lex(text);
@@ -20707,7 +21163,7 @@
return value;
},
- primary: function () {
+ primary: function() {
var primary;
if (this.expect('(')) {
primary = this.filterChain();
@@ -20716,16 +21172,14 @@
primary = this.arrayDeclaration();
} else if (this.expect('{')) {
primary = this.object();
- } else {
- var token = this.expect();
- primary = token.fn;
- if (!primary) {
- this.throwError('not a primary expression', token);
- }
- if (token.constant) {
- primary.constant = true;
- primary.literal = true;
- }
+ } else if (this.peek().identifier && this.peek().text in CONSTANTS) {
+ primary = CONSTANTS[this.consume().text];
+ } else if (this.peek().identifier) {
+ primary = this.identifier();
+ } else if (this.peek().constant) {
+ primary = this.constant();
+ } else {
+ this.throwError('not a primary expression', this.peek());
}
var next, context;
@@ -20759,8 +21213,11 @@
},
peek: function(e1, e2, e3, e4) {
- if (this.tokens.length > 0) {
- var token = this.tokens[0];
+ return this.peekAhead(0, e1, e2, e3, e4);
+ },
+ peekAhead: function(i, e1, e2, e3, e4) {
+ if (this.tokens.length > i) {
+ var token = this.tokens[i];
var t = token.text;
if (t === e1 || t === e2 || t === e3 || t === e4 ||
(!e1 && !e2 && !e3 && !e4)) {
@@ -20770,7 +21227,7 @@
return false;
},
- expect: function(e1, e2, e3, e4){
+ expect: function(e1, e2, e3, e4) {
var token = this.peek(e1, e2, e3, e4);
if (token) {
this.tokens.shift();
@@ -20779,13 +21236,20 @@
return false;
},
- consume: function(e1){
- if (!this.expect(e1)) {
+ consume: function(e1) {
+ if (this.tokens.length === 0) {
+ throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
+ }
+
+ var token = this.expect(e1);
+ if (!token) {
this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
}
- },
-
- unaryFn: function(fn, right) {
+ return token;
+ },
+
+ unaryFn: function(op, right) {
+ var fn = OPERATORS[op];
return extend(function $parseUnaryFn(self, locals) {
return fn(self, locals, right);
}, {
@@ -20794,7 +21258,8 @@
});
},
- binaryFn: function(left, fn, right, isBranching) {
+ binaryFn: function(left, op, right, isBranching) {
+ var fn = OPERATORS[op];
return extend(function $parseBinaryFn(self, locals) {
return fn(self, locals, left, right);
}, {
@@ -20803,6 +21268,28 @@
});
},
+ identifier: function() {
+ var id = this.consume().text;
+
+ //Continue reading each `.identifier` unless it is a method invocation
+ while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) {
+ id += this.consume().text + this.consume().text;
+ }
+
+ return getterFn(id, this.options, this.text);
+ },
+
+ constant: function() {
+ var value = this.consume().value;
+
+ return extend(function $parseConstant() {
+ return value;
+ }, {
+ constant: true,
+ literal: true
+ });
+ },
+
statements: function() {
var statements = [];
while (true) {
@@ -20834,8 +21321,7 @@
},
filter: function(inputFn) {
- var token = this.expect();
- var fn = this.$filter(token.text);
+ var fn = this.$filter(this.consume().text);
var argsFn;
var args;
@@ -20898,17 +21384,14 @@
var token;
if ((token = this.expect('?'))) {
middle = this.assignment();
- if ((token = this.expect(':'))) {
+ if (this.consume(':')) {
var right = this.assignment();
- return extend(function $parseTernary(self, locals){
+ return extend(function $parseTernary(self, locals) {
return left(self, locals) ? middle(self, locals) : right(self, locals);
}, {
constant: left.constant && middle.constant && right.constant
});
-
- } else {
- this.throwError('expected :', token);
}
}
@@ -20919,7 +21402,7 @@
var left = this.logicalAND();
var token;
while ((token = this.expect('||'))) {
- left = this.binaryFn(left, token.fn, this.logicalAND(), true);
+ left = this.binaryFn(left, token.text, this.logicalAND(), true);
}
return left;
},
@@ -20927,8 +21410,8 @@
logicalAND: function() {
var left = this.equality();
var token;
- if ((token = this.expect('&&'))) {
- left = this.binaryFn(left, token.fn, this.logicalAND(), true);
+ while ((token = this.expect('&&'))) {
+ left = this.binaryFn(left, token.text, this.equality(), true);
}
return left;
},
@@ -20936,8 +21419,8 @@
equality: function() {
var left = this.relational();
var token;
- if ((token = this.expect('==','!=','===','!=='))) {
- left = this.binaryFn(left, token.fn, this.equality());
+ while ((token = this.expect('==','!=','===','!=='))) {
+ left = this.binaryFn(left, token.text, this.relational());
}
return left;
},
@@ -20945,8 +21428,8 @@
relational: function() {
var left = this.additive();
var token;
- if ((token = this.expect('<', '>', '<=', '>='))) {
- left = this.binaryFn(left, token.fn, this.relational());
+ while ((token = this.expect('<', '>', '<=', '>='))) {
+ left = this.binaryFn(left, token.text, this.additive());
}
return left;
},
@@ -20955,7 +21438,7 @@
var left = this.multiplicative();
var token;
while ((token = this.expect('+','-'))) {
- left = this.binaryFn(left, token.fn, this.multiplicative());
+ left = this.binaryFn(left, token.text, this.multiplicative());
}
return left;
},
@@ -20964,7 +21447,7 @@
var left = this.unary();
var token;
while ((token = this.expect('*','/','%'))) {
- left = this.binaryFn(left, token.fn, this.unary());
+ left = this.binaryFn(left, token.text, this.unary());
}
return left;
},
@@ -20974,26 +21457,25 @@
if (this.expect('+')) {
return this.primary();
} else if ((token = this.expect('-'))) {
- return this.binaryFn(Parser.ZERO, token.fn, this.unary());
+ return this.binaryFn(Parser.ZERO, token.text, this.unary());
} else if ((token = this.expect('!'))) {
- return this.unaryFn(token.fn, this.unary());
+ return this.unaryFn(token.text, this.unary());
} else {
return this.primary();
}
},
fieldAccess: function(object) {
- var expression = this.text;
- var field = this.expect().text;
- var getter = getterFn(field, this.options, expression);
+ var getter = this.identifier();
return extend(function $parseFieldAccess(scope, locals, self) {
- return getter(self || object(scope, locals));
+ var o = self || object(scope, locals);
+ return (o == null) ? undefined : getter(o);
}, {
assign: function(scope, value, locals) {
var o = object(scope, locals);
if (!o) object.assign(scope, o = {});
- return setter(o, field, value, expression);
+ return getter.assign(o, value);
}
});
},
@@ -21038,7 +21520,7 @@
var args = argsFn.length ? [] : null;
return function $parseFunctionCall(scope, locals) {
- var context = contextGetter ? contextGetter(scope, locals) : scope;
+ var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope;
var fn = fnGetter(scope, locals, context) || noop;
if (args) {
@@ -21051,17 +21533,17 @@
ensureSafeObject(context, expressionText);
ensureSafeFunction(fn, expressionText);
- // IE stupidity! (IE doesn't have apply for some native functions)
+ // IE doesn't have apply for some native functions
var v = fn.apply
? fn.apply(context, args)
: fn(args[0], args[1], args[2], args[3], args[4]);
return ensureSafeObject(v, expressionText);
- };
+ };
},
// This is used with json array declaration
- arrayDeclaration: function () {
+ arrayDeclaration: function() {
var elementFns = [];
if (this.peekToken().text !== ']') {
do {
@@ -21069,8 +21551,7 @@
// Support trailing commas per ES5.1.
break;
}
- var elementFn = this.expression();
- elementFns.push(elementFn);
+ elementFns.push(this.expression());
} while (this.expect(','));
}
this.consume(']');
@@ -21088,7 +21569,7 @@
});
},
- object: function () {
+ object: function() {
var keys = [], valueFns = [];
if (this.peekToken().text !== '}') {
do {
@@ -21096,11 +21577,16 @@
// Support trailing commas per ES5.1.
break;
}
- var token = this.expect();
- keys.push(token.string || token.text);
+ var token = this.consume();
+ if (token.constant) {
+ keys.push(token.value);
+ } else if (token.identifier) {
+ keys.push(token.text);
+ } else {
+ this.throwError("invalid key", token);
+ }
this.consume(':');
- var value = this.expression();
- valueFns.push(value);
+ valueFns.push(this.expression());
} while (this.expect(','));
}
this.consume('}');
@@ -21143,64 +21629,85 @@
return setValue;
}
-var getterFnCache = createMap();
+var getterFnCacheDefault = createMap();
+var getterFnCacheExpensive = createMap();
+
+function isPossiblyDangerousMemberName(name) {
+ return name == 'constructor';
+}
/**
* Implementation of the "Black Hole" variant from:
* - http://jsperf.com/angularjs-parse-getter/4
* - http://jsperf.com/path-evaluation-simplified/7
*/
-function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp) {
+function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, expensiveChecks) {
ensureSafeMemberName(key0, fullExp);
ensureSafeMemberName(key1, fullExp);
ensureSafeMemberName(key2, fullExp);
ensureSafeMemberName(key3, fullExp);
ensureSafeMemberName(key4, fullExp);
+ var eso = function(o) {
+ return ensureSafeObject(o, fullExp);
+ };
+ var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity;
+ var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity;
+ var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity;
+ var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity;
+ var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity;
return function cspSafeGetter(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
if (pathVal == null) return pathVal;
- pathVal = pathVal[key0];
+ pathVal = eso0(pathVal[key0]);
if (!key1) return pathVal;
if (pathVal == null) return undefined;
- pathVal = pathVal[key1];
+ pathVal = eso1(pathVal[key1]);
if (!key2) return pathVal;
if (pathVal == null) return undefined;
- pathVal = pathVal[key2];
+ pathVal = eso2(pathVal[key2]);
if (!key3) return pathVal;
if (pathVal == null) return undefined;
- pathVal = pathVal[key3];
+ pathVal = eso3(pathVal[key3]);
if (!key4) return pathVal;
if (pathVal == null) return undefined;
- pathVal = pathVal[key4];
+ pathVal = eso4(pathVal[key4]);
return pathVal;
};
}
+function getterFnWithEnsureSafeObject(fn, fullExpression) {
+ return function(s, l) {
+ return fn(s, l, ensureSafeObject, fullExpression);
+ };
+}
+
function getterFn(path, options, fullExp) {
+ var expensiveChecks = options.expensiveChecks;
+ var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault);
var fn = getterFnCache[path];
-
if (fn) return fn;
+
var pathKeys = path.split('.'),
pathKeysLength = pathKeys.length;
// http://jsperf.com/angularjs-parse-getter/6
if (options.csp) {
if (pathKeysLength < 6) {
- fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp);
+ fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, expensiveChecks);
} else {
fn = function cspSafeGetter(scope, locals) {
var i = 0, val;
do {
val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
- pathKeys[i++], fullExp)(scope, locals);
+ pathKeys[i++], fullExp, expensiveChecks)(scope, locals);
locals = undefined; // clear after first iteration
scope = val;
@@ -21210,22 +21717,33 @@
}
} else {
var code = '';
+ if (expensiveChecks) {
+ code += 's = eso(s, fe);\nl = eso(l, fe);\n';
+ }
+ var needsEnsureSafeObject = expensiveChecks;
forEach(pathKeys, function(key, index) {
ensureSafeMemberName(key, fullExp);
- code += 'if(s == null) return undefined;\n' +
- 's='+ (index
+ var lookupJs = (index
// we simply dereference 's' on any .dot notation
? 's'
// but if we are first then we check locals first, and if so read it first
- : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key + ';\n';
+ : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key;
+ if (expensiveChecks || isPossiblyDangerousMemberName(key)) {
+ lookupJs = 'eso(' + lookupJs + ', fe)';
+ needsEnsureSafeObject = true;
+ }
+ code += 'if(s == null) return undefined;\n' +
+ 's=' + lookupJs + ';\n';
});
code += 'return s;';
/* jshint -W054 */
- var evaledFnGetter = new Function('s', 'l', code); // s=scope, l=locals
+ var evaledFnGetter = new Function('s', 'l', 'eso', 'fe', code); // s=scope, l=locals, eso=ensureSafeObject
/* jshint +W054 */
evaledFnGetter.toString = valueFn(code);
-
+ if (needsEnsureSafeObject) {
+ evaledFnGetter = getterFnWithEnsureSafeObject(evaledFnGetter, fullExp);
+ }
fn = evaledFnGetter;
}
@@ -21237,6 +21755,12 @@
return fn;
}
+var objectValueOf = Object.prototype.valueOf;
+
+function getValueOf(value) {
+ return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
+}
+
///////////////////////////////////
/**
@@ -21289,15 +21813,20 @@
* service.
*/
function $ParseProvider() {
- var cache = createMap();
-
- var $parseOptions = {
- csp: false
- };
+ var cacheDefault = createMap();
+ var cacheExpensive = createMap();
+
this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
- $parseOptions.csp = $sniffer.csp;
+ var $parseOptions = {
+ csp: $sniffer.csp,
+ expensiveChecks: false
+ },
+ $parseOptionsExpensive = {
+ csp: $sniffer.csp,
+ expensiveChecks: true
+ };
function wrapSharedExpression(exp) {
var wrapped = exp;
@@ -21314,13 +21843,14 @@
return wrapped;
}
- return function $parse(exp, interceptorFn) {
+ return function $parse(exp, interceptorFn, expensiveChecks) {
var parsedExpression, oneTime, cacheKey;
switch (typeof exp) {
case 'string':
cacheKey = exp = exp.trim();
+ var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
parsedExpression = cache[cacheKey];
if (!parsedExpression) {
@@ -21329,8 +21859,9 @@
exp = exp.substring(2);
}
- var lexer = new Lexer($parseOptions);
- var parser = new Parser(lexer, $filter, $parseOptions);
+ var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
+ var lexer = new Lexer(parseOptions);
+ var parser = new Parser(lexer, $filter, parseOptions);
parsedExpression = parser.parse(exp);
if (parsedExpression.constant) {
@@ -21383,7 +21914,7 @@
// attempt to convert the value to a primitive type
// TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
// be cheaply dirty-checked
- newValue = newValue.valueOf();
+ newValue = getValueOf(newValue);
if (typeof newValue === 'object') {
// objects/arrays are not supported - deep-watching them would be too expensive
@@ -21410,7 +21941,7 @@
var newInputValue = inputExpressions(scope);
if (!expressionInputDirtyCheck(newInputValue, oldInputValue)) {
lastResult = parsedExpression(scope);
- oldInputValue = newInputValue && newInputValue.valueOf();
+ oldInputValue = newInputValue && getValueOf(newInputValue);
}
return lastResult;
}, listener, objectEquality);
@@ -21427,7 +21958,7 @@
for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
var newInputValue = inputExpressions[i](scope);
if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
- oldInputValueOfValues[i] = newInputValue && newInputValue.valueOf();
+ oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
}
}
@@ -21449,7 +21980,7 @@
listener.apply(this, arguments);
}
if (isDefined(value)) {
- scope.$$postDigest(function () {
+ scope.$$postDigest(function() {
if (isDefined(lastValue)) {
unwatch();
}
@@ -21459,23 +21990,24 @@
}
function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
- var unwatch;
+ var unwatch, lastValue;
return unwatch = scope.$watch(function oneTimeWatch(scope) {
return parsedExpression(scope);
}, function oneTimeListener(value, old, scope) {
+ lastValue = value;
if (isFunction(listener)) {
listener.call(this, value, old, scope);
}
if (isAllDefined(value)) {
- scope.$$postDigest(function () {
- if(isAllDefined(value)) unwatch();
+ scope.$$postDigest(function() {
+ if (isAllDefined(lastValue)) unwatch();
});
}
}, objectEquality);
function isAllDefined(value) {
var allDefined = true;
- forEach(value, function (val) {
+ forEach(value, function(val) {
if (!isDefined(val)) allDefined = false;
});
return allDefined;
@@ -21496,8 +22028,16 @@
function addInterceptor(parsedExpression, interceptorFn) {
if (!interceptorFn) return parsedExpression;
-
- var fn = function interceptedExpression(scope, locals) {
+ var watchDelegate = parsedExpression.$$watchDelegate;
+
+ var regularWatch =
+ watchDelegate !== oneTimeLiteralWatchDelegate &&
+ watchDelegate !== oneTimeWatchDelegate;
+
+ var fn = regularWatch ? function regularInterceptedExpression(scope, locals) {
+ var value = parsedExpression(scope, locals);
+ return interceptorFn(value, scope, locals);
+ } : function oneTimeInterceptedExpression(scope, locals) {
var value = parsedExpression(scope, locals);
var result = interceptorFn(value, scope, locals);
// we only return the interceptor's result if the
@@ -21527,7 +22067,11 @@
* @requires $rootScope
*
* @description
- * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
+ * A service that helps you run functions asynchronously, and use their return values (or exceptions)
+ * when they are done processing.
+ *
+ * This is an implementation of promises/deferred objects inspired by
+ * [Kris Kowal's Q](https://github.com/kriskowal/q).
*
* $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
* implementations, and the other which resembles ES6 promises to some degree.
@@ -21544,24 +22088,27 @@
* It can be used like so:
*
* ```js
- * return $q(function(resolve, reject) {
- * // perform some asynchronous operation, resolve or reject the promise when appropriate.
- * setInterval(function() {
- * if (pollStatus > 0) {
- * resolve(polledValue);
- * } else if (pollStatus < 0) {
- * reject(polledValue);
- * } else {
- * pollStatus = pollAgain(function(value) {
- * polledValue = value;
- * });
- * }
- * }, 10000);
- * }).
- * then(function(value) {
- * // handle success
+ * // for the purpose of this example let's assume that variables `$q` and `okToGreet`
+ * // are available in the current lexical scope (they could have been injected or passed in).
+ *
+ * function asyncGreet(name) {
+ * // perform some asynchronous operation, resolve or reject the promise when appropriate.
+ * return $q(function(resolve, reject) {
+ * setTimeout(function() {
+ * if (okToGreet(name)) {
+ * resolve('Hello, ' + name + '!');
+ * } else {
+ * reject('Greeting ' + name + ' is not allowed.');
+ * }
+ * }, 1000);
+ * });
+ * }
+ *
+ * var promise = asyncGreet('Robin Hood');
+ * promise.then(function(greeting) {
+ * alert('Success: ' + greeting);
* }, function(reason) {
- * // handle failure
+ * alert('Failed: ' + reason);
* });
* ```
*
@@ -21577,7 +22124,7 @@
* asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
*
* ```js
- * // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
+ * // for the purpose of this example let's assume that variables `$q` and `okToGreet`
* // are available in the current lexical scope (they could have been injected or passed in).
*
* function asyncGreet(name) {
@@ -21660,16 +22207,12 @@
*
* - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
*
- * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
+ * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
* but to do so without modifying the final value. This is useful to release resources or do some
* clean-up that needs to be done whether the promise was rejected or resolved. See the [full
* specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
* more information.
*
- * Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
- * property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
- * make your code IE8 and Android 2.x compatible.
- *
* # Chaining promises
*
* Because calling the `then` method of a promise returns a new derived promise, it is easily
@@ -21836,7 +22379,7 @@
} else {
promise.reject(state.value);
}
- } catch(e) {
+ } catch (e) {
promise.reject(e);
exceptionHandler(e);
}
@@ -21886,7 +22429,7 @@
this.promise.$$state.status = 1;
scheduleProcessQueue(this.promise.$$state);
}
- } catch(e) {
+ } catch (e) {
fns[1](e);
exceptionHandler(e);
}
@@ -21914,7 +22457,7 @@
callback = callbacks[i][3];
try {
result.notify(isFunction(callback) ? callback(progress) : progress);
- } catch(e) {
+ } catch (e) {
exceptionHandler(e);
}
}
@@ -21979,7 +22522,7 @@
var callbackOutput = null;
try {
if (isFunction(callback)) callbackOutput = callback();
- } catch(e) {
+ } catch (e) {
return makePromise(e, false);
}
if (isPromiseLike(callbackOutput)) {
@@ -22087,15 +22630,13 @@
return $Q;
}
-function $$RAFProvider(){ //rAF
+function $$RAFProvider() { //rAF
this.$get = ['$window', '$timeout', function($window, $timeout) {
var requestAnimationFrame = $window.requestAnimationFrame ||
- $window.webkitRequestAnimationFrame ||
- $window.mozRequestAnimationFrame;
+ $window.webkitRequestAnimationFrame;
var cancelAnimationFrame = $window.cancelAnimationFrame ||
$window.webkitCancelAnimationFrame ||
- $window.mozCancelAnimationFrame ||
$window.webkitCancelRequestAnimationFrame;
var rafSupported = !!requestAnimationFrame;
@@ -22186,7 +22727,7 @@
* They also provide an event emission/broadcast and subscription facility. See the
* {@link guide/scope developer guide on scopes}.
*/
-function $RootScopeProvider(){
+function $RootScopeProvider() {
var TTL = 10;
var $rootScopeMinErr = minErr('$rootScope');
var lastDirtyWatch = null;
@@ -22200,7 +22741,7 @@
};
this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
- function( $injector, $exceptionHandler, $parse, $browser) {
+ function($injector, $exceptionHandler, $parse, $browser) {
/**
* @ngdoc type
@@ -22224,7 +22765,6 @@
var child = parent.$new();
parent.salutation = "Hello";
- child.name = "World";
expect(child.salutation).toEqual('Hello');
child.salutation = "Welcome";
@@ -22232,6 +22772,10 @@
expect(parent.salutation).toEqual('Hello');
* ```
*
+ * When interacting with `Scope` in tests, additional helper methods are available on the
+ * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
+ * details.
+ *
*
* @param {Object.=} providers Map of service factory which need to be
* provided for the current scope. Defaults to {@link ng}.
@@ -22543,7 +23087,7 @@
if (!watchExpressions.length) {
// No expressions means we call the listener ASAP
var shouldCall = true;
- self.$evalAsync(function () {
+ self.$evalAsync(function() {
if (shouldCall) listener(newValues, newValues, self);
});
return function deregisterWatchGroup() {
@@ -22560,7 +23104,7 @@
});
}
- forEach(watchExpressions, function (expr, i) {
+ forEach(watchExpressions, function(expr, i) {
var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
newValues[i] = value;
oldValues[i] = oldValue;
@@ -22670,6 +23214,9 @@
newValue = _value;
var newLength, key, bothNaN, newItem, oldItem;
+ // If the new value is undefined, then return undefined as the watch may be a one-time watch
+ if (isUndefined(newValue)) return;
+
if (!isObject(newValue)) { // if primitive
if (oldValue !== newValue) {
oldValue = newValue;
@@ -22732,7 +23279,7 @@
if (oldLength > newLength) {
// we used to have more keys, need to find them and destroy them.
changeDetected++;
- for(key in oldValue) {
+ for (key in oldValue) {
if (!newValue.hasOwnProperty(key)) {
oldLength--;
delete oldValue[key];
@@ -22852,10 +23399,10 @@
dirty = false;
current = target;
- while(asyncQueue.length) {
+ while (asyncQueue.length) {
try {
asyncTask = asyncQueue.shift();
- asyncTask.scope.$eval(asyncTask.expression);
+ asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
} catch (e) {
$exceptionHandler(e);
}
@@ -22885,11 +23432,11 @@
if (ttl < 5) {
logIdx = 4 - ttl;
if (!watchLog[logIdx]) watchLog[logIdx] = [];
- logMsg = (isFunction(watch.exp))
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
- : watch.exp;
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
- watchLog[logIdx].push(logMsg);
+ watchLog[logIdx].push({
+ msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
+ newVal: value,
+ oldVal: last
+ });
}
} else if (watch === lastDirtyWatch) {
// If the most recently dirty watcher is now clean, short circuit since the remaining watchers
@@ -22909,7 +23456,7 @@
// this piece should be kept in sync with the traversal in $broadcast
if (!(next = (current.$$childHead ||
(current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
+ while (current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
@@ -22917,19 +23464,19 @@
// `break traverseScopesLoop;` takes us to here
- if((dirty || asyncQueue.length) && !(ttl--)) {
+ if ((dirty || asyncQueue.length) && !(ttl--)) {
clearPhase();
throw $rootScopeMinErr('infdig',
'{0} $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: {1}',
- TTL, toJson(watchLog));
+ TTL, watchLog);
}
} while (dirty || asyncQueue.length);
clearPhase();
- while(postDigestQueue.length) {
+ while (postDigestQueue.length) {
try {
postDigestQueue.shift()();
} catch (e) {
@@ -23070,8 +23617,9 @@
* - `string`: execute using the rules as defined in {@link guide/expression expression}.
* - `function(scope)`: execute the function with the current `scope` parameter.
*
+ * @param {(object)=} locals Local variables object, useful for overriding values in scope.
*/
- $evalAsync: function(expr) {
+ $evalAsync: function(expr, locals) {
// if we are outside of an $digest loop and this is the first time we are scheduling async
// task also schedule async auto-flush
if (!$rootScope.$$phase && !asyncQueue.length) {
@@ -23082,10 +23630,10 @@
});
}
- asyncQueue.push({scope: this, expression: expr});
+ asyncQueue.push({scope: this, expression: expr, locals: locals});
},
- $$postDigest : function(fn) {
+ $$postDigest: function(fn) {
postDigestQueue.push(fn);
},
@@ -23222,8 +23770,11 @@
var self = this;
return function() {
- namedListeners[namedListeners.indexOf(listener)] = null;
- decrementListenerCount(self, 1, name);
+ var indexOfListener = namedListeners.indexOf(listener);
+ if (indexOfListener !== -1) {
+ namedListeners[indexOfListener] = null;
+ decrementListenerCount(self, 1, name);
+ }
};
},
@@ -23270,7 +23821,7 @@
do {
namedListeners = scope.$$listeners[name] || empty;
event.currentScope = scope;
- for (i=0, length=namedListeners.length; i to learn more about them.
* You can ensure your document is in standards mode and not quirks mode by adding ``
@@ -23964,7 +24506,7 @@
*
* In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
* $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link
- * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
+ * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
* {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
*
* As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
@@ -24180,7 +24722,7 @@
* @description
* Enables/disables SCE and returns the current value.
*/
- this.enabled = function (value) {
+ this.enabled = function(value) {
if (arguments.length) {
enabled = !!value;
}
@@ -24234,13 +24776,13 @@
* sce.js and sceSpecs.js would need to be aware of this detail.
*/
- this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
- $parse, $sniffer, $sceDelegate) {
- // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows
+ this.$get = ['$parse', '$sceDelegate', function(
+ $parse, $sceDelegate) {
+ // Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow
// the "expression(javascript expression)" syntax which is insecure.
- if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
+ if (enabled && msie < 8) {
throw $sceMinErr('iequirks',
- 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
+ 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
'mode. You can fix this by adding the text to the top of your HTML ' +
'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
}
@@ -24258,7 +24800,7 @@
* @description
* Returns a boolean indicating if SCE is enabled.
*/
- sce.isEnabled = function () {
+ sce.isEnabled = function() {
return enabled;
};
sce.trustAs = $sceDelegate.trustAs;
@@ -24294,7 +24836,7 @@
if (parsed.literal && parsed.constant) {
return parsed;
} else {
- return $parse(expr, function (value) {
+ return $parse(expr, function(value) {
return sce.getTrusted(type, value);
});
}
@@ -24463,7 +25005,7 @@
*
* @description
* Shorthand method. `$sce.parseAsHtml(expression string)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -24480,7 +25022,7 @@
*
* @description
* Shorthand method. `$sce.parseAsCss(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -24497,7 +25039,7 @@
*
* @description
* Shorthand method. `$sce.parseAsUrl(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -24514,7 +25056,7 @@
*
* @description
* Shorthand method. `$sce.parseAsResourceUrl(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -24531,7 +25073,7 @@
*
* @description
* Shorthand method. `$sce.parseAsJs(value)` →
- * {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
+ * {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -24547,15 +25089,15 @@
getTrusted = sce.getTrusted,
trustAs = sce.trustAs;
- forEach(SCE_CONTEXTS, function (enumValue, name) {
+ forEach(SCE_CONTEXTS, function(enumValue, name) {
var lName = lowercase(name);
- sce[camelCase("parse_as_" + lName)] = function (expr) {
+ sce[camelCase("parse_as_" + lName)] = function(expr) {
return parse(enumValue, expr);
};
- sce[camelCase("get_trusted_" + lName)] = function (value) {
+ sce[camelCase("get_trusted_" + lName)] = function(value) {
return getTrusted(enumValue, value);
};
- sce[camelCase("trust_as_" + lName)] = function (value) {
+ sce[camelCase("trust_as_" + lName)] = function(value) {
return trustAs(enumValue, value);
};
});
@@ -24585,31 +25127,30 @@
int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
document = $document[0] || {},
- documentMode = document.documentMode,
vendorPrefix,
- vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
+ vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
bodyStyle = document.body && document.body.style,
transitions = false,
animations = false,
match;
if (bodyStyle) {
- for(var prop in bodyStyle) {
- if(match = vendorRegex.exec(prop)) {
+ for (var prop in bodyStyle) {
+ if (match = vendorRegex.exec(prop)) {
vendorPrefix = match[0];
vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
break;
}
}
- if(!vendorPrefix) {
+ if (!vendorPrefix) {
vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
}
transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
- if (android && (!transitions||!animations)) {
+ if (android && (!transitions || !animations)) {
transitions = isString(document.body.style.webkitTransition);
animations = isString(document.body.style.webkitAnimation);
}
@@ -24632,7 +25173,9 @@
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
// it. In particular the event is not fired when backspace or delete key are pressed or
// when cut operation is performed.
- if (event == 'input' && msie == 9) return false;
+ // IE10+ implements 'input' event but it erroneously fires under various situations,
+ // e.g. when placeholder changes, or a form is focused.
+ if (event === 'input' && msie <= 11) return false;
if (isUndefined(eventSupport[event])) {
var divElm = document.createElement('div');
@@ -24643,11 +25186,9 @@
},
csp: csp(),
vendorPrefix: vendorPrefix,
- transitions : transitions,
- animations : animations,
- android: android,
- msie : msie,
- msieDocumentMode: documentMode
+ transitions: transitions,
+ animations: animations,
+ android: android
};
}];
}
@@ -24661,7 +25202,7 @@
* @description
* The `$templateRequest` service downloads the provided template using `$http` and, upon success,
* stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
- * of the HTTP request is empty then a `$compile` error will be thrown (the exception can be thwarted
+ * of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted
* by setting the 2nd parameter of the function to true).
*
* @param {string} tpl The HTTP request template URL
@@ -24677,24 +25218,33 @@
var self = handleRequestFn;
self.totalPendingRequests++;
- return $http.get(tpl, { cache : $templateCache })
+ var transformResponse = $http.defaults && $http.defaults.transformResponse;
+
+ if (isArray(transformResponse)) {
+ transformResponse = transformResponse.filter(function(transformer) {
+ return transformer !== defaultHttpResponseTransform;
+ });
+ } else if (transformResponse === defaultHttpResponseTransform) {
+ transformResponse = null;
+ }
+
+ var httpOptions = {
+ cache: $templateCache,
+ transformResponse: transformResponse
+ };
+
+ return $http.get(tpl, httpOptions)
.then(function(response) {
- var html = response.data;
- if(!html || html.length === 0) {
- return handleError();
- }
-
self.totalPendingRequests--;
- $templateCache.put(tpl, html);
- return html;
+ return response.data;
}, handleError);
- function handleError() {
+ function handleError(resp) {
self.totalPendingRequests--;
if (!ignoreRequestError) {
throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
}
- return $q.reject();
+ return $q.reject(resp);
}
}
@@ -24737,7 +25287,7 @@
if (dataBinding) {
forEach(dataBinding, function(bindingName) {
if (opt_exactMatch) {
- var matcher = new RegExp('(^|\\s)' + expression + '(\\s|\\||$)');
+ var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
if (matcher.test(bindingName)) {
matches.push(binding);
}
@@ -24859,7 +25409,7 @@
timeoutId = $browser.defer(function() {
try {
deferred.resolve(fn());
- } catch(e) {
+ } catch (e) {
deferred.reject(e);
$exceptionHandler(e);
}
@@ -24910,7 +25460,7 @@
// exactly the behavior needed here. There is little value is mocking these out for this
// service.
var urlParsingNode = document.createElement("a");
-var originUrl = urlResolve(window.location.href, true);
+var originUrl = urlResolve(window.location.href);
/**
@@ -24965,7 +25515,7 @@
* | pathname | The pathname, beginning with "/"
*
*/
-function urlResolve(url, base) {
+function urlResolve(url) {
var href = url;
if (msie) {
@@ -25025,7 +25575,7 @@
-
+
{{text}}
@@ -33727,7 +34467,6 @@
compile: function(element, attr) {
if (attr.type == 'text/ng-template') {
var templateUrl = attr.id,
- // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
text = element[0].text;
$templateCache.put(templateUrl, text);
@@ -33749,33 +34488,74 @@
*
* The `ngOptions` attribute can be used to dynamically generate a list of `