diff --git a/1.8.2/docs/partials/misc/version-support-status.html b/1.8.2/docs/partials/misc/version-support-status.html index e3ebdaadb..3c557874d 100644 --- a/1.8.2/docs/partials/misc/version-support-status.html +++ b/1.8.2/docs/partials/misc/version-support-status.html @@ -44,7 +44,7 @@

Blog Post

Extended Long Term Support

If you need support for AngularJS beyond December 2021, you should consider:

diff --git a/1.8.3/docs/partials/misc/version-support-status.html b/1.8.3/docs/partials/misc/version-support-status.html index 71502f956..ce4a95bdd 100644 --- a/1.8.3/docs/partials/misc/version-support-status.html +++ b/1.8.3/docs/partials/misc/version-support-status.html @@ -16,8 +16,7 @@

What does end of support mean?

Extended Long Term Support

If you need extended support for AngularJS, you should consider:

diff --git a/snapshot/angular-1.7.2-build.5558+sha.c9a92fc.zip b/snapshot/angular-1.8.4-local+sha.d8f77817e.zip similarity index 50% rename from snapshot/angular-1.7.2-build.5558+sha.c9a92fc.zip rename to snapshot/angular-1.8.4-local+sha.d8f77817e.zip index 96493f17c..19c619c6f 100644 Binary files a/snapshot/angular-1.7.2-build.5558+sha.c9a92fc.zip and b/snapshot/angular-1.8.4-local+sha.d8f77817e.zip differ diff --git a/snapshot/angular-animate.js b/snapshot/angular-animate.js index aded42696..50cafc808 100644 --- a/snapshot/angular-animate.js +++ b/snapshot/angular-animate.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.7.2-build.5558+sha.c9a92fc - * (c) 2010-2018 Google, Inc. http://angularjs.org + * @license AngularJS v1.8.4-local+sha.d8f77817e + * (c) 2010-2020 Google LLC. http://angularjs.org * License: MIT */ (function(window, angular) {'use strict'; @@ -306,7 +306,7 @@ function getDomNode(element) { return (element instanceof jqLite) ? element[0] : element; } -function applyGeneratedPreparationClasses(element, event, options) { +function applyGeneratedPreparationClasses($$jqLite, element, event, options) { var classes = ''; if (event) { classes = pendClasses(event, EVENT_CLASS_PREFIX, true); @@ -334,15 +334,6 @@ function clearGeneratedClasses(element, options) { } } -function blockTransitions(node, duration) { - // we use a negative delay value since it performs blocking - // yet it doesn't kill any existing transitions running on the - // same element which makes this safe for class-based animations - var value = duration ? '-' + duration + 's' : ''; - applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]); - return [TRANSITION_DELAY_PROP, value]; -} - function blockKeyframeAnimations(node, applyBlock) { var value = applyBlock ? 'paused' : ''; var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY; @@ -362,6 +353,17 @@ function concatWithSpace(a,b) { return a + ' ' + b; } +var helpers = { + blockTransitions: function(node, duration) { + // we use a negative delay value since it performs blocking + // yet it doesn't kill any existing transitions running on the + // same element which makes this safe for class-based animations + var value = duration ? '-' + duration + 's' : ''; + applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]); + return [TRANSITION_DELAY_PROP, value]; + } +}; + var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) { var queue, cancelFn; @@ -814,33 +816,6 @@ function getCssTransitionDurationStyle(duration, applyOnlyDuration) { return [style, value]; } -function createLocalCacheLookup() { - var cache = Object.create(null); - return { - flush: function() { - cache = Object.create(null); - }, - - count: function(key) { - var entry = cache[key]; - return entry ? entry.total : 0; - }, - - get: function(key) { - var entry = cache[key]; - return entry && entry.value; - }, - - put: function(key, value) { - if (!cache[key]) { - cache[key] = { total: 1, value: value }; - } else { - cache[key].total++; - } - } - }; -} - // we do not reassign an already present style value since // if we detect the style property value again we may be // detecting styles that were added via the `from` styles. @@ -859,26 +834,16 @@ function registerRestorableStyles(backup, node, properties) { } var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animateProvider) { - var gcsLookup = createLocalCacheLookup(); - var gcsStaggerLookup = createLocalCacheLookup(); - this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', + this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$$animateCache', '$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue', - function($window, $$jqLite, $$AnimateRunner, $timeout, + function($window, $$jqLite, $$AnimateRunner, $timeout, $$animateCache, $$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) { var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); - var parentCounter = 0; - function gcsHashFn(node, extraClasses) { - var KEY = '$$ngAnimateParentKey'; - var parentNode = node.parentNode; - var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter); - return parentID + '-' + node.getAttribute('class') + '-' + extraClasses; - } - - function computeCachedCssStyles(node, className, cacheKey, properties) { - var timings = gcsLookup.get(cacheKey); + function computeCachedCssStyles(node, className, cacheKey, allowNoDuration, properties) { + var timings = $$animateCache.get(cacheKey); if (!timings) { timings = computeCssStyles($window, node, properties); @@ -887,20 +852,26 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro } } + // if a css animation has no duration we + // should mark that so that repeated addClass/removeClass calls are skipped + var hasDuration = allowNoDuration || (timings.transitionDuration > 0 || timings.animationDuration > 0); + // we keep putting this in multiple times even though the value and the cacheKey are the same // because we're keeping an internal tally of how many duplicate animations are detected. - gcsLookup.put(cacheKey, timings); + $$animateCache.put(cacheKey, timings, hasDuration); + return timings; } function computeCachedCssStaggerStyles(node, className, cacheKey, properties) { var stagger; + var staggerCacheKey = 'stagger-' + cacheKey; // if we have one or more existing matches of matching elements // containing the same parent + CSS styles (which is how cacheKey works) // then staggering is possible - if (gcsLookup.count(cacheKey) > 0) { - stagger = gcsStaggerLookup.get(cacheKey); + if ($$animateCache.count(cacheKey) > 0) { + stagger = $$animateCache.get(staggerCacheKey); if (!stagger) { var staggerClassName = pendClasses(className, '-stagger'); @@ -915,7 +886,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro $$jqLite.removeClass(node, staggerClassName); - gcsStaggerLookup.put(cacheKey, stagger); + $$animateCache.put(staggerCacheKey, stagger, true); } } @@ -926,8 +897,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro function waitUntilQuiet(callback) { rafWaitQueue.push(callback); $$rAFScheduler.waitUntilQuiet(function() { - gcsLookup.flush(); - gcsStaggerLookup.flush(); + $$animateCache.flush(); // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable. // PLEASE EXAMINE THE `$$forceReflow` service to understand why. @@ -942,8 +912,8 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro }); } - function computeTimings(node, className, cacheKey) { - var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES); + function computeTimings(node, className, cacheKey, allowNoDuration) { + var timings = computeCachedCssStyles(node, className, cacheKey, allowNoDuration, DETECT_CSS_PROPERTIES); var aD = timings.animationDelay; var tD = timings.transitionDelay; timings.maxDelay = aD && tD @@ -1030,7 +1000,6 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim(); var fullClassName = classes + ' ' + preparationClasses; - var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX); var hasToStyles = styles.to && Object.keys(styles.to).length > 0; var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0; @@ -1043,7 +1012,12 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro return closeAndReturnNoopAnimator(); } - var cacheKey, stagger; + var stagger, cacheKey = $$animateCache.cacheKey(node, method, options.addClass, options.removeClass); + if ($$animateCache.containsCachedAnimationWithoutDuration(cacheKey)) { + preparationClasses = null; + return closeAndReturnNoopAnimator(); + } + if (options.stagger > 0) { var staggerVal = parseFloat(options.stagger); stagger = { @@ -1053,7 +1027,6 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro animationDuration: 0 }; } else { - cacheKey = gcsHashFn(node, fullClassName); stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES); } @@ -1087,7 +1060,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro var itemIndex = stagger ? options.staggerIndex >= 0 ? options.staggerIndex - : gcsLookup.count(cacheKey) + : $$animateCache.count(cacheKey) : 0; var isFirst = itemIndex === 0; @@ -1099,10 +1072,10 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro // that if there is no transition defined then nothing will happen and this will also allow // other transitions to be stacked on top of each other without any chopping them out. if (isFirst && !options.skipBlocking) { - blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE); + helpers.blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE); } - var timings = computeTimings(node, fullClassName, cacheKey); + var timings = computeTimings(node, fullClassName, cacheKey, !isStructural); var relativeDelay = timings.maxDelay; maxDelay = Math.max(relativeDelay, 0); maxDuration = timings.maxDuration; @@ -1140,6 +1113,8 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro return closeAndReturnNoopAnimator(); } + var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX); + if (options.delay != null) { var delayStyle; if (typeof options.delay !== 'boolean') { @@ -1183,7 +1158,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro if (flags.blockTransition || flags.blockKeyframeAnimation) { applyBlocking(maxDuration); } else if (!options.skipBlocking) { - blockTransitions(node, false); + helpers.blockTransitions(node, false); } // TODO(matsko): for 1.5 change this code to have an animator object for better debugging @@ -1227,13 +1202,16 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro animationClosed = true; animationPaused = false; - if (!options.$$skipPreparationClasses) { + if (preparationClasses && !options.$$skipPreparationClasses) { $$jqLite.removeClass(element, preparationClasses); } - $$jqLite.removeClass(element, activeClasses); + + if (activeClasses) { + $$jqLite.removeClass(element, activeClasses); + } blockKeyframeAnimations(node, false); - blockTransitions(node, false); + helpers.blockTransitions(node, false); forEach(temporaryStyles, function(entry) { // There is only one way to remove inline style properties entirely from elements. @@ -1284,7 +1262,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro function applyBlocking(duration) { if (flags.blockTransition) { - blockTransitions(node, duration); + helpers.blockTransitions(node, duration); } if (flags.blockKeyframeAnimation) { @@ -1414,9 +1392,9 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro if (flags.recalculateTimingStyles) { fullClassName = node.getAttribute('class') + ' ' + preparationClasses; - cacheKey = gcsHashFn(node, fullClassName); + cacheKey = $$animateCache.cacheKey(node, method, options.addClass, options.removeClass); - timings = computeTimings(node, fullClassName, cacheKey); + timings = computeTimings(node, fullClassName, cacheKey, false); relativeDelay = timings.maxDelay; maxDelay = Math.max(relativeDelay, 0); maxDuration = timings.maxDuration; @@ -2153,6 +2131,15 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate join: [] }; + function getEventData(options) { + return { + addClass: options.addClass, + removeClass: options.removeClass, + from: options.from, + to: options.to + }; + } + function makeTruthyCssClassMap(classString) { if (!classString) { return null; @@ -2251,6 +2238,10 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate var disabledElementsLookup = new $$Map(); var animationsEnabled = null; + function removeFromDisabledElementsLookup(evt) { + disabledElementsLookup.delete(evt.target); + } + function postDigestTaskFactory() { var postDigestCalled = false; return function(fn) { @@ -2434,6 +2425,11 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate bool = !disabledElementsLookup.get(node); } else { // (element, bool) - Element setter + if (!disabledElementsLookup.has(node)) { + // The element is added to the map for the first time. + // Create a listener to remove it on `$destroy` (to avoid memory leak). + jqLite(element).on('$destroy', removeFromDisabledElementsLookup); + } disabledElementsLookup.set(node, !bool); } } @@ -2519,9 +2515,9 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate if (skipAnimations) { // Callbacks should fire even if the document is hidden (regression fix for issue #14120) - if (documentHidden) notifyProgress(runner, event, 'start'); + if (documentHidden) notifyProgress(runner, event, 'start', getEventData(options)); close(); - if (documentHidden) notifyProgress(runner, event, 'close'); + if (documentHidden) notifyProgress(runner, event, 'close', getEventData(options)); return runner; } @@ -2578,7 +2574,7 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate if (existingAnimation.state === RUNNING_STATE) { normalizeAnimationDetails(element, newAnimation); } else { - applyGeneratedPreparationClasses(element, isStructural ? event : null, options); + applyGeneratedPreparationClasses($$jqLite, element, isStructural ? event : null, options); event = newAnimation.event = existingAnimation.event; options = mergeAnimationDetails(element, existingAnimation, newAnimation); @@ -2683,7 +2679,7 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate // this will update the runner's flow-control events based on // the `realRunner` object. runner.setHost(realRunner); - notifyProgress(runner, event, 'start', {}); + notifyProgress(runner, event, 'start', getEventData(options)); realRunner.done(function(status) { close(!status); @@ -2691,7 +2687,7 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate if (animationDetails && animationDetails.counter === counter) { clearElementAnimationState(node); } - notifyProgress(runner, event, 'close', {}); + notifyProgress(runner, event, 'close', getEventData(options)); }); }); @@ -2857,6 +2853,62 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate }]; }]; +/** @this */ +var $$AnimateCacheProvider = function() { + + var KEY = '$$ngAnimateParentKey'; + var parentCounter = 0; + var cache = Object.create(null); + + this.$get = [function() { + return { + cacheKey: function(node, method, addClass, removeClass) { + var parentNode = node.parentNode; + var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter); + var parts = [parentID, method, node.getAttribute('class')]; + if (addClass) { + parts.push(addClass); + } + if (removeClass) { + parts.push(removeClass); + } + return parts.join(' '); + }, + + containsCachedAnimationWithoutDuration: function(key) { + var entry = cache[key]; + + // nothing cached, so go ahead and animate + // otherwise it should be a valid animation + return (entry && !entry.isValid) || false; + }, + + flush: function() { + cache = Object.create(null); + }, + + count: function(key) { + var entry = cache[key]; + return entry ? entry.total : 0; + }, + + get: function(key) { + var entry = cache[key]; + return entry && entry.value; + }, + + put: function(key, value, isValid) { + if (!cache[key]) { + cache[key] = { total: 1, value: value, isValid: isValid }; + } else { + cache[key].total++; + cache[key].value = value; + } + } + }; + }]; +}; + /* exported $$AnimationProvider */ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animateProvider) { @@ -2865,6 +2917,7 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro var drivers = this.drivers = []; var RUNNER_STORAGE_KEY = '$$animationRunner'; + var PREPARE_CLASSES_KEY = '$$animatePrepareClasses'; function setRunner(element, runner) { element.data(RUNNER_STORAGE_KEY, runner); @@ -2878,8 +2931,8 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro return element.data(RUNNER_STORAGE_KEY); } - this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$Map', '$$rAFScheduler', - function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$Map, $$rAFScheduler) { + this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$Map', '$$rAFScheduler', '$$animateCache', + function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$Map, $$rAFScheduler, $$animateCache) { var animationQueue = []; var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); @@ -2894,6 +2947,7 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro var animation = animations[i]; lookup.set(animation.domNode, animations[i] = { domNode: animation.domNode, + element: animation.element, fn: animation.fn, children: [] }); @@ -2950,7 +3004,7 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro result.push(row); row = []; } - row.push(entry.fn); + row.push(entry); entry.children.forEach(function(childEntry) { nextLevelEntries++; queue.push(childEntry); @@ -2985,8 +3039,6 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro return runner; } - setRunner(element, runner); - var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass)); var tempClasses = options.tempClasses; if (tempClasses) { @@ -2994,12 +3046,12 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro options.tempClasses = null; } - var prepareClassName; if (isStructural) { - prepareClassName = 'ng-' + event + PREPARE_CLASS_SUFFIX; - $$jqLite.addClass(element, prepareClassName); + element.data(PREPARE_CLASSES_KEY, 'ng-' + event + PREPARE_CLASS_SUFFIX); } + setRunner(element, runner); + animationQueue.push({ // this data is used by the postDigest code and passed into // the driver step function @@ -3039,16 +3091,31 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro var toBeSortedAnimations = []; forEach(groupedAnimations, function(animationEntry) { + var element = animationEntry.from ? animationEntry.from.element : animationEntry.element; + var extraClasses = options.addClass; + + extraClasses = (extraClasses ? (extraClasses + ' ') : '') + NG_ANIMATE_CLASSNAME; + var cacheKey = $$animateCache.cacheKey(element[0], animationEntry.event, extraClasses, options.removeClass); + toBeSortedAnimations.push({ - domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element), + element: element, + domNode: getDomNode(element), fn: function triggerAnimationStart() { + var startAnimationFn, closeFn = animationEntry.close; + + // in the event that we've cached the animation status for this element + // and it's in fact an invalid animation (something that has duration = 0) + // then we should skip all the heavy work from here on + if ($$animateCache.containsCachedAnimationWithoutDuration(cacheKey)) { + closeFn(); + return; + } + // it's important that we apply the `ng-animate` CSS class and the // temporary classes before we do any driver invoking since these // CSS classes may be required for proper CSS detection. animationEntry.beforeStart(); - var startAnimationFn, closeFn = animationEntry.close; - // in the event that the element was removed before the digest runs or // during the RAF sequencing then we should not trigger the animation. var targetElement = animationEntry.anchors @@ -3078,7 +3145,32 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro // we need to sort each of the animations in order of parent to child // relationships. This ensures that the child classes are applied at the // right time. - $$rAFScheduler(sortAnimations(toBeSortedAnimations)); + var finalAnimations = sortAnimations(toBeSortedAnimations); + for (var i = 0; i < finalAnimations.length; i++) { + var innerArray = finalAnimations[i]; + for (var j = 0; j < innerArray.length; j++) { + var entry = innerArray[j]; + var element = entry.element; + + // the RAFScheduler code only uses functions + finalAnimations[i][j] = entry.fn; + + // the first row of elements shouldn't have a prepare-class added to them + // since the elements are at the top of the animation hierarchy and they + // will be applied without a RAF having to pass... + if (i === 0) { + element.removeData(PREPARE_CLASSES_KEY); + continue; + } + + var prepareClassName = element.data(PREPARE_CLASSES_KEY); + if (prepareClassName) { + $$jqLite.addClass(element, prepareClassName); + } + } + } + + $$rAFScheduler(finalAnimations); }); return runner; @@ -3216,10 +3308,10 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro } function beforeStart() { - element.addClass(NG_ANIMATE_CLASSNAME); - if (tempClasses) { - $$jqLite.addClass(element, tempClasses); - } + tempClasses = (tempClasses ? (tempClasses + ' ') : '') + NG_ANIMATE_CLASSNAME; + $$jqLite.addClass(element, tempClasses); + + var prepareClassName = element.data(PREPARE_CLASSES_KEY); if (prepareClassName) { $$jqLite.removeClass(element, prepareClassName); prepareClassName = null; @@ -3259,7 +3351,6 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro $$jqLite.removeClass(element, tempClasses); } - element.removeClass(NG_ANIMATE_CLASSNAME); runner.complete(!rejected); } }; @@ -3358,7 +3449,8 @@ var ngAnimateSwapDirective = ['$animate', function($animate) { restrict: 'A', transclude: 'element', terminal: true, - priority: 600, // we use 600 here to ensure that the directive is caught before others + priority: 550, // We use 550 here to ensure that the directive is caught before others, + // but after `ngIf` (at priority 600). link: function(scope, $element, attrs, ctrl, $transclude) { var previousElement, previousScope; scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) { @@ -4160,13 +4252,14 @@ angular.module('ngAnimate', [], function initAngularHelpers() { isFunction = angular.isFunction; isElement = angular.isElement; }) - .info({ angularVersion: '1.7.2-build.5558+sha.c9a92fc' }) + .info({ angularVersion: '1.8.4-local+sha.d8f77817e' }) .directive('ngAnimateSwap', ngAnimateSwapDirective) .directive('ngAnimateChildren', $$AnimateChildrenDirective) .factory('$$rAFScheduler', $$rAFSchedulerFactory) .provider('$$animateQueue', $$AnimateQueueProvider) + .provider('$$animateCache', $$AnimateCacheProvider) .provider('$$animation', $$AnimationProvider) .provider('$animateCss', $AnimateCssProvider) diff --git a/snapshot/angular-animate.min.js b/snapshot/angular-animate.min.js index 0cc8d5f6f..370ed943f 100644 --- a/snapshot/angular-animate.min.js +++ b/snapshot/angular-animate.min.js @@ -1,57 +1,59 @@ /* - AngularJS v1.7.2-build.5558+sha.c9a92fc - (c) 2010-2018 Google, Inc. http://angularjs.org + AngularJS v1.8.4-local+sha.d8f77817e + (c) 2010-2020 Google LLC. http://angularjs.org License: MIT */ -(function(S,m){'use strict';function Ea(a,b,c){if(!a)throw Pa("areq",b||"?",c||"required");return a}function Fa(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;V(a)&&(a=a.join(" "));V(b)&&(b=b.join(" "));return a+" "+b}function Qa(a){var b={};a&&(a.to||a.from)&&(b.to=a.to,b.from=a.from);return b}function W(a,b,c){var d="";a=V(a)?a:a&&B(a)&&a.length?a.split(/\s+/):[];t(a,function(a,e){a&&0=a&&(a=h,h=0,b.push(e),e=[]);e.push(g.fn);g.children.forEach(function(a){h++;c.push(a)});a--}e.length&&b.push(e);return b}(c)}var l=[],J=X(a);return function(r,m,v){function E(a){a=a.hasAttribute("ng-animate-ref")? -[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];t(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function h(a){var b=[],c={};t(a,function(a,d){var k=I(a.element),h=0<=["enter","move"].indexOf(a.event),k=a.structural?E(k):[];if(k.length){var e=h?"to":"from";t(k,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][e]={animationID:d,element:z(a)}})}else b.push(a)});var d={},h={};t(c,function(c,e){var g=c.from,q=c.to;if(g&&q){var C=a[g.animationID], -p=a[q.animationID],y=g.animationID.toString();if(!h[y]){var n=h[y]={structural:!0,beforeStart:function(){C.beforeStart();p.beforeStart()},close:function(){C.close();p.close()},classes:L(C.classes,p.classes),from:C,to:p,anchors:[]};n.classes.length?b.push(n):(b.push(C),b.push(p))}h[y].anchors.push({out:g.element,"in":q.element})}else g=g?g.animationID:q.animationID,q=g.toString(),d[q]||(d[q]=!0,b.push(a[g]))});return b}function L(a,b){a=a.split(" ");b=b.split(" ");for(var c=[],d=0;d=P&&b>=M&&(ba=!0,n()))}function ga(){function b(){if(!L){K(!1);t(x,function(a){k.style[a[0]]=a[1]});h(a,f); -g.addClass(a,ca);if(s.recalculateTimingStyles){ma=k.getAttribute("class")+" "+fa;ja=m(k,ma);A=E(k,ma,ja);$=A.maxDelay;w=Math.max($,0);M=A.maxDuration;if(0===M){n();return}s.hasTransitions=0F.expectedEndTime)?r.cancel(F.timer):e.push(n)}p&&(l=r(c,l,!1),e[0]={timer:l,expectedEndTime:d},e.push(n),a.data("$$animateCss",e));if(ea.length)a.on(ea.join(" "),y);f.to&&(f.cleanupStyles&&Ma(q,k,Object.keys(f.to)),Ia(a,f))}}function c(){var b= -a.data("$$animateCss");if(b){for(var d=1;d=a&&(a=t,t=0,b.push(f),f=[]);f.push(g);g.children.forEach(function(a){t++;c.push(a)});a--}f.length&&b.push(f);return b}(c)}var C=[],U=aa(a);return function(e, +H,u){function t(a){a=a.hasAttribute("ng-animate-ref")?[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];s(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function I(a){var b=[],c={};s(a,function(a,d){var l=K(a.element),g=0<=["enter","move"].indexOf(a.event),l=a.structural?t(l):[];if(l.length){var f=g?"to":"from";s(l,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][f]={animationID:d,element:A(a)}})}else b.push(a)});var d={},g={};s(c,function(c, +t){var f=c.from,e=c.to;if(f&&e){var h=a[f.animationID],k=a[e.animationID],E=f.animationID.toString();if(!g[E]){var I=g[E]={structural:!0,beforeStart:function(){h.beforeStart();k.beforeStart()},close:function(){h.close();k.close()},classes:da(h.classes,k.classes),from:h,to:k,anchors:[]};I.classes.length?b.push(I):(b.push(h),b.push(k))}g[E].anchors.push({out:f.element,"in":e.element})}else f=f?f.animationID:e.animationID,e=f.toString(),d[e]||(d[e]=!0,b.push(a[f]))});return b}function da(a,b){a=a.split(" "); +b=b.split(" ");for(var c=[],d=0;d=G&&b>=D&&(la=!0,v()))}function F(){function b(){if(!P){u(!1);s(y,function(a){l.style[a[0]]=a[1]});H(a,g);c.addClass(a,ba);if(p.recalculateTimingStyles){T=l.getAttribute("class")+" "+V;ka=k.cacheKey(l,ja,g.addClass,g.removeClass);r=z(l,T,ka,!1);ga=r.maxDelay;W= +Math.max(ga,0);D=r.maxDuration;if(0===D){v();return}p.hasTransitions=0n.expectedEndTime)?f.cancel(n.timer):h.push(v)}F&&(m=f(d,m,!1),h[0]={timer:m,expectedEndTime:e},h.push(v),a.data("$$animateCss",h));if(w.length)a.on(w.join(" "),q);g.to&&(g.cleanupStyles&&Ma(E,l,Object.keys(g.to)),Ja(a,g))}}function d(){var b=a.data("$$animateCss");if(b){for(var c=1;c 4096 bytes)!");h.cookie=b}}e.module("ngCookies",["ng"]).info({angularVersion:"1.7.2-build.5558+sha.c9a92fc"}).provider("$cookies",[function(){var d=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(k,l){return{get:function(a){return k()[a]},getObject:function(a){return(a=this.get(a))?e.fromJson(a):a},getAll:function(){return k()},put:function(a,h,f){l(a,h,f?e.extend({},d,f):d)},putObject:function(a,d,f){this.put(a,e.toJson(d),f)},remove:function(a,h){l(a,void 0,h?e.extend({}, +c+" > 4096 bytes)!");h.cookie=b}}e.module("ngCookies",["ng"]).info({angularVersion:"1.8.4-local+sha.d8f77817e"}).provider("$cookies",[function(){var d=this.defaults={};this.$get=["$$cookieReader","$$cookieWriter",function(k,l){return{get:function(a){return k()[a]},getObject:function(a){return(a=this.get(a))?e.fromJson(a):a},getAll:function(){return k()},put:function(a,h,f){l(a,h,f?e.extend({},d,f):d)},putObject:function(a,d,f){this.put(a,e.toJson(d),f)},remove:function(a,h){l(a,void 0,h?e.extend({}, d,h):d)}}}]}]);m.$inject=["$document","$log","$browser"];e.module("ngCookies").provider("$$cookieWriter",function(){this.$get=m})})(window,window.angular); //# sourceMappingURL=angular-cookies.min.js.map diff --git a/snapshot/angular-cookies.min.js.map b/snapshot/angular-cookies.min.js.map index 26df5d887..847e9c29e 100644 --- a/snapshot/angular-cookies.min.js.map +++ b/snapshot/angular-cookies.min.js.map @@ -2,7 +2,7 @@ "version":3, "file":"angular-cookies.min.js", "lineCount":8, -"mappings":"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", +"mappings":"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", "sources":["angular-cookies.js"], "names":["window","angular","$$CookieWriter","$document","$log","$browser","cookiePath","baseHref","rawDocument","name","value","options","path","expires","isDefined","isUndefined","isString","Date","str","encodeURIComponent","domain","toUTCString","secure","samesite","cookieLength","length","warn","cookie","module","info","angularVersion","provider","$CookiesProvider","defaults","$get","$$cookieReader","$$cookieWriter","get","key","getObject","fromJson","getAll","put","extend","putObject","toJson","remove","undefined","$inject","$$CookieWriterProvider"] } diff --git a/snapshot/angular-loader.js b/snapshot/angular-loader.js index 08d4ad27e..1a72f1562 100644 --- a/snapshot/angular-loader.js +++ b/snapshot/angular-loader.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.7.2-build.5558+sha.c9a92fc - * (c) 2010-2018 Google, Inc. http://angularjs.org + * @license AngularJS v1.8.4-local+sha.d8f77817e + * (c) 2010-2020 Google LLC. http://angularjs.org * License: MIT */ @@ -101,7 +101,7 @@ var minErrConfig = { * non-positive or non-numeric value, removes the max depth limit. * Default: 5 * - * * `urlErrorParamsEnabled` **{Boolean}** - Specifies wether the generated error url will + * * `urlErrorParamsEnabled` **{Boolean}** - Specifies whether the generated error url will * contain the parameters of the thrown error. Disabling the parameters can be useful if the * generated error url is very long. * @@ -151,7 +151,7 @@ function isValidObjectMaxDepth(maxDepth) { * Since data will be parsed statically during a build step, some restrictions * are applied with respect to how minErr instances are created and called. * Instances should have names of the form namespaceMinErr for a minErr created - * using minErr('namespace') . Error codes, namespaces and template strings + * using minErr('namespace'). Error codes, namespaces and template strings * should all be static strings, not variables or general expressions. * * @param {string} module The namespace to use for the new minErr instance. @@ -163,7 +163,7 @@ function isValidObjectMaxDepth(maxDepth) { function minErr(module, ErrorConstructor) { ErrorConstructor = ErrorConstructor || Error; - var url = 'https://errors.angularjs.org/1.7.2-build.5558+sha.c9a92fc/'; + var url = 'https://errors.angularjs.org/1.8.4-local+sha.d8f77817e/'; var regex = url.replace('.', '\\.') + '[\\s\\S]*'; var errRegExp = new RegExp(regex, 'g'); diff --git a/snapshot/angular-loader.min.js b/snapshot/angular-loader.min.js index 0b78a5063..8d95d0475 100644 --- a/snapshot/angular-loader.min.js +++ b/snapshot/angular-loader.min.js @@ -1,9 +1,9 @@ /* - AngularJS v1.7.2-build.5558+sha.c9a92fc - (c) 2010-2018 Google, Inc. http://angularjs.org + AngularJS v1.8.4-local+sha.d8f77817e + (c) 2010-2020 Google LLC. http://angularjs.org License: MIT */ -(function(){'use strict';function g(a,f){f=f||Error;return function(){var d=arguments[0],e;e="["+(a?a+":":"")+d+"] http://errors.angularjs.org/1.7.2-build.5558+sha.c9a92fc/"+(a?a+"/":"")+d;for(d=1;d=d.length)b-=d.length;else return{h:m+1,f:b+1}}}function v(a){function b(){return a}var c=w[a];if(null!=c)return c;b.$$watchDelegate=function(b,c,d){var e=b.$watch(q,function(){c(a,a,b);e()},d);return e};w[a]=b;b.exp=a;b.expressions=[];return b}function D(a,b){function c(c){c=a(c);return null==c?c:c-b}if(0===b)return a;var d;c.$$watchDelegate=function(c,p,e){return d=c.$watch(a,function(a,d){p(null== @@ -21,6 +21,6 @@ this.c.ea(!1,this.text),this.a=this.n):"#"===b?this.c.G(this.B):this.r())};d.pro function(){var a=this.d;this.V();this.c.G(a);this.a=this.Z};d.prototype.X=function(){this.d=null;this.o.push(this.sa);this.a=this.ra};d.prototype.ta=function(){var a=this.d;this.V();this.c.G(a);this.a=this.$};var Q=/\s*}}/g;d.prototype.sa=function(){if(null==this.m(Q)){var a=f(this.text,this.index);throw e("reqendinterp","}}",a.h,a.f,this.text);}null==this.d&&(this.d=this.w(this.b,this.Da),this.d.exp=this.b.exp,this.d.expressions=this.b.expressions);this.a=null};d.prototype.ra=function(){this.j=[]; this.l=this.index;this.a=this.Y};var R=/[[\]{}()'",]/g;d.prototype.Y=function(){var a=this.t(R);if(null==a){if(0===this.j.length){this.index=this.text.length;this.b=this.w(this.text.substring(this.l,this.index));this.b.exp=this.text.substring(this.l,this.index);this.b.expressions=this.b.expressions;this.a=null;return}throw e("badexpr",this.Ga(this.j[0]),this.text);}var b=a[0];if("'"===b||'"'===b)this.o.push(this.Y),this.Ca(a);else if(","===b){if(this.u)throw a=f(this.text,this.index),e("unsafe",this.u, a.h,a.f,this.text);0===this.j.length&&(this.b=this.w(this.text.substring(this.l,a.index)),this.b.exp=this.text.substring(this.l,a.index),this.b.expressions=this.b.expressions,this.a=null,this.a=this.ya)}else if(null!=A(b))this.j.unshift(b);else{var c=E(b);null==c&&this.r();if(0} pendingTasks - A list of task objects. + * @return {Array} A list of stringified tasks. + */ + self.defer.formatPendingTasks = function(pendingTasks) { + return pendingTasks.map(function(task) { + return '{id: ' + task.id + ', type: ' + task.type + ', time: ' + task.time + '}'; + }); + }; + + /** + * @name $browser#defer.verifyNoPendingTasks + * + * @description + * Verifies that there are no pending tasks that need to be flushed. + * You can check for a specific type of tasks only, by specifying a `taskType`. + * + * See {@link $verifyNoPendingTasks} for more info. + * + * @param {string=} taskType - The type tasks to check for. + */ + self.defer.verifyNoPendingTasks = function(taskType) { + var pendingTasks = self.defer.getPendingTasks(taskType); + + if (pendingTasks.length) { + var formattedTasks = self.defer.formatPendingTasks(pendingTasks).join('\n '); + throw new Error('Deferred tasks to flush (' + pendingTasks.length + '):\n ' + + formattedTasks); + } + }; + self.$$baseHref = '/'; self.baseHref = function() { return this.$$baseHref; @@ -184,7 +279,8 @@ angular.mock.$Browser.prototype = { state = null; } if (url) { - this.$$url = url; + // The `$browser` service trims empty hashes; simulate it. + this.$$url = url.replace(/#$/, ''); // Native pushState serializes & copies the object; simulate it. this.$$state = angular.copy(state); return this; @@ -198,6 +294,82 @@ angular.mock.$Browser.prototype = { } }; +/** + * @ngdoc service + * @name $flushPendingTasks + * + * @description + * Flushes all currently pending tasks and executes the corresponding callbacks. + * + * Optionally, you can also pass a `delay` argument to only flush tasks that are scheduled to be + * executed within `delay` milliseconds. Currently, `delay` only applies to timeouts, since all + * other tasks have a delay of 0 (i.e. they are scheduled to be executed as soon as possible, but + * still asynchronously). + * + * If no delay is specified, it uses a delay such that all currently pending tasks are flushed. + * + * The types of tasks that are flushed include: + * + * - Pending timeouts (via {@link $timeout}). + * - Pending tasks scheduled via {@link ng.$rootScope.Scope#$applyAsync $applyAsync}. + * - Pending tasks scheduled via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}. + * These include tasks scheduled via `$evalAsync()` indirectly (such as {@link $q} promises). + * + *
+ * Periodic tasks scheduled via {@link $interval} use a different queue and are not flushed by + * `$flushPendingTasks()`. Use {@link ngMock.$interval#flush $interval.flush(millis)} instead. + *
+ * + * @param {number=} delay - The number of milliseconds to flush. + */ +angular.mock.$FlushPendingTasksProvider = function() { + this.$get = [ + '$browser', + function($browser) { + return function $flushPendingTasks(delay) { + return $browser.defer.flush(delay); + }; + } + ]; +}; + +/** + * @ngdoc service + * @name $verifyNoPendingTasks + * + * @description + * Verifies that there are no pending tasks that need to be flushed. It throws an error if there are + * still pending tasks. + * + * You can check for a specific type of tasks only, by specifying a `taskType`. + * + * Available task types: + * + * - `$timeout`: Pending timeouts (via {@link $timeout}). + * - `$http`: Pending HTTP requests (via {@link $http}). + * - `$route`: In-progress route transitions (via {@link $route}). + * - `$applyAsync`: Pending tasks scheduled via {@link ng.$rootScope.Scope#$applyAsync $applyAsync}. + * - `$evalAsync`: Pending tasks scheduled via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}. + * These include tasks scheduled via `$evalAsync()` indirectly (such as {@link $q} promises). + * + *
+ * Periodic tasks scheduled via {@link $interval} use a different queue and are not taken into + * account by `$verifyNoPendingTasks()`. There is currently no way to verify that there are no + * pending {@link $interval} tasks. + *
+ * + * @param {string=} taskType - The type of tasks to check for. + */ +angular.mock.$VerifyNoPendingTasksProvider = function() { + this.$get = [ + '$browser', + function($browser) { + return function $verifyNoPendingTasks(taskType) { + return $browser.defer.verifyNoPendingTasks(taskType); + }; + } + ]; +}; /** * @ngdoc provider @@ -466,62 +638,40 @@ angular.mock.$LogProvider = function() { * @returns {promise} A promise which will be notified on each iteration. */ angular.mock.$IntervalProvider = function() { - this.$get = ['$browser', '$rootScope', '$q', '$$q', - function($browser, $rootScope, $q, $$q) { + this.$get = ['$browser', '$$intervalFactory', + function($browser, $$intervalFactory) { var repeatFns = [], nextRepeatId = 0, - now = 0; - - var $interval = function(fn, delay, count, invokeApply) { - var hasParams = arguments.length > 4, - args = hasParams ? Array.prototype.slice.call(arguments, 4) : [], - iteration = 0, - skipApply = (angular.isDefined(invokeApply) && !invokeApply), - deferred = (skipApply ? $$q : $q).defer(), - promise = deferred.promise; - - count = (angular.isDefined(count)) ? count : 0; - promise.then(null, function() {}, (!hasParams) ? fn : function() { - fn.apply(null, args); - }); - - promise.$$intervalId = nextRepeatId; - - function tick() { - deferred.notify(iteration++); - - if (count > 0 && iteration >= count) { - var fnIndex; - deferred.resolve(iteration); - - angular.forEach(repeatFns, function(fn, index) { - if (fn.id === promise.$$intervalId) fnIndex = index; + now = 0, + setIntervalFn = function(tick, delay, deferred, skipApply) { + var id = nextRepeatId++; + var fn = !skipApply ? tick : function() { + tick(); + $browser.defer.flush(); + }; + + repeatFns.push({ + nextTime: (now + (delay || 0)), + delay: delay || 1, + fn: fn, + id: id, + deferred: deferred }); + repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime; }); - if (angular.isDefined(fnIndex)) { - repeatFns.splice(fnIndex, 1); + return id; + }, + clearIntervalFn = function(id) { + for (var fnIndex = repeatFns.length - 1; fnIndex >= 0; fnIndex--) { + if (repeatFns[fnIndex].id === id) { + repeatFns.splice(fnIndex, 1); + break; + } } - } - - if (skipApply) { - $browser.defer.flush(); - } else { - $rootScope.$apply(); - } - } + }; - repeatFns.push({ - nextTime: (now + (delay || 0)), - delay: delay || 1, - fn: tick, - id: nextRepeatId, - deferred: deferred - }); - repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;}); + var $interval = $$intervalFactory(setIntervalFn, clearIntervalFn); - nextRepeatId++; - return promise; - }; /** * @ngdoc method * @name $interval#cancel @@ -534,17 +684,15 @@ angular.mock.$IntervalProvider = function() { */ $interval.cancel = function(promise) { if (!promise) return false; - var fnIndex; - angular.forEach(repeatFns, function(fn, index) { - if (fn.id === promise.$$intervalId) fnIndex = index; - }); - - if (angular.isDefined(fnIndex)) { - repeatFns[fnIndex].deferred.promise.then(undefined, function() {}); - repeatFns[fnIndex].deferred.reject('canceled'); - repeatFns.splice(fnIndex, 1); - return true; + for (var fnIndex = repeatFns.length - 1; fnIndex >= 0; fnIndex--) { + if (repeatFns[fnIndex].id === promise.$$intervalId) { + var deferred = repeatFns[fnIndex].deferred; + deferred.promise.then(undefined, function() {}); + deferred.reject('canceled'); + repeatFns.splice(fnIndex, 1); + return true; + } } return false; @@ -557,7 +705,7 @@ angular.mock.$IntervalProvider = function() { * * Runs interval tasks scheduled to be run in the next `millis` milliseconds. * - * @param {number=} millis maximum timeout amount to flush up until. + * @param {number} millis maximum timeout amount to flush up until. * * @return {number} The amount of time moved forward. */ @@ -803,7 +951,7 @@ angular.mock.TzDate.prototype = Date.prototype; * You need to require the `ngAnimateMock` module in your test suite for instance `beforeEach(module('ngAnimateMock'))` */ angular.mock.animate = angular.module('ngAnimateMock', ['ng']) - .info({ angularVersion: '1.7.2-build.5558+sha.c9a92fc' }) + .info({ angularVersion: '1.8.4-local+sha.d8f77817e' }) .config(['$provide', function($provide) { @@ -1289,7 +1437,7 @@ angular.mock.dump = function(object) { * ## Matching route requests * * For extra convenience, `whenRoute` and `expectRoute` shortcuts are available. These methods offer colon - * delimited matching of the url path, ignoring the query string. This allows declarations + * delimited matching of the url path, ignoring the query string and trailing slashes. This allows declarations * similar to how application routes are configured with `$routeProvider`. Because these methods convert * the definition url to regex, declaration order is important. Combined with query parameter parsing, * the following is possible: @@ -1417,16 +1565,25 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { } } + function createFatalError(message) { + var error = new Error(message); + // In addition to being converted to a rejection, these errors also need to be passed to + // the $exceptionHandler and be rethrown (so that the test fails). + error.$$passToExceptionHandler = true; + return error; + } + if (expectation && expectation.match(method, url)) { if (!expectation.matchData(data)) { - throw new Error('Expected ' + expectation + ' with different data\n' + - 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data); + throw createFatalError('Expected ' + expectation + ' with different data\n' + + 'EXPECTED: ' + prettyPrint(expectation.data) + '\n' + + 'GOT: ' + data); } if (!expectation.matchHeaders(headers)) { - throw new Error('Expected ' + expectation + ' with different headers\n' + - 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' + - prettyPrint(headers)); + throw createFatalError('Expected ' + expectation + ' with different headers\n' + + 'EXPECTED: ' + prettyPrint(expectation.headers) + '\n' + + 'GOT: ' + prettyPrint(headers)); } expectations.shift(); @@ -1447,20 +1604,17 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { ($browser ? $browser.defer : responsesPush)(wrapResponse(definition)); } else if (definition.passThrough) { originalHttpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers); - } else throw new Error('No response defined !'); + } else throw createFatalError('No response defined !'); return; } } - var error = wasExpected ? - new Error('No response defined !') : - new Error('Unexpected request: ' + method + ' ' + url + '\n' + - (expectation ? 'Expected ' + expectation : 'No more request expected')); - // In addition to be being converted to a rejection, this error also needs to be passed to - // the $exceptionHandler and be rethrown (so that the test fails). - error.$$passToExceptionHandler = true; + if (wasExpected) { + throw createFatalError('No response defined !'); + } - throw error; + throw createFatalError('Unexpected request: ' + method + ' ' + url + '\n' + + (expectation ? 'Expected ' + expectation : 'No more request expected')); } /** @@ -1488,8 +1642,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * ``` * – The respond method takes a set of static data to be returned or a function that can * return an array containing response status (number), response data (Array|Object|string), - * response headers (Object), and the text for the status (string). The respond method returns - * the `requestHandler` object for possible overrides. + * response headers (Object), HTTP status text (string), and XMLHttpRequest status (string: + * `complete`, `error`, `timeout` or `abort`). The respond method returns the `requestHandler` + * object for possible overrides. */ $httpBackend.when = function(method, url, data, headers, keys) { @@ -1518,12 +1673,12 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { /** * @ngdoc method - * @name $httpBackend#matchLatestDefinition + * @name $httpBackend#matchLatestDefinitionEnabled * @description * This method can be used to change which mocked responses `$httpBackend` returns, when defining * them with {@link ngMock.$httpBackend#when $httpBackend.when()} (and shortcut methods). * By default, `$httpBackend` returns the first definition that matches. When setting - * `$http.matchLatestDefinition(true)`, it will use the last response that matches, i.e. the + * `$http.matchLatestDefinitionEnabled(true)`, it will use the last response that matches, i.e. the * one that was added last. * * ```js @@ -1531,7 +1686,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * hb.when('GET', '/url1').respond(201, 'another', {}); * hb('GET', '/url1'); // receives "content" * - * $http.matchLatestDefinition(true) + * $http.matchLatestDefinitionEnabled(true) * hb('GET', '/url1'); // receives "another" * * hb.when('GET', '/url1').respond(201, 'onemore', {}); @@ -1540,7 +1695,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * * This is useful if a you have a default response that is overriden inside specific tests. * - * Note that different from config methods on providers, `matchLatestDefinition()` can be changed + * Note that different from config methods on providers, `matchLatestDefinitionEnabled()` can be changed * even when the application is already running. * * @param {Boolean=} value value to set, either `true` or `false`. Default is `false`. @@ -1549,7 +1704,7 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * as a getter */ $httpBackend.matchLatestDefinitionEnabled = function(value) { - if (isDefined(value)) { + if (angular.isDefined(value)) { matchLatestDefinition = value; return this; } else { @@ -1670,39 +1825,9 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * See {@link ngMock.$httpBackend#when `when`} for more info. */ $httpBackend.whenRoute = function(method, url) { - var pathObj = parseRoute(url); - return $httpBackend.when(method, pathObj.regexp, undefined, undefined, pathObj.keys); - }; - - function parseRoute(url) { - var ret = { - regexp: url - }, - keys = ret.keys = []; - - if (!url || !angular.isString(url)) return ret; - - url = url - .replace(/([().])/g, '\\$1') - .replace(/(\/)?:(\w+)([?*])?/g, function(_, slash, key, option) { - var optional = option === '?' ? option : null; - var star = option === '*' ? option : null; - keys.push({ name: key, optional: !!optional }); - slash = slash || ''; - return '' - + (optional ? '' : slash) - + '(?:' - + (optional ? slash : '') - + (star && '(.+?)' || '([^/]+)') - + (optional || '') - + ')' - + (optional || ''); - }) - .replace(/([/$*])/g, '\\$1'); - - ret.regexp = new RegExp('^' + url, 'i'); - return ret; - } + var parsed = parseRouteUrl(url); + return $httpBackend.when(method, parsed.regexp, undefined, undefined, parsed.keys); + }; /** * @ngdoc method @@ -1724,14 +1849,15 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * order to change how a matched request is handled. * * - respond – - * ``` - * { function([status,] data[, headers, statusText]) - * | function(function(method, url, data, headers, params)} - * ``` + * ```js + * {function([status,] data[, headers, statusText]) + * | function(function(method, url, data, headers, params)} + * ``` * – The respond method takes a set of static data to be returned or a function that can * return an array containing response status (number), response data (Array|Object|string), - * response headers (Object), and the text for the status (string). The respond method returns - * the `requestHandler` object for possible overrides. + * response headers (Object), HTTP status text (string), and XMLHttpRequest status (string: + * `complete`, `error`, `timeout` or `abort`). The respond method returns the `requestHandler` + * object for possible overrides. */ $httpBackend.expect = function(method, url, data, headers, keys) { @@ -1883,8 +2009,8 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { * See {@link ngMock.$httpBackend#expect `expect`} for more info. */ $httpBackend.expectRoute = function(method, url) { - var pathObj = parseRoute(url); - return $httpBackend.expect(method, pathObj.regexp, undefined, undefined, pathObj.keys); + var parsed = parseRouteUrl(url); + return $httpBackend.expect(method, parsed.regexp, undefined, undefined, parsed.keys); }; @@ -2012,6 +2138,12 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { }; }); } + + function parseRouteUrl(url) { + var strippedUrl = stripQueryAndHash(url); + var parseOptions = {caseInsensitiveMatch: true, ignoreTrailingSlashes: true}; + return routeToRegExp(strippedUrl, parseOptions); + } } function assertArgDefined(args, index, name) { @@ -2020,110 +2152,124 @@ function assertArgDefined(args, index, name) { } } +function stripQueryAndHash(url) { + return url.replace(/[?#].*$/, ''); +} -function MockHttpExpectation(method, url, data, headers, keys) { - - function getUrlParams(u) { - var params = u.slice(u.indexOf('?') + 1).split('&'); - return params.sort(); - } +function MockHttpExpectation(expectedMethod, expectedUrl, expectedData, expectedHeaders, + expectedKeys) { - function compareUrl(u) { - return (url.slice(0, url.indexOf('?')) === u.slice(0, u.indexOf('?')) && - getUrlParams(url).join() === getUrlParams(u).join()); - } + this.data = expectedData; + this.headers = expectedHeaders; - this.data = data; - this.headers = headers; - - this.match = function(m, u, d, h) { - if (method !== m) return false; - if (!this.matchUrl(u)) return false; - if (angular.isDefined(d) && !this.matchData(d)) return false; - if (angular.isDefined(h) && !this.matchHeaders(h)) return false; + this.match = function(method, url, data, headers) { + if (expectedMethod !== method) return false; + if (!this.matchUrl(url)) return false; + if (angular.isDefined(data) && !this.matchData(data)) return false; + if (angular.isDefined(headers) && !this.matchHeaders(headers)) return false; return true; }; - this.matchUrl = function(u) { - if (!url) return true; - if (angular.isFunction(url.test)) return url.test(u); - if (angular.isFunction(url)) return https://github.com/url(u); - return (url === u || compareUrl(u)); + this.matchUrl = function(url) { + if (!expectedUrl) return true; + if (angular.isFunction(expectedUrl.test)) return expectedUrl.test(url); + if (angular.isFunction(expectedUrl)) return expectedUrl(url); + return (expectedUrl === url || compareUrlWithQuery(url)); }; - this.matchHeaders = function(h) { - if (angular.isUndefined(headers)) return true; - if (angular.isFunction(headers)) return headers(h); - return angular.equals(headers, h); + this.matchHeaders = function(headers) { + if (angular.isUndefined(expectedHeaders)) return true; + if (angular.isFunction(expectedHeaders)) return expectedHeaders(headers); + return angular.equals(expectedHeaders, headers); }; - this.matchData = function(d) { - if (angular.isUndefined(data)) return true; - if (data && angular.isFunction(data.test)) return data.test(d); - if (data && angular.isFunction(data)) return data(d); - if (data && !angular.isString(data)) { - return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d)); + this.matchData = function(data) { + if (angular.isUndefined(expectedData)) return true; + if (expectedData && angular.isFunction(expectedData.test)) return expectedData.test(data); + if (expectedData && angular.isFunction(expectedData)) return expectedData(data); + if (expectedData && !angular.isString(expectedData)) { + return angular.equals(angular.fromJson(angular.toJson(expectedData)), angular.fromJson(data)); } // eslint-disable-next-line eqeqeq - return data == d; + return expectedData == data; }; this.toString = function() { - return method + ' ' + url; + return expectedMethod + ' ' + expectedUrl; + }; + + this.params = function(url) { + var queryStr = url.indexOf('?') === -1 ? '' : url.substring(url.indexOf('?') + 1); + var strippedUrl = stripQueryAndHash(url); + + return angular.extend(extractParamsFromQuery(queryStr), extractParamsFromPath(strippedUrl)); }; - this.params = function(u) { - return angular.extend(parseQuery(), pathParams()); + function compareUrlWithQuery(url) { + var urlWithQueryRe = /^([^?]*)\?(.*)$/; - function pathParams() { - var keyObj = {}; - if (!url || !angular.isFunction(url.test) || !keys || keys.length === 0) return keyObj; + var expectedMatch = urlWithQueryRe.exec(expectedUrl); + var actualMatch = urlWithQueryRe.exec(url); - var m = url.exec(u); - if (!m) return keyObj; - for (var i = 1, len = m.length; i < len; ++i) { - var key = keys[i - 1]; - var val = m[i]; - if (key && val) { - keyObj[key.name || key] = val; - } - } + return !!(expectedMatch && actualMatch) && + (expectedMatch[1] === actualMatch[1]) && + (normalizeQuery(expectedMatch[2]) === normalizeQuery(actualMatch[2])); + } - return keyObj; + function normalizeQuery(queryStr) { + return queryStr.split('&').sort().join('&'); + } + + function extractParamsFromPath(strippedUrl) { + var keyObj = {}; + + if (!expectedUrl || !angular.isFunction(expectedUrl.test) || + !expectedKeys || !expectedKeys.length) return keyObj; + + var match = expectedUrl.exec(strippedUrl); + if (!match) return keyObj; + + for (var i = 1, len = match.length; i < len; ++i) { + var key = expectedKeys[i - 1]; + var val = match[i]; + if (key && val) { + keyObj[key.name || key] = val; + } } - function parseQuery() { - var obj = {}, key_value, key, - queryStr = u.indexOf('?') > -1 - ? u.substring(u.indexOf('?') + 1) - : ''; - - angular.forEach(queryStr.split('&'), function(keyValue) { - if (keyValue) { - key_value = keyValue.replace(/\+/g,'%20').split('='); - key = tryDecodeURIComponent(key_value[0]); - if (angular.isDefined(key)) { - var val = angular.isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; - if (!hasOwnProperty.call(obj, key)) { - obj[key] = val; - } else if (angular.isArray(obj[key])) { - obj[key].push(val); - } else { - obj[key] = [obj[key],val]; - } - } + return keyObj; + } + + function extractParamsFromQuery(queryStr) { + var obj = {}, + keyValuePairs = queryStr.split('&'). + filter(angular.identity). // Ignore empty segments. + map(function(keyValue) { return keyValue.replace(/\+/g, '%20').split('='); }); + + angular.forEach(keyValuePairs, function(pair) { + var key = tryDecodeURIComponent(pair[0]); + if (angular.isDefined(key)) { + var val = angular.isDefined(pair[1]) ? tryDecodeURIComponent(pair[1]) : true; + if (!hasOwnProperty.call(obj, key)) { + obj[key] = val; + } else if (angular.isArray(obj[key])) { + obj[key].push(val); + } else { + obj[key] = [obj[key], val]; } - }); - return obj; - } - function tryDecodeURIComponent(value) { - try { - return decodeURIComponent(value); - } catch (e) { - // Ignore any invalid uri component } + }); + + return obj; + } + + function tryDecodeURIComponent(value) { + try { + return decodeURIComponent(value); + } catch (e) { + // Ignore any invalid uri component } - }; + } } function createMockXhr() { @@ -2213,39 +2359,86 @@ angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $ /** * @ngdoc method * @name $timeout#flush + * + * @deprecated + * sinceVersion="1.7.3" + * + * This method flushes all types of tasks (not only timeouts), which is unintuitive. + * It is recommended to use {@link ngMock.$flushPendingTasks} instead. + * * @description * * Flushes the queue of pending tasks. * + * _This method is essentially an alias of {@link ngMock.$flushPendingTasks}._ + * + *
+ * For historical reasons, this method will also flush non-`$timeout` pending tasks, such as + * {@link $q} promises and tasks scheduled via + * {@link ng.$rootScope.Scope#$applyAsync $applyAsync} and + * {@link ng.$rootScope.Scope#$evalAsync $evalAsync}. + *
+ * * @param {number=} delay maximum timeout amount to flush up until */ $delegate.flush = function(delay) { + // For historical reasons, `$timeout.flush()` flushes all types of pending tasks. + // Keep the same behavior for backwards compatibility (and because it doesn't make sense to + // selectively flush scheduled events out of order). $browser.defer.flush(delay); }; /** * @ngdoc method * @name $timeout#verifyNoPendingTasks + * + * @deprecated + * sinceVersion="1.7.3" + * + * This method takes all types of tasks (not only timeouts) into account, which is unintuitive. + * It is recommended to use {@link ngMock.$verifyNoPendingTasks} instead, which additionally + * allows checking for timeouts only (with `$verifyNoPendingTasks('$timeout')`). + * * @description * - * Verifies that there are no pending tasks that need to be flushed. + * Verifies that there are no pending tasks that need to be flushed. It throws an error if there + * are still pending tasks. + * + * _This method is essentially an alias of {@link ngMock.$verifyNoPendingTasks} (called with no + * arguments)._ + * + *
+ *

+ * For historical reasons, this method will also verify non-`$timeout` pending tasks, such as + * pending {@link $http} requests, in-progress {@link $route} transitions, unresolved + * {@link $q} promises and tasks scheduled via + * {@link ng.$rootScope.Scope#$applyAsync $applyAsync} and + * {@link ng.$rootScope.Scope#$evalAsync $evalAsync}. + *

+ *

+ * It is recommended to use {@link ngMock.$verifyNoPendingTasks} instead, which additionally + * supports verifying a specific type of tasks. For example, you can verify there are no + * pending timeouts with `$verifyNoPendingTasks('$timeout')`. + *

+ *
*/ $delegate.verifyNoPendingTasks = function() { - if ($browser.deferredFns.length) { - throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' + - formatPendingTasksAsString($browser.deferredFns)); + // For historical reasons, `$timeout.verifyNoPendingTasks()` takes all types of pending tasks + // into account. Keep the same behavior for backwards compatibility. + var pendingTasks = $browser.defer.getPendingTasks(); + + if (pendingTasks.length) { + var formattedTasks = $browser.defer.formatPendingTasks(pendingTasks).join('\n '); + var hasPendingTimeout = pendingTasks.some(function(task) { return task.type === '$timeout'; }); + var extraMessage = hasPendingTimeout ? '' : '\n\nNone of the pending tasks are timeouts. ' + + 'If you only want to verify pending timeouts, use ' + + '`$verifyNoPendingTasks(\'$timeout\')` instead.'; + + throw new Error('Deferred tasks to flush (' + pendingTasks.length + '):\n ' + + formattedTasks + extraMessage); } }; - function formatPendingTasksAsString(tasks) { - var result = []; - angular.forEach(tasks, function(task) { - result.push('{id: ' + task.id + ', time: ' + task.time + '}'); - }); - - return result.join(', '); - } - return $delegate; }]; @@ -2467,14 +2660,16 @@ angular.module('ngMock', ['ng']).provider({ $log: angular.mock.$LogProvider, $interval: angular.mock.$IntervalProvider, $rootElement: angular.mock.$RootElementProvider, - $componentController: angular.mock.$ComponentControllerProvider + $componentController: angular.mock.$ComponentControllerProvider, + $flushPendingTasks: angular.mock.$FlushPendingTasksProvider, + $verifyNoPendingTasks: angular.mock.$VerifyNoPendingTasksProvider }).config(['$provide', '$compileProvider', function($provide, $compileProvider) { $provide.decorator('$timeout', angular.mock.$TimeoutDecorator); $provide.decorator('$$rAF', angular.mock.$RAFDecorator); $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator); $provide.decorator('$controller', createControllerDecorator($compileProvider)); $provide.decorator('$httpBackend', angular.mock.$httpBackendDecorator); -}]).info({ angularVersion: '1.7.2-build.5558+sha.c9a92fc' }); +}]).info({ angularVersion: '1.8.4-local+sha.d8f77817e' }); /** * @ngdoc module @@ -2489,7 +2684,7 @@ angular.module('ngMock', ['ng']).provider({ */ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator); -}]).info({ angularVersion: '1.7.2-build.5558+sha.c9a92fc' }); +}]).info({ angularVersion: '1.8.4-local+sha.d8f77817e' }); /** * @ngdoc service @@ -2778,13 +2973,13 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { */ /** * @ngdoc method - * @name $httpBackend#matchLatestDefinition + * @name $httpBackend#matchLatestDefinitionEnabled * @module ngMockE2E * @description * This method can be used to change which mocked responses `$httpBackend` returns, when defining * them with {@link ngMock.$httpBackend#when $httpBackend.when()} (and shortcut methods). * By default, `$httpBackend` returns the first definition that matches. When setting - * `$http.matchLatestDefinition(true)`, it will use the last response that matches, i.e. the + * `$http.matchLatestDefinitionEnabled(true)`, it will use the last response that matches, i.e. the * one that was added last. * * ```js @@ -2792,7 +2987,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { * hb.when('GET', '/url1').respond(201, 'another', {}); * hb('GET', '/url1'); // receives "content" * - * $http.matchLatestDefinition(true) + * $http.matchLatestDefinitionEnabled(true) * hb('GET', '/url1'); // receives "another" * * hb.when('GET', '/url1').respond(201, 'onemore', {}); @@ -2801,7 +2996,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { * * This is useful if a you have a default response that is overriden inside specific tests. * - * Note that different from config methods on providers, `matchLatestDefinition()` can be changed + * Note that different from config methods on providers, `matchLatestDefinitionEnabled()` can be changed * even when the application is already running. * * @param {Boolean=} value value to set, either `true` or `false`. Default is `false`. @@ -3330,6 +3525,9 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) { * - `charcode`: [charCode](https://developer.mozilla.org/docs/Web/API/KeyboardEvent/charcode) * for keyboard events (keydown, keypress, and keyup). * + * - `data`: [data](https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent/data) for + * [CompositionEvents](https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent). + * * - `elapsedTime`: the elapsedTime for * [TransitionEvent](https://developer.mozilla.org/docs/Web/API/TransitionEvent) * and [AnimationEvent](https://developer.mozilla.org/docs/Web/API/AnimationEvent). diff --git a/snapshot/angular-parse-ext.js b/snapshot/angular-parse-ext.js index ef0b041f5..afbddf79b 100644 --- a/snapshot/angular-parse-ext.js +++ b/snapshot/angular-parse-ext.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.7.2-build.5558+sha.c9a92fc - * (c) 2010-2018 Google, Inc. http://angularjs.org + * @license AngularJS v1.8.4-local+sha.d8f77817e + * (c) 2010-2020 Google LLC. http://angularjs.org * License: MIT */ (function(window, angular) {'use strict'; @@ -1229,6 +1229,7 @@ function IDC_Y(cp) { * @ngdoc module * @name ngParseExt * @packageName angular-parse-ext + * * @description * * The `ngParseExt` module provides functionality to allow Unicode characters in @@ -1238,6 +1239,11 @@ function IDC_Y(cp) { * to be used as an identifier in an AngularJS expression. ES6 delegates some of the identifier * rules definition to Unicode, this module uses ES6 and Unicode 8.0 identifiers convention. * + *
+ * You cannot use Unicode characters for variable names in the {@link ngRepeat} or {@link ngOptions} + * expressions (e.g. `ng-repeat="f in поля"`), because even with `ngParseExt` included, these + * special expressions are not parsed by the {@link $parse} service. + *
*/ /* global angularParseExtModule: true, @@ -1263,7 +1269,7 @@ angular.module('ngParseExt', []) .config(['$parseProvider', function($parseProvider) { $parseProvider.setIdentifierFns(isValidIdentifierStart, isValidIdentifierContinue); }]) - .info({ angularVersion: '1.7.2-build.5558+sha.c9a92fc' }); + .info({ angularVersion: '1.8.4-local+sha.d8f77817e' }); })(window, window.angular); diff --git a/snapshot/angular-parse-ext.min.js b/snapshot/angular-parse-ext.min.js index adee040a3..bc3300414 100644 --- a/snapshot/angular-parse-ext.min.js +++ b/snapshot/angular-parse-ext.min.js @@ -1,6 +1,6 @@ /* - AngularJS v1.7.2-build.5558+sha.c9a92fc - (c) 2010-2018 Google, Inc. http://angularjs.org + AngularJS v1.8.4-local+sha.d8f77817e + (c) 2010-2020 Google LLC. http://angularjs.org License: MIT */ (function(f,c){'use strict';function d(b,a){return"$"===b||"_"===b||(65<=a&&90>=a||97<=a&&122>=a||170===a||181===a||186===a||192<=a&&214>=a||216<=a&&246>=a||248<=a&&705>=a||710<=a&&721>=a||736<=a&&740>=a||748===a||750===a||880<=a&&884>=a||886<=a&&887>=a||890<=a&&893>=a||895===a||902===a||904<=a&&906>=a||908===a||910<=a&&929>=a||931<=a&&1013>=a||1015<=a&&1153>=a||1162<=a&&1327>=a||1329<=a&&1366>=a||1369===a||1377<=a&&1415>=a||1488<=a&&1514>=a||1520<=a&&1522>=a||1568<=a&&1610>=a||1646<=a&&1647>=a|| @@ -45,6 +45,6 @@ a&&71104>=a||71128<=a&&71133>=a||71168<=a&&71232>=a||71236===a||71248<=a&&71257> a&&93047>=a||93053<=a&&93071>=a||93952<=a&&94020>=a||94032<=a&&94078>=a||94095<=a&&94111>=a||110592<=a&&110593>=a||113664<=a&&113770>=a||113776<=a&&113788>=a||113792<=a&&113800>=a||113808<=a&&113817>=a||113821<=a&&113822>=a||119141<=a&&119145>=a||119149<=a&&119154>=a||119163<=a&&119170>=a||119173<=a&&119179>=a||119210<=a&&119213>=a||119362<=a&&119364>=a||119808<=a&&119892>=a||119894<=a&&119964>=a||119966<=a&&119967>=a||119970===a||119973<=a&&119974>=a||119977<=a&&119980>=a||119982<=a&&119993>=a|| 119995===a||119997<=a&&120003>=a||120005<=a&&120069>=a||120071<=a&&120074>=a||120077<=a&&120084>=a||120086<=a&&120092>=a||120094<=a&&120121>=a||120123<=a&&120126>=a||120128<=a&&120132>=a||120134===a||120138<=a&&120144>=a||120146<=a&&120485>=a||120488<=a&&120512>=a||120514<=a&&120538>=a||120540<=a&&120570>=a||120572<=a&&120596>=a||120598<=a&&120628>=a||120630<=a&&120654>=a||120656<=a&&120686>=a||120688<=a&&120712>=a||120714<=a&&120744>=a||120746<=a&&120770>=a||120772<=a&&120779>=a||120782<=a&&120831>= a||121344<=a&&121398>=a||121403<=a&&121452>=a||121461===a||121476===a||121499<=a&&121503>=a||121505<=a&&121519>=a||124928<=a&&125124>=a||125136<=a&&125142>=a||126464<=a&&126467>=a||126469<=a&&126495>=a||126497<=a&&126498>=a||126500===a||126503===a||126505<=a&&126514>=a||126516<=a&&126519>=a||126521===a||126523===a||126530===a||126535===a||126537===a||126539===a||126541<=a&&126543>=a||126545<=a&&126546>=a||126548===a||126551===a||126553===a||126555===a||126557===a||126559===a||126561<=a&&126562>=a|| -126564===a||126567<=a&&126570>=a||126572<=a&&126578>=a||126580<=a&&126583>=a||126585<=a&&126588>=a||126590===a||126592<=a&&126601>=a||126603<=a&&126619>=a||126625<=a&&126627>=a||126629<=a&&126633>=a||126635<=a&&126651>=a||131072<=a&&173782>=a||173824<=a&&177972>=a||177984<=a&&178205>=a||178208<=a&&183969>=a||194560<=a&&195101>=a||917760<=a&&917999>=a?!0:!1)}c.module("ngParseExt",[]).config(["$parseProvider",function(b){b.setIdentifierFns(d,e)}]).info({angularVersion:"1.7.2-build.5558+sha.c9a92fc"})})(window, +126564===a||126567<=a&&126570>=a||126572<=a&&126578>=a||126580<=a&&126583>=a||126585<=a&&126588>=a||126590===a||126592<=a&&126601>=a||126603<=a&&126619>=a||126625<=a&&126627>=a||126629<=a&&126633>=a||126635<=a&&126651>=a||131072<=a&&173782>=a||173824<=a&&177972>=a||177984<=a&&178205>=a||178208<=a&&183969>=a||194560<=a&&195101>=a||917760<=a&&917999>=a?!0:!1)}c.module("ngParseExt",[]).config(["$parseProvider",function(b){b.setIdentifierFns(d,e)}]).info({angularVersion:"1.8.4-local+sha.d8f77817e"})})(window, window.angular); //# sourceMappingURL=angular-parse-ext.min.js.map diff --git a/snapshot/angular-parse-ext.min.js.map b/snapshot/angular-parse-ext.min.js.map index 14b17e95c..8b140f8fe 100644 --- a/snapshot/angular-parse-ext.min.js.map +++ b/snapshot/angular-parse-ext.min.js.map @@ -2,7 +2,7 @@ "version":3, "file":"angular-parse-ext.min.js", "lineCount":49, -"mappings":"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", +"mappings":"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", "sources":["angular-parse-ext.js"], "names":["window","angular","isValidIdentifierStart","ch","cp","isValidIdentifierContinue","module","config","$parseProvider","setIdentifierFns","info","angularVersion"] } diff --git a/snapshot/angular-resource.js b/snapshot/angular-resource.js index 16994e8a9..8ad072fef 100644 --- a/snapshot/angular-resource.js +++ b/snapshot/angular-resource.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.7.2-build.5558+sha.c9a92fc - * (c) 2010-2018 Google, Inc. http://angularjs.org + * @license AngularJS v1.8.4-local+sha.d8f77817e + * (c) 2010-2020 Google LLC. http://angularjs.org * License: MIT */ (function(window, angular) {'use strict'; @@ -497,7 +497,7 @@ function shallowClearAndCopy(src, dst) { * */ angular.module('ngResource', ['ng']). - info({ angularVersion: '1.7.2-build.5558+sha.c9a92fc' }). + info({ angularVersion: '1.8.4-local+sha.d8f77817e' }). provider('$resource', function ResourceProvider() { var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/; diff --git a/snapshot/angular-resource.min.js b/snapshot/angular-resource.min.js index 5e932be53..e8ed23342 100644 --- a/snapshot/angular-resource.min.js +++ b/snapshot/angular-resource.min.js @@ -1,9 +1,9 @@ /* - AngularJS v1.7.2-build.5558+sha.c9a92fc - (c) 2010-2018 Google, Inc. http://angularjs.org + AngularJS v1.8.4-local+sha.d8f77817e + (c) 2010-2020 Google LLC. http://angularjs.org License: MIT */ -(function(T,a){'use strict';function M(m,f){f=f||{};a.forEach(f,function(a,d){delete f[d]});for(var d in m)!m.hasOwnProperty(d)||"$"===d.charAt(0)&&"$"===d.charAt(1)||(f[d]=m[d]);return f}var B=a.$$minErr("$resource"),H=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;a.module("ngResource",["ng"]).info({angularVersion:"1.7.2-build.5558+sha.c9a92fc"}).provider("$resource",function(){var m=/^https?:\/\/\[[^\]]*][^/]*/,f=this;this.defaults={stripTrailingSlashes:!0,cancellable:!1,actions:{get:{method:"GET"},save:{method:"POST"}, +(function(T,a){'use strict';function M(m,f){f=f||{};a.forEach(f,function(a,d){delete f[d]});for(var d in m)!m.hasOwnProperty(d)||"$"===d.charAt(0)&&"$"===d.charAt(1)||(f[d]=m[d]);return f}var B=a.$$minErr("$resource"),H=/^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;a.module("ngResource",["ng"]).info({angularVersion:"1.8.4-local+sha.d8f77817e"}).provider("$resource",function(){var m=/^https?:\/\/\[[^\]]*][^/]*/,f=this;this.defaults={stripTrailingSlashes:!0,cancellable:!1,actions:{get:{method:"GET"},save:{method:"POST"}, query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}};this.$get=["$http","$log","$q","$timeout",function(d,F,G,N){function C(a,d){this.template=a;this.defaults=n({},f.defaults,d);this.urlParams={}}var O=a.noop,r=a.forEach,n=a.extend,R=a.copy,P=a.isArray,D=a.isDefined,x=a.isFunction,I=a.isNumber,y=a.$$encodeUriQuery,S=a.$$encodeUriSegment;C.prototype={setUrlParams:function(a,d,f){var g=this,c=f||g.template,s,h,n="",b=g.urlParams=Object.create(null);r(c.split(/\W/),function(a){if("hasOwnProperty"=== a)throw B("badname");!/^\d+$/.test(a)&&a&&(new RegExp("(^|[^\\\\]):"+a+"(\\W|$)")).test(c)&&(b[a]={isQueryParamValue:(new RegExp("\\?.*=:"+a+"(?:\\W|$)")).test(c)})});c=c.replace(/\\:/g,":");c=c.replace(m,function(b){n=b;return""});d=d||{};r(g.urlParams,function(b,a){s=d.hasOwnProperty(a)?d[a]:g.defaults[a];D(s)&&null!==s?(h=b.isQueryParamValue?y(s,!0):S(s),c=c.replace(new RegExp(":"+a+"(\\W|$)","g"),function(b,a){return h+a})):c=c.replace(new RegExp("(/?):"+a+"(\\W|$)","g"),function(b,a,e){return"/"=== e.charAt(0)?e:a+e})});g.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/");c=c.replace(/\/\.(?=\w+($|\?))/,".");a.url=n+c.replace(/\/(\\|%5C)\./,"/.");r(d,function(b,c){g.urlParams[c]||(a.params=a.params||{},a.params[c]=b)})}};return function(m,y,z,g){function c(b,c){var d={};c=n({},y,c);r(c,function(c,f){x(c)&&(c=c(b));var e;if(c&&c.charAt&&"@"===c.charAt(0)){e=b;var k=c.substr(1);if(null==k||""===k||"hasOwnProperty"===k||!H.test("."+k))throw B("badmember",k);for(var k=k.split("."),h=0, diff --git a/snapshot/angular-resource.min.js.map b/snapshot/angular-resource.min.js.map index 56e44d7a4..b9a4ef470 100644 --- a/snapshot/angular-resource.min.js.map +++ b/snapshot/angular-resource.min.js.map @@ -2,7 +2,7 @@ "version":3, "file":"angular-resource.min.js", "lineCount":14, -"mappings":"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", +"mappings":"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", "sources":["angular-resource.js"], "names":["window","angular","shallowClearAndCopy","src","dst","forEach","value","key","hasOwnProperty","charAt","$resourceMinErr","$$minErr","MEMBER_NAME_REGEX","module","info","angularVersion","provider","ResourceProvider","PROTOCOL_AND_IPV6_REGEX","defaults","stripTrailingSlashes","cancellable","actions","method","isArray","$get","$http","$log","$q","$timeout","Route","template","extend","urlParams","noop","copy","isDefined","isFunction","isNumber","encodeUriQuery","$$encodeUriQuery","encodeUriSegment","$$encodeUriSegment","prototype","setUrlParams","config","params","actionUrl","self","url","val","encodedVal","protocolAndIpv6","Object","create","split","param","test","RegExp","isQueryParamValue","replace","match","paramInfo","urlParam","p1","leadingSlashes","tail","resourceFactory","paramDefaults","options","extractParams","data","actionParams","ids","path","keys","i","ii","length","obj","undefined","defaultResponseInterceptor","response","resource","Resource","route","toJSON","Resource.prototype.toJSON","$promise","$resolved","$cancelRequest","action","name","hasBody","numericTimeout","timeout","debug","a1","a2","a3","a4","cancelRequest","promise","catch","timeoutDeferred","resolve","onSuccess","onError","arguments","isInstanceCall","httpConfig","requestInterceptor","interceptor","request","requestErrorInterceptor","requestError","responseInterceptor","responseErrorInterceptor","responseError","reject","successCallback","headers","status","statusText","errorCallback","numericTimeoutPromise","defer","then","resp","item","push","rejectionOrResponse","cancel","success","error","result","call"] } diff --git a/snapshot/angular-route.js b/snapshot/angular-route.js index 10cc102e6..3b5e788cb 100644 --- a/snapshot/angular-route.js +++ b/snapshot/angular-route.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.7.2-build.5558+sha.c9a92fc - * (c) 2010-2018 Google, Inc. http://angularjs.org + * @license AngularJS v1.8.4-local+sha.d8f77817e + * (c) 2010-2020 Google LLC. http://angularjs.org * License: MIT */ (function(window, angular) {'use strict'; @@ -32,6 +32,52 @@ function shallowCopy(src, dst) { return dst || src; } +/* global routeToRegExp: true */ + +/** + * @param {string} path - The path to parse. (It is assumed to have query and hash stripped off.) + * @param {Object} opts - Options. + * @return {Object} - An object containing an array of path parameter names (`keys`) and a regular + * expression (`regexp`) that can be used to identify a matching URL and extract the path + * parameter values. + * + * @description + * Parses the given path, extracting path parameter names and a regular expression to match URLs. + * + * Originally inspired by `pathRexp` in `visionmedia/express/lib/utils.js`. + */ +function routeToRegExp(path, opts) { + var keys = []; + + var pattern = path + .replace(/([().])/g, '\\$1') + .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { + var optional = option === '?' || option === '*?'; + var star = option === '*' || option === '*?'; + keys.push({name: key, optional: optional}); + slash = slash || ''; + return ( + (optional ? '(?:' + slash : slash + '(?:') + + (star ? '(.+?)' : '([^/]+)') + + (optional ? '?)?' : ')') + ); + }) + .replace(/([/$*])/g, '\\$1'); + + if (opts.ignoreTrailingSlashes) { + pattern = pattern.replace(/\/+$/, '') + '/*'; + } + + return { + keys: keys, + regexp: new RegExp( + '^' + pattern + '(?:[?#]|$)', + opts.caseInsensitiveMatch ? 'i' : '' + ) + }; +} + +/* global routeToRegExp: false */ /* global shallowCopy: false */ // `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`). @@ -55,7 +101,7 @@ var noop; /* global -ngRouteModule */ var ngRouteModule = angular. module('ngRoute', []). - info({ angularVersion: '1.7.2-build.5558+sha.c9a92fc' }). + info({ angularVersion: '1.8.4-local+sha.d8f77817e' }). provider('$route', $RouteProvider). // Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess` // event (unless explicitly disabled). This is necessary in case `ngView` is included in an @@ -216,7 +262,7 @@ function $RouteProvider() { * route definition, will cause the latter to be ignored. * * - `[reloadOnUrl=true]` - `{boolean=}` - reload route when any part of the URL changes - * (inluding the path) even if the new URL maps to the same route. + * (including the path) even if the new URL maps to the same route. * * If the option is set to `false` and the URL in the browser changes, but the new URL maps * to the same route, then a `$routeUpdate` event is broadcasted on the root scope (without @@ -256,7 +302,8 @@ function $RouteProvider() { } routes[path] = angular.extend( routeCopy, - path && pathRegExp(path, routeCopy) + {originalPath: path}, + path && routeToRegExp(path, routeCopy) ); // create redirection for trailing slashes @@ -266,8 +313,8 @@ function $RouteProvider() { : path + '/'; routes[redirectPath] = angular.extend( - {redirectTo: path}, - pathRegExp(redirectPath, routeCopy) + {originalPath: path, redirectTo: path}, + routeToRegExp(redirectPath, routeCopy) ); } @@ -285,47 +332,6 @@ function $RouteProvider() { */ this.caseInsensitiveMatch = false; - /** - * @param path {string} path - * @param opts {Object} options - * @return {?Object} - * - * @description - * Normalizes the given path, returning a regular expression - * and the original path. - * - * Inspired by pathRexp in visionmedia/express/lib/utils.js. - */ - function pathRegExp(path, opts) { - var insensitive = opts.caseInsensitiveMatch, - ret = { - originalPath: path, - regexp: path - }, - keys = ret.keys = []; - - path = path - .replace(/([().])/g, '\\$1') - .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { - var optional = (option === '?' || option === '*?') ? '?' : null; - var star = (option === '*' || option === '*?') ? '*' : null; - keys.push({ name: key, optional: !!optional }); - slash = slash || ''; - return '' - + (optional ? '' : slash) - + '(?:' - + (optional ? slash : '') - + (star && '(.+?)' || '([^/]+)') - + (optional || '') - + ')' - + (optional || ''); - }) - .replace(/([/$*])/g, '\\$1'); - - ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : ''); - return ret; - } - /** * @ngdoc method * @name $routeProvider#otherwise @@ -725,7 +731,7 @@ function $RouteProvider() { var nextRoutePromise = $q.resolve(nextRoute); - $browser.$$incOutstandingRequestCount(); + $browser.$$incOutstandingRequestCount('$route'); nextRoutePromise. then(getRedirectionData). @@ -753,7 +759,7 @@ function $RouteProvider() { // `outstandingRequestCount` to hit zero. This is important in case we are redirecting // to a new route which also requires some asynchronous work. - $browser.$$completeOutstandingRequest(noop); + $browser.$$completeOutstandingRequest(noop, '$route'); }); } } diff --git a/snapshot/angular-route.min.js b/snapshot/angular-route.min.js index 5e3cbe2e9..88916496a 100644 --- a/snapshot/angular-route.min.js +++ b/snapshot/angular-route.min.js @@ -1,17 +1,17 @@ /* - AngularJS v1.7.2-build.5558+sha.c9a92fc - (c) 2010-2018 Google, Inc. http://angularjs.org + AngularJS v1.8.4-local+sha.d8f77817e + (c) 2010-2020 Google LLC. http://angularjs.org License: MIT */ -(function(J,d){'use strict';function A(d){k&&d.get("$route")}function B(t,u,g){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,f,b,c,m){function v(){l&&(g.cancel(l),l=null);p&&(p.$destroy(),p=null);q&&(l=g.leave(q),l.done(function(a){!1!==a&&(l=null)}),q=null)}function E(){var b=t.current&&t.current.locals;if(d.isDefined(b&&b.$template)){var b=a.$new(),c=t.current;q=m(b,function(b){g.enter(b,null,q||f).done(function(b){!1===b||!d.isDefined(w)||w&&!a.$eval(w)||u()}); -v()});p=c.scope=b;p.$emit("$viewContentLoaded");p.$eval(k)}else v()}var p,q,l,w=b.autoscroll,k=b.onload||"";a.$on("$routeChangeSuccess",E);E()}}}function C(d,k,g){return{restrict:"ECA",priority:-400,link:function(a,f){var b=g.current,c=b.locals;f.html(c.$template);var m=d(f.contents());if(b.controller){c.$scope=a;var v=k(b.controller,c);b.controllerAs&&(a[b.controllerAs]=v);f.data("$ngControllerController",v);f.children().data("$ngControllerController",v)}a[b.resolveAs||"$resolve"]=c;m(a)}}}var x, -y,F,G,z=d.module("ngRoute",[]).info({angularVersion:"1.7.2-build.5558+sha.c9a92fc"}).provider("$route",function(){function t(a,f){return d.extend(Object.create(a),f)}function u(a,d){var b=d.caseInsensitiveMatch,c={originalPath:a,regexp:a},g=c.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[?*])?/g,function(a,b,d,c){a="?"===c||"*?"===c?"?":null;c="*"===c||"*?"===c?"*":null;g.push({name:d,optional:!!a});b=b||"";return""+(a?"":b)+"(?:"+(a?b:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a|| -"")}).replace(/([/$*])/g,"\\$1");c.regexp=new RegExp("^"+a+"$",b?"i":"");return c}x=d.isArray;y=d.isObject;F=d.isDefined;G=d.noop;var g={};this.when=function(a,f){var b;b=void 0;if(x(f)){b=b||[];for(var c=0,m=f.length;c * This method must be called during the {@link angular.Module#config config} phase. Once the @@ -426,50 +426,28 @@ function $SanitizeProvider() { } /** - * Create an inert document that contains the dirty HTML that needs sanitizing - * Depending upon browser support we use one of three strategies for doing this. - * Support: Safari 10.x -> XHR strategy - * Support: Firefox -> DomParser strategy + * Create an inert document that contains the dirty HTML that needs sanitizing. + * We use the DOMParser API by default and fall back to createHTMLDocument if DOMParser is not + * available. */ var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) { - var inertDocument; - if (document && document.implementation) { - inertDocument = document.implementation.createHTMLDocument('inert'); - } else { - throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document'); + if (isDOMParserAvailable()) { + return getInertBodyElement_DOMParser; } - var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body'); - // Check for the Safari 10.1 bug - which allows JS to run inside the SVG G element - inertBodyElement.innerHTML = ''; - if (!inertBodyElement.querySelector('svg')) { - return getInertBodyElement_XHR; - } else { - // Check for the Firefox bug - which prevents the inner img JS from being sanitized - inertBodyElement.innerHTML = '

'); \ No newline at end of file +!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend(window.angular.element(''); +c){var e=a|0,f=c;void 0===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),x(function(){Ee(z.document,Wc)}))})(window);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend(window.angular.element(" + * ``` + * + * All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since + * ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest. + * + * In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation + * with CSS styles. + * + * ```html + *

+ * Highlight this box + *
+ * + * + * + * ``` + * + * We can also make use of CSS keyframes by placing them within the CSS classes. + * + * + * ### CSS Staggering Animations + * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a + * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be + * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for + * the animation. The style property expected within the stagger class can either be a **transition-delay** or an + * **animation-delay** property (or both if your animation contains both transitions and keyframe animations). + * + * ```css + * .my-animation.ng-enter { + * /* standard transition code */ + * transition: 1s linear all; + * opacity:0; + * } + * .my-animation.ng-enter-stagger { + * /* this will have a 100ms delay between each successive leave animation */ + * transition-delay: 0.1s; + * + * /* As of 1.4.4, this must always be set: it signals ngAnimate + * to not accidentally inherit a delay property from another CSS class */ + * transition-duration: 0s; + * + * /* if you are using animations instead of transitions you should configure as follows: + * animation-delay: 0.1s; + * animation-duration: 0s; */ + * } + * .my-animation.ng-enter.ng-enter-active { + * /* standard transition styles */ + * opacity:1; + * } + * ``` + * + * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations + * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this + * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation + * will also be reset if one or more animation frames have passed since the multiple calls to `$animate` were fired. + * + * The following code will issue the **ng-leave-stagger** event on the element provided: + * + * ```js + * var kids = parent.children(); + * + * $animate.leave(kids[0]); //stagger index=0 + * $animate.leave(kids[1]); //stagger index=1 + * $animate.leave(kids[2]); //stagger index=2 + * $animate.leave(kids[3]); //stagger index=3 + * $animate.leave(kids[4]); //stagger index=4 + * + * window.requestAnimationFrame(function() { + * //stagger has reset itself + * $animate.leave(kids[5]); //stagger index=0 + * $animate.leave(kids[6]); //stagger index=1 + * + * $scope.$digest(); + * }); + * ``` + * + * Stagger animations are currently only supported within CSS-defined animations. + * + * ### The `ng-animate` CSS class + * + * When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation. + * This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations). + * + * Therefore, animations can be applied to an element using this temporary class directly via CSS. + * + * ```css + * .zipper.ng-animate { + * transition:0.5s linear all; + * } + * .zipper.ng-enter { + * opacity:0; + * } + * .zipper.ng-enter.ng-enter-active { + * opacity:1; + * } + * .zipper.ng-leave { + * opacity:1; + * } + * .zipper.ng-leave.ng-leave-active { + * opacity:0; + * } + * ``` + * + * (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove + * the CSS class once an animation has completed.) + * + * + * ### The `ng-[event]-prepare` class + * + * This is a special class that can be used to prevent unwanted flickering / flash of content before + * the actual animation starts. The class is added as soon as an animation is initialized, but removed + * before the actual animation starts (after waiting for a $digest). + * It is also only added for *structural* animations (`enter`, `move`, and `leave`). + * + * In practice, flickering can appear when nesting elements with structural animations such as `ngIf` + * into elements that have class-based animations such as `ngClass`. + * + * ```html + *
+ *
+ *
+ *
+ *
+ * ``` + * + * It is possible that during the `enter` animation, the `.message` div will be briefly visible before it starts animating. + * In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts: + * + * ```css + * .message.ng-enter-prepare { + * opacity: 0; + * } + * ``` + * + * ### Animating between value changes + * + * Sometimes you need to animate between different expression states, whose values + * don't necessary need to be known or referenced in CSS styles. + * Unless possible with another {@link ngAnimate#directive-support "animation aware" directive}, + * that specific use case can always be covered with {@link ngAnimate.directive:ngAnimateSwap} as + * can be seen in {@link ngAnimate.directive:ngAnimateSwap#examples this example}. + * + * Note that {@link ngAnimate.directive:ngAnimateSwap} is a *structural directive*, which means it + * creates a new instance of the element (including any other/child directives it may have) and + * links it to a new scope every time *swap* happens. In some cases this might not be desirable + * (e.g. for performance reasons, or when you wish to retain internal state on the original + * element instance). + * + * ## JavaScript-based Animations + * + * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared + * CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the + * `module.animation()` module function we can register the animation. + * + * Let's see an example of a enter/leave animation using `ngRepeat`: + * + * ```html + *
+ * {{ item }} + *
+ * ``` + * + * See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`: + * + * ```js + * myModule.animation('.slide', [function() { + * return { + * // make note that other events (like addClass/removeClass) + * // have different function input parameters + * enter: function(element, doneFn) { + * jQuery(element).fadeIn(1000, doneFn); + * + * // remember to call doneFn so that AngularJS + * // knows that the animation has concluded + * }, + * + * move: function(element, doneFn) { + * jQuery(element).fadeIn(1000, doneFn); + * }, + * + * leave: function(element, doneFn) { + * jQuery(element).fadeOut(1000, doneFn); + * } + * } + * }]); + * ``` + * + * The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as + * greensock.js and velocity.js. + * + * If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define + * our animations inside of the same registered animation, however, the function input arguments are a bit different: + * + * ```html + *
+ * this box is moody + *
+ * + * + * + * ``` + * + * ```js + * myModule.animation('.colorful', [function() { + * return { + * addClass: function(element, className, doneFn) { + * // do some cool animation and call the doneFn + * }, + * removeClass: function(element, className, doneFn) { + * // do some cool animation and call the doneFn + * }, + * setClass: function(element, addedClass, removedClass, doneFn) { + * // do some cool animation and call the doneFn + * } + * } + * }]); + * ``` + * + * ## CSS + JS Animations Together + * + * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of AngularJS, + * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking + * charge of the animation**: + * + * ```html + *
+ * Slide in and out + *
+ * ``` + * + * ```js + * myModule.animation('.slide', [function() { + * return { + * enter: function(element, doneFn) { + * jQuery(element).slideIn(1000, doneFn); + * } + * } + * }]); + * ``` + * + * ```css + * .slide.ng-enter { + * transition:0.5s linear all; + * transform:translateY(-100px); + * } + * .slide.ng-enter.ng-enter-active { + * transform:translateY(0); + * } + * ``` + * + * Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the + * lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from + * our own JS-based animation code: + * + * ```js + * myModule.animation('.slide', ['$animateCss', function($animateCss) { + * return { + * enter: function(element) { +* // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`. + * return $animateCss(element, { + * event: 'enter', + * structural: true + * }); + * } + * } + * }]); + * ``` + * + * The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework. + * + * The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or + * keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that + * data into `$animateCss` directly: + * + * ```js + * myModule.animation('.slide', ['$animateCss', function($animateCss) { + * return { + * enter: function(element) { + * return $animateCss(element, { + * event: 'enter', + * structural: true, + * addClass: 'maroon-setting', + * from: { height:0 }, + * to: { height: 200 } + * }); + * } + * } + * }]); + * ``` + * + * Now we can fill in the rest via our transition CSS code: + * + * ```css + * /* the transition tells ngAnimate to make the animation happen */ + * .slide.ng-enter { transition:0.5s linear all; } + * + * /* this extra CSS class will be absorbed into the transition + * since the $animateCss code is adding the class */ + * .maroon-setting { background:red; } + * ``` + * + * And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over. + * + * To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}. + * + * ## Animation Anchoring (via `ng-animate-ref`) + * + * ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between + * structural areas of an application (like views) by pairing up elements using an attribute + * called `ng-animate-ref`. + * + * Let's say for example we have two views that are managed by `ng-view` and we want to show + * that there is a relationship between two components situated in within these views. By using the + * `ng-animate-ref` attribute we can identify that the two components are paired together and we + * can then attach an animation, which is triggered when the view changes. + * + * Say for example we have the following template code: + * + * ```html + * + *
+ *
+ * + * + * + * + * + * + * + * + * ``` + * + * Now, when the view changes (once the link is clicked), ngAnimate will examine the + * HTML contents to see if there is a match reference between any components in the view + * that is leaving and the view that is entering. It will scan both the view which is being + * removed (leave) and inserted (enter) to see if there are any paired DOM elements that + * contain a matching ref value. + * + * The two images match since they share the same ref value. ngAnimate will now create a + * transport element (which is a clone of the first image element) and it will then attempt + * to animate to the position of the second image element in the next view. For the animation to + * work a special CSS class called `ng-anchor` will be added to the transported element. + * + * We can now attach a transition onto the `.banner.ng-anchor` CSS class and then + * ngAnimate will handle the entire transition for us as well as the addition and removal of + * any changes of CSS classes between the elements: + * + * ```css + * .banner.ng-anchor { + * /* this animation will last for 1 second since there are + * two phases to the animation (an `in` and an `out` phase) */ + * transition:0.5s linear all; + * } + * ``` + * + * We also **must** include animations for the views that are being entered and removed + * (otherwise anchoring wouldn't be possible since the new view would be inserted right away). + * + * ```css + * .view-animation.ng-enter, .view-animation.ng-leave { + * transition:0.5s linear all; + * position:fixed; + * left:0; + * top:0; + * width:100%; + * } + * .view-animation.ng-enter { + * transform:translateX(100%); + * } + * .view-animation.ng-leave, + * .view-animation.ng-enter.ng-enter-active { + * transform:translateX(0%); + * } + * .view-animation.ng-leave.ng-leave-active { + * transform:translateX(-100%); + * } + * ``` + * + * Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur: + * an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away + * from its origin. Once that animation is over then the `in` stage occurs which animates the + * element to its destination. The reason why there are two animations is to give enough time + * for the enter animation on the new element to be ready. + * + * The example above sets up a transition for both the in and out phases, but we can also target the out or + * in phases directly via `ng-anchor-out` and `ng-anchor-in`. + * + * ```css + * .banner.ng-anchor-out { + * transition: 0.5s linear all; + * + * /* the scale will be applied during the out animation, + * but will be animated away when the in animation runs */ + * transform: scale(1.2); + * } + * + * .banner.ng-anchor-in { + * transition: 1s linear all; + * } + * ``` + * + * + * + * + * ### Anchoring Demo + * + + + Home +
+
+
+
+
+ + angular.module('anchoringExample', ['ngAnimate', 'ngRoute']) + .config(['$routeProvider', function($routeProvider) { + $routeProvider.when('/', { + templateUrl: 'home.html', + controller: 'HomeController as home' + }); + $routeProvider.when('/profile/:id', { + templateUrl: 'profile.html', + controller: 'ProfileController as profile' + }); + }]) + .run(['$rootScope', function($rootScope) { + $rootScope.records = [ + { id: 1, title: 'Miss Beulah Roob' }, + { id: 2, title: 'Trent Morissette' }, + { id: 3, title: 'Miss Ava Pouros' }, + { id: 4, title: 'Rod Pouros' }, + { id: 5, title: 'Abdul Rice' }, + { id: 6, title: 'Laurie Rutherford Sr.' }, + { id: 7, title: 'Nakia McLaughlin' }, + { id: 8, title: 'Jordon Blanda DVM' }, + { id: 9, title: 'Rhoda Hand' }, + { id: 10, title: 'Alexandrea Sauer' } + ]; + }]) + .controller('HomeController', [function() { + //empty + }]) + .controller('ProfileController', ['$rootScope', '$routeParams', + function ProfileController($rootScope, $routeParams) { + var index = parseInt($routeParams.id, 10); + var record = $rootScope.records[index - 1]; + + this.title = record.title; + this.id = record.id; + }]); + + +

Welcome to the home page

+

Please click on an element

+ + {{ record.title }} + +
+ +
+ {{ profile.title }} +
+
+ + .record { + display:block; + font-size:20px; + } + .profile { + background:black; + color:white; + font-size:100px; + } + .view-container { + position:relative; + } + .view-container > .view.ng-animate { + position:absolute; + top:0; + left:0; + width:100%; + min-height:500px; + } + .view.ng-enter, .view.ng-leave, + .record.ng-anchor { + transition:0.5s linear all; + } + .view.ng-enter { + transform:translateX(100%); + } + .view.ng-enter.ng-enter-active, .view.ng-leave { + transform:translateX(0%); + } + .view.ng-leave.ng-leave-active { + transform:translateX(-100%); + } + .record.ng-anchor-out { + background:red; + } + +
+ * + * ### How is the element transported? + * + * When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting + * element is located on screen via absolute positioning. The cloned element will be placed inside of the root element + * of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The + * element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match + * the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied + * to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class + * is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element + * will become visible since the shim class will be removed. + * + * ### How is the morphing handled? + * + * CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out + * what CSS classes differ between the starting element and the destination element. These different CSS classes + * will be added/removed on the anchor element and a transition will be applied (the transition that is provided + * in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will + * make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that + * do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since + * the cloned element is placed inside of root element which is likely close to the body element). + * + * Note that if the root element is on the `` element then the cloned node will be placed inside of body. + * + * + * ## Using $animate in your directive code + * + * So far we've explored how to feed in animations into an AngularJS application, but how do we trigger animations within our own directives in our application? + * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's + * imagine we have a greeting box that shows and hides itself when the data changes + * + * ```html + * Hi there + * ``` + * + * ```js + * ngModule.directive('greetingBox', ['$animate', function($animate) { + * return function(scope, element, attrs) { + * attrs.$observe('active', function(value) { + * value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on'); + * }); + * }); + * }]); + * ``` + * + * Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element + * in our HTML code then we can trigger a CSS or JS animation to happen. + * + * ```css + * /* normally we would create a CSS class to reference on the element */ + * greeting-box.on { transition:0.5s linear all; background:green; color:white; } + * ``` + * + * The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's + * possible be sure to visit the {@link ng.$animate $animate service API page}. + * + * + * ## Callbacks and Promises + * + * When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger + * an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has + * ended by chaining onto the returned promise that animation method returns. + * + * ```js + * // somewhere within the depths of the directive + * $animate.enter(element, parent).then(function() { + * //the animation has completed + * }); + * ``` + * + * (Note that earlier versions of AngularJS prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case + * anymore.) + * + * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering + * an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view + * routing controller to hook into that: + * + * ```js + * ngModule.controller('HomePageController', ['$animate', function($animate) { + * $animate.on('enter', ngViewElement, function(element) { + * // the animation for this route has completed + * }]); + * }]) + * ``` + * + * (Note that you will need to trigger a digest within the callback to get AngularJS to notice any scope-related changes.) + */ + +var copy; +var extend; +var forEach; +var isArray; +var isDefined; +var isElement; +var isFunction; +var isObject; +var isString; +var isUndefined; +var jqLite; +var noop; + +/** + * @ngdoc service + * @name $animate + * @kind object + * + * @description + * The ngAnimate `$animate` service documentation is the same for the core `$animate` service. + * + * Click here {@link ng.$animate to learn more about animations with `$animate`}. + */ +angular.module('ngAnimate', [], function initAngularHelpers() { + // Access helpers from AngularJS core. + // Do it inside a `config` block to ensure `window.angular` is available. + noop = angular.noop; + copy = angular.copy; + extend = angular.extend; + jqLite = angular.element; + forEach = angular.forEach; + isArray = angular.isArray; + isString = angular.isString; + isObject = angular.isObject; + isUndefined = angular.isUndefined; + isDefined = angular.isDefined; + isFunction = angular.isFunction; + isElement = angular.isElement; +}) + .info({ angularVersion: '1.8.4-local+sha.d8f77817e' }) + .directive('ngAnimateSwap', ngAnimateSwapDirective) + + .directive('ngAnimateChildren', $$AnimateChildrenDirective) + .factory('$$rAFScheduler', $$rAFSchedulerFactory) + + .provider('$$animateQueue', $$AnimateQueueProvider) + .provider('$$animateCache', $$AnimateCacheProvider) + .provider('$$animation', $$AnimationProvider) + + .provider('$animateCss', $AnimateCssProvider) + .provider('$$animateCssDriver', $$AnimateCssDriverProvider) + + .provider('$$animateJs', $$AnimateJsProvider) + .provider('$$animateJsDriver', $$AnimateJsDriverProvider); + + +})(window, window.angular); + +/* global shallowCopy: true */ + +/** + * Creates a shallow copy of an object, an array or a primitive. + * + * Assumes that there are no proto properties for objects. + */ +function shallowCopy(src, dst) { + if (isArray(src)) { + dst = dst || []; + + for (var i = 0, ii = src.length; i < ii; i++) { + dst[i] = src[i]; + } + } else if (isObject(src)) { + dst = dst || {}; + + for (var key in src) { + if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { + dst[key] = src[key]; + } + } + } + + return dst || src; +} + +/* global routeToRegExp: true */ + +/** + * @param {string} path - The path to parse. (It is assumed to have query and hash stripped off.) + * @param {Object} opts - Options. + * @return {Object} - An object containing an array of path parameter names (`keys`) and a regular + * expression (`regexp`) that can be used to identify a matching URL and extract the path + * parameter values. + * + * @description + * Parses the given path, extracting path parameter names and a regular expression to match URLs. + * + * Originally inspired by `pathRexp` in `visionmedia/express/lib/utils.js`. + */ +function routeToRegExp(path, opts) { + var keys = []; + + var pattern = path + .replace(/([().])/g, '\\$1') + .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) { + var optional = option === '?' || option === '*?'; + var star = option === '*' || option === '*?'; + keys.push({name: key, optional: optional}); + slash = slash || ''; + return ( + (optional ? '(?:' + slash : slash + '(?:') + + (star ? '(.+?)' : '([^/]+)') + + (optional ? '?)?' : ')') + ); + }) + .replace(/([/$*])/g, '\\$1'); + + if (opts.ignoreTrailingSlashes) { + pattern = pattern.replace(/\/+$/, '') + '/*'; + } + + return { + keys: keys, + regexp: new RegExp( + '^' + pattern + '(?:[?#]|$)', + opts.caseInsensitiveMatch ? 'i' : '' + ) + }; +} + +/* global routeToRegExp: false */ +/* global shallowCopy: false */ + +// `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`). +// They are initialized inside the `$RouteProvider`, to ensure `window.angular` is available. +var isArray; +var isObject; +var isDefined; +var noop; + +/** + * @ngdoc module + * @name ngRoute + * @description + * + * The `ngRoute` module provides routing and deeplinking services and directives for AngularJS apps. + * + * ## Example + * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`. + * + */ +/* global -ngRouteModule */ +var ngRouteModule = angular. + module('ngRoute', []). + info({ angularVersion: '1.8.4-local+sha.d8f77817e' }). + provider('$route', $RouteProvider). + // Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess` + // event (unless explicitly disabled). This is necessary in case `ngView` is included in an + // asynchronously loaded template. + run(instantiateRoute); +var $routeMinErr = angular.$$minErr('ngRoute'); +var isEagerInstantiationEnabled; + + +/** + * @ngdoc provider + * @name $routeProvider + * @this + * + * @description + * + * Used for configuring routes. + * + * ## Example + * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`. + * + * ## Dependencies + * Requires the {@link ngRoute `ngRoute`} module to be installed. + */ +function $RouteProvider() { + isArray = angular.isArray; + isObject = angular.isObject; + isDefined = angular.isDefined; + noop = angular.noop; + + function inherit(parent, extra) { + return angular.extend(Object.create(parent), extra); + } + + var routes = {}; + + /** + * @ngdoc method + * @name $routeProvider#when + * + * @param {string} path Route path (matched against `$location.path`). If `$location.path` + * contains redundant trailing slash or is missing one, the route will still match and the + * `$location.path` will be updated to add or drop the trailing slash to exactly match the + * route definition. + * + * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up + * to the next slash are matched and stored in `$routeParams` under the given `name` + * when the route matches. + * * `path` can contain named groups starting with a colon and ending with a star: + * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name` + * when the route matches. + * * `path` can contain optional named groups with a question mark: e.g.`:name?`. + * + * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match + * `/color/brown/largecode/code/with/slashes/edit` and extract: + * + * * `color: brown` + * * `largecode: code/with/slashes`. + * + * + * @param {Object} route Mapping information to be assigned to `$route.current` on route + * match. + * + * Object properties: + * + * - `controller` – `{(string|Function)=}` – Controller fn that should be associated with + * newly created scope or the name of a {@link angular.Module#controller registered + * controller} if passed as a string. + * - `controllerAs` – `{string=}` – An identifier name for a reference to the controller. + * If present, the controller will be published to scope under the `controllerAs` name. + * - `template` – `{(string|Function)=}` – html template as a string or a function that + * returns an html template as a string which should be used by {@link + * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives. + * This property takes precedence over `templateUrl`. + * + * If `template` is a function, it will be called with the following parameters: + * + * - `{Array.}` - route parameters extracted from the current + * `$location.path()` by applying the current route + * + * One of `template` or `templateUrl` is required. + * + * - `templateUrl` – `{(string|Function)=}` – path or function that returns a path to an html + * template that should be used by {@link ngRoute.directive:ngView ngView}. + * + * If `templateUrl` is a function, it will be called with the following parameters: + * + * - `{Array.}` - route parameters extracted from the current + * `$location.path()` by applying the current route + * + * One of `templateUrl` or `template` is required. + * + * - `resolve` - `{Object.=}` - An optional map of dependencies which should + * be injected into the controller. If any of these dependencies are promises, the router + * will wait for them all to be resolved or one to be rejected before the controller is + * instantiated. + * If all the promises are resolved successfully, the values of the resolved promises are + * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is + * fired. If any of the promises are rejected the + * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. + * For easier access to the resolved dependencies from the template, the `resolve` map will + * be available on the scope of the route, under `$resolve` (by default) or a custom name + * specified by the `resolveAs` property (see below). This can be particularly useful, when + * working with {@link angular.Module#component components} as route templates.
+ *
+ * **Note:** If your scope already contains a property with this name, it will be hidden + * or overwritten. Make sure, you specify an appropriate name for this property, that + * does not collide with other properties on the scope. + *
+ * The map object is: + * + * - `key` – `{string}`: a name of a dependency to be injected into the controller. + * - `factory` - `{string|Function}`: If `string` then it is an alias for a service. + * Otherwise if function, then it is {@link auto.$injector#invoke injected} + * and the return value is treated as the dependency. If the result is a promise, it is + * resolved before its value is injected into the controller. Be aware that + * `ngRoute.$routeParams` will still refer to the previous route within these resolve + * functions. Use `$route.current.params` to access the new route parameters, instead. + * + * - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on + * the scope of the route. If omitted, defaults to `$resolve`. + * + * - `redirectTo` – `{(string|Function)=}` – value to update + * {@link ng.$location $location} path with and trigger route redirection. + * + * If `redirectTo` is a function, it will be called with the following parameters: + * + * - `{Object.}` - route parameters extracted from the current + * `$location.path()` by applying the current route templateUrl. + * - `{string}` - current `$location.path()` + * - `{Object}` - current `$location.search()` + * + * The custom `redirectTo` function is expected to return a string which will be used + * to update `$location.url()`. If the function throws an error, no further processing will + * take place and the {@link ngRoute.$route#$routeChangeError $routeChangeError} event will + * be fired. + * + * Routes that specify `redirectTo` will not have their controllers, template functions + * or resolves called, the `$location` will be changed to the redirect url and route + * processing will stop. The exception to this is if the `redirectTo` is a function that + * returns `undefined`. In this case the route transition occurs as though there was no + * redirection. + * + * - `resolveRedirectTo` – `{Function=}` – a function that will (eventually) return the value + * to update {@link ng.$location $location} URL with and trigger route redirection. In + * contrast to `redirectTo`, dependencies can be injected into `resolveRedirectTo` and the + * return value can be either a string or a promise that will be resolved to a string. + * + * Similar to `redirectTo`, if the return value is `undefined` (or a promise that gets + * resolved to `undefined`), no redirection takes place and the route transition occurs as + * though there was no redirection. + * + * If the function throws an error or the returned promise gets rejected, no further + * processing will take place and the + * {@link ngRoute.$route#$routeChangeError $routeChangeError} event will be fired. + * + * `redirectTo` takes precedence over `resolveRedirectTo`, so specifying both on the same + * route definition, will cause the latter to be ignored. + * + * - `[reloadOnUrl=true]` - `{boolean=}` - reload route when any part of the URL changes + * (including the path) even if the new URL maps to the same route. + * + * If the option is set to `false` and the URL in the browser changes, but the new URL maps + * to the same route, then a `$routeUpdate` event is broadcasted on the root scope (without + * reloading the route). + * + * - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()` + * or `$location.hash()` changes. + * + * If the option is set to `false` and the URL in the browser changes, then a `$routeUpdate` + * event is broadcasted on the root scope (without reloading the route). + * + *
+ * **Note:** This option has no effect if `reloadOnUrl` is set to `false`. + *
+ * + * - `[caseInsensitiveMatch=false]` - `{boolean=}` - match routes without being case sensitive + * + * If the option is set to `true`, then the particular route can be matched without being + * case sensitive + * + * @returns {Object} self + * + * @description + * Adds a new route definition to the `$route` service. + */ + this.when = function(path, route) { + //copy original route object to preserve params inherited from proto chain + var routeCopy = shallowCopy(route); + if (angular.isUndefined(routeCopy.reloadOnUrl)) { + routeCopy.reloadOnUrl = true; + } + if (angular.isUndefined(routeCopy.reloadOnSearch)) { + routeCopy.reloadOnSearch = true; + } + if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) { + routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch; + } + routes[path] = angular.extend( + routeCopy, + {originalPath: path}, + path && routeToRegExp(path, routeCopy) + ); + + // create redirection for trailing slashes + if (path) { + var redirectPath = (path[path.length - 1] === '/') + ? path.substr(0, path.length - 1) + : path + '/'; + + routes[redirectPath] = angular.extend( + {originalPath: path, redirectTo: path}, + routeToRegExp(redirectPath, routeCopy) + ); + } + + return this; + }; + + /** + * @ngdoc property + * @name $routeProvider#caseInsensitiveMatch + * @description + * + * A boolean property indicating if routes defined + * using this provider should be matched using a case insensitive + * algorithm. Defaults to `false`. + */ + this.caseInsensitiveMatch = false; + + /** + * @ngdoc method + * @name $routeProvider#otherwise + * + * @description + * Sets route definition that will be used on route change when no other route definition + * is matched. + * + * @param {Object|string} params Mapping information to be assigned to `$route.current`. + * If called with a string, the value maps to `redirectTo`. + * @returns {Object} self + */ + this.otherwise = function(params) { + if (typeof params === 'string') { + params = {redirectTo: params}; + } + this.when(null, params); + return this; + }; + + /** + * @ngdoc method + * @name $routeProvider#eagerInstantiationEnabled + * @kind function + * + * @description + * Call this method as a setter to enable/disable eager instantiation of the + * {@link ngRoute.$route $route} service upon application bootstrap. You can also call it as a + * getter (i.e. without any arguments) to get the current value of the + * `eagerInstantiationEnabled` flag. + * + * Instantiating `$route` early is necessary for capturing the initial + * {@link ng.$location#$locationChangeStart $locationChangeStart} event and navigating to the + * appropriate route. Usually, `$route` is instantiated in time by the + * {@link ngRoute.ngView ngView} directive. Yet, in cases where `ngView` is included in an + * asynchronously loaded template (e.g. in another directive's template), the directive factory + * might not be called soon enough for `$route` to be instantiated _before_ the initial + * `$locationChangeSuccess` event is fired. Eager instantiation ensures that `$route` is always + * instantiated in time, regardless of when `ngView` will be loaded. + * + * The default value is true. + * + * **Note**:
+ * You may want to disable the default behavior when unit-testing modules that depend on + * `ngRoute`, in order to avoid an unexpected request for the default route's template. + * + * @param {boolean=} enabled - If provided, update the internal `eagerInstantiationEnabled` flag. + * + * @returns {*} The current value of the `eagerInstantiationEnabled` flag if used as a getter or + * itself (for chaining) if used as a setter. + */ + isEagerInstantiationEnabled = true; + this.eagerInstantiationEnabled = function eagerInstantiationEnabled(enabled) { + if (isDefined(enabled)) { + isEagerInstantiationEnabled = enabled; + return this; + } + + return isEagerInstantiationEnabled; + }; + + + this.$get = ['$rootScope', + '$location', + '$routeParams', + '$q', + '$injector', + '$templateRequest', + '$sce', + '$browser', + function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) { + + /** + * @ngdoc service + * @name $route + * @requires $location + * @requires $routeParams + * + * @property {Object} current Reference to the current route definition. + * The route definition contains: + * + * - `controller`: The controller constructor as defined in the route definition. + * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for + * controller instantiation. The `locals` contain + * the resolved values of the `resolve` map. Additionally the `locals` also contain: + * + * - `$scope` - The current route scope. + * - `$template` - The current route template HTML. + * + * The `locals` will be assigned to the route scope's `$resolve` property. You can override + * the property name, using `resolveAs` in the route definition. See + * {@link ngRoute.$routeProvider $routeProvider} for more info. + * + * @property {Object} routes Object with all route configuration Objects as its properties. + * + * @description + * `$route` is used for deep-linking URLs to controllers and views (HTML partials). + * It watches `$location.url()` and tries to map the path to an existing route definition. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API. + * + * The `$route` service is typically used in conjunction with the + * {@link ngRoute.directive:ngView `ngView`} directive and the + * {@link ngRoute.$routeParams `$routeParams`} service. + * + * @example + * This example shows how changing the URL hash causes the `$route` to match a route against the + * URL, and the `ngView` pulls in the partial. + * + * + * + *
+ * Choose: + * Moby | + * Moby: Ch1 | + * Gatsby | + * Gatsby: Ch4 | + * Scarlet Letter
+ * + *
+ * + *
+ * + *
$location.path() = {{$location.path()}}
+ *
$route.current.templateUrl = {{$route.current.templateUrl}}
+ *
$route.current.params = {{$route.current.params}}
+ *
$route.current.scope.name = {{$route.current.scope.name}}
+ *
$routeParams = {{$routeParams}}
+ *
+ *
+ * + * + * controller: {{name}}
+ * Book Id: {{params.bookId}}
+ *
+ * + * + * controller: {{name}}
+ * Book Id: {{params.bookId}}
+ * Chapter Id: {{params.chapterId}} + *
+ * + * + * angular.module('ngRouteExample', ['ngRoute']) + * + * .controller('MainController', function($scope, $route, $routeParams, $location) { + * $scope.$route = $route; + * $scope.$location = $location; + * $scope.$routeParams = $routeParams; + * }) + * + * .controller('BookController', function($scope, $routeParams) { + * $scope.name = 'BookController'; + * $scope.params = $routeParams; + * }) + * + * .controller('ChapterController', function($scope, $routeParams) { + * $scope.name = 'ChapterController'; + * $scope.params = $routeParams; + * }) + * + * .config(function($routeProvider, $locationProvider) { + * $routeProvider + * .when('/Book/:bookId', { + * templateUrl: 'book.html', + * controller: 'BookController', + * resolve: { + * // I will cause a 1 second delay + * delay: function($q, $timeout) { + * var delay = $q.defer(); + * $timeout(delay.resolve, 1000); + * return delay.promise; + * } + * } + * }) + * .when('/Book/:bookId/ch/:chapterId', { + * templateUrl: 'chapter.html', + * controller: 'ChapterController' + * }); + * + * // configure html5 to get links working on jsfiddle + * $locationProvider.html5Mode(true); + * }); + * + * + * + * + * it('should load and compile correct template', function() { + * element(by.linkText('Moby: Ch1')).click(); + * var content = element(by.css('[ng-view]')).getText(); + * expect(content).toMatch(/controller: ChapterController/); + * expect(content).toMatch(/Book Id: Moby/); + * expect(content).toMatch(/Chapter Id: 1/); + * + * element(by.partialLinkText('Scarlet')).click(); + * + * content = element(by.css('[ng-view]')).getText(); + * expect(content).toMatch(/controller: BookController/); + * expect(content).toMatch(/Book Id: Scarlet/); + * }); + * + *
+ */ + + /** + * @ngdoc event + * @name $route#$routeChangeStart + * @eventType broadcast on root scope + * @description + * Broadcasted before a route change. At this point the route services starts + * resolving all of the dependencies needed for the route change to occur. + * Typically this involves fetching the view template as well as any dependencies + * defined in `resolve` route property. Once all of the dependencies are resolved + * `$routeChangeSuccess` is fired. + * + * The route change (and the `$location` change that triggered it) can be prevented + * by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} + * for more details about event object. + * + * @param {Object} angularEvent Synthetic event object. + * @param {Route} next Future route information. + * @param {Route} current Current route information. + */ + + /** + * @ngdoc event + * @name $route#$routeChangeSuccess + * @eventType broadcast on root scope + * @description + * Broadcasted after a route change has happened successfully. + * The `resolve` dependencies are now available in the `current.locals` property. + * + * {@link ngRoute.directive:ngView ngView} listens for the directive + * to instantiate the controller and render the view. + * + * @param {Object} angularEvent Synthetic event object. + * @param {Route} current Current route information. + * @param {Route|Undefined} previous Previous route information, or undefined if current is + * first route entered. + */ + + /** + * @ngdoc event + * @name $route#$routeChangeError + * @eventType broadcast on root scope + * @description + * Broadcasted if a redirection function fails or any redirection or resolve promises are + * rejected. + * + * @param {Object} angularEvent Synthetic event object + * @param {Route} current Current route information. + * @param {Route} previous Previous route information. + * @param {Route} rejection The thrown error or the rejection reason of the promise. Usually + * the rejection reason is the error that caused the promise to get rejected. + */ + + /** + * @ngdoc event + * @name $route#$routeUpdate + * @eventType broadcast on root scope + * @description + * Broadcasted if the same instance of a route (including template, controller instance, + * resolved dependencies, etc.) is being reused. This can happen if either `reloadOnSearch` or + * `reloadOnUrl` has been set to `false`. + * + * @param {Object} angularEvent Synthetic event object + * @param {Route} current Current/previous route information. + */ + + var forceReload = false, + preparedRoute, + preparedRouteIsUpdateOnly, + $route = { + routes: routes, + + /** + * @ngdoc method + * @name $route#reload + * + * @description + * Causes `$route` service to reload the current route even if + * {@link ng.$location $location} hasn't changed. + * + * As a result of that, {@link ngRoute.directive:ngView ngView} + * creates new scope and reinstantiates the controller. + */ + reload: function() { + forceReload = true; + + var fakeLocationEvent = { + defaultPrevented: false, + preventDefault: function fakePreventDefault() { + this.defaultPrevented = true; + forceReload = false; + } + }; + + $rootScope.$evalAsync(function() { + prepareRoute(fakeLocationEvent); + if (!fakeLocationEvent.defaultPrevented) commitRoute(); + }); + }, + + /** + * @ngdoc method + * @name $route#updateParams + * + * @description + * Causes `$route` service to update the current URL, replacing + * current route parameters with those specified in `newParams`. + * Provided property names that match the route's path segment + * definitions will be interpolated into the location's path, while + * remaining properties will be treated as query params. + * + * @param {!Object} newParams mapping of URL parameter names to values + */ + updateParams: function(newParams) { + if (this.current && this.current.$$route) { + newParams = angular.extend({}, this.current.params, newParams); + $location.path(interpolate(this.current.$$route.originalPath, newParams)); + // interpolate modifies newParams, only query params are left + $location.search(newParams); + } else { + throw $routeMinErr('norout', 'Tried updating route with no current route'); + } + } + }; + + $rootScope.$on('$locationChangeStart', prepareRoute); + $rootScope.$on('$locationChangeSuccess', commitRoute); + + return $route; + + ///////////////////////////////////////////////////// + + /** + * @param on {string} current url + * @param route {Object} route regexp to match the url against + * @return {?Object} + * + * @description + * Check if the route matches the current url. + * + * Inspired by match in + * visionmedia/express/lib/router/router.js. + */ + function switchRouteMatcher(on, route) { + var keys = route.keys, + params = {}; + + if (!route.regexp) return null; + + var m = route.regexp.exec(on); + if (!m) return null; + + for (var i = 1, len = m.length; i < len; ++i) { + var key = keys[i - 1]; + + var val = m[i]; + + if (key && val) { + params[key.name] = val; + } + } + return params; + } + + function prepareRoute($locationEvent) { + var lastRoute = $route.current; + + preparedRoute = parseRoute(); + preparedRouteIsUpdateOnly = isNavigationUpdateOnly(preparedRoute, lastRoute); + + if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) { + if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) { + if ($locationEvent) { + $locationEvent.preventDefault(); + } + } + } + } + + function commitRoute() { + var lastRoute = $route.current; + var nextRoute = preparedRoute; + + if (preparedRouteIsUpdateOnly) { + lastRoute.params = nextRoute.params; + angular.copy(lastRoute.params, $routeParams); + $rootScope.$broadcast('$routeUpdate', lastRoute); + } else if (nextRoute || lastRoute) { + forceReload = false; + $route.current = nextRoute; + + var nextRoutePromise = $q.resolve(nextRoute); + + $browser.$$incOutstandingRequestCount('$route'); + + nextRoutePromise. + then(getRedirectionData). + then(handlePossibleRedirection). + then(function(keepProcessingRoute) { + return keepProcessingRoute && nextRoutePromise. + then(resolveLocals). + then(function(locals) { + // after route change + if (nextRoute === $route.current) { + if (nextRoute) { + nextRoute.locals = locals; + angular.copy(nextRoute.params, $routeParams); + } + $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute); + } + }); + }).catch(function(error) { + if (nextRoute === $route.current) { + $rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error); + } + }).finally(function() { + // Because `commitRoute()` is called from a `$rootScope.$evalAsync` block (see + // `$locationWatch`), this `$$completeOutstandingRequest()` call will not cause + // `outstandingRequestCount` to hit zero. This is important in case we are redirecting + // to a new route which also requires some asynchronous work. + + $browser.$$completeOutstandingRequest(noop, '$route'); + }); + } + } + + function getRedirectionData(route) { + var data = { + route: route, + hasRedirection: false + }; + + if (route) { + if (route.redirectTo) { + if (angular.isString(route.redirectTo)) { + data.path = interpolate(route.redirectTo, route.params); + data.search = route.params; + data.hasRedirection = true; + } else { + var oldPath = $location.path(); + var oldSearch = $location.search(); + var newUrl = route.redirectTo(route.pathParams, oldPath, oldSearch); + + if (angular.isDefined(newUrl)) { + data.url = newUrl; + data.hasRedirection = true; + } + } + } else if (route.resolveRedirectTo) { + return $q. + resolve($injector.invoke(route.resolveRedirectTo)). + then(function(newUrl) { + if (angular.isDefined(newUrl)) { + data.url = newUrl; + data.hasRedirection = true; + } + + return data; + }); + } + } + + return data; + } + + function handlePossibleRedirection(data) { + var keepProcessingRoute = true; + + if (data.route !== $route.current) { + keepProcessingRoute = false; + } else if (data.hasRedirection) { + var oldUrl = $location.url(); + var newUrl = data.url; + + if (newUrl) { + $location. + url(https://github.com/newUrl). + replace(); + } else { + newUrl = $location. + path(data.path). + search(data.search). + replace(). + url(); + } + + if (newUrl !== oldUrl) { + // Exit out and don't process current next value, + // wait for next location change from redirect + keepProcessingRoute = false; + } + } + + return keepProcessingRoute; + } + + function resolveLocals(route) { + if (route) { + var locals = angular.extend({}, route.resolve); + angular.forEach(locals, function(value, key) { + locals[key] = angular.isString(value) ? + $injector.get(value) : + $injector.invoke(value, null, null, key); + }); + var template = getTemplateFor(route); + if (angular.isDefined(template)) { + locals['$template'] = template; + } + return $q.all(locals); + } + } + + function getTemplateFor(route) { + var template, templateUrl; + if (angular.isDefined(template = route.template)) { + if (angular.isFunction(template)) { + template = template(route.params); + } + } else if (angular.isDefined(templateUrl = route.templateUrl)) { + if (angular.isFunction(templateUrl)) { + templateUrl = templateUrl(route.params); + } + if (angular.isDefined(templateUrl)) { + route.loadedTemplateUrl = $sce.valueOf(templateUrl); + template = $templateRequest(templateUrl); + } + } + return template; + } + + /** + * @returns {Object} the current active route, by matching it against the URL + */ + function parseRoute() { + // Match a route + var params, match; + angular.forEach(routes, function(route, path) { + if (!match && (params = switchRouteMatcher($location.path(), route))) { + match = inherit(route, { + params: angular.extend({}, $location.search(), params), + pathParams: params}); + match.$$route = route; + } + }); + // No route matched; fallback to "otherwise" route + return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); + } + + /** + * @param {Object} newRoute - The new route configuration (as returned by `parseRoute()`). + * @param {Object} oldRoute - The previous route configuration (as returned by `parseRoute()`). + * @returns {boolean} Whether this is an "update-only" navigation, i.e. the URL maps to the same + * route and it can be reused (based on the config and the type of change). + */ + function isNavigationUpdateOnly(newRoute, oldRoute) { + // IF this is not a forced reload + return !forceReload + // AND both `newRoute`/`oldRoute` are defined + && newRoute && oldRoute + // AND they map to the same Route Definition Object + && (newRoute.$$route === oldRoute.$$route) + // AND `reloadOnUrl` is disabled + && (!newRoute.reloadOnUrl + // OR `reloadOnSearch` is disabled + || (!newRoute.reloadOnSearch + // AND both routes have the same path params + && angular.equals(newRoute.pathParams, oldRoute.pathParams) + ) + ); + } + + /** + * @returns {string} interpolation of the redirect path with the parameters + */ + function interpolate(string, params) { + var result = []; + angular.forEach((string || '').split(':'), function(segment, i) { + if (i === 0) { + result.push(segment); + } else { + var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/); + var key = segmentMatch[1]; + result.push(params[key]); + result.push(segmentMatch[2] || ''); + delete params[key]; + } + }); + return result.join(''); + } + }]; +} + +instantiateRoute.$inject = ['$injector']; +function instantiateRoute($injector) { + if (isEagerInstantiationEnabled) { + // Instantiate `$route` + $injector.get('$route'); + } +} + +ngRouteModule.provider('$routeParams', $RouteParamsProvider); + + +/** + * @ngdoc service + * @name $routeParams + * @requires $route + * @this + * + * @description + * The `$routeParams` service allows you to retrieve the current set of route parameters. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * The route parameters are a combination of {@link ng.$location `$location`}'s + * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}. + * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. + * + * In case of parameter name collision, `path` params take precedence over `search` params. + * + * The service guarantees that the identity of the `$routeParams` object will remain unchanged + * (but its properties will likely change) even when a route change occurs. + * + * Note that the `$routeParams` are only updated *after* a route change completes successfully. + * This means that you cannot rely on `$routeParams` being correct in route resolve functions. + * Instead you can use `$route.current.params` to access the new route's parameters. + * + * @example + * ```js + * // Given: + * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby + * // Route: /Chapter/:chapterId/Section/:sectionId + * // + * // Then + * $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'} + * ``` + */ +function $RouteParamsProvider() { + this.$get = function() { return {}; }; +} + +ngRouteModule.directive('ngView', ngViewFactory); +ngRouteModule.directive('ngView', ngViewFillContentFactory); + + +/** + * @ngdoc directive + * @name ngView + * @restrict ECA + * + * @description + * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by + * including the rendered template of the current route into the main layout (`index.html`) file. + * Every time the current route changes, the included view changes with it according to the + * configuration of the `$route` service. + * + * Requires the {@link ngRoute `ngRoute`} module to be installed. + * + * @animations + * | Animation | Occurs | + * |----------------------------------|-------------------------------------| + * | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM | + * | {@link ng.$animate#leave leave} | when the old element is removed from to the DOM | + * + * The enter and leave animation occur concurrently. + * + * @scope + * @priority 400 + * @param {string=} onload Expression to evaluate whenever the view updates. + * + * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll + * $anchorScroll} to scroll the viewport after the view is updated. + * + * - If the attribute is not set, disable scrolling. + * - If the attribute is set without value, enable scrolling. + * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated + * as an expression yields a truthy value. + * @example + + +
+ Choose: + Moby | + Moby: Ch1 | + Gatsby | + Gatsby: Ch4 | + Scarlet Letter
+ +
+
+
+
+ +
$location.path() = {{main.$location.path()}}
+
$route.current.templateUrl = {{main.$route.current.templateUrl}}
+
$route.current.params = {{main.$route.current.params}}
+
$routeParams = {{main.$routeParams}}
+
+
+ + +
+ controller: {{book.name}}
+ Book Id: {{book.params.bookId}}
+
+
+ + +
+ controller: {{chapter.name}}
+ Book Id: {{chapter.params.bookId}}
+ Chapter Id: {{chapter.params.chapterId}} +
+
+ + + .view-animate-container { + position:relative; + height:100px!important; + background:white; + border:1px solid black; + height:40px; + overflow:hidden; + } + + .view-animate { + padding:10px; + } + + .view-animate.ng-enter, .view-animate.ng-leave { + transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; + + display:block; + width:100%; + border-left:1px solid black; + + position:absolute; + top:0; + left:0; + right:0; + bottom:0; + padding:10px; + } + + .view-animate.ng-enter { + left:100%; + } + .view-animate.ng-enter.ng-enter-active { + left:0; + } + .view-animate.ng-leave.ng-leave-active { + left:-100%; + } + + + + angular.module('ngViewExample', ['ngRoute', 'ngAnimate']) + .config(['$routeProvider', '$locationProvider', + function($routeProvider, $locationProvider) { + $routeProvider + .when('/Book/:bookId', { + templateUrl: 'book.html', + controller: 'BookCtrl', + controllerAs: 'book' + }) + .when('/Book/:bookId/ch/:chapterId', { + templateUrl: 'chapter.html', + controller: 'ChapterCtrl', + controllerAs: 'chapter' + }); + + $locationProvider.html5Mode(true); + }]) + .controller('MainCtrl', ['$route', '$routeParams', '$location', + function MainCtrl($route, $routeParams, $location) { + this.$route = $route; + this.$location = $location; + this.$routeParams = $routeParams; + }]) + .controller('BookCtrl', ['$routeParams', function BookCtrl($routeParams) { + this.name = 'BookCtrl'; + this.params = $routeParams; + }]) + .controller('ChapterCtrl', ['$routeParams', function ChapterCtrl($routeParams) { + this.name = 'ChapterCtrl'; + this.params = $routeParams; + }]); + + + + + it('should load and compile correct template', function() { + element(by.linkText('Moby: Ch1')).click(); + var content = element(by.css('[ng-view]')).getText(); + expect(content).toMatch(/controller: ChapterCtrl/); + expect(content).toMatch(/Book Id: Moby/); + expect(content).toMatch(/Chapter Id: 1/); + + element(by.partialLinkText('Scarlet')).click(); + + content = element(by.css('[ng-view]')).getText(); + expect(content).toMatch(/controller: BookCtrl/); + expect(content).toMatch(/Book Id: Scarlet/); + }); + +
+ */ + + +/** + * @ngdoc event + * @name ngView#$viewContentLoaded + * @eventType emit on the current ngView scope + * @description + * Emitted every time the ngView content is reloaded. + */ +ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate']; +function ngViewFactory($route, $anchorScroll, $animate) { + return { + restrict: 'ECA', + terminal: true, + priority: 400, + transclude: 'element', + link: function(scope, $element, attr, ctrl, $transclude) { + var currentScope, + currentElement, + previousLeaveAnimation, + autoScrollExp = attr.autoscroll, + onloadExp = attr.onload || ''; + + scope.$on('$routeChangeSuccess', update); + update(); + + function cleanupLastView() { + if (previousLeaveAnimation) { + $animate.cancel(previousLeaveAnimation); + previousLeaveAnimation = null; + } + + if (currentScope) { + currentScope.$destroy(); + currentScope = null; + } + if (currentElement) { + previousLeaveAnimation = $animate.leave(currentElement); + previousLeaveAnimation.done(function(response) { + if (response !== false) previousLeaveAnimation = null; + }); + currentElement = null; + } + } + + function update() { + var locals = $route.current && $route.current.locals, + template = locals && locals.$template; + + if (angular.isDefined(template)) { + var newScope = scope.$new(); + var current = $route.current; + + // Note: This will also link all children of ng-view that were contained in the original + // html. If that content contains controllers, ... they could pollute/change the scope. + // However, using ng-view on an element with additional content does not make sense... + // Note: We can't remove them in the cloneAttchFn of $transclude as that + // function is called before linking the content, which would apply child + // directives to non existing elements. + var clone = $transclude(newScope, function(clone) { + $animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) { + if (response !== false && angular.isDefined(autoScrollExp) + && (!autoScrollExp || scope.$eval(autoScrollExp))) { + $anchorScroll(); + } + }); + cleanupLastView(); + }); + + currentElement = clone; + currentScope = current.scope = newScope; + currentScope.$emit('$viewContentLoaded'); + currentScope.$eval(onloadExp); + } else { + cleanupLastView(); + } + } + } + }; +} + +// This directive is called during the $transclude call of the first `ngView` directive. +// It will replace and compile the content of the element with the loaded template. +// We need this directive so that the element content is already filled when +// the link function of another directive on the same element as ngView +// is called. +ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route']; +function ngViewFillContentFactory($compile, $controller, $route) { + return { + restrict: 'ECA', + priority: -400, + link: function(scope, $element) { + var current = $route.current, + locals = current.locals; + + $element.html(locals.$template); + + var link = $compile($element.contents()); + + if (current.controller) { + locals.$scope = scope; + var controller = $controller(current.controller, locals); + if (current.controllerAs) { + scope[current.controllerAs] = controller; + } + $element.data('$ngControllerController', controller); + $element.children().data('$ngControllerController', controller); + } + scope[current.resolveAs || '$resolve'] = locals; + + link(scope); + } + }; +} + +describe('ngView', function() { + + describe('basics', function() { + var element; + + beforeEach(module('ngRoute')); + + beforeEach(module(function($provide) { + return function($rootScope, $compile, $animate) { + element = $compile('
')($rootScope); + }; + })); + + + afterEach(function() { + dealoc(element); + }); + + + it('should do nothing when no routes are defined', + inject(function($rootScope, $compile, $location) { + $location.path('/unknown'); + $rootScope.$digest(); + expect(element.text()).toEqual(''); + })); + + + it('should instantiate controller after compiling the content', function() { + var log = [], controllerScope, + Ctrl = function($scope) { + controllerScope = $scope; + log.push('ctrl-init'); + }; + + module(function($compileProvider, $routeProvider) { + $compileProvider.directive('compileLog', function() { + return { + compile: function() { + log.push('compile'); + } + }; + }); + + $routeProvider.when('/some', {templateUrl: '/tpl.html', controller: Ctrl}); + }); + + inject(function($route, $rootScope, $templateCache, $location) { + $templateCache.put('/tpl.html', [200, '
partial
', {}]); + $location.path('/some'); + $rootScope.$digest(); + + expect(controllerScope.$parent).toBe($rootScope); + expect(controllerScope).toBe($route.current.scope); + expect(log).toEqual(['compile', 'ctrl-init']); + }); + }); + + + it('should instantiate the associated controller when an empty template is downloaded', function() { + var log = [], controllerScope, + Ctrl = function($scope) { + controllerScope = $scope; + log.push('ctrl-init'); + }; + + module(function($routeProvider) { + $routeProvider.when('/some', {templateUrl: '/tpl.html', controller: Ctrl}); + }); + + inject(function($route, $rootScope, $templateCache, $location) { + $templateCache.put('/tpl.html', [200, '', {}]); + $location.path('/some'); + + expect(function() { + $rootScope.$digest(); + }).not.toThrow(); + + expect(controllerScope).toBeDefined(); + }); + }); + + + it('should instantiate controller with an alias', function() { + var log = [], controllerScope; + + function Ctrl($scope) { + this.name = 'alias'; + controllerScope = $scope; + } + + module(function($compileProvider, $routeProvider) { + $routeProvider.when('/some', {templateUrl: '/tpl.html', controller: Ctrl, controllerAs: 'ctrl'}); + }); + + inject(function($route, $rootScope, $templateCache, $location) { + $templateCache.put('/tpl.html', [200, '
', {}]); + $location.path('/some'); + $rootScope.$digest(); + + expect(controllerScope.ctrl.name).toBe('alias'); + }); + }); + + + it('should support string controller declaration', function() { + var MyCtrl = jasmine.createSpy('MyCtrl'); + + module(function($controllerProvider, $routeProvider) { + $controllerProvider.register('MyCtrl', ['$scope', MyCtrl]); + $routeProvider.when('/foo', {controller: 'MyCtrl', templateUrl: '/tpl.html'}); + }); + + inject(function($route, $location, $rootScope, $templateCache) { + $templateCache.put('/tpl.html', [200, '
', {}]); + $location.path('/foo'); + $rootScope.$digest(); + + expect($route.current.controller).toBe('MyCtrl'); + expect(MyCtrl).toHaveBeenCalledWith(element.children().scope()); + }); + }); + + + it('should reference resolved locals in scope', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', { + resolve: { + name: function() { + return 'shahar'; + } + }, + template: '
{{$resolve.name}}
' + }); + }); + + inject(function($location, $rootScope) { + $location.path('/foo'); + $rootScope.$digest(); + expect(element.text()).toEqual('shahar'); + }); + }); + + + it('should allow to provide an alias for resolved locals using resolveAs', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', { + resolveAs: 'myResolve', + resolve: { + name: function() { + return 'shahar'; + } + }, + template: '
{{myResolve.name}}
' + }); + }); + + inject(function($location, $rootScope) { + $location.path('/foo'); + $rootScope.$digest(); + expect(element.text()).toEqual('shahar'); + }); + }); + + + it('should load content via xhr when route changes', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'myUrl1'}); + $routeProvider.when('/bar', {templateUrl: 'myUrl2'}); + }); + + inject(function($rootScope, $compile, $httpBackend, $location, $route) { + expect(element.text()).toEqual(''); + + $location.path('/foo'); + $httpBackend.expect('GET', 'myUrl1').respond('
{{1+3}}
'); + $rootScope.$digest(); + $httpBackend.flush(); + expect(element.text()).toEqual('4'); + + $location.path('/bar'); + $httpBackend.expect('GET', 'myUrl2').respond('angular is da best'); + $rootScope.$digest(); + $httpBackend.flush(); + expect(element.text()).toEqual('angular is da best'); + }); + }); + + + it('should use inline content route changes', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {template: '
{{1+3}}
'}); + $routeProvider.when('/bar', {template: 'AngularJS is da best'}); + $routeProvider.when('/blank', {template: ''}); + }); + + inject(function($rootScope, $compile, $location, $route) { + expect(element.text()).toEqual(''); + + $location.path('/foo'); + $rootScope.$digest(); + expect(element.text()).toEqual('4'); + + $location.path('/bar'); + $rootScope.$digest(); + expect(element.text()).toEqual('AngularJS is da best'); + + $location.path('/blank'); + $rootScope.$digest(); + expect(element.text()).toEqual(''); + }); + }); + + + it('should remove all content when location changes to an unknown route', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'myUrl1'}); + }); + + inject(function($rootScope, $compile, $location, $httpBackend, $route) { + $location.path('/foo'); + $httpBackend.expect('GET', 'myUrl1').respond('
{{1+3}}
'); + $rootScope.$digest(); + $httpBackend.flush(); + expect(element.text()).toEqual('4'); + + $location.path('/unknown'); + $rootScope.$digest(); + expect(element.text()).toEqual(''); + }); + }); + + + it('should chain scopes and propagate evals to the child scope', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'myUrl1'}); + }); + + inject(function($rootScope, $compile, $location, $httpBackend, $route) { + $rootScope.parentVar = 'parent'; + + $location.path('/foo'); + $httpBackend.expect('GET', 'myUrl1').respond('
{{parentVar}}
'); + $rootScope.$digest(); + $httpBackend.flush(); + expect(element.text()).toEqual('parent'); + + $rootScope.parentVar = 'new parent'; + $rootScope.$digest(); + expect(element.text()).toEqual('new parent'); + }); + }); + + + it('should be possible to nest ngView in ngInclude', function() { + + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'viewPartial.html'}); + }); + + inject(function($httpBackend, $location, $route, $compile, $rootScope) { + $httpBackend.whenGET('includePartial.html').respond('view: '); + $httpBackend.whenGET('viewPartial.html').respond('content'); + $location.path('/foo'); + + var elm = $compile( + '
' + + 'include: ' + + '
')($rootScope); + $rootScope.$digest(); + $httpBackend.flush(); + + expect(elm.text()).toEqual('include: view: content'); + expect($route.current.templateUrl).toEqual('viewPartial.html'); + dealoc(elm); + }); + }); + + + it('should initialize view template after the view controller was initialized even when ' + + 'templates were cached', function() { + //this is a test for a regression that was introduced by making the ng-view cache sync + function ParentCtrl($scope) { + $scope.log.push('parent'); + } + + module(function($routeProvider) { + $routeProvider.when('/foo', {controller: ParentCtrl, templateUrl: 'viewPartial.html'}); + }); + + + inject(function($rootScope, $compile, $location, $httpBackend, $route) { + $rootScope.log = []; + + $rootScope.ChildCtrl = function($scope) { + $scope.log.push('child'); + }; + + $location.path('/foo'); + $httpBackend.expect('GET', 'viewPartial.html'). + respond('
' + + '
' + + '
'); + $rootScope.$apply(); + $httpBackend.flush(); + + expect($rootScope.log).toEqual(['parent', 'init', 'child']); + + $location.path('/'); + $rootScope.$apply(); + expect($rootScope.log).toEqual(['parent', 'init', 'child']); + + $rootScope.log = []; + $location.path('/foo'); + $rootScope.$apply(); + + expect($rootScope.log).toEqual(['parent', 'init', 'child']); + }); + }); + + + it('should discard pending xhr callbacks if a new route is requested before the current ' + + 'finished loading', function() { + // this is a test for a bad race condition that affected feedback + + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'myUrl1'}); + $routeProvider.when('/bar', {templateUrl: 'myUrl2'}); + }); + + inject(function($route, $rootScope, $location, $httpBackend) { + expect(element.text()).toEqual(''); + + $location.path('/foo'); + $httpBackend.expect('GET', 'myUrl1').respond('
{{1+3}}
'); + $rootScope.$digest(); + $location.path('/bar'); + $httpBackend.expect('GET', 'myUrl2').respond('
{{1+1}}
'); + $rootScope.$digest(); + $httpBackend.flush(); // now that we have two requests pending, flush! + + expect(element.text()).toEqual('2'); + }); + }); + + + it('should be async even if served from cache', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {controller: angular.noop, templateUrl: 'myUrl1'}); + }); + + inject(function($route, $rootScope, $location, $templateCache) { + $templateCache.put('myUrl1', [200, 'my partial', {}]); + $location.path('/foo'); + + var called = 0; + // we want to assert only during first watch + $rootScope.$watch(function() { + if (!called) expect(element.text()).toBe(''); + called++; + }); + + $rootScope.$digest(); + expect(element.text()).toBe('my partial'); + }); + }); + + it('should fire $contentLoaded event when content compiled and linked', function() { + var log = []; + var logger = function(name) { + return function() { + log.push(name); + }; + }; + var Ctrl = function($scope) { + $scope.value = 'bound-value'; + log.push('init-ctrl'); + }; + + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'tpl.html', controller: Ctrl}); + }); + + inject(function($templateCache, $rootScope, $location) { + $rootScope.$on('$routeChangeStart', logger('$routeChangeStart')); + $rootScope.$on('$routeChangeSuccess', logger('$routeChangeSuccess')); + $rootScope.$on('$viewContentLoaded', logger('$viewContentLoaded')); + + $templateCache.put('tpl.html', [200, '{{value}}', {}]); + $location.path('/foo'); + $rootScope.$digest(); + + expect(element.text()).toBe('bound-value'); + expect(log).toEqual([ + '$routeChangeStart', 'init-ctrl', '$viewContentLoaded', '$routeChangeSuccess' + ]); + }); + }); + + it('should destroy previous scope', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'tpl.html'}); + }); + + inject(function($templateCache, $rootScope, $location) { + $templateCache.put('tpl.html', [200, 'partial', {}]); + + expect($rootScope.$$childHead).toBeNull(); + expect($rootScope.$$childTail).toBeNull(); + + $location.path('/foo'); + $rootScope.$digest(); + + expect(element.text()).toBe('partial'); + expect($rootScope.$$childHead).not.toBeNull(); + expect($rootScope.$$childTail).not.toBeNull(); + + $location.path('/non/existing/route'); + $rootScope.$digest(); + + expect(element.text()).toBe(''); + expect($rootScope.$$childHead).toBeNull(); + expect($rootScope.$$childTail).toBeNull(); + }); + }); + + + it('should destroy previous scope if multiple route changes occur before server responds', + function() { + var log = []; + var createCtrl = function(name) { + return function($scope) { + log.push('init-' + name); + $scope.$on('$destroy', function() {log.push('destroy-' + name);}); + }; + }; + + module(function($routeProvider) { + $routeProvider.when('/one', {templateUrl: 'one.html', controller: createCtrl('ctrl1')}); + $routeProvider.when('/two', {templateUrl: 'two.html', controller: createCtrl('ctrl2')}); + }); + + inject(function($httpBackend, $rootScope, $location) { + $httpBackend.whenGET('one.html').respond('content 1'); + $httpBackend.whenGET('two.html').respond('content 2'); + + $location.path('/one'); + $rootScope.$digest(); + $location.path('/two'); + $rootScope.$digest(); + + $httpBackend.flush(); + expect(element.text()).toBe('content 2'); + expect(log).toEqual(['init-ctrl2']); + + $location.path('/non-existing'); + $rootScope.$digest(); + + expect(element.text()).toBe(''); + expect(log).toEqual(['init-ctrl2', 'destroy-ctrl2']); + + expect($rootScope.$$childHead).toBeNull(); + expect($rootScope.$$childTail).toBeNull(); + }); + }); + + + it('should $destroy scope after update and reload', function() { + // this is a regression of bug, where $route doesn't copy scope when only updating + + var log = []; + + function logger(msg) { + return function() { + log.push(msg); + }; + } + + function createController(name) { + return function($scope) { + log.push('init-' + name); + $scope.$on('$destroy', logger('destroy-' + name)); + $scope.$on('$routeUpdate', logger('route-update')); + }; + } + + module(function($routeProvider) { + $routeProvider.when('/bar', {templateUrl: 'tpl.html', controller: createController('bar')}); + $routeProvider.when('/foo', { + templateUrl: 'tpl.html', + controller: createController('foo'), + reloadOnSearch: false + }); + }); + + inject(function($templateCache, $location, $rootScope) { + $templateCache.put('tpl.html', [200, 'partial', {}]); + + $location.url('https://github.com/foo'); + $rootScope.$digest(); + expect(log).toEqual(['init-foo']); + + $location.search({q: 'some'}); + $rootScope.$digest(); + expect(log).toEqual(['init-foo', 'route-update']); + + $location.url('https://github.com/bar'); + $rootScope.$digest(); + expect(log).toEqual(['init-foo', 'route-update', 'destroy-foo', 'init-bar']); + }); + }); + + + it('should evaluate onload expression after linking the content', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'tpl.html'}); + }); + + inject(function($templateCache, $location, $rootScope) { + $templateCache.put('tpl.html', [200, '{{1+1}}', {}]); + $rootScope.load = jasmine.createSpy('onload'); + + $location.url('https://github.com/foo'); + $rootScope.$digest(); + expect($rootScope.load).toHaveBeenCalledOnce(); + }); + }); + + + it('should set $scope and $controllerController on the view elements (except for non-element nodes)', function() { + function MyCtrl($scope) { + $scope.state = 'WORKS'; + $scope.ctrl = this; + } + + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'tpl.html', controller: MyCtrl}); + }); + + inject(function($templateCache, $location, $rootScope, $route) { + // in the template the white-space before the div is an intentional non-element node, + // a text might get wrapped into span so it's safer to just use white space + $templateCache.put('tpl.html', [200, ' \n
{{state}}
', {}]); + + $location.url('https://github.com/foo'); + $rootScope.$digest(); + expect(element.text()).toEqual(' \n WORKS'); + + var div = element.find('div'); + expect(div.parent()[0].nodeName.toUpperCase()).toBeOneOf('NG:VIEW', 'VIEW'); + + expect(div.scope()).toBe($route.current.scope); + expect(div.scope().hasOwnProperty('state')).toBe(true); + expect(div.scope().state).toEqual('WORKS'); + + expect(div.controller()).toBe($route.current.scope.ctrl); + }); + }); + + it('should not set $scope or $controllerController on top level text elements in the view', function() { + function MyCtrl($scope) {} + + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'tpl.html', controller: MyCtrl}); + }); + + inject(function($templateCache, $location, $rootScope, $route) { + $templateCache.put('tpl.html', '
'); + $location.url('https://github.com/foo'); + $rootScope.$digest(); + + angular.forEach(element.contents(), function(node) { + if (node.nodeType === 3 /* text node */) { + expect(angular.element(node).scope()).not.toBe($route.current.scope); + expect(angular.element(node).controller()).not.toBeDefined(); + } else if (node.nodeType === 8 /* comment node */) { + expect(angular.element(node).scope()).toBe(element.scope()); + expect(angular.element(node).controller()).toBe(element.controller()); + } else { + expect(angular.element(node).scope()).toBe($route.current.scope); + expect(angular.element(node).controller()).toBeDefined(); + } + }); + }); + }); + + + it('should not trigger a digest when the view is changed', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'myUrl1'}); + $routeProvider.when('/bar', {templateUrl: 'myUrl2'}); + }); + + inject(function($$rAF, $templateCache, $rootScope, $compile, $timeout, $location, $httpBackend) { + var spy = spyOn($rootScope, '$digest').and.callThrough(); + + $templateCache.put('myUrl1', 'my template content'); + $templateCache.put('myUrl2', 'my other template content'); + + $location.path('/foo'); + $rootScope.$digest(); + + // The animation completion is async even without actual animations + $$rAF.flush(); + expect(element.text()).toEqual('my template content'); + + $location.path('/bar'); + $rootScope.$digest(); + spy.calls.reset(); + + $$rAF.flush(); + expect(element.text()).toEqual('my other template content'); + + expect(spy).not.toHaveBeenCalled(); + // A digest may have been triggered asynchronously, so check the queue + $timeout.verifyNoPendingTasks(); + }); + }); + + }); + + describe('and transcludes', function() { + var element, directive; + + beforeEach(module('ngRoute', function($compileProvider) { + element = null; + directive = $compileProvider.directive; + })); + + afterEach(function() { + if (element) { + dealoc(element); + } + }); + + it('should allow access to directive controller from children when used in a replace template', function() { + var controller; + module(function($routeProvider) { + $routeProvider.when('/view', {templateUrl: 'view.html'}); + directive('template', function() { + return { + template: '
', + replace: true, + controller: function() { + this.flag = true; + } + }; + }); + + directive('test', function() { + return { + require: '^template', + link: function(scope, el, attr, ctrl) { + controller = ctrl; + } + }; + }); + }); + inject(function($compile, $rootScope, $httpBackend, $location) { + $httpBackend.expectGET('view.html').respond('
'); + element = $compile('
')($rootScope); + $location.url('https://github.com/view'); + $rootScope.$apply(); + $httpBackend.flush(); + expect(controller.flag).toBe(true); + }); + }); + + it('should compile its content correctly (although we remove it later)', function() { + var testElement; + module(function($compileProvider, $routeProvider) { + $routeProvider.when('/view', {template: ' '}); + var directive = $compileProvider.directive; + directive('test', function() { + return { + link: function(scope, element) { + testElement = element; + } + }; + }); + }); + inject(function($compile, $rootScope, $location) { + element = $compile('
')($rootScope); + $location.url('https://github.com/view'); + $rootScope.$apply(); + expect(testElement[0].nodeName).toBe('DIV'); + }); + + }); + + it('should link directives on the same element after the content has been loaded', function() { + var contentOnLink; + module(function($compileProvider, $routeProvider) { + $routeProvider.when('/view', {template: 'someContent'}); + $compileProvider.directive('test', function() { + return { + link: function(scope, element) { + contentOnLink = element.text(); + } + }; + }); + }); + inject(function($compile, $rootScope, $location) { + element = $compile('
')($rootScope); + $location.url('https://github.com/view'); + $rootScope.$apply(); + expect(contentOnLink).toBe('someContent'); + }); + }); + + it('should add the content to the element before compiling it', function() { + var root; + module(function($compileProvider, $routeProvider) { + $routeProvider.when('/view', {template: ''}); + $compileProvider.directive('test', function() { + return { + link: function(scope, element) { + root = element.parent().parent(); + } + }; + }); + }); + inject(function($compile, $rootScope, $location) { + element = $compile('
')($rootScope); + $location.url('https://github.com/view'); + $rootScope.$apply(); + expect(root[0]).toBe(element[0]); + }); + }); + }); + + describe('animations', function() { + var body, element, $rootElement; + + beforeEach(module('ngRoute')); + + function html(content) { + $rootElement.html(content); + body.append($rootElement); + element = $rootElement.children().eq(0); + return element; + } + + beforeEach(module(function() { + // we need to run animation on attached elements; + return function(_$rootElement_) { + $rootElement = _$rootElement_; + body = angular.element(window.document.body); + }; + })); + + afterEach(function() { + dealoc(body); + dealoc(element); + }); + + + beforeEach(module(function($provide, $routeProvider) { + $routeProvider.when('/foo', {controller: angular.noop, templateUrl: '/foo.html'}); + $routeProvider.when('/bar', {controller: angular.noop, templateUrl: '/bar.html'}); + return function($templateCache) { + $templateCache.put('/foo.html', [200, '
data
', {}]); + $templateCache.put('/bar.html', [200, '
data2
', {}]); + }; + })); + + describe('hooks', function() { + beforeEach(module('ngAnimate')); + beforeEach(module('ngAnimateMock')); + + it('should fire off the enter animation', + inject(function($compile, $rootScope, $location, $timeout, $animate) { + element = $compile(html('
'))($rootScope); + + $location.path('/foo'); + $rootScope.$digest(); + + var animation = $animate.queue.pop(); + expect(animation.event).toBe('enter'); + })); + + it('should fire off the leave animation', + inject(function($compile, $rootScope, $location, $templateCache, $timeout, $animate) { + + var item; + $templateCache.put('/foo.html', [200, '
foo
', {}]); + element = $compile(html('
'))($rootScope); + + $location.path('/foo'); + $rootScope.$digest(); + + + $location.path('/'); + $rootScope.$digest(); + + var animation = $animate.queue.pop(); + expect(animation.event).toBe('leave'); + })); + + it('should animate two separate ngView elements', + inject(function($compile, $rootScope, $templateCache, $location, $animate) { + var item; + $rootScope.tpl = 'one'; + element = $compile(html('
'))($rootScope); + $rootScope.$digest(); + + $location.path('/foo'); + $rootScope.$digest(); + + //we don't care about the enter animation for the first element + $animate.queue.pop(); + + $location.path('/bar'); + $rootScope.$digest(); + + var animationB = $animate.queue.pop(); + expect(animationB.event).toBe('leave'); + var itemB = animationB.args[0]; + + var animationA = $animate.queue.pop(); + expect(animationA.event).toBe('enter'); + var itemA = animationA.args[0]; + + expect(itemA).not.toEqual(itemB); + }) + ); + + it('should render ngClass on ngView', + inject(function($compile, $rootScope, $templateCache, $animate, $location) { + + var item; + $rootScope.tpl = 'one'; + $rootScope.klass = 'classy'; + element = $compile(html('
'))($rootScope); + $rootScope.$digest(); + + $location.path('/foo'); + $rootScope.$digest(); + $animate.flush(); + + //we don't care about the enter animation + $animate.queue.shift(); + + var animation = $animate.queue.shift(); + expect(animation.event).toBe('addClass'); + + item = animation.element; + expect(item.hasClass('classy')).toBe(true); + + $rootScope.klass = 'boring'; + $rootScope.$digest(); + + expect($animate.queue.shift().event).toBe('addClass'); + expect($animate.queue.shift().event).toBe('removeClass'); + + $animate.flush(); + + expect(item.hasClass('classy')).toBe(false); + expect(item.hasClass('boring')).toBe(true); + + $location.path('/bar'); + $rootScope.$digest(); + + //we don't care about the enter animation + $animate.queue.shift(); + + animation = $animate.queue.shift(); + item = animation.element; + expect(animation.event).toBe('leave'); + + expect($animate.queue.shift().event).toBe('addClass'); + + expect(item.hasClass('boring')).toBe(true); + }) + ); + + it('should not double compile when the route changes', function() { + + var window; + module(function($routeProvider, $animateProvider, $provide) { + $routeProvider.when('/foo', {template: '
{{i}}
'}); + $routeProvider.when('/bar', {template: '
{{i}}
'}); + $animateProvider.register('.my-animation', function() { + return { + leave: function(element, done) { + done(); + } + }; + }); + }); + + inject(function($rootScope, $compile, $location, $route, $timeout, $rootElement, $sniffer, $animate) { + element = $compile(html('
'))($rootScope); + $animate.enabled(true); + + $location.path('/foo'); + $rootScope.$digest(); + + expect($animate.queue.shift().event).toBe('enter'); //ngView + expect($animate.queue.shift().event).toBe('enter'); //repeat 1 + expect($animate.queue.shift().event).toBe('enter'); //repeat 2 + + expect(element.text()).toEqual('12'); + + $location.path('/bar'); + $rootScope.$digest(); + + expect($animate.queue.shift().event).toBe('enter'); //ngView new + expect($animate.queue.shift().event).toBe('leave'); //ngView old + + $rootScope.$digest(); + + expect($animate.queue.shift().event).toBe('enter'); //ngRepeat 3 + expect($animate.queue.shift().event).toBe('enter'); //ngRepeat 4 + + $animate.flush(); + + expect(element.text()).toEqual('34'); + + function n(text) { + return text.replace(/\r\n/m, '').replace(/\r\n/m, ''); + } + }); + }); + + it('should destroy the previous leave animation if a new one takes place', + inject(function($compile, $rootScope, $animate, $location, $timeout) { + var $scope = $rootScope.$new(); + element = $compile(html( + '
' + + '
' + + '
' + ))($scope); + + $scope.$apply('value = true'); + + $location.path('/bar'); + $rootScope.$digest(); + + var destroyed, inner = element.children(0); + inner.on('$destroy', function() { + destroyed = true; + }); + + $location.path('/foo'); + $rootScope.$digest(); + + $location.path('/bar'); + $rootScope.$digest(); + + $location.path('/bar'); + $rootScope.$digest(); + + expect(destroyed).toBe(true); + }) + ); + }); + + + describe('autoscroll', function() { + var autoScrollSpy; + + function spyOnAnchorScroll() { + return function($provide, $routeProvider) { + autoScrollSpy = jasmine.createSpy('$anchorScroll'); + $provide.value('$anchorScroll', autoScrollSpy); + $routeProvider.when('/foo', { + controller: angular.noop, + template: '
' + }); + }; + } + + function spyOnAnimateEnter() { + return function($animate) { + spyOn($animate, 'enter').and.callThrough(); + }; + } + + function compileAndLink(tpl) { + return function($compile, $rootScope, $location) { + element = $compile(tpl)($rootScope); + }; + } + + beforeEach(module(spyOnAnchorScroll(), 'ngAnimateMock')); + beforeEach(inject(spyOnAnimateEnter())); + + it('should call $anchorScroll if autoscroll attribute is present', inject( + compileAndLink('
'), + function($rootScope, $animate, $timeout, $location) { + + $location.path('/foo'); + $rootScope.$digest(); + + $animate.flush(); + $rootScope.$digest(); + + expect($animate.queue.shift().event).toBe('enter'); + expect(autoScrollSpy).toHaveBeenCalledOnce(); + })); + + + it('should call $anchorScroll if autoscroll evaluates to true', inject( + compileAndLink('
'), + function($rootScope, $animate, $timeout, $location) { + + $rootScope.value = true; + $location.path('/foo'); + $rootScope.$digest(); + + $animate.flush(); + $rootScope.$digest(); + + expect($animate.queue.shift().event).toBe('enter'); + expect(autoScrollSpy).toHaveBeenCalledOnce(); + })); + + + it('should not call $anchorScroll if autoscroll attribute is not present', inject( + compileAndLink('
'), + function($rootScope, $location, $animate, $timeout) { + + $location.path('/foo'); + $rootScope.$digest(); + expect($animate.queue.shift().event).toBe('enter'); + + expect(autoScrollSpy).not.toHaveBeenCalled(); + })); + + + it('should not call $anchorScroll if autoscroll evaluates to false', inject( + compileAndLink('
'), + function($rootScope, $location, $animate, $timeout) { + + $rootScope.value = false; + $location.path('/foo'); + $rootScope.$digest(); + expect($animate.queue.shift().event).toBe('enter'); + + expect(autoScrollSpy).not.toHaveBeenCalled(); + })); + + + it('should only call $anchorScroll after the "enter" animation completes', inject( + compileAndLink('
'), + function($rootScope, $location, $animate, $timeout) { + $location.path('/foo'); + + expect($animate.enter).not.toHaveBeenCalled(); + $rootScope.$digest(); + + expect(autoScrollSpy).not.toHaveBeenCalled(); + + expect($animate.queue.shift().event).toBe('enter'); + + $animate.flush(); + $rootScope.$digest(); + + expect($animate.enter).toHaveBeenCalledOnce(); + expect(autoScrollSpy).toHaveBeenCalledOnce(); + } + )); + }); + }); + + describe('in async template', function() { + beforeEach(module('ngRoute')); + beforeEach(module(function($compileProvider, $provide, $routeProvider) { + $compileProvider.directive('asyncView', function() { + return {templateUrl: 'async-view.html'}; + }); + + $provide.decorator('$templateRequest', function($timeout) { + return function() { + return $timeout(angular.identity, 500, false, ''); + }; + }); + + $routeProvider.when('/', {template: 'Hello, world!'}); + })); + + + it('should work correctly upon initial page load', + // Injecting `$location` here is necessary, so that it gets instantiated early + inject(function($compile, $location, $rootScope, $timeout) { + var elem = $compile('')($rootScope); + $rootScope.$digest(); + $timeout.flush(500); + + expect(elem.text()).toBe('Hello, world!'); + + dealoc(elem); + }) + ); + }); +}); + +describe('$routeParams', function() { + + beforeEach(module('ngRoute')); + + + it('should publish the params into a service', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {}); + $routeProvider.when('/bar/:barId', {}); + }); + + inject(function($rootScope, $route, $location, $routeParams) { + $location.path('/foo').search('a=b'); + $rootScope.$digest(); + expect($routeParams).toEqual({a:'b'}); + + $location.path('/bar/123').search('x=abc'); + $rootScope.$digest(); + expect($routeParams).toEqual({barId:'123', x:'abc'}); + }); + }); + + it('should correctly extract the params when a param name is part of the route', function() { + module(function($routeProvider) { + $routeProvider.when('/bar/:foo/:bar', {}); + }); + + inject(function($rootScope, $route, $location, $routeParams) { + $location.path('/bar/foovalue/barvalue'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar:'barvalue', foo:'foovalue'}); + }); + }); + + it('should support route params not preceded by slashes', function() { + module(function($routeProvider) { + $routeProvider.when('/bar:barId/foo:fooId/', {}); + }); + + inject(function($rootScope, $route, $location, $routeParams) { + $location.path('/barbarvalue/foofoovalue/'); + $rootScope.$digest(); + expect($routeParams).toEqual({barId: 'barvalue', fooId: 'foovalue'}); + }); + }); + + it('should correctly extract the params when an optional param name is part of the route', function() { + module(function($routeProvider) { + $routeProvider.when('/bar/:foo?', {}); + $routeProvider.when('/baz/:foo?/edit', {}); + $routeProvider.when('/qux/:bar?/:baz?', {}); + }); + + inject(function($rootScope, $route, $location, $routeParams) { + $location.path('/bar'); + $rootScope.$digest(); + expect($routeParams).toEqual({}); + + $location.path('/bar/fooValue'); + $rootScope.$digest(); + expect($routeParams).toEqual({foo: 'fooValue'}); + + $location.path('/baz/fooValue/edit'); + $rootScope.$digest(); + expect($routeParams).toEqual({foo: 'fooValue'}); + + $location.path('/baz/edit'); + $rootScope.$digest(); + expect($routeParams).toEqual({}); + + $location.path('/qux//bazValue'); + $rootScope.$digest(); + expect($routeParams).toEqual({baz: 'bazValue'}); + + }); + }); + + it('should correctly extract path params containing hashes and/or question marks', function() { + module(function($routeProvider) { + $routeProvider.when('/foo/:bar', {}); + $routeProvider.when('/zoo/:bar/:baz/:qux', {}); + }); + + inject(function($location, $rootScope, $routeParams) { + $location.path('/foo/bar?baz'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar?baz'}); + + $location.path('/foo/bar?baz=val'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar?baz=val'}); + + $location.path('/foo/bar#baz'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar#baz'}); + + $location.path('/foo/bar?baz#qux'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar?baz#qux'}); + + $location.path('/foo/bar?baz=val#qux'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar?baz=val#qux'}); + + $location.path('/foo/bar#baz?qux'); + $rootScope.$digest(); + expect($routeParams).toEqual({bar: 'bar#baz?qux'}); + + $location.path('/zoo/bar?p1=v1#h1/baz?p2=v2#h2/qux?p3=v3#h3'); + $rootScope.$digest(); + expect($routeParams).toEqual({ + bar: 'bar?p1=v1#h1', + baz: 'baz?p2=v2#h2', + qux: 'qux?p3=v3#h3' + }); + }); + }); + +}); + +describe('$routeProvider', function() { + var $routeProvider; + + beforeEach(module('ngRoute')); + beforeEach(module(function(_$routeProvider_) { + $routeProvider = _$routeProvider_; + $routeProvider.when('/foo', {template: 'Hello, world!'}); + })); + + + it('should support enabling/disabling automatic instantiation upon initial load', + inject(function() { + expect($routeProvider.eagerInstantiationEnabled(true)).toBe($routeProvider); + expect($routeProvider.eagerInstantiationEnabled()).toBe(true); + + expect($routeProvider.eagerInstantiationEnabled(false)).toBe($routeProvider); + expect($routeProvider.eagerInstantiationEnabled()).toBe(false); + + expect($routeProvider.eagerInstantiationEnabled(true)).toBe($routeProvider); + expect($routeProvider.eagerInstantiationEnabled()).toBe(true); + }) + ); + + + it('should automatically instantiate `$route` upon initial load', function() { + inject(function($location, $rootScope) { + $location.path('/foo'); + $rootScope.$digest(); + }); + + inject(function($route) { + expect($route.current).toBeDefined(); + }); + }); + + + it('should not automatically instantiate `$route` if disabled', function() { + module(function($routeProvider) { + $routeProvider.eagerInstantiationEnabled(false); + }); + + inject(function($location, $rootScope) { + $location.path('/foo'); + $rootScope.$digest(); + }); + + inject(function($route) { + expect($route.current).toBeUndefined(); + }); + }); +}); + + +describe('$route', function() { + var $httpBackend, + element; + + beforeEach(module('ngRoute')); + + beforeEach(module(function() { + return function(_$httpBackend_) { + $httpBackend = _$httpBackend_; + $httpBackend.when('GET', 'Chapter.html').respond('chapter'); + $httpBackend.when('GET', 'test.html').respond('test'); + $httpBackend.when('GET', 'foo.html').respond('foo'); + $httpBackend.when('GET', 'bar.html').respond('bar'); + $httpBackend.when('GET', 'baz.html').respond('baz'); + $httpBackend.when('GET', 'http://example.com/trusted-template.html').respond('cross domain trusted template'); + $httpBackend.when('GET', '404.html').respond('not found'); + }; + })); + + afterEach(function() { + dealoc(element); + }); + + + it('should allow cancellation via $locationChangeStart via $routeChangeStart', function() { + module(function($routeProvider) { + $routeProvider.when('/Edit', { + id: 'edit', template: 'Some edit functionality' + }); + $routeProvider.when('/Home', { + id: 'home' + }); + }); + module(provideLog); + inject(function($route, $location, $rootScope, $compile, log) { + $rootScope.$on('$routeChangeStart', function(event, next, current) { + if (next.id === 'home' && current.scope.unsavedChanges) { + event.preventDefault(); + } + }); + element = $compile('
')($rootScope); + $rootScope.$apply(function() { + $location.path('/Edit'); + }); + $rootScope.$on('$routeChangeSuccess', log.fn('routeChangeSuccess')); + $rootScope.$on('$locationChangeSuccess', log.fn('locationChangeSuccess')); + + // aborted route change + $rootScope.$apply(function() { + $route.current.scope.unsavedChanges = true; + }); + $rootScope.$apply(function() { + $location.path('/Home'); + }); + expect($route.current.id).toBe('edit'); + expect($location.path()).toBe('/Edit'); + expect(log).toEqual([]); + + // successful route change + $rootScope.$apply(function() { + $route.current.scope.unsavedChanges = false; + }); + $rootScope.$apply(function() { + $location.path('/Home'); + }); + expect($route.current.id).toBe('home'); + expect($location.path()).toBe('/Home'); + expect(log).toEqual(['locationChangeSuccess', 'routeChangeSuccess']); + }); + }); + + it('should allow redirects while handling $routeChangeStart', function() { + module(function($routeProvider) { + $routeProvider.when('/some', { + id: 'some', template: 'Some functionality' + }); + $routeProvider.when('/redirect', { + id: 'redirect' + }); + }); + module(provideLog); + inject(function($route, $location, $rootScope, $compile, log) { + $rootScope.$on('$routeChangeStart', function(event, next, current) { + if (next.id === 'some') { + $location.path('/redirect'); + } + }); + $compile('
')($rootScope); + $rootScope.$on('$routeChangeStart', log.fn('routeChangeStart')); + $rootScope.$on('$routeChangeError', log.fn('routeChangeError')); + $rootScope.$on('$routeChangeSuccess', log.fn('routeChangeSuccess')); + $rootScope.$apply(function() { + $location.path('/some'); + }); + + expect($route.current.id).toBe('redirect'); + expect($location.path()).toBe('/redirect'); + expect(log).toEqual(['routeChangeStart', 'routeChangeStart', 'routeChangeSuccess']); + }); + }); + + it('should route and fire change event', function() { + var log = '', + lastRoute, + nextRoute; + + module(function($routeProvider) { + $routeProvider.when('/Book/:book/Chapter/:chapter', + {controller: angular.noop, templateUrl: 'Chapter.html'}); + $routeProvider.when('/Blank', {}); + }); + inject(function($route, $location, $rootScope) { + $rootScope.$on('$routeChangeStart', function(event, next, current) { + log += 'before();'; + expect(current).toBe($route.current); + lastRoute = current; + nextRoute = next; + }); + $rootScope.$on('$routeChangeSuccess', function(event, current, last) { + log += 'after();'; + expect(current).toBe($route.current); + expect(lastRoute).toBe(last); + expect(nextRoute).toBe(current); + }); + + $location.path('/Book/Moby/Chapter/Intro').search('p=123'); + $rootScope.$digest(); + $httpBackend.flush(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', p:'123'}); + + log = ''; + $location.path('/Blank').search('ignore'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({ignore:true}); + + log = ''; + $location.path('/NONE'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current).toEqual(undefined); + }); + }); + + it('should route and fire change event when catch-all params are used', function() { + var log = '', + lastRoute, + nextRoute; + + module(function($routeProvider) { + $routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit', + {controller: angular.noop, templateUrl: 'Chapter.html'}); + $routeProvider.when('/Book2/:book/:highlight*/Chapter/:chapter', + {controller: angular.noop, templateUrl: 'Chapter.html'}); + $routeProvider.when('/Blank', {}); + }); + inject(function($route, $location, $rootScope) { + $rootScope.$on('$routeChangeStart', function(event, next, current) { + log += 'before();'; + expect(current).toBe($route.current); + lastRoute = current; + nextRoute = next; + }); + $rootScope.$on('$routeChangeSuccess', function(event, current, last) { + log += 'after();'; + expect(current).toBe($route.current); + expect(lastRoute).toBe(last); + expect(nextRoute).toBe(current); + }); + + $location.path('/Book1/Moby/Chapter/Intro/one/edit').search('p=123'); + $rootScope.$digest(); + $httpBackend.flush(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', highlight:'one', p:'123'}); + + log = ''; + $location.path('/Blank').search('ignore'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({ignore:true}); + + log = ''; + $location.path('/Book1/Moby/Chapter/Intro/one/two/edit').search('p=123'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', highlight:'one/two', p:'123'}); + + log = ''; + $location.path('/Book2/Moby/one/two/Chapter/Intro').search('p=123'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', highlight:'one/two', p:'123'}); + + log = ''; + $location.path('/NONE'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current).toEqual(undefined); + }); + }); + + + it('should route and fire change event correctly whenever the case insensitive flag is utilized', function() { + var log = '', + lastRoute, + nextRoute; + + module(function($routeProvider) { + $routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit', + {controller: angular.noop, templateUrl: 'Chapter.html', caseInsensitiveMatch: true}); + $routeProvider.when('/Book2/:book/:highlight*/Chapter/:chapter', + {controller: angular.noop, templateUrl: 'Chapter.html'}); + $routeProvider.when('/Blank', {}); + }); + inject(function($route, $location, $rootScope) { + $rootScope.$on('$routeChangeStart', function(event, next, current) { + log += 'before();'; + expect(current).toBe($route.current); + lastRoute = current; + nextRoute = next; + }); + $rootScope.$on('$routeChangeSuccess', function(event, current, last) { + log += 'after();'; + expect(current).toBe($route.current); + expect(lastRoute).toBe(last); + expect(nextRoute).toBe(current); + }); + + $location.path('/Book1/Moby/Chapter/Intro/one/edit').search('p=123'); + $rootScope.$digest(); + $httpBackend.flush(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', highlight:'one', p:'123'}); + + log = ''; + $location.path('/BOOK1/Moby/CHAPTER/Intro/one/EDIT').search('p=123'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', highlight:'one', p:'123'}); + + log = ''; + $location.path('/Blank').search('ignore'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({ignore:true}); + + log = ''; + $location.path('/BLANK'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current).toEqual(undefined); + + log = ''; + $location.path('/Book2/Moby/one/two/Chapter/Intro').search('p=123'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', highlight:'one/two', p:'123'}); + + log = ''; + $location.path('/BOOK2/Moby/one/two/CHAPTER/Intro').search('p=123'); + $rootScope.$digest(); + expect(log).toEqual('before();after();'); + expect($route.current).toEqual(undefined); + }); + }); + + it('should allow configuring caseInsensitiveMatch on the route provider level', function() { + module(function($routeProvider) { + $routeProvider.caseInsensitiveMatch = true; + $routeProvider.when('/Blank', {template: 'blank'}); + $routeProvider.otherwise({template: 'other'}); + }); + inject(function($route, $location, $rootScope) { + $location.path('/bLaNk'); + $rootScope.$digest(); + expect($route.current.template).toBe('blank'); + }); + }); + + it('should allow overriding provider\'s caseInsensitiveMatch setting on the route level', function() { + module(function($routeProvider) { + $routeProvider.caseInsensitiveMatch = true; + $routeProvider.when('/Blank', {template: 'blank', caseInsensitiveMatch: false}); + $routeProvider.otherwise({template: 'other'}); + }); + inject(function($route, $location, $rootScope) { + $location.path('/bLaNk'); + $rootScope.$digest(); + expect($route.current.template).toBe('other'); + }); + }); + + it('should not change route when location is canceled', function() { + module(function($routeProvider) { + $routeProvider.when('/somePath', {template: 'some path'}); + }); + inject(function($route, $location, $rootScope, $log) { + $rootScope.$on('$locationChangeStart', function(event) { + $log.info('$locationChangeStart'); + event.preventDefault(); + }); + + $rootScope.$on('$routeChangeSuccess', function(event) { + throw new Error('Should not get here'); + }); + + $location.path('/somePath'); + $rootScope.$digest(); + + expect($log.info.logs.shift()).toEqual(['$locationChangeStart']); + }); + }); + + + describe('should match a route that contains special chars in the path', function() { + beforeEach(module(function($routeProvider) { + $routeProvider.when('/$test.23/foo*(bar)/:baz', {templateUrl: 'test.html'}); + })); + + it('matches the full path', inject(function($route, $location, $rootScope) { + $location.path('/test'); + $rootScope.$digest(); + expect($route.current).toBeUndefined(); + })); + + it('matches literal .', inject(function($route, $location, $rootScope) { + $location.path('/$testX23/foo*(bar)/222'); + $rootScope.$digest(); + expect($route.current).toBeUndefined(); + })); + + it('matches literal *', inject(function($route, $location, $rootScope) { + $location.path('/$test.23/foooo(bar)/222'); + $rootScope.$digest(); + expect($route.current).toBeUndefined(); + })); + + it('treats backslashes normally', inject(function($route, $location, $rootScope) { + $location.path('/$test.23/foo*\\(bar)/222'); + $rootScope.$digest(); + expect($route.current).toBeUndefined(); + })); + + it('matches a URL with special chars', inject(function($route, $location, $rootScope) { + $location.path('/$test.23/foo*(bar)/~!@#$%^&*()_+=-`'); + $rootScope.$digest(); + expect($route.current).toBeDefined(); + })); + + it('should use route params inherited from prototype chain', function() { + function BaseRoute() {} + BaseRoute.prototype.templateUrl = 'foo.html'; + + module(function($routeProvider) { + $routeProvider.when('/foo', new BaseRoute()); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo'); + $rootScope.$digest(); + expect($route.current.templateUrl).toBe('foo.html'); + }); + }); + }); + + + describe('should match a route that contains optional params in the path', function() { + beforeEach(module(function($routeProvider) { + $routeProvider.when('/test/:opt?/:baz/edit', {templateUrl: 'test.html'}); + })); + + it('matches a URL with optional params', inject(function($route, $location, $rootScope) { + $location.path('/test/optValue/bazValue/edit'); + $rootScope.$digest(); + expect($route.current).toBeDefined(); + })); + + it('matches a URL without optional param', inject(function($route, $location, $rootScope) { + $location.path('/test//bazValue/edit'); + $rootScope.$digest(); + expect($route.current).toBeDefined(); + })); + + it('not match a URL with a required param', inject(function($route, $location, $rootScope) { + $location.path('///edit'); + $rootScope.$digest(); + expect($route.current).not.toBeDefined(); + })); + }); + + + it('should change route even when only search param changes', function() { + module(function($routeProvider) { + $routeProvider.when('/test', {templateUrl: 'test.html'}); + }); + + inject(function($route, $location, $rootScope) { + var callback = jasmine.createSpy('onRouteChange'); + + $rootScope.$on('$routeChangeStart', callback); + $location.path('/test'); + $rootScope.$digest(); + callback.calls.reset(); + + $location.search({any: true}); + $rootScope.$digest(); + + expect(callback).toHaveBeenCalled(); + }); + }); + + + it('should allow routes to be defined with just templates without controllers', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'foo.html'}); + }); + + inject(function($route, $location, $rootScope) { + var onChangeSpy = jasmine.createSpy('onChange'); + + $rootScope.$on('$routeChangeStart', onChangeSpy); + expect($route.current).toBeUndefined(); + expect(onChangeSpy).not.toHaveBeenCalled(); + + $location.path('/foo'); + $rootScope.$digest(); + + expect($route.current.templateUrl).toEqual('foo.html'); + expect($route.current.controller).toBeUndefined(); + expect(onChangeSpy).toHaveBeenCalled(); + }); + }); + + + it('should chain whens and otherwise', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'foo.html'}). + otherwise({templateUrl: 'bar.html'}). + when('/baz', {templateUrl: 'baz.html'}); + }); + + inject(function($route, $location, $rootScope) { + $rootScope.$digest(); + expect($route.current.templateUrl).toBe('bar.html'); + + $location.url('https://github.com/baz'); + $rootScope.$digest(); + expect($route.current.templateUrl).toBe('baz.html'); + }); + }); + + + it('should skip routes with incomplete params', function() { + module(function($routeProvider) { + $routeProvider + .otherwise({template: 'other'}) + .when('/pages/:page/:comment*', {template: 'comment'}) + .when('/pages/:page', {template: 'page'}) + .when('/pages', {template: 'index'}) + .when('/foo/', {template: 'foo'}) + .when('/foo/:bar', {template: 'bar'}) + .when('/foo/:bar*/:baz', {template: 'baz'}); + }); + + inject(function($route, $location, $rootScope) { + $location.url('https://github.com/pages/'); + $rootScope.$digest(); + expect($route.current.template).toBe('index'); + + $location.url('https://github.com/pages/page/'); + $rootScope.$digest(); + expect($route.current.template).toBe('page'); + + $location.url('https://github.com/pages/page/1/'); + $rootScope.$digest(); + expect($route.current.template).toBe('comment'); + + $location.url('https://github.com/foo/'); + $rootScope.$digest(); + expect($route.current.template).toBe('foo'); + + $location.url('https://github.com/foo/bar/'); + $rootScope.$digest(); + expect($route.current.template).toBe('bar'); + + $location.url('https://github.com/foo/bar/baz/'); + $rootScope.$digest(); + expect($route.current.template).toBe('baz'); + + $location.url('https://github.com/something/'); + $rootScope.$digest(); + expect($route.current.template).toBe('other'); + }); + }); + + + describe('otherwise', function() { + + it('should handle unknown routes with "otherwise" route definition', function() { + function NotFoundCtrl() {} + + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'foo.html'}); + $routeProvider.otherwise({templateUrl: '404.html', controller: NotFoundCtrl}); + }); + + inject(function($route, $location, $rootScope) { + var onChangeSpy = jasmine.createSpy('onChange'); + + $rootScope.$on('$routeChangeStart', onChangeSpy); + expect($route.current).toBeUndefined(); + expect(onChangeSpy).not.toHaveBeenCalled(); + + $location.path('/unknownRoute'); + $rootScope.$digest(); + + expect($route.current.templateUrl).toBe('404.html'); + expect($route.current.controller).toBe(NotFoundCtrl); + expect(onChangeSpy).toHaveBeenCalled(); + + onChangeSpy.calls.reset(); + $location.path('/foo'); + $rootScope.$digest(); + + expect($route.current.templateUrl).toEqual('foo.html'); + expect($route.current.controller).toBeUndefined(); + expect(onChangeSpy).toHaveBeenCalled(); + }); + }); + + + it('should update $route.current and $route.next when default route is matched', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'foo.html'}); + $routeProvider.otherwise({templateUrl: '404.html'}); + }); + + inject(function($route, $location, $rootScope) { + var currentRoute, nextRoute, + onChangeSpy = jasmine.createSpy('onChange').and.callFake(function(e, next) { + currentRoute = $route.current; + nextRoute = next; + }); + + + // init + $rootScope.$on('$routeChangeStart', onChangeSpy); + expect($route.current).toBeUndefined(); + expect(onChangeSpy).not.toHaveBeenCalled(); + + + // match otherwise route + $location.path('/unknownRoute'); + $rootScope.$digest(); + + expect(currentRoute).toBeUndefined(); + expect(nextRoute.templateUrl).toBe('404.html'); + expect($route.current.templateUrl).toBe('404.html'); + expect(onChangeSpy).toHaveBeenCalled(); + onChangeSpy.calls.reset(); + + // match regular route + $location.path('/foo'); + $rootScope.$digest(); + + expect(currentRoute.templateUrl).toBe('404.html'); + expect(nextRoute.templateUrl).toBe('foo.html'); + expect($route.current.templateUrl).toEqual('foo.html'); + expect(onChangeSpy).toHaveBeenCalled(); + onChangeSpy.calls.reset(); + + // match otherwise route again + $location.path('/anotherUnknownRoute'); + $rootScope.$digest(); + + expect(currentRoute.templateUrl).toBe('foo.html'); + expect(nextRoute.templateUrl).toBe('404.html'); + expect($route.current.templateUrl).toEqual('404.html'); + expect(onChangeSpy).toHaveBeenCalled(); + }); + }); + + + it('should interpret a string as a redirect route', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'foo.html'}); + $routeProvider.when('/baz', {templateUrl: 'baz.html'}); + $routeProvider.otherwise('/foo'); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/unknownRoute'); + $rootScope.$digest(); + + expect($location.path()).toBe('/foo'); + expect($route.current.templateUrl).toBe('foo.html'); + }); + }); + }); + + + describe('events', function() { + it('should not fire $routeChangeStart/Success during bootstrap (if no route)', function() { + var routeChangeSpy = jasmine.createSpy('route change'); + + module(function($routeProvider) { + $routeProvider.when('/one', {}); // no otherwise defined + }); + + inject(function($rootScope, $route, $location) { + $rootScope.$on('$routeChangeStart', routeChangeSpy); + $rootScope.$on('$routeChangeSuccess', routeChangeSpy); + + $rootScope.$digest(); + expect(routeChangeSpy).not.toHaveBeenCalled(); + + $location.path('/no-route-here'); + $rootScope.$digest(); + expect(routeChangeSpy).not.toHaveBeenCalled(); + + $location.path('/one'); + $rootScope.$digest(); + expect(routeChangeSpy).toHaveBeenCalled(); + }); + }); + + it('should fire $routeChangeStart and resolve promises', function() { + var deferA, + deferB; + + module(function($provide, $routeProvider) { + $provide.factory('b', function($q) { + deferB = $q.defer(); + return deferB.promise; + }); + $routeProvider.when('/path', { templateUrl: 'foo.html', resolve: { + a: ['$q', function($q) { + deferA = $q.defer(); + return deferA.promise; + }], + b: 'b' + } }); + }); + + inject(function($location, $route, $rootScope, $httpBackend) { + var log = ''; + + $httpBackend.expectGET('foo.html').respond('FOO'); + + $location.path('/path'); + $rootScope.$digest(); + expect(log).toEqual(''); + $httpBackend.flush(); + expect(log).toEqual(''); + deferA.resolve(); + $rootScope.$digest(); + expect(log).toEqual(''); + deferB.resolve(); + $rootScope.$digest(); + expect($route.current.locals.$template).toEqual('FOO'); + }); + }); + + + it('should fire $routeChangeError event on resolution error', function() { + var deferA; + + module(function($provide, $routeProvider) { + $routeProvider.when('/path', { template: 'foo', resolve: { + a: function($q) { + deferA = $q.defer(); + return deferA.promise; + } + } }); + }); + + inject(function($location, $route, $rootScope) { + var log = ''; + + $rootScope.$on('$routeChangeStart', function() { log += 'before();'; }); + $rootScope.$on('$routeChangeError', function(e, n, l, reason) { log += 'failed(' + reason + ');'; }); + + $location.path('/path'); + $rootScope.$digest(); + expect(log).toEqual('before();'); + + deferA.reject('MyError'); + $rootScope.$digest(); + expect(log).toEqual('before();failed(MyError);'); + }); + }); + + + it('should fetch templates', function() { + module(function($routeProvider) { + $routeProvider. + when('/r1', { templateUrl: 'r1.html' }). + when('/r2', { templateUrl: 'r2.html' }); + }); + + inject(function($route, $httpBackend, $location, $rootScope) { + var log = ''; + $rootScope.$on('$routeChangeStart', function(e, next) { log += '$before(' + next.templateUrl + ');'; }); + $rootScope.$on('$routeChangeSuccess', function(e, next) { log += '$after(' + next.templateUrl + ');'; }); + + $httpBackend.expectGET('r1.html').respond('R1'); + $httpBackend.expectGET('r2.html').respond('R2'); + + $location.path('/r1'); + $rootScope.$digest(); + expect(log).toBe('$before(r1.html);'); + + $location.path('/r2'); + $rootScope.$digest(); + expect(log).toBe('$before(r1.html);$before(r2.html);'); + + $httpBackend.flush(); + expect(log).toBe('$before(r1.html);$before(r2.html);$after(r2.html);'); + expect(log).not.toContain('$after(r1.html);'); + }); + }); + + it('should NOT load cross domain templates by default', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', { templateUrl: 'http://example.com/foo.html' }); + }); + + inject(function($route, $location, $rootScope) { + var onError = jasmine.createSpy('onError'); + var onSuccess = jasmine.createSpy('onSuccess'); + + $rootScope.$on('$routeChangeError', onError); + $rootScope.$on('$routeChangeSuccess', onSuccess); + + $location.path('/foo'); + $rootScope.$digest(); + + expect(onSuccess).not.toHaveBeenCalled(); + expect(onError).toHaveBeenCalled(); + expect(onError.calls.mostRecent().args[3]).toEqualMinErr('$sce', 'insecurl', + 'Blocked loading resource from url not allowed by $sceDelegate policy. ' + + 'URL: http://example.com/foo.html'); + }); + }); + + it('should load cross domain templates that are trusted', function() { + module(function($routeProvider, $sceDelegateProvider) { + $routeProvider.when('/foo', { templateUrl: 'http://example.com/foo.html' }); + $sceDelegateProvider.trustedResourceUrlList([/^http:\/\/example\.com\/foo\.html$/]); + }); + + inject(function($route, $location, $rootScope) { + $httpBackend.whenGET('http://example.com/foo.html').respond('FOO BODY'); + $location.path('/foo'); + $rootScope.$digest(); + $httpBackend.flush(); + expect($route.current.locals.$template).toEqual('FOO BODY'); + }); + }); + + it('should not update $routeParams until $routeChangeSuccess', function() { + module(function($routeProvider) { + $routeProvider. + when('/r1/:id', { templateUrl: 'r1.html' }). + when('/r2/:id', { templateUrl: 'r2.html' }); + }); + + inject(function($route, $httpBackend, $location, $rootScope, $routeParams) { + var log = ''; + $rootScope.$on('$routeChangeStart', function(e, next) { log += '$before' + angular.toJson($routeParams) + ';'; }); + $rootScope.$on('$routeChangeSuccess', function(e, next) { log += '$after' + angular.toJson($routeParams) + ';'; }); + + $httpBackend.whenGET('r1.html').respond('R1'); + $httpBackend.whenGET('r2.html').respond('R2'); + + $location.path('/r1/1'); + $rootScope.$digest(); + expect(log).toBe('$before{};'); + $httpBackend.flush(); + expect(log).toBe('$before{};$after{"id":"1"};'); + + log = ''; + + $location.path('/r2/2'); + $rootScope.$digest(); + expect(log).toBe('$before{"id":"1"};'); + $httpBackend.flush(); + expect(log).toBe('$before{"id":"1"};$after{"id":"2"};'); + }); + }); + + + it('should drop in progress route change when new route change occurs', function() { + module(function($routeProvider) { + $routeProvider. + when('/r1', { templateUrl: 'r1.html' }). + when('/r2', { templateUrl: 'r2.html' }); + }); + + inject(function($route, $httpBackend, $location, $rootScope) { + var log = ''; + $rootScope.$on('$routeChangeStart', function(e, next) { log += '$before(' + next.templateUrl + ');'; }); + $rootScope.$on('$routeChangeSuccess', function(e, next) { log += '$after(' + next.templateUrl + ');'; }); + + $httpBackend.expectGET('r1.html').respond('R1'); + $httpBackend.expectGET('r2.html').respond('R2'); + + $location.path('/r1'); + $rootScope.$digest(); + expect(log).toBe('$before(r1.html);'); + + $location.path('/r2'); + $rootScope.$digest(); + expect(log).toBe('$before(r1.html);$before(r2.html);'); + + $httpBackend.flush(); + expect(log).toBe('$before(r1.html);$before(r2.html);$after(r2.html);'); + expect(log).not.toContain('$after(r1.html);'); + }); + }); + + + it('should throw an error when a template is not found', function() { + module(function($routeProvider, $exceptionHandlerProvider) { + $exceptionHandlerProvider.mode('log'); + $routeProvider. + when('/r1', { templateUrl: 'r1.html' }). + when('/r2', { templateUrl: 'r2.html' }). + when('/r3', { templateUrl: 'r3.html' }); + }); + + inject(function($route, $httpBackend, $location, $rootScope, $exceptionHandler) { + $httpBackend.expectGET('r1.html').respond(404, 'R1'); + $location.path('/r1'); + $rootScope.$digest(); + + $httpBackend.flush(); + expect($exceptionHandler.errors.pop()). + toEqualMinErr('$templateRequest', 'tpload', 'Failed to load template: r1.html'); + + $httpBackend.expectGET('r2.html').respond(''); + $location.path('/r2'); + $rootScope.$digest(); + + $httpBackend.flush(); + expect($exceptionHandler.errors.length).toBe(0); + + $httpBackend.expectGET('r3.html').respond('abc'); + $location.path('/r3'); + $rootScope.$digest(); + + $httpBackend.flush(); + expect($exceptionHandler.errors.length).toBe(0); + }); + }); + + + it('should catch local factory errors', function() { + var myError = new Error('MyError'); + module(function($routeProvider) { + $routeProvider.when('/locals', { + resolve: { + a: function($q) { + throw myError; + } + } + }); + }); + + inject(function($location, $route, $rootScope) { + spyOn($rootScope, '$broadcast').and.callThrough(); + + $location.path('/locals'); + $rootScope.$digest(); + + expect($rootScope.$broadcast).toHaveBeenCalledWith( + '$routeChangeError', jasmine.any(Object), undefined, myError); + }); + }); + }); + + + it('should match route with and without trailing slash', function() { + module(function($routeProvider) { + $routeProvider.when('/foo', {templateUrl: 'foo.html'}); + $routeProvider.when('/bar/', {templateUrl: 'bar.html'}); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($route.current.templateUrl).toBe('foo.html'); + + $location.path('/foo/'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($route.current.templateUrl).toBe('foo.html'); + + $location.path('/bar'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/'); + expect($route.current.templateUrl).toBe('bar.html'); + + $location.path('/bar/'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/'); + expect($route.current.templateUrl).toBe('bar.html'); + }); + }); + + + it('should not get affected by modifying the route definition object after route registration', + function() { + module(function($routeProvider) { + var rdo = {}; + + rdo.templateUrl = 'foo.html'; + $routeProvider.when('/foo', rdo); + + rdo.templateUrl = 'bar.html'; + $routeProvider.when('/bar', rdo); + }); + + inject(function($location, $rootScope, $route) { + $location.path('/bar'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar'); + expect($route.current.templateUrl).toBe('bar.html'); + + $location.path('/foo'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($route.current.templateUrl).toBe('foo.html'); + }); + } + ); + + + it('should use the property values of the passed in route definition object directly', + function() { + var $routeProvider; + + module(function(_$routeProvider_) { + $routeProvider = _$routeProvider_; + }); + + inject(function($location, $rootScope, $route, $sce) { + var sceWrappedUrl = $sce.trustAsResourceUrl('foo.html'); + $routeProvider.when('/foo', {templateUrl: sceWrappedUrl}); + + $location.path('/foo'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($route.current.templateUrl).toBe(sceWrappedUrl); + }); + } + ); + + + it('should support custom `$sce` implementations', function() { + function MySafeResourceUrl(val) { + var self = this; + this._val = val; + this.getVal = function() { + return (this !== self) ? null : this._val; + }; + } + + var $routeProvider; + + module(function($provide, _$routeProvider_) { + $routeProvider = _$routeProvider_; + + $provide.decorator('$sce', function($delegate) { + function getVal(v) { return v.getVal ? v.getVal() : v; } + $delegate.trustAsResourceUrl = function(url) { return new MySafeResourceUrl(url); }; + $delegate.getTrustedResourceUrl = function(v) { return getVal(v); }; + $delegate.valueOf = function(v) { return getVal(v); }; + return $delegate; + }); + }); + + inject(function($location, $rootScope, $route, $sce) { + $routeProvider.when('/foo', {templateUrl: $sce.trustAsResourceUrl('foo.html')}); + + $location.path('/foo'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($sce.valueOf($route.current.templateUrl)).toBe('foo.html'); + }); + }); + + + describe('redirection', function() { + describe('via `redirectTo`', function() { + it('should support redirection via redirectTo property by updating $location', function() { + module(function($routeProvider) { + $routeProvider.when('/', {redirectTo: '/foo'}); + $routeProvider.when('/foo', {templateUrl: 'foo.html'}); + $routeProvider.when('/bar', {templateUrl: 'bar.html'}); + $routeProvider.when('/baz', {redirectTo: '/bar'}); + $routeProvider.otherwise({templateUrl: '404.html'}); + }); + + inject(function($route, $location, $rootScope) { + var onChangeSpy = jasmine.createSpy('onChange'); + + $rootScope.$on('$routeChangeStart', onChangeSpy); + expect($route.current).toBeUndefined(); + expect(onChangeSpy).not.toHaveBeenCalled(); + + $location.path('/'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($route.current.templateUrl).toBe('foo.html'); + expect(onChangeSpy).toHaveBeenCalledTimes(2); + + onChangeSpy.calls.reset(); + $location.path('/baz'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar'); + expect($route.current.templateUrl).toBe('bar.html'); + expect(onChangeSpy).toHaveBeenCalledTimes(2); + }); + }); + + + it('should interpolate route vars in the redirected path from original path', function() { + module(function($routeProvider) { + $routeProvider.when('/foo/:id/foo/:subid/:extraId', {redirectTo: '/bar/:id/:subid/23'}); + $routeProvider.when('/bar/:id/:subid/:subsubid', {templateUrl: 'bar.html'}); + $routeProvider.when('/baz/:id/:path*', {redirectTo: '/path/:path/:id'}); + $routeProvider.when('/path/:path*/:id', {templateUrl: 'foo.html'}); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo/id1/foo/subid3/gah'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/bar/id1/subid3/23'); + expect($location.search()).toEqual({extraId: 'gah'}); + expect($route.current.templateUrl).toEqual('bar.html'); + + $location.path('/baz/1/foovalue/barvalue'); + $rootScope.$digest(); + expect($location.path()).toEqual('/path/foovalue/barvalue/1'); + expect($route.current.templateUrl).toEqual('foo.html'); + }); + }); + + + it('should interpolate route vars in the redirected path from original search', function() { + module(function($routeProvider) { + $routeProvider.when('/bar/:id/:subid/:subsubid', {templateUrl: 'bar.html'}); + $routeProvider.when('/foo/:id/:extra', {redirectTo: '/bar/:id/:subid/99'}); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo/id3/eId').search('subid=sid1&appended=true'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/bar/id3/sid1/99'); + expect($location.search()).toEqual({appended: 'true', extra: 'eId'}); + expect($route.current.templateUrl).toEqual('bar.html'); + }); + }); + + + it('should properly process route params which are both eager and optional', function() { + module(function($routeProvider) { + $routeProvider.when('/foo/:param1*?/:param2', {templateUrl: 'foo.html'}); + }); + + inject(function($location, $rootScope, $route) { + $location.path('/foo/bar1/bar2/bar3/baz'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/foo/bar1/bar2/bar3/baz'); + expect($route.current.params.param1).toEqual('bar1/bar2/bar3'); + expect($route.current.params.param2).toEqual('baz'); + expect($route.current.templateUrl).toEqual('foo.html'); + + $location.path('/foo/baz'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/foo/baz'); + expect($route.current.params.param1).toEqual(undefined); + expect($route.current.params.param2).toEqual('baz'); + expect($route.current.templateUrl).toEqual('foo.html'); + + }); + }); + + + it('should properly interpolate optional and eager route vars ' + + 'when redirecting from path with trailing slash', function() { + module(function($routeProvider) { + $routeProvider.when('/foo/:id?/:subid?', {templateUrl: 'foo.html'}); + $routeProvider.when('/bar/:id*/:subid', {templateUrl: 'bar.html'}); + }); + + inject(function($location, $rootScope, $route) { + $location.path('/foo/id1/subid2/'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/foo/id1/subid2'); + expect($route.current.templateUrl).toEqual('foo.html'); + + $location.path('/bar/id1/extra/subid2/'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/bar/id1/extra/subid2'); + expect($route.current.templateUrl).toEqual('bar.html'); + }); + }); + + + it('should allow custom redirectTo function to be used', function() { + function customRedirectFn(routePathParams, path, search) { + expect(routePathParams).toEqual({id: 'id3'}); + expect(path).toEqual('/foo/id3'); + expect(search).toEqual({subid: 'sid1', appended: 'true'}); + return '/custom'; + } + + module(function($routeProvider) { + $routeProvider.when('/foo/:id', {redirectTo: customRedirectFn}); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo/id3').search('subid=sid1&appended=true'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/custom'); + }); + }); + + + it('should broadcast `$routeChangeError` when redirectTo throws', function() { + var error = new Error('Test'); + + module(function($routeProvider) { + $routeProvider.when('/foo', {redirectTo: function() { throw error; }}); + }); + + inject(function($exceptionHandler, $location, $rootScope, $route) { + spyOn($rootScope, '$broadcast').and.callThrough(); + + $location.path('/foo'); + $rootScope.$digest(); + + var lastCallArgs = $rootScope.$broadcast.calls.mostRecent().args; + expect(lastCallArgs[0]).toBe('$routeChangeError'); + expect(lastCallArgs[3]).toBe(error); + }); + }); + + + it('should replace the url when redirecting', function() { + module(function($routeProvider) { + $routeProvider.when('/bar/:id', {templateUrl: 'bar.html'}); + $routeProvider.when('/foo/:id/:extra', {redirectTo: '/bar/:id'}); + }); + inject(function($browser, $route, $location, $rootScope) { + var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').and.callThrough(); + + $location.path('/foo/id3/eId'); + $rootScope.$digest(); + + expect($location.path()).toEqual('/bar/id3'); + expect($browserUrl.calls.mostRecent().args) + .toEqual(['http://server/#!/bar/id3?extra=eId', true, null]); + }); + }); + + + it('should not process route bits', function() { + var firstController = jasmine.createSpy('first controller spy'); + var firstTemplate = jasmine.createSpy('first template spy').and.returnValue('redirected view'); + var firstResolve = jasmine.createSpy('first resolve spy'); + var secondController = jasmine.createSpy('second controller spy'); + var secondTemplate = jasmine.createSpy('second template spy').and.returnValue('redirected view'); + var secondResolve = jasmine.createSpy('second resolve spy'); + module(function($routeProvider) { + $routeProvider.when('/redirect', { + template: firstTemplate, + redirectTo: '/redirected', + resolve: { value: firstResolve }, + controller: firstController + }); + $routeProvider.when('/redirected', { + template: secondTemplate, + resolve: { value: secondResolve }, + controller: secondController + }); + }); + inject(function($route, $location, $rootScope, $compile) { + var element = $compile('
')($rootScope); + $location.path('/redirect'); + $rootScope.$digest(); + + expect(firstController).not.toHaveBeenCalled(); + expect(firstTemplate).not.toHaveBeenCalled(); + expect(firstResolve).not.toHaveBeenCalled(); + + expect(secondController).toHaveBeenCalled(); + expect(secondTemplate).toHaveBeenCalled(); + expect(secondResolve).toHaveBeenCalled(); + + dealoc(element); + }); + }); + + + it('should not redirect transition if `redirectTo` returns `undefined`', function() { + var controller = jasmine.createSpy('first controller spy'); + var templateFn = jasmine.createSpy('first template spy').and.returnValue('redirected view'); + module(function($routeProvider) { + $routeProvider.when('/redirect/to/undefined', { + template: templateFn, + redirectTo: function() {}, + controller: controller + }); + }); + inject(function($route, $location, $rootScope, $compile) { + var element = $compile('
')($rootScope); + $location.path('/redirect/to/undefined'); + $rootScope.$digest(); + expect(controller).toHaveBeenCalled(); + expect(templateFn).toHaveBeenCalled(); + expect($location.path()).toEqual('/redirect/to/undefined'); + dealoc(element); + }); + }); + }); + + describe('via `resolveRedirectTo`', function() { + var $compile; + var $location; + var $rootScope; + var $route; + + beforeEach(module(function() { + return function(_$compile_, _$location_, _$rootScope_, _$route_) { + $compile = _$compile_; + $location = _$location_; + $rootScope = _$rootScope_; + $route = _$route_; + }; + })); + + + it('should be ignored if `redirectTo` is also present', function() { + var newUrl; + var getNewUrl = function() { return newUrl; }; + + var resolveRedirectToSpy = jasmine.createSpy('resolveRedirectTo').and.returnValue('/bar'); + var redirectToSpy = jasmine.createSpy('redirectTo').and.callFake(getNewUrl); + var templateSpy = jasmine.createSpy('template').and.returnValue('Foo'); + + module(function($routeProvider) { + $routeProvider. + when('/foo', { + resolveRedirectTo: resolveRedirectToSpy, + redirectTo: redirectToSpy, + template: templateSpy + }). + when('/bar', {template: 'Bar'}). + when('/baz', {template: 'Baz'}); + }); + + inject(function() { + newUrl = '/baz'; + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/baz'); + expect($route.current.template).toBe('Baz'); + expect(resolveRedirectToSpy).not.toHaveBeenCalled(); + expect(redirectToSpy).toHaveBeenCalled(); + expect(templateSpy).not.toHaveBeenCalled(); + + redirectToSpy.calls.reset(); + + newUrl = undefined; + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/foo'); + expect($route.current.template).toBe(templateSpy); + expect(resolveRedirectToSpy).not.toHaveBeenCalled(); + expect(redirectToSpy).toHaveBeenCalled(); + expect(templateSpy).toHaveBeenCalled(); + }); + }); + + + it('should redirect to the returned url', function() { + module(function($routeProvider) { + $routeProvider. + when('/foo', {resolveRedirectTo: function() { return '/bar?baz=qux'; }}). + when('/bar', {template: 'Bar'}); + }); + + inject(function() { + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/bar'); + expect($location.search()).toEqual({baz: 'qux'}); + expect($route.current.template).toBe('Bar'); + }); + }); + + + it('should support returning a promise', function() { + module(function($routeProvider) { + $routeProvider. + when('/foo', {resolveRedirectTo: function($q) { return $q.resolve('/bar'); }}). + when('/bar', {template: 'Bar'}); + }); + + inject(function() { + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/bar'); + expect($route.current.template).toBe('Bar'); + }); + }); + + + it('should support dependency injection', function() { + module(function($provide, $routeProvider) { + $provide.value('nextRoute', '/bar'); + + $routeProvider. + when('/foo', { + resolveRedirectTo: function(nextRoute) { + return nextRoute; + } + }); + }); + + inject(function() { + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/bar'); + }); + }); + + + it('should have access to the current routeParams via `$route.current.params`', function() { + module(function($routeProvider) { + $routeProvider. + when('/foo/:bar/baz/:qux', { + resolveRedirectTo: function($route) { + expect($route.current.params).toEqual(jasmine.objectContaining({ + bar: '1', + qux: '2' + })); + + return '/passed'; + } + }); + }); + + inject(function() { + $location.path('/foo/1/baz/2').search({bar: 'qux'}); + $rootScope.$digest(); + + expect($location.path()).toBe('/passed'); + }); + }); + + + it('should not process route bits until the promise is resolved', function() { + var spies = createSpies(); + var called = false; + var deferred; + + module(function($routeProvider) { + setupRoutes($routeProvider, spies, function($q) { + called = true; + deferred = $q.defer(); + return deferred.promise; + }); + }); + + inject(function() { + var element = $compile('
')($rootScope); + + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/foo'); + expect(called).toBe(true); + expect(spies.fooResolveSpy).not.toHaveBeenCalled(); + expect(spies.fooTemplateSpy).not.toHaveBeenCalled(); + expect(spies.fooControllerSpy).not.toHaveBeenCalled(); + expect(spies.barResolveSpy).not.toHaveBeenCalled(); + expect(spies.barTemplateSpy).not.toHaveBeenCalled(); + expect(spies.barControllerSpy).not.toHaveBeenCalled(); + + deferred.resolve('/bar'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar'); + expect(spies.fooResolveSpy).not.toHaveBeenCalled(); + expect(spies.fooTemplateSpy).not.toHaveBeenCalled(); + expect(spies.fooControllerSpy).not.toHaveBeenCalled(); + expect(spies.barResolveSpy).toHaveBeenCalled(); + expect(spies.barTemplateSpy).toHaveBeenCalled(); + expect(spies.barControllerSpy).toHaveBeenCalled(); + + dealoc(element); + }); + }); + + + it('should not redirect if `undefined` is returned', function() { + var spies = createSpies(); + var called = false; + + module(function($routeProvider) { + setupRoutes($routeProvider, spies, function() { + called = true; + return undefined; + }); + }); + + inject(function() { + var element = $compile('
')($rootScope); + + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/foo'); + expect(called).toBe(true); + expect(spies.fooResolveSpy).toHaveBeenCalled(); + expect(spies.fooTemplateSpy).toHaveBeenCalled(); + expect(spies.fooControllerSpy).toHaveBeenCalled(); + expect(spies.barResolveSpy).not.toHaveBeenCalled(); + expect(spies.barTemplateSpy).not.toHaveBeenCalled(); + expect(spies.barControllerSpy).not.toHaveBeenCalled(); + + dealoc(element); + }); + }); + + + it('should not redirect if the returned promise resolves to `undefined`', function() { + var spies = createSpies(); + var called = false; + + module(function($routeProvider) { + setupRoutes($routeProvider, spies, function($q) { + called = true; + return $q.resolve(undefined); + }); + }); + + inject(function() { + var element = $compile('
')($rootScope); + + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/foo'); + expect(called).toBe(true); + expect(spies.fooResolveSpy).toHaveBeenCalled(); + expect(spies.fooTemplateSpy).toHaveBeenCalled(); + expect(spies.fooControllerSpy).toHaveBeenCalled(); + expect(spies.barResolveSpy).not.toHaveBeenCalled(); + expect(spies.barTemplateSpy).not.toHaveBeenCalled(); + expect(spies.barControllerSpy).not.toHaveBeenCalled(); + + dealoc(element); + }); + }); + + + it('should not redirect if the returned promise gets rejected', function() { + var spies = createSpies(); + var called = false; + + module(function($routeProvider) { + setupRoutes($routeProvider, spies, function($q) { + called = true; + return $q.reject(''); + }); + }); + + inject(function() { + spyOn($rootScope, '$broadcast').and.callThrough(); + + var element = $compile('
')($rootScope); + + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/foo'); + expect(called).toBe(true); + expect(spies.fooResolveSpy).not.toHaveBeenCalled(); + expect(spies.fooTemplateSpy).not.toHaveBeenCalled(); + expect(spies.fooControllerSpy).not.toHaveBeenCalled(); + expect(spies.barResolveSpy).not.toHaveBeenCalled(); + expect(spies.barTemplateSpy).not.toHaveBeenCalled(); + expect(spies.barControllerSpy).not.toHaveBeenCalled(); + + var lastCallArgs = $rootScope.$broadcast.calls.mostRecent().args; + expect(lastCallArgs[0]).toBe('$routeChangeError'); + + dealoc(element); + }); + }); + + + it('should ignore previous redirection if newer transition happened', function() { + var spies = createSpies(); + var called = false; + var deferred; + + module(function($routeProvider) { + setupRoutes($routeProvider, spies, function($q) { + called = true; + deferred = $q.defer(); + return deferred.promise; + }); + }); + + inject(function() { + spyOn($location, 'url').and.callThrough(); + + var element = $compile('
')($rootScope); + + $location.path('/foo'); + $rootScope.$digest(); + + expect($location.path()).toBe('/foo'); + expect(called).toBe(true); + expect(spies.fooResolveSpy).not.toHaveBeenCalled(); + expect(spies.fooTemplateSpy).not.toHaveBeenCalled(); + expect(spies.fooControllerSpy).not.toHaveBeenCalled(); + expect(spies.barResolveSpy).not.toHaveBeenCalled(); + expect(spies.barTemplateSpy).not.toHaveBeenCalled(); + expect(spies.barControllerSpy).not.toHaveBeenCalled(); + expect(spies.bazResolveSpy).not.toHaveBeenCalled(); + expect(spies.bazTemplateSpy).not.toHaveBeenCalled(); + expect(spies.bazControllerSpy).not.toHaveBeenCalled(); + + $location.path('/baz'); + $rootScope.$digest(); + + expect($location.path()).toBe('/baz'); + expect(spies.fooResolveSpy).not.toHaveBeenCalled(); + expect(spies.fooTemplateSpy).not.toHaveBeenCalled(); + expect(spies.fooControllerSpy).not.toHaveBeenCalled(); + expect(spies.barResolveSpy).not.toHaveBeenCalled(); + expect(spies.barTemplateSpy).not.toHaveBeenCalled(); + expect(spies.barControllerSpy).not.toHaveBeenCalled(); + expect(spies.bazResolveSpy).toHaveBeenCalledOnce(); + expect(spies.bazTemplateSpy).toHaveBeenCalledOnce(); + expect(spies.bazControllerSpy).toHaveBeenCalledOnce(); + + deferred.resolve(); + $rootScope.$digest(); + + expect($location.path()).toBe('/baz'); + expect(spies.fooResolveSpy).not.toHaveBeenCalled(); + expect(spies.fooTemplateSpy).not.toHaveBeenCalled(); + expect(spies.fooControllerSpy).not.toHaveBeenCalled(); + expect(spies.barResolveSpy).not.toHaveBeenCalled(); + expect(spies.barTemplateSpy).not.toHaveBeenCalled(); + expect(spies.barControllerSpy).not.toHaveBeenCalled(); + expect(spies.bazResolveSpy).toHaveBeenCalledOnce(); + expect(spies.bazTemplateSpy).toHaveBeenCalledOnce(); + expect(spies.bazControllerSpy).toHaveBeenCalledOnce(); + + dealoc(element); + }); + }); + + + // Helpers + function createSpies() { + return { + fooResolveSpy: jasmine.createSpy('fooResolve'), + fooTemplateSpy: jasmine.createSpy('fooTemplate').and.returnValue('Foo'), + fooControllerSpy: jasmine.createSpy('fooController'), + barResolveSpy: jasmine.createSpy('barResolve'), + barTemplateSpy: jasmine.createSpy('barTemplate').and.returnValue('Bar'), + barControllerSpy: jasmine.createSpy('barController'), + bazResolveSpy: jasmine.createSpy('bazResolve'), + bazTemplateSpy: jasmine.createSpy('bazTemplate').and.returnValue('Baz'), + bazControllerSpy: jasmine.createSpy('bazController') + }; + } + + function setupRoutes(routeProvider, spies, resolveRedirectToFn) { + routeProvider. + when('/foo', { + resolveRedirectTo: resolveRedirectToFn, + resolve: {_: spies.fooResolveSpy}, + template: spies.fooTemplateSpy, + controller: spies.fooControllerSpy + }). + when('/bar', { + resolve: {_: spies.barResolveSpy}, + template: spies.barTemplateSpy, + controller: spies.barControllerSpy + }). + when('/baz', { + resolve: {_: spies.bazResolveSpy}, + template: spies.bazTemplateSpy, + controller: spies.bazControllerSpy + }); + } + }); + }); + + + describe('reloadOnUrl', function() { + it('should reload when `reloadOnUrl` is true and `.url()` changes', function() { + var routeChange = jasmine.createSpy('routeChange'); + + module(function($routeProvider) { + $routeProvider.when('/path/:param', {}); + }); + + inject(function($location, $rootScope, $routeParams) { + $rootScope.$on('$routeChangeStart', routeChange); + + // Initial load + $location.path('/path/foo'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({param: 'foo'}); + + routeChange.calls.reset(); + + // Reload on `path` change + $location.path('/path/bar'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({param: 'bar'}); + + routeChange.calls.reset(); + + // Reload on `search` change + $location.search('foo', 'bar'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({param: 'bar', foo: 'bar'}); + + routeChange.calls.reset(); + + // Reload on `hash` change + $location.hash('baz'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({param: 'bar', foo: 'bar'}); + }); + }); + + + it('should reload when `reloadOnUrl` is false and URL maps to different route', + function() { + var routeChange = jasmine.createSpy('routeChange'); + var routeUpdate = jasmine.createSpy('routeUpdate'); + + module(function($routeProvider) { + $routeProvider. + when('/path/:param', {reloadOnUrl: false}). + otherwise({}); + }); + + inject(function($location, $rootScope, $routeParams) { + $rootScope.$on('$routeChangeStart', routeChange); + $rootScope.$on('$routeChangeSuccess', routeChange); + $rootScope.$on('$routeUpdate', routeUpdate); + + expect(routeChange).not.toHaveBeenCalled(); + + // Initial load + $location.path('/path/foo'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledTimes(2); + expect(routeUpdate).not.toHaveBeenCalled(); + expect($routeParams).toEqual({param: 'foo'}); + + routeChange.calls.reset(); + + // Route change + $location.path('/other/path/bar'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledTimes(2); + expect(routeUpdate).not.toHaveBeenCalled(); + expect($routeParams).toEqual({}); + }); + } + ); + + + it('should not reload when `reloadOnUrl` is false and URL maps to the same route', + function() { + var routeChange = jasmine.createSpy('routeChange'); + var routeUpdate = jasmine.createSpy('routeUpdate'); + + module(function($routeProvider) { + $routeProvider.when('/path/:param', {reloadOnUrl: false}); + }); + + inject(function($location, $rootScope, $routeParams) { + $rootScope.$on('$routeChangeStart', routeChange); + $rootScope.$on('$routeChangeSuccess', routeChange); + $rootScope.$on('$routeUpdate', routeUpdate); + + expect(routeChange).not.toHaveBeenCalled(); + + // Initial load + $location.path('/path/foo'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledTimes(2); + expect(routeUpdate).not.toHaveBeenCalled(); + expect($routeParams).toEqual({param: 'foo'}); + + routeChange.calls.reset(); + + // Route update (no reload) + $location.path('/path/bar').search('foo', 'bar').hash('baz'); + $rootScope.$digest(); + expect(routeChange).not.toHaveBeenCalled(); + expect(routeUpdate).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({param: 'bar', foo: 'bar'}); + }); + } + ); + + + it('should update `$routeParams` even when not reloading a route', function() { + var routeChange = jasmine.createSpy('routeChange'); + + module(function($routeProvider) { + $routeProvider.when('/path/:param', {reloadOnUrl: false}); + }); + + inject(function($location, $rootScope, $routeParams) { + $rootScope.$on('$routeChangeStart', routeChange); + $rootScope.$on('$routeChangeSuccess', routeChange); + + expect(routeChange).not.toHaveBeenCalled(); + + // Initial load + $location.path('/path/foo'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledTimes(2); + expect($routeParams).toEqual({param: 'foo'}); + + routeChange.calls.reset(); + + // Route update (no reload) + $location.path('/path/bar'); + $rootScope.$digest(); + expect(routeChange).not.toHaveBeenCalled(); + expect($routeParams).toEqual({param: 'bar'}); + }); + }); + + + describe('with `$route.reload()`', function() { + var $location; + var $log; + var $rootScope; + var $route; + var routeChangeStart; + var routeChangeSuccess; + + beforeEach(module(function($routeProvider) { + $routeProvider.when('/path/:param', { + template: '', + reloadOnUrl: false, + controller: function Controller($log) { + $log.debug('initialized'); + } + }); + })); + + beforeEach(inject(function($compile, _$location_, _$log_, _$rootScope_, _$route_) { + $location = _$location_; + $log = _$log_; + $rootScope = _$rootScope_; + $route = _$route_; + + routeChangeStart = jasmine.createSpy('routeChangeStart'); + routeChangeSuccess = jasmine.createSpy('routeChangeSuccess'); + + $rootScope.$on('$routeChangeStart', routeChangeStart); + $rootScope.$on('$routeChangeSuccess', routeChangeSuccess); + + element = $compile('
')($rootScope); + })); + + + it('should reload the current route', function() { + $location.path('/path/foo'); + $rootScope.$digest(); + expect($location.path()).toBe('/path/foo'); + expect(routeChangeStart).toHaveBeenCalledOnce(); + expect(routeChangeSuccess).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + routeChangeStart.calls.reset(); + routeChangeSuccess.calls.reset(); + $log.reset(); + + $route.reload(); + $rootScope.$digest(); + expect($location.path()).toBe('/path/foo'); + expect(routeChangeStart).toHaveBeenCalledOnce(); + expect(routeChangeSuccess).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + $log.reset(); + }); + + + it('should support preventing a route reload', function() { + $location.path('/path/foo'); + $rootScope.$digest(); + expect($location.path()).toBe('/path/foo'); + expect(routeChangeStart).toHaveBeenCalledOnce(); + expect(routeChangeSuccess).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + routeChangeStart.calls.reset(); + routeChangeSuccess.calls.reset(); + $log.reset(); + + routeChangeStart.and.callFake(function(evt) { evt.preventDefault(); }); + + $route.reload(); + $rootScope.$digest(); + expect($location.path()).toBe('/path/foo'); + expect(routeChangeStart).toHaveBeenCalledOnce(); + expect(routeChangeSuccess).not.toHaveBeenCalled(); + expect($log.debug.logs).toEqual([]); + }); + + + it('should reload the current route even if `reloadOnUrl` is disabled', + inject(function($routeParams) { + $location.path('/path/foo'); + $rootScope.$digest(); + expect(routeChangeStart).toHaveBeenCalledOnce(); + expect(routeChangeSuccess).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + expect($routeParams).toEqual({param: 'foo'}); + + routeChangeStart.calls.reset(); + routeChangeSuccess.calls.reset(); + $log.reset(); + + $location.path('/path/bar'); + $rootScope.$digest(); + expect(routeChangeStart).not.toHaveBeenCalled(); + expect(routeChangeSuccess).not.toHaveBeenCalled(); + expect($log.debug.logs).toEqual([]); + expect($routeParams).toEqual({param: 'bar'}); + + $route.reload(); + $rootScope.$digest(); + expect(routeChangeStart).toHaveBeenCalledOnce(); + expect(routeChangeSuccess).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + expect($routeParams).toEqual({param: 'bar'}); + + $log.reset(); + }) + ); + }); + }); + + describe('reloadOnSearch', function() { + it('should not have any effect if `reloadOnUrl` is false', function() { + var reloaded = jasmine.createSpy('route reload'); + + module(function($routeProvider) { + $routeProvider.when('/foo', { + reloadOnUrl: false, + reloadOnSearch: true + }); + }); + + inject(function($route, $location, $rootScope, $routeParams) { + $rootScope.$on('$routeChangeStart', reloaded); + + $location.path('/foo'); + $rootScope.$digest(); + expect(reloaded).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({}); + + reloaded.calls.reset(); + + // trigger reload (via .search()) + $location.search({foo: 'bar'}); + $rootScope.$digest(); + expect(reloaded).not.toHaveBeenCalled(); + expect($routeParams).toEqual({foo: 'bar'}); + + // trigger reload (via .hash()) + $location.hash('baz'); + $rootScope.$digest(); + expect(reloaded).not.toHaveBeenCalled(); + expect($routeParams).toEqual({foo: 'bar'}); + }); + }); + + + it('should reload when `reloadOnSearch` is true and `.search()`/`.hash()` changes', + function() { + var reloaded = jasmine.createSpy('route reload'); + + module(function($routeProvider) { + $routeProvider.when('/foo', {controller: angular.noop}); + }); + + inject(function($route, $location, $rootScope, $routeParams) { + $rootScope.$on('$routeChangeStart', reloaded); + + $location.path('/foo'); + $rootScope.$digest(); + expect(reloaded).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({}); + + reloaded.calls.reset(); + + // trigger reload (via .search()) + $location.search({foo: 'bar'}); + $rootScope.$digest(); + expect(reloaded).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({foo: 'bar'}); + + reloaded.calls.reset(); + + // trigger reload (via .hash()) + $location.hash('baz'); + $rootScope.$digest(); + expect(reloaded).toHaveBeenCalledOnce(); + expect($routeParams).toEqual({foo: 'bar'}); + }); + } + ); + + + it('should not reload when `reloadOnSearch` is false and `.search()`/`.hash()` changes', + function() { + var routeChange = jasmine.createSpy('route change'), + routeUpdate = jasmine.createSpy('route update'); + + module(function($routeProvider) { + $routeProvider.when('/foo', {controller: angular.noop, reloadOnSearch: false}); + }); + + inject(function($route, $location, $rootScope) { + $rootScope.$on('$routeChangeStart', routeChange); + $rootScope.$on('$routeChangeSuccess', routeChange); + $rootScope.$on('$routeUpdate', routeUpdate); + + expect(routeChange).not.toHaveBeenCalled(); + + $location.path('/foo'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledTimes(2); + expect(routeUpdate).not.toHaveBeenCalled(); + + routeChange.calls.reset(); + + // don't trigger reload (via .search()) + $location.search({foo: 'bar'}); + $rootScope.$digest(); + expect(routeChange).not.toHaveBeenCalled(); + expect(routeUpdate).toHaveBeenCalledOnce(); + + routeUpdate.calls.reset(); + + // don't trigger reload (via .hash()) + $location.hash('baz'); + $rootScope.$digest(); + expect(routeChange).not.toHaveBeenCalled(); + expect(routeUpdate).toHaveBeenCalled(); + }); + } + ); + + + it('should reload when `reloadOnSearch` is false and url differs only in route path param', + function() { + var routeChange = jasmine.createSpy('route change'); + + module(function($routeProvider) { + $routeProvider.when('/foo/:fooId', {controller: angular.noop, reloadOnSearch: false}); + }); + + inject(function($route, $location, $rootScope) { + $rootScope.$on('$routeChangeStart', routeChange); + $rootScope.$on('$routeChangeSuccess', routeChange); + + expect(routeChange).not.toHaveBeenCalled(); + + $location.path('/foo/aaa'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledTimes(2); + routeChange.calls.reset(); + + $location.path('/foo/bbb'); + $rootScope.$digest(); + expect(routeChange).toHaveBeenCalledTimes(2); + routeChange.calls.reset(); + + $location.search({foo: 'bar'}).hash('baz'); + $rootScope.$digest(); + expect(routeChange).not.toHaveBeenCalled(); + }); + } + ); + + + it('should update params when `reloadOnSearch` is false and `.search()` changes', function() { + var routeParamsWatcher = jasmine.createSpy('routeParamsWatcher'); + + module(function($routeProvider) { + $routeProvider.when('/foo', {controller: angular.noop}); + $routeProvider.when('/bar/:barId', {controller: angular.noop, reloadOnSearch: false}); + }); + + inject(function($route, $location, $rootScope, $routeParams) { + $rootScope.$watch(function() { + return $routeParams; + }, function(value) { + routeParamsWatcher(value); + }, true); + + expect(routeParamsWatcher).not.toHaveBeenCalled(); + + $location.path('/foo'); + $rootScope.$digest(); + expect(routeParamsWatcher).toHaveBeenCalledWith({}); + routeParamsWatcher.calls.reset(); + + // trigger reload + $location.search({foo: 'bar'}); + $rootScope.$digest(); + expect(routeParamsWatcher).toHaveBeenCalledWith({foo: 'bar'}); + routeParamsWatcher.calls.reset(); + + $location.path('/bar/123').search({}); + $rootScope.$digest(); + expect(routeParamsWatcher).toHaveBeenCalledWith({barId: '123'}); + routeParamsWatcher.calls.reset(); + + // don't trigger reload + $location.search({foo: 'bar'}); + $rootScope.$digest(); + expect(routeParamsWatcher).toHaveBeenCalledWith({barId: '123', foo: 'bar'}); + }); + }); + + + it('should allow using a function as a template', function() { + var customTemplateWatcher = jasmine.createSpy('customTemplateWatcher'); + + function customTemplateFn(routePathParams) { + customTemplateWatcher(routePathParams); + expect(routePathParams).toEqual({id: 'id3'}); + return '

' + routePathParams.id + '

'; + } + + module(function($routeProvider) { + $routeProvider.when('/bar/:id/:subid/:subsubid', {templateUrl: 'bar.html'}); + $routeProvider.when('/foo/:id', {template: customTemplateFn}); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo/id3'); + $rootScope.$digest(); + + expect(customTemplateWatcher).toHaveBeenCalledWith({id: 'id3'}); + }); + }); + + + it('should allow using a function as a templateUrl', function() { + var customTemplateUrlWatcher = jasmine.createSpy('customTemplateUrlWatcher'); + + function customTemplateUrlFn(routePathParams) { + customTemplateUrlWatcher(routePathParams); + expect(routePathParams).toEqual({id: 'id3'}); + return 'foo.html'; + } + + module(function($routeProvider) { + $routeProvider.when('/bar/:id/:subid/:subsubid', {templateUrl: 'bar.html'}); + $routeProvider.when('/foo/:id', {templateUrl: customTemplateUrlFn}); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo/id3'); + $rootScope.$digest(); + + expect(customTemplateUrlWatcher).toHaveBeenCalledWith({id: 'id3'}); + expect($route.current.loadedTemplateUrl).toEqual('foo.html'); + }); + }); + + + describe('with `$route.reload()`', function() { + var $location; + var $log; + var $rootScope; + var $route; + var routeChangeStartSpy; + var routeChangeSuccessSpy; + + beforeEach(module(function($routeProvider) { + $routeProvider.when('/bar/:barId', { + template: '', + controller: controller, + reloadOnSearch: false + }); + + function controller($log) { + $log.debug('initialized'); + } + })); + beforeEach(inject(function($compile, _$location_, _$log_, _$rootScope_, _$route_) { + $location = _$location_; + $log = _$log_; + $rootScope = _$rootScope_; + $route = _$route_; + + routeChangeStartSpy = jasmine.createSpy('routeChangeStart'); + routeChangeSuccessSpy = jasmine.createSpy('routeChangeSuccess'); + + $rootScope.$on('$routeChangeStart', routeChangeStartSpy); + $rootScope.$on('$routeChangeSuccess', routeChangeSuccessSpy); + + element = $compile('
')($rootScope); + })); + + + it('should reload the current route', function() { + $location.path('/bar/123'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/123'); + expect(routeChangeStartSpy).toHaveBeenCalledOnce(); + expect(routeChangeSuccessSpy).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + routeChangeStartSpy.calls.reset(); + routeChangeSuccessSpy.calls.reset(); + $log.reset(); + + $route.reload(); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/123'); + expect(routeChangeStartSpy).toHaveBeenCalledOnce(); + expect(routeChangeSuccessSpy).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + $log.reset(); + }); + + + it('should support preventing a route reload', function() { + $location.path('/bar/123'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/123'); + expect(routeChangeStartSpy).toHaveBeenCalledOnce(); + expect(routeChangeSuccessSpy).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + routeChangeStartSpy.calls.reset(); + routeChangeSuccessSpy.calls.reset(); + $log.reset(); + + routeChangeStartSpy.and.callFake(function(evt) { evt.preventDefault(); }); + + $route.reload(); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/123'); + expect(routeChangeStartSpy).toHaveBeenCalledOnce(); + expect(routeChangeSuccessSpy).not.toHaveBeenCalled(); + expect($log.debug.logs).toEqual([]); + }); + + + it('should reload even if reloadOnSearch is false', inject(function($routeParams) { + $location.path('/bar/123'); + $rootScope.$digest(); + expect($routeParams).toEqual({barId: '123'}); + expect(routeChangeSuccessSpy).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + routeChangeSuccessSpy.calls.reset(); + $log.reset(); + + $location.search('a=b'); + $rootScope.$digest(); + expect($routeParams).toEqual({barId: '123', a: 'b'}); + expect(routeChangeSuccessSpy).not.toHaveBeenCalled(); + expect($log.debug.logs).toEqual([]); + + routeChangeSuccessSpy.calls.reset(); + $log.reset(); + + $location.hash('c'); + $rootScope.$digest(); + expect($routeParams).toEqual({barId: '123', a: 'b'}); + expect(routeChangeSuccessSpy).not.toHaveBeenCalled(); + expect($log.debug.logs).toEqual([]); + + $route.reload(); + $rootScope.$digest(); + expect($routeParams).toEqual({barId: '123', a: 'b'}); + expect(routeChangeSuccessSpy).toHaveBeenCalledOnce(); + expect($log.debug.logs).toEqual([['initialized']]); + + $log.reset(); + })); + }); + }); + + describe('update', function() { + it('should support single-parameter route updating', function() { + var routeChangeSpy = jasmine.createSpy('route change'); + + module(function($routeProvider) { + $routeProvider.when('/bar/:barId', {controller: angular.noop}); + }); + + inject(function($route, $routeParams, $location, $rootScope) { + $rootScope.$on('$routeChangeSuccess', routeChangeSpy); + + $location.path('/bar/1'); + $rootScope.$digest(); + routeChangeSpy.calls.reset(); + + $route.updateParams({barId: '2'}); + $rootScope.$digest(); + + expect($routeParams).toEqual({barId: '2'}); + expect(routeChangeSpy).toHaveBeenCalledOnce(); + expect($location.path()).toEqual('/bar/2'); + }); + }); + + it('should support total multi-parameter route updating', function() { + var routeChangeSpy = jasmine.createSpy('route change'); + + module(function($routeProvider) { + $routeProvider.when('/bar/:barId/:fooId/:spamId/:eggId', {controller: angular.noop}); + }); + + inject(function($route, $routeParams, $location, $rootScope) { + $rootScope.$on('$routeChangeSuccess', routeChangeSpy); + + $location.path('/bar/1/2/3/4'); + $rootScope.$digest(); + routeChangeSpy.calls.reset(); + + $route.updateParams({barId: '5', fooId: '6', spamId: '7', eggId: '8'}); + $rootScope.$digest(); + + expect($routeParams).toEqual({barId: '5', fooId: '6', spamId: '7', eggId: '8'}); + expect(routeChangeSpy).toHaveBeenCalledOnce(); + expect($location.path()).toEqual('/bar/5/6/7/8'); + }); + }); + + it('should support partial multi-parameter route updating', function() { + var routeChangeSpy = jasmine.createSpy('route change'); + + module(function($routeProvider) { + $routeProvider.when('/bar/:barId/:fooId/:spamId/:eggId', {controller: angular.noop}); + }); + + inject(function($route, $routeParams, $location, $rootScope) { + $rootScope.$on('$routeChangeSuccess', routeChangeSpy); + + $location.path('/bar/1/2/3/4'); + $rootScope.$digest(); + routeChangeSpy.calls.reset(); + + $route.updateParams({barId: '5', fooId: '6'}); + $rootScope.$digest(); + + expect($routeParams).toEqual({barId: '5', fooId: '6', spamId: '3', eggId: '4'}); + expect(routeChangeSpy).toHaveBeenCalledOnce(); + expect($location.path()).toEqual('/bar/5/6/3/4'); + }); + }); + + + it('should update query params when new properties are not in path', function() { + var routeChangeSpy = jasmine.createSpy('route change'); + + module(function($routeProvider) { + $routeProvider.when('/bar/:barId/:fooId/:spamId/', {controller: angular.noop}); + }); + + inject(function($route, $routeParams, $location, $rootScope) { + $rootScope.$on('$routeChangeSuccess', routeChangeSpy); + + $location.path('/bar/1/2/3'); + $location.search({initial: 'true'}); + $rootScope.$digest(); + routeChangeSpy.calls.reset(); + + $route.updateParams({barId: '5', fooId: '6', eggId: '4'}); + $rootScope.$digest(); + + expect($routeParams).toEqual({barId: '5', fooId: '6', spamId: '3', eggId: '4', initial: 'true'}); + expect(routeChangeSpy).toHaveBeenCalledOnce(); + expect($location.path()).toEqual('/bar/5/6/3/'); + expect($location.search()).toEqual({eggId: '4', initial: 'true'}); + }); + }); + + it('should not update query params when an optional property was previously not in path', function() { + var routeChangeSpy = jasmine.createSpy('route change'); + + module(function($routeProvider) { + $routeProvider.when('/bar/:barId/:fooId/:spamId/:eggId?', {controller: angular.noop}); + }); + + inject(function($route, $routeParams, $location, $rootScope) { + $rootScope.$on('$routeChangeSuccess', routeChangeSpy); + + $location.path('/bar/1/2/3'); + $location.search({initial: 'true'}); + $rootScope.$digest(); + routeChangeSpy.calls.reset(); + + $route.updateParams({barId: '5', fooId: '6', eggId: '4'}); + $rootScope.$digest(); + + expect($routeParams).toEqual({barId: '5', fooId: '6', spamId: '3', eggId: '4', initial: 'true'}); + expect(routeChangeSpy).toHaveBeenCalledOnce(); + expect($location.path()).toEqual('/bar/5/6/3/4'); + expect($location.search()).toEqual({initial: 'true'}); + }); + }); + + it('should complain if called without an existing route', inject(function($route) { + expect(function() { $route.updateParams(); }).toThrowMinErr('ngRoute', 'norout'); + })); + }); + + describe('testability', function() { + it('should wait for $resolve promises before calling callbacks', function() { + var deferred; + + module(function($routeProvider) { + $routeProvider.when('/path', { + resolve: { + a: function($q) { + deferred = $q.defer(); + return deferred.promise; + } + } + }); + }); + + inject(function($browser, $location, $rootScope, $$testability) { + $location.path('/path'); + $rootScope.$digest(); + + var callback = jasmine.createSpy('callback'); + $$testability.whenStable(callback); + expect(callback).not.toHaveBeenCalled(); + + deferred.resolve(); + $browser.defer.flush(); + expect(callback).toHaveBeenCalled(); + }); + }); + + it('should call callback after $resolve promises are rejected', function() { + var deferred; + + module(function($routeProvider) { + $routeProvider.when('/path', { + resolve: { + a: function($q) { + deferred = $q.defer(); + return deferred.promise; + } + } + }); + }); + + inject(function($browser, $location, $rootScope, $$testability) { + $location.path('/path'); + $rootScope.$digest(); + + var callback = jasmine.createSpy('callback'); + $$testability.whenStable(callback); + expect(callback).not.toHaveBeenCalled(); + + deferred.reject(); + $browser.defer.flush(); + expect(callback).toHaveBeenCalled(); + }); + }); + + it('should wait for resolveRedirectTo promises before calling callbacks', function() { + var deferred; + + module(function($routeProvider) { + $routeProvider.when('/path', { + resolveRedirectTo: function($q) { + deferred = $q.defer(); + return deferred.promise; + } + }); + }); + + inject(function($browser, $location, $rootScope, $$testability) { + $location.path('/path'); + $rootScope.$digest(); + + var callback = jasmine.createSpy('callback'); + $$testability.whenStable(callback); + expect(callback).not.toHaveBeenCalled(); + + deferred.resolve(); + $browser.defer.flush(); + expect(callback).toHaveBeenCalled(); + }); + }); + + it('should call callback after resolveRedirectTo promises are rejected', function() { + var deferred; + + module(function($routeProvider) { + $routeProvider.when('/path', { + resolveRedirectTo: function($q) { + deferred = $q.defer(); + return deferred.promise; + } + }); + }); + + inject(function($browser, $location, $rootScope, $$testability) { + $location.path('/path'); + $rootScope.$digest(); + + var callback = jasmine.createSpy('callback'); + $$testability.whenStable(callback); + expect(callback).not.toHaveBeenCalled(); + + deferred.reject(); + $browser.defer.flush(); + expect(callback).toHaveBeenCalled(); + }); + }); + + it('should wait for all route promises before calling callbacks', function() { + var deferreds = {}; + + module(function($routeProvider) { + addRouteWithAsyncRedirect('/foo', '/bar'); + addRouteWithAsyncRedirect('/bar', '/baz'); + addRouteWithAsyncRedirect('/baz', '/qux'); + $routeProvider.when('/qux', { + resolve: { + a: function($q) { + var deferred = deferreds['/qux'] = $q.defer(); + return deferred.promise; + } + } + }); + + // Helpers + function addRouteWithAsyncRedirect(fromPath, toPath) { + $routeProvider.when(fromPath, { + resolveRedirectTo: function($q) { + var deferred = deferreds[fromPath] = $q.defer(); + return deferred.promise.then(function() { return toPath; }); + } + }); + } + }); + + inject(function($browser, $location, $rootScope, $$testability) { + $location.path('/foo'); + $rootScope.$digest(); + + var callback = jasmine.createSpy('callback'); + $$testability.whenStable(callback); + expect(callback).not.toHaveBeenCalled(); + + deferreds['/foo'].resolve(); + $browser.defer.flush(); + expect(callback).not.toHaveBeenCalled(); + + deferreds['/bar'].resolve(); + $browser.defer.flush(); + expect(callback).not.toHaveBeenCalled(); + + deferreds['/baz'].resolve(); + $browser.defer.flush(); + expect(callback).not.toHaveBeenCalled(); + + deferreds['/qux'].resolve(); + $browser.defer.flush(); + expect(callback).toHaveBeenCalled(); + }); + }); + }); +}); + + +})(window, window.angular); diff --git a/snapshot/test-bundles/angular-sanitize.js b/snapshot/test-bundles/angular-sanitize.js new file mode 100644 index 000000000..515e53f9d --- /dev/null +++ b/snapshot/test-bundles/angular-sanitize.js @@ -0,0 +1,1726 @@ +/** + * @license AngularJS v1.8.4-local+sha.d8f77817e + * (c) 2010-2020 Google LLC. http://angularjs.org + * License: MIT + */ +(function(window, angular) {'use strict'; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Any commits to this file should be reviewed with security in mind. * + * Changes to this file can potentially create security vulnerabilities. * + * An approval from 2 Core members with history of modifying * + * this file is required. * + * * + * Does the change somehow allow for arbitrary javascript to be executed? * + * Or allows for someone to change the prototype of built-in objects? * + * Or gives undesired access to variables likes document or window? * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +var $sanitizeMinErr = angular.$$minErr('$sanitize'); +var bind; +var extend; +var forEach; +var isArray; +var isDefined; +var lowercase; +var noop; +var nodeContains; +var htmlParser; +var htmlSanitizeWriter; + +/** + * @ngdoc module + * @name ngSanitize + * @description + * + * The `ngSanitize` module provides functionality to sanitize HTML. + * + * See {@link ngSanitize.$sanitize `$sanitize`} for usage. + */ + +/** + * @ngdoc service + * @name $sanitize + * @kind function + * + * @description + * Sanitizes an html string by stripping all potentially dangerous tokens. + * + * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a trusted URI list) are + * then serialized back to a properly escaped HTML string. This means that no unsafe input can make + * it into the returned string. + * + * The trusted URIs for URL sanitization of attribute values is configured using the functions + * `aHrefSanitizationTrustedUrlList` and `imgSrcSanitizationTrustedUrlList` of {@link $compileProvider}. + * + * The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}. + * + * @param {string} html HTML input. + * @returns {string} Sanitized HTML. + * + * @example + + + +
+ Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveHowSourceRendered
ng-bind-htmlAutomatically uses $sanitize
<div ng-bind-html="snippet">
</div>
ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value +
<div ng-bind-html="deliberatelyTrustDangerousSnippet()">
+</div>
+
ng-bindAutomatically escapes
<div ng-bind="snippet">
</div>
+
+
+ + it('should sanitize the html snippet by default', function() { + expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')). + toBe('

an html\nclick here\nsnippet

'); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')). + toBe("

an html\n" + + "click here\n" + + "snippet

"); + }); + + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getAttribute('innerHTML')). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +
+
+ */ + + +/** + * @ngdoc provider + * @name $sanitizeProvider + * @this + * + * @description + * Creates and configures {@link $sanitize} instance. + */ +function $SanitizeProvider() { + var hasBeenInstantiated = false; + var svgEnabled = false; + + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + hasBeenInstantiated = true; + if (svgEnabled) { + extend(validElements, svgElements); + } + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe:/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; + + + /** + * @ngdoc method + * @name $sanitizeProvider#enableSvg + * @kind function + * + * @description + * Enables a subset of svg to be supported by the sanitizer. + * + *
+ *

By enabling this setting without taking other precautions, you might expose your + * application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned + * outside of the containing element and be rendered over other elements on the page (e.g. a login + * link). Such behavior can then result in phishing incidents.

+ * + *

To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg + * tags within the sanitized content:

+ * + *
+ * + *

+   *   .rootOfTheIncludedContent svg {
+   *     overflow: hidden !important;
+   *   }
+   *   
+ *
+ * + * @param {boolean=} flag Enable or disable SVG support in the sanitizer. + * @returns {boolean|$sanitizeProvider} Returns the currently configured value if called + * without an argument or self for chaining otherwise. + */ + this.enableSvg = function(enableSvg) { + if (isDefined(enableSvg)) { + svgEnabled = enableSvg; + return this; + } else { + return svgEnabled; + } + }; + + + /** + * @ngdoc method + * @name $sanitizeProvider#addValidElements + * @kind function + * + * @description + * Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe + * and are not stripped off during sanitization. You can extend the following lists of elements: + * + * - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML + * elements. HTML elements considered safe will not be removed during sanitization. All other + * elements will be stripped off. + * + * - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as + * "void elements" (similar to HTML + * [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These + * elements have no end tag and cannot have content. + * + * - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only + * taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for + * `$sanitize`. + * + *
+ * This method must be called during the {@link angular.Module#config config} phase. Once the + * `$sanitize` service has been instantiated, this method has no effect. + *
+ * + *
+ * Keep in mind that extending the built-in lists of elements may expose your app to XSS or + * other vulnerabilities. Be very mindful of the elements you add. + *
+ * + * @param {Array|Object} elements - A list of valid HTML elements or an object with one or + * more of the following properties: + * - **htmlElements** - `{Array}` - A list of elements to extend the current list of + * HTML elements. + * - **htmlVoidElements** - `{Array}` - A list of elements to extend the current list of + * void HTML elements; i.e. elements that do not have an end tag. + * - **svgElements** - `{Array}` - A list of elements to extend the current list of SVG + * elements. The list of SVG elements is only taken into account if SVG is + * {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`. + * + * Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`. + * + * @return {$sanitizeProvider} Returns self for chaining. + */ + this.addValidElements = function(elements) { + if (!hasBeenInstantiated) { + if (isArray(elements)) { + elements = {htmlElements: elements}; + } + + addElementsTo(svgElements, elements.svgElements); + addElementsTo(voidElements, elements.htmlVoidElements); + addElementsTo(validElements, elements.htmlVoidElements); + addElementsTo(validElements, elements.htmlElements); + } + + return this; + }; + + + /** + * @ngdoc method + * @name $sanitizeProvider#addValidAttrs + * @kind function + * + * @description + * Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are + * not stripped off during sanitization. + * + * **Note**: + * The new attributes will not be treated as URI attributes, which means their values will not be + * sanitized as URIs using `$compileProvider`'s + * {@link ng.$compileProvider#aHrefSanitizationTrustedUrlList aHrefSanitizationTrustedUrlList} and + * {@link ng.$compileProvider#imgSrcSanitizationTrustedUrlList imgSrcSanitizationTrustedUrlList}. + * + *
+ * This method must be called during the {@link angular.Module#config config} phase. Once the + * `$sanitize` service has been instantiated, this method has no effect. + *
+ * + *
+ * Keep in mind that extending the built-in list of attributes may expose your app to XSS or + * other vulnerabilities. Be very mindful of the attributes you add. + *
+ * + * @param {Array} attrs - A list of valid attributes. + * + * @returns {$sanitizeProvider} Returns self for chaining. + */ + this.addValidAttrs = function(attrs) { + if (!hasBeenInstantiated) { + extend(validAttrs, arrayToMap(attrs, true)); + } + return this; + }; + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Private stuff + ////////////////////////////////////////////////////////////////////////////////////////////////// + + bind = angular.bind; + extend = angular.extend; + forEach = angular.forEach; + isArray = angular.isArray; + isDefined = angular.isDefined; + lowercase = angular.$$lowercase; + noop = angular.noop; + + htmlParser = htmlParserImpl; + htmlSanitizeWriter = htmlSanitizeWriterImpl; + + nodeContains = window.Node.prototype.contains || /** @this */ function(arg) { + // eslint-disable-next-line no-bitwise + return !!(this.compareDocumentPosition(arg) & 16); + }; + + // Regular Expressions for parsing tags and attributes + var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g; + + + // Good source of info about elements and attributes + // http://dev.w3.org/html5/spec/Overview.html#semantics + // http://simon.html5.org/html-elements + + // Safe Void Elements - HTML5 + // http://dev.w3.org/html5/spec/Overview.html#void-elements + var voidElements = stringToMap('area,br,col,hr,img,wbr'); + + // Elements that you can, intentionally, leave open (and which close themselves) + // http://dev.w3.org/html5/spec/Overview.html#optional-tags + var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'), + optionalEndTagInlineElements = stringToMap('rp,rt'), + optionalEndTagElements = extend({}, + optionalEndTagInlineElements, + optionalEndTagBlockElements); + + // Safe Block Elements - HTML5 + var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('address,article,' + + 'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' + + 'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul')); + + // Inline Elements - HTML5 + var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('a,abbr,acronym,b,' + + 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,' + + 'samp,small,span,strike,strong,sub,sup,time,tt,u,var')); + + // SVG Elements + // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements + // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted. + // They can potentially allow for arbitrary javascript to be executed. See #11290 + var svgElements = stringToMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' + + 'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,' + + 'radialGradient,rect,stop,svg,switch,text,title,tspan'); + + // Blocked Elements (will be stripped) + var blockedElements = stringToMap('script,style'); + + var validElements = extend({}, + voidElements, + blockElements, + inlineElements, + optionalEndTagElements); + + //Attributes that have href and hence need to be sanitized + var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base'); + + var htmlAttrs = stringToMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + + 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' + + 'valign,value,vspace,width'); + + // SVG attributes (without "id" and "name" attributes) + // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes + var svgAttrs = stringToMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + + 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' + + 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' + + 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' + + 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' + + 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' + + 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' + + 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' + + 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' + + 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' + + 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' + + 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' + + 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' + + 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' + + 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true); + + var validAttrs = extend({}, + uriAttrs, + svgAttrs, + htmlAttrs); + + function stringToMap(str, lowercaseKeys) { + return arrayToMap(str.split(','), lowercaseKeys); + } + + function arrayToMap(items, lowercaseKeys) { + var obj = {}, i; + for (i = 0; i < items.length; i++) { + obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true; + } + return obj; + } + + function addElementsTo(elementsMap, newElements) { + if (newElements && newElements.length) { + extend(elementsMap, arrayToMap(newElements)); + } + } + + /** + * Create an inert document that contains the dirty HTML that needs sanitizing. + * We use the DOMParser API by default and fall back to createHTMLDocument if DOMParser is not + * available. + */ + var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) { + if (isDOMParserAvailable()) { + return getInertBodyElement_DOMParser; + } + + if (!document || !document.implementation) { + throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document'); + } + var inertDocument = document.implementation.createHTMLDocument('inert'); + var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body'); + return getInertBodyElement_InertDocument; + + function isDOMParserAvailable() { + try { + return !!getInertBodyElement_DOMParser(''); + } catch (e) { + return false; + } + } + + function getInertBodyElement_DOMParser(html) { + // We add this dummy element to ensure that the rest of the content is parsed as expected + // e.g. leading whitespace is maintained and tags like `` do not get hoisted to the `` tag. + html = '' + html; + try { + var body = new window.DOMParser().parseFromString(html, 'text/html').body; + body.firstChild.remove(); + return body; + } catch (e) { + return undefined; + } + } + + function getInertBodyElement_InertDocument(html) { + inertBodyElement.innerHTML = html; + + // Support: IE 9-11 only + // strip custom-namespaced attributes on IE<=11 + if (document.documentMode) { + stripCustomNsAttrs(inertBodyElement); + } + + return inertBodyElement; + } + })(window, window.document); + + /** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ + function htmlParserImpl(html, handler) { + if (html === null || html === undefined) { + html = ''; + } else if (typeof html !== 'string') { + html = '' + html; + } + + var inertBodyElement = getInertBodyElement(html); + if (!inertBodyElement) return ''; + + //mXSS protection + var mXSSAttempts = 5; + do { + if (mXSSAttempts === 0) { + throw $sanitizeMinErr('uinput', 'Failed to sanitize html because the input is unstable'); + } + mXSSAttempts--; + + // trigger mXSS if it is going to happen by reading and writing the innerHTML + html = inertBodyElement.innerHTML; + inertBodyElement = getInertBodyElement(html); + } while (html !== inertBodyElement.innerHTML); + + var node = inertBodyElement.firstChild; + while (node) { + switch (node.nodeType) { + case 1: // ELEMENT_NODE + handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes)); + break; + case 3: // TEXT NODE + handler.chars(node.textContent); + break; + } + + var nextNode; + if (!(nextNode = node.firstChild)) { + if (node.nodeType === 1) { + handler.end(node.nodeName.toLowerCase()); + } + nextNode = getNonDescendant('nextSibling', node); + if (!nextNode) { + while (nextNode == null) { + node = getNonDescendant('parentNode', node); + if (node === inertBodyElement) break; + nextNode = getNonDescendant('nextSibling', node); + if (node.nodeType === 1) { + handler.end(node.nodeName.toLowerCase()); + } + } + } + } + node = nextNode; + } + + while ((node = inertBodyElement.firstChild)) { + inertBodyElement.removeChild(node); + } + } + + function attrToMap(attrs) { + var map = {}; + for (var i = 0, ii = attrs.length; i < ii; i++) { + var attr = attrs[i]; + map[attr.name] = attr.value; + } + return map; + } + + + /** + * Escapes all potentially dangerous characters, so that the + * resulting string can be safely inserted into attribute or + * element text. + * @param value + * @returns {string} escaped text + */ + function encodeEntities(value) { + return value. + replace(/&/g, '&'). + replace(SURROGATE_PAIR_REGEXP, function(value) { + var hi = value.charCodeAt(0); + var low = value.charCodeAt(1); + return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'; + }). + replace(NON_ALPHANUMERIC_REGEXP, function(value) { + return '&#' + value.charCodeAt(0) + ';'; + }). + replace(//g, '>'); + } + + /** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.join('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ + function htmlSanitizeWriterImpl(buf, uriValidator) { + var ignoreCurrentElement = false; + var out = bind(buf, buf.push); + return { + start: function(tag, attrs) { + tag = lowercase(tag); + if (!ignoreCurrentElement && blockedElements[tag]) { + ignoreCurrentElement = tag; + } + if (!ignoreCurrentElement && validElements[tag] === true) { + out('<'); + out(tag); + forEach(attrs, function(value, key) { + var lkey = lowercase(key); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out('>'); + } + }, + end: function(tag) { + tag = lowercase(tag); + if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) { + out(''); + } + // eslint-disable-next-line eqeqeq + if (tag == ignoreCurrentElement) { + ignoreCurrentElement = false; + } + }, + chars: function(chars) { + if (!ignoreCurrentElement) { + out(encodeEntities(chars)); + } + } + }; + } + + + /** + * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare + * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want + * to allow any of these custom attributes. This method strips them all. + * + * @param node Root element to process + */ + function stripCustomNsAttrs(node) { + while (node) { + if (node.nodeType === window.Node.ELEMENT_NODE) { + var attrs = node.attributes; + for (var i = 0, l = attrs.length; i < l; i++) { + var attrNode = attrs[i]; + var attrName = attrNode.name.toLowerCase(); + if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) { + node.removeAttributeNode(attrNode); + i--; + l--; + } + } + } + + var nextNode = node.firstChild; + if (nextNode) { + stripCustomNsAttrs(nextNode); + } + + node = getNonDescendant('nextSibling', node); + } + } + + function getNonDescendant(propName, node) { + // An element is clobbered if its `propName` property points to one of its descendants + var nextNode = node[propName]; + if (nextNode && nodeContains.call(node, nextNode)) { + throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText); + } + return nextNode; + } +} + +function sanitizeText(chars) { + var buf = []; + var writer = htmlSanitizeWriter(buf, noop); + writer.chars(chars); + return buf.join(''); +} + + +// define ngSanitize module and register $sanitize service +angular.module('ngSanitize', []) + .provider('$sanitize', $SanitizeProvider) + .info({ angularVersion: '1.8.4-local+sha.d8f77817e' }); + +/** + * @ngdoc filter + * @name linky + * @kind function + * + * @description + * Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and + * plain email address links. + * + * Requires the {@link ngSanitize `ngSanitize`} module to be installed. + * + * @param {string} text Input text. + * @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in. + * @param {object|function(url)} [attributes] Add custom attributes to the link element. + * + * Can be one of: + * + * - `object`: A map of attributes + * - `function`: Takes the url as a parameter and returns a map of attributes + * + * If the map of attributes contains a value for `target`, it overrides the value of + * the target parameter. + * + * + * @returns {string} Html-linkified and {@link $sanitize sanitized} text. + * + * @usage + + * + * @example + + +
+ Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + + +
FilterSourceRendered
linky filter +
<div ng-bind-html="snippet | linky">
</div>
+
+
+
linky target +
<div ng-bind-html="snippetWithSingleURL | linky:'_blank'">
</div>
+
+
+
linky custom attributes +
<div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}">
</div>
+
+
+
no filter
<div ng-bind="snippet">
</div>
+ + + angular.module('linkyExample', ['ngSanitize']) + .controller('ExampleController', ['$scope', function($scope) { + $scope.snippet = + 'Pretty text with some links:\n' + + 'http://angularjs.org/,/n' + + 'mailto:us@somewhere.org,\n' + + 'another@somewhere.org,\n' + + 'and one more: ftp://127.0.0.1/.'; + $scope.snippetWithSingleURL = 'http://angularjs.org/'; + }]); + + + it('should linkify the snippet with urls', function() { + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); + }); + + it('should not linkify snippet without the linky filter', function() { + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new http://link.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('new http://link.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) + .toBe('new http://link.'); + }); + + it('should work with the target property', function() { + expect(element(by.id('linky-target')). + element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); + }); + + it('should optionally add custom attributes', function() { + expect(element(by.id('linky-custom-attributes')). + element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow'); + }); + + + */ +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { + var LINKY_URL_REGEXP = + /((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, + MAILTO_REGEXP = /^mailto:/i; + + var linkyMinErr = angular.$$minErr('linky'); + var isDefined = angular.isDefined; + var isFunction = angular.isFunction; + var isObject = angular.isObject; + var isString = angular.isString; + + return function(text, target, attributes) { + if (text == null || text === '') return text; + if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', text); + + var attributesFn = + isFunction(attributes) ? attributes : + isObject(attributes) ? function getAttributesObject() {return attributes;} : + function getEmptyAttributesObject() {return {};}; + + var match; + var raw = text; + var html = []; + var url; + var i; + while ((match = raw.match(LINKY_URL_REGEXP))) { + // We can not end in these as they are sometimes found at the end of the sentence + url = match[0]; + // if we did not match ftp/http/www/mailto then assume mailto + if (!match[2] && !match[4]) { + url = (match[3] ? 'http://' : 'mailto:') + url; + } + i = match.index; + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); + raw = raw.substring(i + match[0].length); + } + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + var key, linkAttributes = attributesFn(url); + html.push(''); + addText(text); + html.push(''); + } + }; +}]); + +describe('ngBindHtml', function() { + beforeEach(module('ngSanitize')); + + it('should set html', inject(function($rootScope, $compile) { + var element = $compile('
')($rootScope); + $rootScope.html = '
hello
'; + $rootScope.$digest(); + expect(lowercase(element.html())).toEqual('
hello
'); + })); + + + it('should reset html when value is null or undefined', inject(function($compile, $rootScope) { + var element = $compile('
')($rootScope); + + angular.forEach([null, undefined, ''], function(val) { + $rootScope.html = 'some val'; + $rootScope.$digest(); + expect(lowercase(element.html())).toEqual('some val'); + + $rootScope.html = val; + $rootScope.$digest(); + expect(lowercase(element.html())).toEqual(''); + }); + })); +}); + +describe('linky', function() { + var linky; + + beforeEach(module('ngSanitize')); + + beforeEach(inject(function($filter) { + linky = $filter('linky'); + })); + + it('should do basic filter', function() { + expect(linky('http://ab/%20(http://a/)%20%3Chttp://a/%3E%20http://1.2/v:~-123.%20c%20%E2%80%9Chttp://example.com%E2%80%9D%20%E2%80%98http://me.com%E2%80%99')). + toEqual('http://ab/ ' + + '(http://a/) ' + + '<http://a/> ' + + 'http://1.2/v:~-123. c ' + + '“http://example.com” ' + + '‘http://me.com’'); + expect(linky(undefined)).not.toBeDefined(); + }); + + it('should return `undefined`/`null`/`""` values unchanged', function() { + expect(linky(undefined)).toBeUndefined(); + expect(linky(null)).toBe(null); + expect(linky('')).toBe(''); + }); + + it('should throw an error when used with a non-string value (other than `undefined`/`null`)', + function() { + expect(function() { linky(false); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: false'); + + expect(function() { linky(true); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: true'); + + expect(function() { linky(0); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: 0'); + + expect(function() { linky(42); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: 42'); + + expect(function() { linky({}); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: {}'); + + expect(function() { linky([]); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: []'); + + expect(function() { linky(noop); }). + toThrowMinErr('linky', 'notstring', 'Expected string but received: function noop()'); + } + ); + + it('should be case-insensitive', function() { + expect(linky('WWW.example.com')).toEqual('WWW.example.com'); + expect(linky('WWW.EXAMPLE.COM')).toEqual('WWW.EXAMPLE.COM'); + expect(linky('HTTP://www.example.com')).toEqual('HTTP://www.example.com'); + expect(linky('HTTP://example.com')).toEqual('HTTP://example.com'); + expect(linky('HTTPS://www.example.com')).toEqual('HTTPS://www.example.com'); + expect(linky('HTTPS://example.com')).toEqual('HTTPS://example.com'); + expect(linky('FTP://www.example.com')).toEqual('FTP://www.example.com'); + expect(linky('FTP://example.com')).toEqual('FTP://example.com'); + expect(linky('SFTP://www.example.com')).toEqual('SFTP://www.example.com'); + expect(linky('SFTP://example.com')).toEqual('SFTP://example.com'); + }); + + it('should handle www.', function() { + expect(linky('www.example.com')).toEqual('www.example.com'); + }); + + it('should handle mailto:', function() { + expect(linky('mailto:me@example.com')). + toEqual('me@example.com'); + expect(linky('me@example.com')). + toEqual('me@example.com'); + expect(linky('send email to me@example.com, but')). + toEqual('send email to me@example.com, but'); + expect(linky('my email is "me@example.com"')). + toEqual('my email is "me@example.com"'); + }); + + it('should handle quotes in the email', function() { + expect(linky('foo@"bar".com')).toEqual('foo@"bar".com'); + }); + + it('should handle target:', function() { + expect(linky('http://example.com/', '_blank')). + toBeOneOf('http://example.com', + 'http://example.com'); + expect(linky('http://example.com/', 'someNamedIFrame')). + toBeOneOf('http://example.com', + 'http://example.com'); + }); + + describe('custom attributes', function() { + + it('should optionally add custom attributes', function() { + expect(linky('http://example.com/', '_self', {rel: 'nofollow'})). + toBeOneOf('http://example.com', + 'http://example.com'); + }); + + + it('should override target parameter with custom attributes', function() { + expect(linky('http://example.com/', '_self', {target: '_blank'})). + toBeOneOf('http://example.com', + 'http://example.com'); + }); + + + it('should optionally add custom attributes from function', function() { + expect(linky('http://example.com/', '_self', function(url) {return {'class': 'blue'};})). + toBeOneOf('http://example.com', + 'http://example.com', + 'http://example.com'); + }); + + + it('should pass url as parameter to custom attribute function', function() { + var linkParameters = jasmine.createSpy('linkParameters').and.returnValue({'class': 'blue'}); + linky('http://example.com/', '_self', linkParameters); + expect(linkParameters).toHaveBeenCalledWith('http://example.com/'); + }); + + + it('should call the attribute function for all links in the input', function() { + var attributeFn = jasmine.createSpy('attributeFn').and.returnValue({}); + linky('http://example.com and http://google.com', '_self', attributeFn); + expect(attributeFn.calls.allArgs()).toEqual([['http://example.com/'], ['http://google.com/']]); + }); + + + it('should strip unsafe attributes', function() { + expect(linky('http://example.com/', '_self', {'class': 'blue', 'onclick': 'alert(\'Hi\')'})). + toBeOneOf('http://example.com', + 'http://example.com', + 'http://example.com'); + }); + }); +}); + +describe('HTML', function() { + var ua = window.navigator.userAgent; + var isChrome = /Chrome/.test(ua) && !/Edge/.test(ua); + + var expectHTML; + + beforeEach(module('ngSanitize')); + beforeEach(function() { + expectHTML = function(html) { + var sanitize; + inject(function($sanitize) { + sanitize = $sanitize; + }); + return expect(sanitize(html)); + }; + }); + + describe('htmlParser', function() { + /* global htmlParser */ + + var handler, start, text, comment; + beforeEach(function() { + text = ''; + start = null; + handler = { + start: function(tag, attrs) { + start = { + tag: tag, + attrs: attrs + }; + // Since different browsers handle newlines differently we trim + // so that it is easier to write tests. + for (var i = 0, ii = attrs.length; i < ii; i++) { + var keyValue = attrs[i]; + var key = keyValue.key; + var value = keyValue.value; + attrs[key] = value.replace(/^\s*/, '').replace(/\s*$/, ''); + } + }, + chars: function(text_) { + text += text_; + }, + end:function(tag) { + expect(tag).toEqual(start.tag); + }, + comment:function(comment_) { + comment = comment_; + } + }; + // Trigger the $sanitizer provider to execute, which initializes the `htmlParser` function. + inject(function($sanitize) {}); + }); + + it('should not parse comments', function() { + htmlParser('', handler); + expect(comment).not.toBeDefined(); + }); + + it('should parse basic format', function() { + htmlParser('text', handler); + expect(start).toEqual({tag:'tag', attrs:{attr:'value'}}); + expect(text).toEqual('text'); + }); + + it('should not treat "<" followed by a non-/ or non-letter as a tag', function() { + expectHTML('<- text1 text2 <1 text1 text2 <{', handler). + toBe('<- text1 text2 <1 text1 text2 <{'); + }); + + it('should accept tag delimiters such as "<" inside real tags', function() { + // Assert that the < is part of the text node content, and not part of a tag name. + htmlParser('

10 < 100

', handler); + expect(text).toEqual(' 10 < 100 '); + }); + + it('should parse newlines in tags', function() { + htmlParser('text', handler); + expect(start).toEqual({tag:'tag', attrs:{attr:'value'}}); + expect(text).toEqual('text'); + }); + + it('should parse newlines in attributes', function() { + htmlParser('text', handler); + expect(start).toEqual({tag:'tag', attrs:{attr:'\nvalue\n'}}); + expect(text).toEqual('text'); + }); + + it('should parse namespace', function() { + htmlParser('text', handler); + expect(start).toEqual({tag:'ns:t-a-g', attrs:{'ns:a-t-t-r':'\nvalue\n'}}); + expect(text).toEqual('text'); + }); + + it('should parse empty value attribute of node', function() { + htmlParser('abc', handler); + expect(start).toEqual({tag:'test-foo', attrs:{selected:'', value:''}}); + expect(text).toEqual('abc'); + }); + }); + + // THESE TESTS ARE EXECUTED WITH COMPILED ANGULAR + it('should echo html', function() { + expectHTML('helloworld.'). + toBeOneOf('helloworld.', + 'helloworld.'); + }); + + it('should remove script', function() { + expectHTML('ac.').toEqual('ac.'); + }); + + it('should remove script that has newline characters', function() { + expectHTML('a\n\revil\n\rc.').toEqual('ac.'); + }); + + it('should remove DOCTYPE header', function() { + expectHTML('').toEqual(''); + expectHTML('').toEqual(''); + expectHTML('ac.').toEqual('ac.'); + expectHTML('ac.').toEqual('ac.'); + }); + + it('should escape non-start tags', function() { + expectHTML('a< SCRIPT >A< SCRIPT >evil< / scrIpt >B< / scrIpt >c.'). + toBe('a< SCRIPT >A< SCRIPT >evil< / scrIpt >B< / scrIpt >c.'); + }); + + it('should remove attrs', function() { + expectHTML('a
b
c').toEqual('a
b
c'); + }); + + it('should handle large datasets', function() { + // Large is non-trivial to quantify, but handling ~100,000 should be sufficient for most purposes. + var largeNumber = 17; // 2^17 = 131,072 + var result = '
b
'; + // Ideally we would use repeat, but that isn't supported in IE. + for (var i = 0; i < largeNumber; i++) { + result += result; + } + expectHTML('a' + result + 'c').toEqual('a' + result + 'c'); + }); + + it('should remove style', function() { + expectHTML('ac.').toEqual('ac.'); + }); + + it('should remove style that has newline characters', function() { + expectHTML('ac.').toEqual('ac.'); + }); + + it('should remove double nested script', function() { + expectHTML('ailc.').toEqual('ailc.'); + }); + + it('should remove unknown names', function() { + expectHTML('abc').toEqual('abc'); + }); + + it('should remove unsafe value', function() { + expectHTML('').toEqual(''); + expectHTML('').toEqual(''); + }); + + it('should handle self closed elements', function() { + expectHTML('a
c').toEqual('a
c'); + }); + + it('should handle namespace', function() { + expectHTML('abc').toEqual('abc'); + }); + + it('should handle entities', function() { + var everything = '
' + + '!@#$%^&*()_+-={}[]:";\'<>?,./`~ ħ
'; + expectHTML(everything).toEqual(everything); + }); + + it('should mangle improper html', function() { + // This text is encoded more than a real HTML parser would, but it should render the same. + expectHTML('< div rel="
" alt=abc dir=\'"\' >text< /div>'). + toBe('< div rel="" alt=abc dir=\'"\' >text< /div>'); + }); + + it('should mangle improper html2', function() { + // A proper HTML parser would clobber this more in most cases, but it looks reasonable. + expectHTML('< div rel="
" / >'). + toBe('< div rel="" / >'); + }); + + it('should ignore back slash as escape', function() { + expectHTML('xxx\\'). + toBeOneOf('xxx\\', + 'xxx\\'); + }); + + it('should ignore object attributes', function() { + expectHTML(':)'). + toEqual(':)'); + expectHTML(':)'). + toEqual(''); + }); + + it('should keep spaces as prefix/postfix', function() { + expectHTML(' a ').toEqual(' a '); + }); + + it('should allow multiline strings', function() { + expectHTML('\na\n').toEqual(' a '); + }); + + it('should accept tag delimiters such as "<" inside real tags (with nesting)', function() { + //this is an integrated version of the 'should accept tag delimiters such as "<" inside real tags' test + expectHTML('

10 < 100

') + .toEqual('

10 < 100

'); + }); + + it('should accept non-string arguments', function() { + expectHTML(null).toBe(''); + expectHTML(undefined).toBe(''); + expectHTML(42).toBe('42'); + expectHTML({}).toBe('[object Object]'); + expectHTML([1, 2, 3]).toBe('1,2,3'); + expectHTML(true).toBe('true'); + expectHTML(false).toBe('false'); + }); + + + it('should strip svg elements if not enabled via provider', function() { + expectHTML('') + .toEqual(''); + }); + + it('should prevent mXSS attacks', function() { + expectHTML('CLICKME').toBe('CLICKME'); + }); + + it('should strip html comments', function() { + expectHTML('

text1text2

') + .toEqual('

text1text2

'); + }); + + describe('clobbered elements', function() { + + it('should throw on a form with an input named "parentNode"', function() { + inject(function($sanitize) { + + expect(function() { + $sanitize('
'); + }).toThrowMinErr('$sanitize', 'elclob'); + + expect(function() { + $sanitize('
'); + }).toThrowMinErr('$sanitize', 'elclob'); + }); + }); + + if (!/Edge\/\d{2,}/.test(window.navigator.userAgent)) { + // Skip test on Edge due to a browser bug. + it('should throw on a form with an input named "nextSibling"', function() { + inject(function($sanitize) { + + expect(function() { + $sanitize('
'); + }).toThrowMinErr('$sanitize', 'elclob'); + + expect(function() { + $sanitize('
'); + }).toThrowMinErr('$sanitize', 'elclob'); + + }); + }); + } + }); + + // See https://github.com/cure53/DOMPurify/blob/a992d3a75031cb8bb032e5ea8399ba972bdf9a65/src/purify.js#L439-L449 + it('should not allow JavaScript execution when creating inert document', inject(function($sanitize) { + $sanitize(''); + + expect(window.xxx).toBe(undefined); + delete window.xxx; + })); + + // See https://github.com/cure53/DOMPurify/releases/tag/0.6.7 + it('should not allow JavaScript hidden in badly formed HTML to get through sanitization (Firefox bug)', inject(function($sanitize) { + var doc = $sanitize('