Update XStatic-Angular to 1.5.8.0
Change-Id: I94e5ada8bac3d29513e83c9d7e58c7b73ed154a8
This commit is contained in:
parent
5a30bee80d
commit
984630723e
@ -11,9 +11,9 @@ NAME = __name__.split('.')[-1] # package name (e.g. 'foo' or 'foo_bar')
|
||||
# please use a all-lowercase valid python
|
||||
# package name
|
||||
|
||||
VERSION = '1.4.10' # version of the packaged files, please use the upstream
|
||||
VERSION = '1.5.8' # version of the packaged files, please use the upstream
|
||||
# version number
|
||||
BUILD = '1' # our package build number, so we can release new builds
|
||||
BUILD = '0' # our package build number, so we can release new builds
|
||||
# with fixes for xstatic stuff.
|
||||
PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi
|
||||
|
||||
|
341
xstatic/pkg/angular/data/angular-animate.js
vendored
341
xstatic/pkg/angular/data/angular-animate.js
vendored
@ -1,23 +1,9 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
/* jshint ignore:start */
|
||||
var noop = angular.noop;
|
||||
var copy = angular.copy;
|
||||
var extend = angular.extend;
|
||||
var jqLite = angular.element;
|
||||
var forEach = angular.forEach;
|
||||
var isArray = angular.isArray;
|
||||
var isString = angular.isString;
|
||||
var isObject = angular.isObject;
|
||||
var isUndefined = angular.isUndefined;
|
||||
var isDefined = angular.isDefined;
|
||||
var isFunction = angular.isFunction;
|
||||
var isElement = angular.isElement;
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
var ELEMENT_NODE = 1;
|
||||
var COMMENT_NODE = 8;
|
||||
@ -43,7 +29,7 @@ var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMA
|
||||
// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
|
||||
// therefore there is no reason to test anymore for other vendor prefixes:
|
||||
// http://caniuse.com/#search=transition
|
||||
if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionend)) {
|
||||
if ((window.ontransitionend === void 0) && (window.onwebkittransitionend !== void 0)) {
|
||||
CSS_PREFIX = '-webkit-';
|
||||
TRANSITION_PROP = 'WebkitTransition';
|
||||
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
|
||||
@ -52,7 +38,7 @@ if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionen
|
||||
TRANSITIONEND_EVENT = 'transitionend';
|
||||
}
|
||||
|
||||
if (isUndefined(window.onanimationend) && isDefined(window.onwebkitanimationend)) {
|
||||
if ((window.onanimationend === void 0) && (window.onwebkitanimationend !== void 0)) {
|
||||
CSS_PREFIX = '-webkit-';
|
||||
ANIMATION_PROP = 'WebkitAnimation';
|
||||
ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
|
||||
@ -74,10 +60,6 @@ var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
|
||||
var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
|
||||
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
|
||||
|
||||
var isPromiseLike = function(p) {
|
||||
return p && p.then ? true : false;
|
||||
};
|
||||
|
||||
var ngMinErr = angular.$$minErr('ng');
|
||||
function assertArg(arg, name, reason) {
|
||||
if (!arg) {
|
||||
@ -132,8 +114,7 @@ function stripCommentsFromElement(element) {
|
||||
if (element instanceof jqLite) {
|
||||
switch (element.length) {
|
||||
case 0:
|
||||
return [];
|
||||
break;
|
||||
return element;
|
||||
|
||||
case 1:
|
||||
// there is no point of stripping anything if the element
|
||||
@ -146,7 +127,6 @@ function stripCommentsFromElement(element) {
|
||||
|
||||
default:
|
||||
return jqLite(extractElementNode(element));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +167,7 @@ function applyAnimationClassesFactory($$jqLite) {
|
||||
$$removeClass($$jqLite, element, options.removeClass);
|
||||
options.removeClass = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function prepareAnimationOptions(options) {
|
||||
@ -290,10 +270,10 @@ function resolveElementClasses(existing, toAdd, toRemove) {
|
||||
var prop, allow;
|
||||
if (val === ADD_CLASS) {
|
||||
prop = 'addClass';
|
||||
allow = !existing[klass];
|
||||
allow = !existing[klass] || existing[klass + REMOVE_CLASS_SUFFIX];
|
||||
} else if (val === REMOVE_CLASS) {
|
||||
prop = 'removeClass';
|
||||
allow = existing[klass];
|
||||
allow = existing[klass] || existing[klass + ADD_CLASS_SUFFIX];
|
||||
}
|
||||
if (allow) {
|
||||
if (classes[prop].length) {
|
||||
@ -323,7 +303,7 @@ function resolveElementClasses(existing, toAdd, toRemove) {
|
||||
}
|
||||
|
||||
function getDomNode(element) {
|
||||
return (element instanceof angular.element) ? element[0] : element;
|
||||
return (element instanceof jqLite) ? element[0] : element;
|
||||
}
|
||||
|
||||
function applyGeneratedPreparationClasses(element, event, options) {
|
||||
@ -396,7 +376,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
|
||||
queue = scheduler.queue = [];
|
||||
|
||||
/* waitUntilQuiet does two things:
|
||||
* 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through
|
||||
* 1. It will run the FINAL `fn` value only when an uncanceled RAF has passed through
|
||||
* 2. It will delay the next wave of tasks from running until the quiet `fn` has run.
|
||||
*
|
||||
* The motivation here is that animation code can request more time from the scheduler
|
||||
@ -513,7 +493,7 @@ var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) {
|
||||
return {
|
||||
link: function(scope, element, attrs) {
|
||||
var val = attrs.ngAnimateChildren;
|
||||
if (angular.isString(val) && val.length === 0) { //empty attribute
|
||||
if (isString(val) && val.length === 0) { //empty attribute
|
||||
element.data(NG_ANIMATE_CHILDREN_DATA, true);
|
||||
} else {
|
||||
// Interpolate and set the value, so that it is available to
|
||||
@ -697,7 +677,7 @@ var ANIMATE_TIMER_KEY = '$$animateCss';
|
||||
* ```
|
||||
*
|
||||
* To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.
|
||||
* If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and stlyes may have been
|
||||
* If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and styles may have been
|
||||
* applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties
|
||||
* and that changing them will not reconfigure the parameters of the animation.
|
||||
*
|
||||
@ -734,11 +714,11 @@ var ANIMATE_TIMER_KEY = '$$animateCss';
|
||||
* * `stagger` - A numeric time value representing the delay between successively animated elements
|
||||
* ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})
|
||||
* * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a
|
||||
* * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
|
||||
* * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.)
|
||||
* `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
|
||||
* * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occurring on the classes being added and removed.)
|
||||
* * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once
|
||||
* the animation is closed. This is useful for when the styles are used purely for the sake of
|
||||
* the animation and do not have a lasting visual effect on the element (e.g. a colapse and open animation).
|
||||
* the animation and do not have a lasting visual effect on the element (e.g. a collapse and open animation).
|
||||
* By default this value is set to `false`.
|
||||
*
|
||||
* @return {object} an object with start and end methods and details about the animation.
|
||||
@ -791,7 +771,7 @@ function computeCssStyles($window, element, properties) {
|
||||
}
|
||||
|
||||
// by setting this to null in the event that the delay is not set or is set directly as 0
|
||||
// then we can still allow for zegative values to be used later on and not mistake this
|
||||
// then we can still allow for negative values to be used later on and not mistake this
|
||||
// value for being greater than any other negative value.
|
||||
if (val === 0) {
|
||||
val = null;
|
||||
@ -907,7 +887,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
|
||||
// we keep putting this in multiple times even though the value and the cacheKey are the same
|
||||
// because we're keeping an interal tally of how many duplicate animations are detected.
|
||||
// because we're keeping an internal tally of how many duplicate animations are detected.
|
||||
gcsLookup.put(cacheKey, timings);
|
||||
return timings;
|
||||
}
|
||||
@ -1381,9 +1361,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
};
|
||||
|
||||
// checking the stagger duration prevents an accidently cascade of the CSS delay style
|
||||
// checking the stagger duration prevents an accidentally cascade of the CSS delay style
|
||||
// being inherited from the parent. If the transition duration is zero then we can safely
|
||||
// rely that the delay value is an intential stagger delay style.
|
||||
// rely that the delay value is an intentional stagger delay style.
|
||||
var maxStagger = itemIndex > 0
|
||||
&& ((timings.transitionDuration && stagger.transitionDuration === 0) ||
|
||||
(timings.animationDuration && stagger.animationDuration === 0))
|
||||
@ -1556,7 +1536,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
||||
|
||||
var rootBodyElement = jqLite(
|
||||
// this is to avoid using something that exists outside of the body
|
||||
// we also special case the doc fragement case because our unit test code
|
||||
// we also special case the doc fragment case because our unit test code
|
||||
// appends the $rootElement to the body after the app has been bootstrapped
|
||||
isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
|
||||
);
|
||||
@ -1656,7 +1636,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
||||
var coords = getDomNode(anchor).getBoundingClientRect();
|
||||
|
||||
// we iterate directly since safari messes up and doesn't return
|
||||
// all the keys for the coods object when iterated
|
||||
// all the keys for the coords object when iterated
|
||||
forEach(['width','height','top','left'], function(key) {
|
||||
var value = coords[key];
|
||||
switch (key) {
|
||||
@ -2225,6 +2205,11 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
});
|
||||
|
||||
rules.cancel.push(function(element, newAnimation, currentAnimation) {
|
||||
// cancel the animation if classes added / removed in both animation cancel each other out,
|
||||
// but only if the current animation isn't structural
|
||||
|
||||
if (currentAnimation.structural) return false;
|
||||
|
||||
var nA = newAnimation.addClass;
|
||||
var nR = newAnimation.removeClass;
|
||||
var cA = currentAnimation.addClass;
|
||||
@ -2294,7 +2279,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
);
|
||||
|
||||
var callbackRegistry = {};
|
||||
var callbackRegistry = Object.create(null);
|
||||
|
||||
// remember that the classNameFilter is set during the provider/config
|
||||
// stage therefore we can optimize here and setup a helper function
|
||||
@ -2312,7 +2297,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
|
||||
// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
|
||||
var contains = Node.prototype.contains || function(arg) {
|
||||
var contains = window.Node.prototype.contains || function(arg) {
|
||||
// jshint bitwise: false
|
||||
return this === arg || !!(this.compareDocumentPosition(arg) & 16);
|
||||
// jshint bitwise: true
|
||||
@ -2337,7 +2322,24 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
return matches;
|
||||
}
|
||||
|
||||
return {
|
||||
function filterFromRegistry(list, matchContainer, matchCallback) {
|
||||
var containerNode = extractElementNode(matchContainer);
|
||||
return list.filter(function(entry) {
|
||||
var isMatch = entry.node === containerNode &&
|
||||
(!matchCallback || entry.callback === matchCallback);
|
||||
return !isMatch;
|
||||
});
|
||||
}
|
||||
|
||||
function cleanupEventListeners(phase, element) {
|
||||
if (phase === 'close' && !element[0].parentNode) {
|
||||
// If the element is not attached to a parentNode, it has been removed by
|
||||
// the domOperation, and we can safely remove the event callbacks
|
||||
$animate.off(element);
|
||||
}
|
||||
}
|
||||
|
||||
var $animate = {
|
||||
on: function(event, container, callback) {
|
||||
var node = extractElementNode(container);
|
||||
callbackRegistry[event] = callbackRegistry[event] || [];
|
||||
@ -2345,24 +2347,36 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
node: node,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
// Remove the callback when the element is removed from the DOM
|
||||
jqLite(container).on('$destroy', function() {
|
||||
var animationDetails = activeAnimationsLookup.get(node);
|
||||
|
||||
if (!animationDetails) {
|
||||
// If there's an animation ongoing, the callback calling code will remove
|
||||
// the event listeners. If we'd remove here, the callbacks would be removed
|
||||
// before the animation ends
|
||||
$animate.off(event, container, callback);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
off: function(event, container, callback) {
|
||||
if (arguments.length === 1 && !isString(arguments[0])) {
|
||||
container = arguments[0];
|
||||
for (var eventType in callbackRegistry) {
|
||||
callbackRegistry[eventType] = filterFromRegistry(callbackRegistry[eventType], container);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var entries = callbackRegistry[event];
|
||||
if (!entries) return;
|
||||
|
||||
callbackRegistry[event] = arguments.length === 1
|
||||
? null
|
||||
: filterFromRegistry(entries, container, callback);
|
||||
|
||||
function filterFromRegistry(list, matchContainer, matchCallback) {
|
||||
var containerNode = extractElementNode(matchContainer);
|
||||
return list.filter(function(entry) {
|
||||
var isMatch = entry.node === containerNode &&
|
||||
(!matchCallback || entry.callback === matchCallback);
|
||||
return !isMatch;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
pin: function(element, parentElement) {
|
||||
@ -2396,11 +2410,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
bool = animationsEnabled = !!element;
|
||||
} else {
|
||||
var node = getDomNode(element);
|
||||
var recordExists = disabledElementsLookup.get(node);
|
||||
|
||||
if (argCount === 1) {
|
||||
// (element) - Element getter
|
||||
bool = !recordExists;
|
||||
bool = !disabledElementsLookup.get(node);
|
||||
} else {
|
||||
// (element, bool) - Element setter
|
||||
disabledElementsLookup.put(node, !bool);
|
||||
@ -2412,6 +2425,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
};
|
||||
|
||||
return $animate;
|
||||
|
||||
function queueAnimation(element, event, initialOptions) {
|
||||
// we always make a copy of the options since
|
||||
// there should never be any side effects on
|
||||
@ -2474,12 +2489,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
|
||||
var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
|
||||
|
||||
var documentHidden = $document[0].hidden;
|
||||
|
||||
// this is a hard disable of all animations for the application or on
|
||||
// the element itself, therefore there is no need to continue further
|
||||
// past this point if not enabled
|
||||
// Animations are also disabled if the document is currently hidden (page is not visible
|
||||
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
|
||||
var skipAnimations = !animationsEnabled || $document[0].hidden || disabledElementsLookup.get(node);
|
||||
var skipAnimations = !animationsEnabled || documentHidden || disabledElementsLookup.get(node);
|
||||
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
|
||||
var hasExistingAnimation = !!existingAnimation.state;
|
||||
|
||||
@ -2490,7 +2507,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
|
||||
if (skipAnimations) {
|
||||
// Callbacks should fire even if the document is hidden (regression fix for issue #14120)
|
||||
if (documentHidden) notifyProgress(runner, event, 'start');
|
||||
close();
|
||||
if (documentHidden) notifyProgress(runner, event, 'close');
|
||||
return runner;
|
||||
}
|
||||
|
||||
@ -2640,6 +2660,11 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
markElementAnimationState(element, RUNNING_STATE);
|
||||
var realRunner = $$animation(element, event, animationDetails.options);
|
||||
|
||||
// this will update the runner's flow-control events based on
|
||||
// the `realRunner` object.
|
||||
runner.setHost(realRunner);
|
||||
notifyProgress(runner, event, 'start', {});
|
||||
|
||||
realRunner.done(function(status) {
|
||||
close(!status);
|
||||
var animationDetails = activeAnimationsLookup.get(node);
|
||||
@ -2648,11 +2673,6 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
notifyProgress(runner, event, 'close', {});
|
||||
});
|
||||
|
||||
// this will update the runner's flow-control events based on
|
||||
// the `realRunner` object.
|
||||
runner.setHost(realRunner);
|
||||
notifyProgress(runner, event, 'start', {});
|
||||
});
|
||||
|
||||
return runner;
|
||||
@ -2669,7 +2689,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
forEach(callbacks, function(callback) {
|
||||
callback(element, phase, data);
|
||||
});
|
||||
cleanupEventListeners(phase, element);
|
||||
});
|
||||
} else {
|
||||
cleanupEventListeners(phase, element);
|
||||
}
|
||||
});
|
||||
runner.progress(event, phase, data);
|
||||
@ -3126,7 +3149,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
};
|
||||
|
||||
// the anchor animations require that the from and to elements both have at least
|
||||
// one shared CSS class which effictively marries the two elements together to use
|
||||
// one shared CSS class which effectively marries the two elements together to use
|
||||
// the same animation driver and to properly sequence the anchor animation.
|
||||
if (group.classes.length) {
|
||||
preparedAnimations.push(group);
|
||||
@ -3169,8 +3192,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
// may attempt more elements, but custom drivers are more particular
|
||||
for (var i = drivers.length - 1; i >= 0; i--) {
|
||||
var driverName = drivers[i];
|
||||
if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check
|
||||
|
||||
var factory = $injector.get(driverName);
|
||||
var driver = factory(animationDetails);
|
||||
if (driver) {
|
||||
@ -3199,7 +3220,8 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
|
||||
function update(element) {
|
||||
getRunner(element).setHost(newRunner);
|
||||
var runner = getRunner(element);
|
||||
if (runner) runner.setHost(newRunner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3229,18 +3251,120 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
}];
|
||||
}];
|
||||
|
||||
/* global angularAnimateModule: true,
|
||||
|
||||
$$AnimateAsyncRunFactory,
|
||||
$$rAFSchedulerFactory,
|
||||
$$AnimateChildrenDirective,
|
||||
$$AnimateQueueProvider,
|
||||
$$AnimationProvider,
|
||||
$AnimateCssProvider,
|
||||
$$AnimateCssDriverProvider,
|
||||
$$AnimateJsProvider,
|
||||
$$AnimateJsDriverProvider,
|
||||
*/
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngAnimateSwap
|
||||
* @restrict A
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* ngAnimateSwap is a animation-oriented directive that allows for the container to
|
||||
* be removed and entered in whenever the associated expression changes. A
|
||||
* common usecase for this directive is a rotating banner or slider component which
|
||||
* contains one image being present at a time. When the active image changes
|
||||
* then the old image will perform a `leave` animation and the new element
|
||||
* will be inserted via an `enter` animation.
|
||||
*
|
||||
* @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 the DOM |
|
||||
*
|
||||
* @example
|
||||
* <example name="ngAnimateSwap-directive" module="ngAnimateSwapExample"
|
||||
* deps="angular-animate.js"
|
||||
* animations="true" fixBase="true">
|
||||
* <file name="index.html">
|
||||
* <div class="container" ng-controller="AppCtrl">
|
||||
* <div ng-animate-swap="number" class="cell swap-animation" ng-class="colorClass(number)">
|
||||
* {{ number }}
|
||||
* </div>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="script.js">
|
||||
* angular.module('ngAnimateSwapExample', ['ngAnimate'])
|
||||
* .controller('AppCtrl', ['$scope', '$interval', function($scope, $interval) {
|
||||
* $scope.number = 0;
|
||||
* $interval(function() {
|
||||
* $scope.number++;
|
||||
* }, 1000);
|
||||
*
|
||||
* var colors = ['red','blue','green','yellow','orange'];
|
||||
* $scope.colorClass = function(number) {
|
||||
* return colors[number % colors.length];
|
||||
* };
|
||||
* }]);
|
||||
* </file>
|
||||
* <file name="animations.css">
|
||||
* .container {
|
||||
* height:250px;
|
||||
* width:250px;
|
||||
* position:relative;
|
||||
* overflow:hidden;
|
||||
* border:2px solid black;
|
||||
* }
|
||||
* .container .cell {
|
||||
* font-size:150px;
|
||||
* text-align:center;
|
||||
* line-height:250px;
|
||||
* position:absolute;
|
||||
* top:0;
|
||||
* left:0;
|
||||
* right:0;
|
||||
* border-bottom:2px solid black;
|
||||
* }
|
||||
* .swap-animation.ng-enter, .swap-animation.ng-leave {
|
||||
* transition:0.5s linear all;
|
||||
* }
|
||||
* .swap-animation.ng-enter {
|
||||
* top:-250px;
|
||||
* }
|
||||
* .swap-animation.ng-enter-active {
|
||||
* top:0px;
|
||||
* }
|
||||
* .swap-animation.ng-leave {
|
||||
* top:0px;
|
||||
* }
|
||||
* .swap-animation.ng-leave-active {
|
||||
* top:250px;
|
||||
* }
|
||||
* .red { background:red; }
|
||||
* .green { background:green; }
|
||||
* .blue { background:blue; }
|
||||
* .yellow { background:yellow; }
|
||||
* .orange { background:orange; }
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $rootScope) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
transclude: 'element',
|
||||
terminal: true,
|
||||
priority: 600, // we use 600 here to ensure that the directive is caught before others
|
||||
link: function(scope, $element, attrs, ctrl, $transclude) {
|
||||
var previousElement, previousScope;
|
||||
scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) {
|
||||
if (previousElement) {
|
||||
$animate.leave(previousElement);
|
||||
}
|
||||
if (previousScope) {
|
||||
previousScope.$destroy();
|
||||
previousScope = null;
|
||||
}
|
||||
if (value || value === 0) {
|
||||
previousScope = scope.$new();
|
||||
$transclude(previousScope, function(element) {
|
||||
previousElement = element;
|
||||
$animate.enter(element, null, $element);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@ -3358,7 +3482,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
* <div ng-show="bool" class="fade">
|
||||
* Show and hide me
|
||||
* </div>
|
||||
* <button ng-click="bool=true">Toggle</button>
|
||||
* <button ng-click="bool=!bool">Toggle</button>
|
||||
*
|
||||
* <style>
|
||||
* .fade.ng-hide {
|
||||
@ -3514,7 +3638,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
*
|
||||
* 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 ainmation.
|
||||
* `module.animation()` module function we can register the animation.
|
||||
*
|
||||
* Let's see an example of a enter/leave animation using `ngRepeat`:
|
||||
*
|
||||
@ -3927,31 +4051,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
* possible be sure to visit the {@link ng.$animate $animate service API page}.
|
||||
*
|
||||
*
|
||||
* ### Preventing Collisions With Third Party Libraries
|
||||
*
|
||||
* Some third-party frameworks place animation duration defaults across many element or className
|
||||
* selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which
|
||||
* is expecting actual animations on these elements and has to wait for their completion.
|
||||
*
|
||||
* You can prevent this unwanted behavior by using a prefix on all your animation classes:
|
||||
*
|
||||
* ```css
|
||||
* /* prefixed with animate- */
|
||||
* .animate-fade-add.animate-fade-add-active {
|
||||
* transition:1s linear all;
|
||||
* opacity:0;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* You then configure `$animate` to enforce this prefix:
|
||||
*
|
||||
* ```js
|
||||
* $animateProvider.classNameFilter(/animate-/);
|
||||
* ```
|
||||
*
|
||||
* This also may provide your application with a speed boost since only specific elements containing CSS class prefix
|
||||
* will be evaluated for animation when any DOM changes occur in the application.
|
||||
*
|
||||
* ## 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
|
||||
@ -3983,6 +4082,19 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
* (Note that you will need to trigger a digest within the callback to get angular 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
|
||||
@ -3993,7 +4105,24 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
*
|
||||
* Click here {@link ng.$animate to learn more about animations with `$animate`}.
|
||||
*/
|
||||
angular.module('ngAnimate', [])
|
||||
angular.module('ngAnimate', [], function initAngularHelpers() {
|
||||
// Access helpers from angular 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;
|
||||
})
|
||||
.directive('ngAnimateSwap', ngAnimateSwapDirective)
|
||||
|
||||
.directive('ngAnimateChildren', $$AnimateChildrenDirective)
|
||||
.factory('$$rAFScheduler', $$rAFSchedulerFactory)
|
||||
|
||||
|
115
xstatic/pkg/angular/data/angular-aria.js
vendored
115
xstatic/pkg/angular/data/angular-aria.js
vendored
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@ -21,24 +21,29 @@
|
||||
*
|
||||
* For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
|
||||
* directives are supported:
|
||||
* `ngModel`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`, `ngDblClick`, and `ngMessages`.
|
||||
* `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`,
|
||||
* `ngDblClick`, and `ngMessages`.
|
||||
*
|
||||
* Below is a more detailed breakdown of the attributes handled by ngAria:
|
||||
*
|
||||
* | Directive | Supported Attributes |
|
||||
* |---------------------------------------------|----------------------------------------------------------------------------------------|
|
||||
* | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |
|
||||
* | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
|
||||
* | {@link ng.directive:ngRequired ngRequired} | aria-required
|
||||
* | {@link ng.directive:ngChecked ngChecked} | aria-checked
|
||||
* | {@link ng.directive:ngReadonly ngReadonly} | aria-readonly |
|
||||
* | {@link ng.directive:ngValue ngValue} | aria-checked |
|
||||
* | {@link ng.directive:ngShow ngShow} | aria-hidden |
|
||||
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
|
||||
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
|
||||
* | {@link module:ngMessages ngMessages} | aria-live |
|
||||
* | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |
|
||||
* | {@link ng.directive:ngClick ngClick} | tabindex, keypress event, button role |
|
||||
* | {@link ng.directive:ngClick ngClick} | tabindex, keypress event, button role |
|
||||
*
|
||||
* Find out more information about each directive by reading the
|
||||
* {@link guide/accessibility ngAria Developer Guide}.
|
||||
*
|
||||
* ##Example
|
||||
* ## Example
|
||||
* Using ngDisabled with ngAria:
|
||||
* ```html
|
||||
* <md-checkbox ng-disabled="disabled">
|
||||
@ -48,7 +53,7 @@
|
||||
* <md-checkbox ng-disabled="disabled" aria-disabled="true">
|
||||
* ```
|
||||
*
|
||||
* ##Disabling Attributes
|
||||
* ## Disabling Attributes
|
||||
* It's possible to disable individual attributes added by ngAria with the
|
||||
* {@link ngAria.$ariaProvider#config config} method. For more details, see the
|
||||
* {@link guide/accessibility Developer Guide}.
|
||||
@ -92,10 +97,10 @@ function $AriaProvider() {
|
||||
var config = {
|
||||
ariaHidden: true,
|
||||
ariaChecked: true,
|
||||
ariaReadonly: true,
|
||||
ariaDisabled: true,
|
||||
ariaRequired: true,
|
||||
ariaInvalid: true,
|
||||
ariaMultiline: true,
|
||||
ariaValue: true,
|
||||
tabindex: true,
|
||||
bindKeypress: true,
|
||||
@ -110,14 +115,14 @@ function $AriaProvider() {
|
||||
*
|
||||
* - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
|
||||
* - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
|
||||
* - **ariaReadonly** – `{boolean}` – Enables/disables aria-readonly tags
|
||||
* - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
|
||||
* - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
|
||||
* - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags
|
||||
* - **ariaMultiline** – `{boolean}` – Enables/disables aria-multiline tags
|
||||
* - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags
|
||||
* - **tabindex** – `{boolean}` – Enables/disables tabindex tags
|
||||
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `<div>` and
|
||||
* `<li>` elements with ng-click
|
||||
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `div` and
|
||||
* `li` elements with ng-click
|
||||
* - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements like `div`
|
||||
* using ng-click, making them more accessible to users of assistive technologies
|
||||
*
|
||||
@ -156,15 +161,15 @@ function $AriaProvider() {
|
||||
*
|
||||
*```js
|
||||
* ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
|
||||
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled');
|
||||
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
|
||||
* }])
|
||||
*```
|
||||
* Shown above, the ngAria module creates a directive with the same signature as the
|
||||
* traditional `ng-disabled` directive. But this ngAria version is dedicated to
|
||||
* solely managing accessibility attributes. The internal `$aria` service is used to watch the
|
||||
* boolean attribute `ngDisabled`. If it has not been explicitly set by the developer,
|
||||
* `aria-disabled` is injected as an attribute with its value synchronized to the value in
|
||||
* `ngDisabled`.
|
||||
* solely managing accessibility attributes on custom elements. The internal `$aria` service is
|
||||
* used to watch the boolean attribute `ngDisabled`. If it has not been explicitly set by the
|
||||
* developer, `aria-disabled` is injected as an attribute with its value synchronized to the
|
||||
* value in `ngDisabled`.
|
||||
*
|
||||
* Because ngAria hooks into the `ng-disabled` directive, developers do not have to do
|
||||
* anything to enable this feature. The `aria-disabled` attribute is automatically managed
|
||||
@ -172,12 +177,16 @@ function $AriaProvider() {
|
||||
*
|
||||
* The full list of directives that interface with ngAria:
|
||||
* * **ngModel**
|
||||
* * **ngChecked**
|
||||
* * **ngReadonly**
|
||||
* * **ngRequired**
|
||||
* * **ngDisabled**
|
||||
* * **ngValue**
|
||||
* * **ngShow**
|
||||
* * **ngHide**
|
||||
* * **ngClick**
|
||||
* * **ngDblclick**
|
||||
* * **ngMessages**
|
||||
* * **ngDisabled**
|
||||
*
|
||||
* Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
|
||||
* directive.
|
||||
@ -203,13 +212,28 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
.directive('ngHide', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);
|
||||
}])
|
||||
.directive('ngValue', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngValue', 'aria-checked', nodeBlackList, false);
|
||||
}])
|
||||
.directive('ngChecked', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngChecked', 'aria-checked', nodeBlackList, false);
|
||||
}])
|
||||
.directive('ngReadonly', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nodeBlackList, false);
|
||||
}])
|
||||
.directive('ngRequired', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngRequired', 'aria-required', nodeBlackList, false);
|
||||
}])
|
||||
.directive('ngModel', ['$aria', function($aria) {
|
||||
|
||||
function shouldAttachAttr(attr, normalizedAttr, elem) {
|
||||
return $aria.config(normalizedAttr) && !elem.attr(attr);
|
||||
function shouldAttachAttr(attr, normalizedAttr, elem, allowBlacklistEls) {
|
||||
return $aria.config(normalizedAttr) && !elem.attr(attr) && (allowBlacklistEls || !isNodeOneOf(elem, nodeBlackList));
|
||||
}
|
||||
|
||||
function shouldAttachRole(role, elem) {
|
||||
// if element does not have role attribute
|
||||
// AND element type is equal to role (if custom element has a type equaling shape) <-- remove?
|
||||
// AND element is not INPUT
|
||||
return !elem.attr('role') && (elem.attr('type') === role) && (elem[0].nodeName !== 'INPUT');
|
||||
}
|
||||
|
||||
@ -219,20 +243,19 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
|
||||
return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' :
|
||||
((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' :
|
||||
(type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' :
|
||||
(type || role) === 'textbox' || elem[0].nodeName === 'TEXTAREA' ? 'multiline' : '';
|
||||
(type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' : '';
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '?ngModel',
|
||||
require: 'ngModel',
|
||||
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
|
||||
compile: function(elem, attr) {
|
||||
var shape = getShape(attr, elem);
|
||||
|
||||
return {
|
||||
pre: function(scope, elem, attr, ngModel) {
|
||||
if (shape === 'checkbox' && attr.type !== 'checkbox') {
|
||||
if (shape === 'checkbox') {
|
||||
//Use the input[checkbox] $isEmpty implementation for elements with checkbox roles
|
||||
ngModel.$isEmpty = function(value) {
|
||||
return value === false;
|
||||
@ -240,29 +263,18 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
}
|
||||
},
|
||||
post: function(scope, elem, attr, ngModel) {
|
||||
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem)
|
||||
&& !isNodeOneOf(elem, nodeBlackList);
|
||||
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
|
||||
|
||||
function ngAriaWatchModelValue() {
|
||||
return ngModel.$modelValue;
|
||||
}
|
||||
|
||||
function getRadioReaction() {
|
||||
if (needsTabIndex) {
|
||||
needsTabIndex = false;
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
var boolVal = (attr.value == ngModel.$viewValue);
|
||||
elem.attr('aria-checked', boolVal);
|
||||
elem.attr('tabindex', 0 - !boolVal);
|
||||
};
|
||||
} else {
|
||||
return function ngAriaRadioReaction(newVal) {
|
||||
elem.attr('aria-checked', (attr.value == ngModel.$viewValue));
|
||||
};
|
||||
}
|
||||
function getRadioReaction(newVal) {
|
||||
var boolVal = (attr.value == ngModel.$viewValue);
|
||||
elem.attr('aria-checked', boolVal);
|
||||
}
|
||||
|
||||
function ngAriaCheckboxReaction() {
|
||||
function getCheckboxReaction() {
|
||||
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
|
||||
}
|
||||
|
||||
@ -272,9 +284,9 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
if (shouldAttachRole(shape, elem)) {
|
||||
elem.attr('role', shape);
|
||||
}
|
||||
if (shouldAttachAttr('aria-checked', 'ariaChecked', elem)) {
|
||||
if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {
|
||||
scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
|
||||
getRadioReaction() : ngAriaCheckboxReaction);
|
||||
getRadioReaction : getCheckboxReaction);
|
||||
}
|
||||
if (needsTabIndex) {
|
||||
elem.attr('tabindex', 0);
|
||||
@ -311,22 +323,17 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
elem.attr('tabindex', 0);
|
||||
}
|
||||
break;
|
||||
case 'multiline':
|
||||
if (shouldAttachAttr('aria-multiline', 'ariaMultiline', elem)) {
|
||||
elem.attr('aria-multiline', true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ngModel.$validators.required && shouldAttachAttr('aria-required', 'ariaRequired', elem)) {
|
||||
scope.$watch(function ngAriaRequiredWatch() {
|
||||
return ngModel.$error.required;
|
||||
}, function ngAriaRequiredReaction(newVal) {
|
||||
elem.attr('aria-required', !!newVal);
|
||||
if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required
|
||||
&& shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {
|
||||
// ngModel.$error.required is undefined on custom controls
|
||||
attr.$observe('required', function() {
|
||||
elem.attr('aria-required', !!attr['required']);
|
||||
});
|
||||
}
|
||||
|
||||
if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem)) {
|
||||
if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {
|
||||
scope.$watch(function ngAriaInvalidWatch() {
|
||||
return ngModel.$invalid;
|
||||
}, function ngAriaInvalidReaction(newVal) {
|
||||
@ -339,7 +346,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
};
|
||||
}])
|
||||
.directive('ngDisabled', ['$aria', function($aria) {
|
||||
return $aria.$$watchExpr('ngDisabled', 'aria-disabled', []);
|
||||
return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
|
||||
}])
|
||||
.directive('ngMessages', function() {
|
||||
return {
|
||||
|
6
xstatic/pkg/angular/data/angular-cookies.js
vendored
6
xstatic/pkg/angular/data/angular-cookies.js
vendored
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
|
27
xstatic/pkg/angular/data/angular-loader.js
vendored
27
xstatic/pkg/angular/data/angular-loader.js
vendored
@ -1,13 +1,13 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
(function() {'use strict';
|
||||
function isFunction(value) {return typeof value === 'function';};
|
||||
|
||||
/* global: toDebugString: true */
|
||||
/* global toDebugString: true */
|
||||
|
||||
function serializeObject(obj) {
|
||||
var seen = [];
|
||||
@ -87,7 +87,7 @@ function minErr(module, ErrorConstructor) {
|
||||
return match;
|
||||
});
|
||||
|
||||
message += '\nhttp://errors.angularjs.org/1.4.10/' +
|
||||
message += '\nhttp://errors.angularjs.org/1.5.8/' +
|
||||
(module ? module + '/' : '') + code;
|
||||
|
||||
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||
@ -296,9 +296,9 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#decorator
|
||||
* @module ng
|
||||
* @param {string} The name of the service to decorate.
|
||||
* @param {Function} This function will be invoked when the service needs to be
|
||||
* instantiated and should return the decorated service instance.
|
||||
* @param {string} name The name of the service to decorate.
|
||||
* @param {Function} decorFn This function will be invoked when the service needs to be
|
||||
* instantiated and should return the decorated service instance.
|
||||
* @description
|
||||
* See {@link auto.$provide#decorator $provide.decorator()}.
|
||||
*/
|
||||
@ -381,6 +381,19 @@ function setupModuleLoader(window) {
|
||||
*/
|
||||
directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#component
|
||||
* @module ng
|
||||
* @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
|
||||
* @param {Object} options Component definition object (a simplified
|
||||
* {@link ng.$compile#directive-definition-object directive definition object})
|
||||
*
|
||||
* @description
|
||||
* See {@link ng.$compileProvider#component $compileProvider.component()}.
|
||||
*/
|
||||
component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#config
|
||||
|
172
xstatic/pkg/angular/data/angular-message-format.js
vendored
172
xstatic/pkg/angular/data/angular-message-format.js
vendored
@ -1,20 +1,18 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
// NOTE: ADVANCED_OPTIMIZATIONS mode.
|
||||
//
|
||||
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
|
||||
// constructs incompatible with that mode.
|
||||
|
||||
var $interpolateMinErr = window['angular']['$interpolateMinErr'];
|
||||
|
||||
var noop = window['angular']['noop'],
|
||||
isFunction = window['angular']['isFunction'],
|
||||
toJson = window['angular']['toJson'];
|
||||
/* global isFunction: false */
|
||||
/* global noop: false */
|
||||
/* global toJson: false */
|
||||
|
||||
function stringify(value) {
|
||||
if (value == null /* null/undefined */) { return ''; }
|
||||
@ -861,31 +859,90 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
|
||||
// constructs incompatible with that mode.
|
||||
|
||||
/* global $interpolateMinErr: false */
|
||||
/* global $interpolateMinErr: true */
|
||||
/* global isFunction: true */
|
||||
/* global noop: true */
|
||||
/* global toJson: true */
|
||||
/* global MessageFormatParser: false */
|
||||
/* global stringify: false */
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $$messageFormat
|
||||
* @ngdoc module
|
||||
* @name ngMessageFormat
|
||||
* @packageName angular-message-format
|
||||
*
|
||||
* @description
|
||||
* Angular internal service to recognize MessageFormat extensions in interpolation expressions.
|
||||
* For more information, see:
|
||||
* https://docs.google.com/a/google.com/document/d/1pbtW2yvtmFBikfRrJd8VAsabiFkKezmYZ_PbgdjQOVU/edit
|
||||
*
|
||||
* ## Example
|
||||
* ## What is ngMessageFormat?
|
||||
*
|
||||
* <example name="ngMessageFormat-example" module="msgFmtExample" deps="angular-message-format.min.js">
|
||||
* The ngMessageFormat module extends the Angular {@link ng.$interpolate `$interpolate`} service
|
||||
* with a syntax for handling pluralization and gender specific messages, which is based on the
|
||||
* [ICU MessageFormat syntax][ICU].
|
||||
*
|
||||
* See [the design doc][ngMessageFormat doc] for more information.
|
||||
*
|
||||
* [ICU]: http://userguide.icu-project.org/formatparse/messages#TOC-MessageFormat
|
||||
* [ngMessageFormat doc]: https://docs.google.com/a/google.com/document/d/1pbtW2yvtmFBikfRrJd8VAsabiFkKezmYZ_PbgdjQOVU/edit
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ### Gender
|
||||
*
|
||||
* This example uses the "select" keyword to specify the message based on gender.
|
||||
*
|
||||
* <example name="ngMessageFormat-example-gender" module="msgFmtExample" deps="angular-message-format.js">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="AppController">
|
||||
* Select Recipient:<br>
|
||||
<select ng-model="recipient" ng-options="person as person.name for person in recipients">
|
||||
</select>
|
||||
<p>{{recipient.gender, select,
|
||||
male {{{recipient.name}} unwrapped his gift. }
|
||||
female {{{recipient.name}} unwrapped her gift. }
|
||||
other {{{recipient.name}} unwrapped their gift. }
|
||||
}}</p>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="script.js">
|
||||
* function Person(name, gender) {
|
||||
* this.name = name;
|
||||
* this.gender = gender;
|
||||
* }
|
||||
*
|
||||
* var alice = new Person("Alice", "female"),
|
||||
* bob = new Person("Bob", "male"),
|
||||
* ashley = new Person("Ashley", "");
|
||||
*
|
||||
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
||||
* .controller('AppController', ['$scope', function($scope) {
|
||||
* $scope.recipients = [alice, bob, ashley];
|
||||
* $scope.recipient = $scope.recipients[0];
|
||||
* }]);
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* ### Plural
|
||||
*
|
||||
* This example shows how the "plural" keyword is used to account for a variable number of entities.
|
||||
* The "#" variable holds the current number and can be embedded in the message.
|
||||
*
|
||||
* Note that "=1" takes precedence over "one".
|
||||
*
|
||||
* The example also shows the "offset" keyword, which allows you to offset the value of the "#" variable.
|
||||
*
|
||||
* <example name="ngMessageFormat-example-plural" module="msgFmtExample" deps="angular-message-format.js">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="AppController">
|
||||
* <button ng-click="decreaseRecipients()" id="decreaseRecipients">decreaseRecipients</button><br>
|
||||
* <span>{{recipients.length, plural, offset:1
|
||||
* <button ng-click="recipients.pop()" id="decreaseRecipients">decreaseRecipients</button><br>
|
||||
* Select recipients:<br>
|
||||
* <select multiple size=5 ng-model="recipients" ng-options="person as person.name for person in people">
|
||||
* </select><br>
|
||||
* <p>{{recipients.length, plural, offset:1
|
||||
* =0 {{{sender.name}} gave no gifts (\#=#)}
|
||||
* =1 {{{sender.name}} gave one gift to {{recipients[0].name}} (\#=#)}
|
||||
* =1 {{{sender.name}} gave a gift to {{recipients[0].name}} (\#=#)}
|
||||
* one {{{sender.name}} gave {{recipients[0].name}} and one other person a gift (\#=#)}
|
||||
* other {{{sender.name}} gave {{recipients[0].name}} and # other people a gift (\#=#)}
|
||||
* }}</span>
|
||||
* }}</p>
|
||||
* </div>
|
||||
* </file>
|
||||
*
|
||||
@ -897,35 +954,79 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
||||
*
|
||||
* var alice = new Person("Alice", "female"),
|
||||
* bob = new Person("Bob", "male"),
|
||||
* charlie = new Person("Charlie", "male"),
|
||||
* harry = new Person("Harry Potter", "male");
|
||||
* sarah = new Person("Sarah", "female"),
|
||||
* harry = new Person("Harry Potter", "male"),
|
||||
* ashley = new Person("Ashley", "");
|
||||
*
|
||||
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
||||
* .controller('AppController', ['$scope', function($scope) {
|
||||
* $scope.recipients = [alice, bob, charlie];
|
||||
* $scope.people = [alice, bob, sarah, ashley];
|
||||
* $scope.recipients = [alice, bob, sarah];
|
||||
* $scope.sender = harry;
|
||||
* $scope.decreaseRecipients = function() {
|
||||
* --$scope.recipients.length;
|
||||
* };
|
||||
* }]);
|
||||
* </file>
|
||||
*
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* describe('MessageFormat plural', function() {
|
||||
*
|
||||
* it('should pluralize initial values', function() {
|
||||
* var messageElem = element(by.binding('recipients.length')), decreaseRecipientsBtn = element(by.id('decreaseRecipients'));
|
||||
* var messageElem = element(by.binding('recipients.length')),
|
||||
* decreaseRecipientsBtn = element(by.id('decreaseRecipients'));
|
||||
*
|
||||
* expect(messageElem.getText()).toEqual('Harry Potter gave Alice and 2 other people a gift (#=2)');
|
||||
* decreaseRecipientsBtn.click();
|
||||
* expect(messageElem.getText()).toEqual('Harry Potter gave Alice and one other person a gift (#=1)');
|
||||
* decreaseRecipientsBtn.click();
|
||||
* expect(messageElem.getText()).toEqual('Harry Potter gave one gift to Alice (#=0)');
|
||||
* expect(messageElem.getText()).toEqual('Harry Potter gave a gift to Alice (#=0)');
|
||||
* decreaseRecipientsBtn.click();
|
||||
* expect(messageElem.getText()).toEqual('Harry Potter gave no gifts (#=-1)');
|
||||
* });
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* ### Plural and Gender together
|
||||
*
|
||||
* This example shows how you can specify gender rules for specific plural matches - in this case,
|
||||
* =1 is special cased for gender.
|
||||
* <example name="ngMessageFormat-example-plural-gender" module="msgFmtExample" deps="angular-message-format.js">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="AppController">
|
||||
Select recipients:<br>
|
||||
<select multiple size=5 ng-model="recipients" ng-options="person as person.name for person in people">
|
||||
</select><br>
|
||||
<p>{{recipients.length, plural,
|
||||
=0 {{{sender.name}} has not given any gifts to anyone.}
|
||||
=1 { {{recipients[0].gender, select,
|
||||
female { {{sender.name}} gave {{recipients[0].name}} her gift.}
|
||||
male { {{sender.name}} gave {{recipients[0].name}} his gift.}
|
||||
other { {{sender.name}} gave {{recipients[0].name}} their gift.}
|
||||
}}
|
||||
}
|
||||
other {{{sender.name}} gave {{recipients.length}} people gifts.}
|
||||
}}</p>
|
||||
</file>
|
||||
* <file name="script.js">
|
||||
* function Person(name, gender) {
|
||||
* this.name = name;
|
||||
* this.gender = gender;
|
||||
* }
|
||||
*
|
||||
* var alice = new Person("Alice", "female"),
|
||||
* bob = new Person("Bob", "male"),
|
||||
* harry = new Person("Harry Potter", "male"),
|
||||
* ashley = new Person("Ashley", "");
|
||||
*
|
||||
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
||||
* .controller('AppController', ['$scope', function($scope) {
|
||||
* $scope.people = [alice, bob, ashley];
|
||||
* $scope.recipients = [alice];
|
||||
* $scope.sender = harry;
|
||||
* }]);
|
||||
* </file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
var $$MessageFormatFactory = ['$parse', '$locale', '$sce', '$exceptionHandler', function $$messageFormat(
|
||||
$parse, $locale, $sce, $exceptionHandler) {
|
||||
|
||||
@ -963,16 +1064,19 @@ var $$interpolateDecorator = ['$$messageFormat', '$delegate', function $$interpo
|
||||
return interpolate;
|
||||
}];
|
||||
|
||||
var $interpolateMinErr;
|
||||
var isFunction;
|
||||
var noop;
|
||||
var toJson;
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngMessageFormat
|
||||
* @packageName angular-message-format
|
||||
* @description
|
||||
*/
|
||||
var module = window['angular']['module']('ngMessageFormat', ['ng']);
|
||||
module['factory']('$$messageFormat', $$MessageFormatFactory);
|
||||
module['config'](['$provide', function($provide) {
|
||||
$interpolateMinErr = window['angular']['$interpolateMinErr'];
|
||||
isFunction = window['angular']['isFunction'];
|
||||
noop = window['angular']['noop'];
|
||||
toJson = window['angular']['toJson'];
|
||||
|
||||
$provide['decorator']('$interpolate', $$interpolateDecorator);
|
||||
}]);
|
||||
|
||||
|
707
xstatic/pkg/angular/data/angular-messages.js
vendored
707
xstatic/pkg/angular/data/angular-messages.js
vendored
@ -1,17 +1,14 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
/* jshint ignore:start */
|
||||
// this code is in the core, but not in angular-messages.js
|
||||
var isArray = angular.isArray;
|
||||
var forEach = angular.forEach;
|
||||
var isString = angular.isString;
|
||||
var jqLite = angular.element;
|
||||
/* jshint ignore:end */
|
||||
var forEach;
|
||||
var isArray;
|
||||
var isString;
|
||||
var jqLite;
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@ -267,369 +264,404 @@ var jqLite = angular.element;
|
||||
*
|
||||
* {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
|
||||
*/
|
||||
angular.module('ngMessages', [])
|
||||
angular.module('ngMessages', [], function initAngularHelpers() {
|
||||
// Access helpers from angular core.
|
||||
// Do it inside a `config` block to ensure `window.angular` is available.
|
||||
forEach = angular.forEach;
|
||||
isArray = angular.isArray;
|
||||
isString = angular.isString;
|
||||
jqLite = angular.element;
|
||||
})
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @module ngMessages
|
||||
* @name ngMessages
|
||||
* @restrict AE
|
||||
*
|
||||
* @description
|
||||
* `ngMessages` is a directive that is designed to show and hide messages based on the state
|
||||
* of a key/value object that it listens on. The directive itself complements error message
|
||||
* reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
|
||||
*
|
||||
* `ngMessages` manages the state of internal messages within its container element. The internal
|
||||
* messages use the `ngMessage` directive and will be inserted/removed from the page depending
|
||||
* on if they're present within the key/value object. By default, only one message will be displayed
|
||||
* at a time and this depends on the prioritization of the messages within the template. (This can
|
||||
* be changed by using the `ng-messages-multiple` or `multiple` attribute on the directive container.)
|
||||
*
|
||||
* A remote template can also be used to promote message reusability and messages can also be
|
||||
* overridden.
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression" role="alert">
|
||||
* <ANY ng-message="stringValue">...</ANY>
|
||||
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
|
||||
* <ANY ng-message-exp="expressionValue">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression" role="alert">
|
||||
* <ng-message when="stringValue">...</ng-message>
|
||||
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
|
||||
* <ng-message when-exp="expressionValue">...</ng-message>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* @param {string} ngMessages an angular expression evaluating to a key/value object
|
||||
* (this is typically the $error object on an ngModel instance).
|
||||
* @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
|
||||
*
|
||||
* @example
|
||||
* <example name="ngMessages-directive" module="ngMessagesExample"
|
||||
* deps="angular-messages.js"
|
||||
* animations="true" fixBase="true">
|
||||
* <file name="index.html">
|
||||
* <form name="myForm">
|
||||
* <label>
|
||||
* Enter your name:
|
||||
* <input type="text"
|
||||
* name="myName"
|
||||
* ng-model="name"
|
||||
* ng-minlength="5"
|
||||
* ng-maxlength="20"
|
||||
* required />
|
||||
* </label>
|
||||
* <pre>myForm.myName.$error = {{ myForm.myName.$error | json }}</pre>
|
||||
*
|
||||
* <div ng-messages="myForm.myName.$error" style="color:maroon" role="alert">
|
||||
* <div ng-message="required">You did not enter a field</div>
|
||||
* <div ng-message="minlength">Your field is too short</div>
|
||||
* <div ng-message="maxlength">Your field is too long</div>
|
||||
* </div>
|
||||
* </form>
|
||||
* </file>
|
||||
* <file name="script.js">
|
||||
* angular.module('ngMessagesExample', ['ngMessages']);
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
.directive('ngMessages', ['$animate', function($animate) {
|
||||
var ACTIVE_CLASS = 'ng-active';
|
||||
var INACTIVE_CLASS = 'ng-inactive';
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @module ngMessages
|
||||
* @name ngMessages
|
||||
* @restrict AE
|
||||
*
|
||||
* @description
|
||||
* `ngMessages` is a directive that is designed to show and hide messages based on the state
|
||||
* of a key/value object that it listens on. The directive itself complements error message
|
||||
* reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
|
||||
*
|
||||
* `ngMessages` manages the state of internal messages within its container element. The internal
|
||||
* messages use the `ngMessage` directive and will be inserted/removed from the page depending
|
||||
* on if they're present within the key/value object. By default, only one message will be displayed
|
||||
* at a time and this depends on the prioritization of the messages within the template. (This can
|
||||
* be changed by using the `ng-messages-multiple` or `multiple` attribute on the directive container.)
|
||||
*
|
||||
* A remote template can also be used to promote message reusability and messages can also be
|
||||
* overridden.
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression" role="alert">
|
||||
* <ANY ng-message="stringValue">...</ANY>
|
||||
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
|
||||
* <ANY ng-message-exp="expressionValue">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression" role="alert">
|
||||
* <ng-message when="stringValue">...</ng-message>
|
||||
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
|
||||
* <ng-message when-exp="expressionValue">...</ng-message>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* @param {string} ngMessages an angular expression evaluating to a key/value object
|
||||
* (this is typically the $error object on an ngModel instance).
|
||||
* @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
|
||||
*
|
||||
* @example
|
||||
* <example name="ngMessages-directive" module="ngMessagesExample"
|
||||
* deps="angular-messages.js"
|
||||
* animations="true" fixBase="true">
|
||||
* <file name="index.html">
|
||||
* <form name="myForm">
|
||||
* <label>
|
||||
* Enter your name:
|
||||
* <input type="text"
|
||||
* name="myName"
|
||||
* ng-model="name"
|
||||
* ng-minlength="5"
|
||||
* ng-maxlength="20"
|
||||
* required />
|
||||
* </label>
|
||||
* <pre>myForm.myName.$error = {{ myForm.myName.$error | json }}</pre>
|
||||
*
|
||||
* <div ng-messages="myForm.myName.$error" style="color:maroon" role="alert">
|
||||
* <div ng-message="required">You did not enter a field</div>
|
||||
* <div ng-message="minlength">Your field is too short</div>
|
||||
* <div ng-message="maxlength">Your field is too long</div>
|
||||
* </div>
|
||||
* </form>
|
||||
* </file>
|
||||
* <file name="script.js">
|
||||
* angular.module('ngMessagesExample', ['ngMessages']);
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
.directive('ngMessages', ['$animate', function($animate) {
|
||||
var ACTIVE_CLASS = 'ng-active';
|
||||
var INACTIVE_CLASS = 'ng-inactive';
|
||||
|
||||
return {
|
||||
require: 'ngMessages',
|
||||
restrict: 'AE',
|
||||
controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
|
||||
var ctrl = this;
|
||||
var latestKey = 0;
|
||||
var nextAttachId = 0;
|
||||
return {
|
||||
require: 'ngMessages',
|
||||
restrict: 'AE',
|
||||
controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
|
||||
var ctrl = this;
|
||||
var latestKey = 0;
|
||||
var nextAttachId = 0;
|
||||
|
||||
this.getAttachId = function getAttachId() { return nextAttachId++; };
|
||||
this.getAttachId = function getAttachId() { return nextAttachId++; };
|
||||
|
||||
var messages = this.messages = {};
|
||||
var renderLater, cachedCollection;
|
||||
var messages = this.messages = {};
|
||||
var renderLater, cachedCollection;
|
||||
|
||||
this.render = function(collection) {
|
||||
collection = collection || {};
|
||||
this.render = function(collection) {
|
||||
collection = collection || {};
|
||||
|
||||
renderLater = false;
|
||||
cachedCollection = collection;
|
||||
renderLater = false;
|
||||
cachedCollection = collection;
|
||||
|
||||
// this is true if the attribute is empty or if the attribute value is truthy
|
||||
var multiple = isAttrTruthy($scope, $attrs.ngMessagesMultiple) ||
|
||||
isAttrTruthy($scope, $attrs.multiple);
|
||||
// this is true if the attribute is empty or if the attribute value is truthy
|
||||
var multiple = isAttrTruthy($scope, $attrs.ngMessagesMultiple) ||
|
||||
isAttrTruthy($scope, $attrs.multiple);
|
||||
|
||||
var unmatchedMessages = [];
|
||||
var matchedKeys = {};
|
||||
var messageItem = ctrl.head;
|
||||
var messageFound = false;
|
||||
var totalMessages = 0;
|
||||
var unmatchedMessages = [];
|
||||
var matchedKeys = {};
|
||||
var messageItem = ctrl.head;
|
||||
var messageFound = false;
|
||||
var totalMessages = 0;
|
||||
|
||||
// we use != instead of !== to allow for both undefined and null values
|
||||
while (messageItem != null) {
|
||||
totalMessages++;
|
||||
var messageCtrl = messageItem.message;
|
||||
// we use != instead of !== to allow for both undefined and null values
|
||||
while (messageItem != null) {
|
||||
totalMessages++;
|
||||
var messageCtrl = messageItem.message;
|
||||
|
||||
var messageUsed = false;
|
||||
if (!messageFound) {
|
||||
forEach(collection, function(value, key) {
|
||||
if (!messageUsed && truthy(value) && messageCtrl.test(key)) {
|
||||
// this is to prevent the same error name from showing up twice
|
||||
if (matchedKeys[key]) return;
|
||||
matchedKeys[key] = true;
|
||||
var messageUsed = false;
|
||||
if (!messageFound) {
|
||||
forEach(collection, function(value, key) {
|
||||
if (!messageUsed && truthy(value) && messageCtrl.test(key)) {
|
||||
// this is to prevent the same error name from showing up twice
|
||||
if (matchedKeys[key]) return;
|
||||
matchedKeys[key] = true;
|
||||
|
||||
messageUsed = true;
|
||||
messageCtrl.attach();
|
||||
}
|
||||
});
|
||||
}
|
||||
messageUsed = true;
|
||||
messageCtrl.attach();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (messageUsed) {
|
||||
// unless we want to display multiple messages then we should
|
||||
// set a flag here to avoid displaying the next message in the list
|
||||
messageFound = !multiple;
|
||||
} else {
|
||||
unmatchedMessages.push(messageCtrl);
|
||||
}
|
||||
if (messageUsed) {
|
||||
// unless we want to display multiple messages then we should
|
||||
// set a flag here to avoid displaying the next message in the list
|
||||
messageFound = !multiple;
|
||||
} else {
|
||||
unmatchedMessages.push(messageCtrl);
|
||||
}
|
||||
|
||||
messageItem = messageItem.next;
|
||||
}
|
||||
messageItem = messageItem.next;
|
||||
}
|
||||
|
||||
forEach(unmatchedMessages, function(messageCtrl) {
|
||||
messageCtrl.detach();
|
||||
});
|
||||
forEach(unmatchedMessages, function(messageCtrl) {
|
||||
messageCtrl.detach();
|
||||
});
|
||||
|
||||
unmatchedMessages.length !== totalMessages
|
||||
unmatchedMessages.length !== totalMessages
|
||||
? $animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS)
|
||||
: $animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
|
||||
};
|
||||
};
|
||||
|
||||
$scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
|
||||
$scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
|
||||
|
||||
this.reRender = function() {
|
||||
if (!renderLater) {
|
||||
renderLater = true;
|
||||
$scope.$evalAsync(function() {
|
||||
if (renderLater) {
|
||||
cachedCollection && ctrl.render(cachedCollection);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
// If the element is destroyed, proactively destroy all the currently visible messages
|
||||
$element.on('$destroy', function() {
|
||||
forEach(messages, function(item) {
|
||||
item.message.detach();
|
||||
});
|
||||
});
|
||||
|
||||
this.register = function(comment, messageCtrl) {
|
||||
var nextKey = latestKey.toString();
|
||||
messages[nextKey] = {
|
||||
message: messageCtrl
|
||||
};
|
||||
insertMessageNode($element[0], comment, nextKey);
|
||||
comment.$$ngMessageNode = nextKey;
|
||||
latestKey++;
|
||||
this.reRender = function() {
|
||||
if (!renderLater) {
|
||||
renderLater = true;
|
||||
$scope.$evalAsync(function() {
|
||||
if (renderLater) {
|
||||
cachedCollection && ctrl.render(cachedCollection);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ctrl.reRender();
|
||||
};
|
||||
this.register = function(comment, messageCtrl) {
|
||||
var nextKey = latestKey.toString();
|
||||
messages[nextKey] = {
|
||||
message: messageCtrl
|
||||
};
|
||||
insertMessageNode($element[0], comment, nextKey);
|
||||
comment.$$ngMessageNode = nextKey;
|
||||
latestKey++;
|
||||
|
||||
this.deregister = function(comment) {
|
||||
var key = comment.$$ngMessageNode;
|
||||
delete comment.$$ngMessageNode;
|
||||
removeMessageNode($element[0], comment, key);
|
||||
delete messages[key];
|
||||
ctrl.reRender();
|
||||
};
|
||||
ctrl.reRender();
|
||||
};
|
||||
|
||||
function findPreviousMessage(parent, comment) {
|
||||
var prevNode = comment;
|
||||
var parentLookup = [];
|
||||
while (prevNode && prevNode !== parent) {
|
||||
var prevKey = prevNode.$$ngMessageNode;
|
||||
if (prevKey && prevKey.length) {
|
||||
return messages[prevKey];
|
||||
}
|
||||
this.deregister = function(comment) {
|
||||
var key = comment.$$ngMessageNode;
|
||||
delete comment.$$ngMessageNode;
|
||||
removeMessageNode($element[0], comment, key);
|
||||
delete messages[key];
|
||||
ctrl.reRender();
|
||||
};
|
||||
|
||||
// dive deeper into the DOM and examine its children for any ngMessage
|
||||
// comments that may be in an element that appears deeper in the list
|
||||
if (prevNode.childNodes.length && parentLookup.indexOf(prevNode) == -1) {
|
||||
parentLookup.push(prevNode);
|
||||
prevNode = prevNode.childNodes[prevNode.childNodes.length - 1];
|
||||
} else {
|
||||
prevNode = prevNode.previousSibling || prevNode.parentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
function findPreviousMessage(parent, comment) {
|
||||
var prevNode = comment;
|
||||
var parentLookup = [];
|
||||
|
||||
function insertMessageNode(parent, comment, key) {
|
||||
var messageNode = messages[key];
|
||||
if (!ctrl.head) {
|
||||
ctrl.head = messageNode;
|
||||
} else {
|
||||
var match = findPreviousMessage(parent, comment);
|
||||
if (match) {
|
||||
messageNode.next = match.next;
|
||||
match.next = messageNode;
|
||||
} else {
|
||||
messageNode.next = ctrl.head;
|
||||
ctrl.head = messageNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (prevNode && prevNode !== parent) {
|
||||
var prevKey = prevNode.$$ngMessageNode;
|
||||
if (prevKey && prevKey.length) {
|
||||
return messages[prevKey];
|
||||
}
|
||||
|
||||
function removeMessageNode(parent, comment, key) {
|
||||
var messageNode = messages[key];
|
||||
// dive deeper into the DOM and examine its children for any ngMessage
|
||||
// comments that may be in an element that appears deeper in the list
|
||||
if (prevNode.childNodes.length && parentLookup.indexOf(prevNode) === -1) {
|
||||
parentLookup.push(prevNode);
|
||||
prevNode = prevNode.childNodes[prevNode.childNodes.length - 1];
|
||||
} else if (prevNode.previousSibling) {
|
||||
prevNode = prevNode.previousSibling;
|
||||
} else {
|
||||
prevNode = prevNode.parentNode;
|
||||
parentLookup.push(prevNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var match = findPreviousMessage(parent, comment);
|
||||
if (match) {
|
||||
match.next = messageNode.next;
|
||||
} else {
|
||||
ctrl.head = messageNode.next;
|
||||
}
|
||||
}
|
||||
}]
|
||||
};
|
||||
function insertMessageNode(parent, comment, key) {
|
||||
var messageNode = messages[key];
|
||||
if (!ctrl.head) {
|
||||
ctrl.head = messageNode;
|
||||
} else {
|
||||
var match = findPreviousMessage(parent, comment);
|
||||
if (match) {
|
||||
messageNode.next = match.next;
|
||||
match.next = messageNode;
|
||||
} else {
|
||||
messageNode.next = ctrl.head;
|
||||
ctrl.head = messageNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isAttrTruthy(scope, attr) {
|
||||
return (isString(attr) && attr.length === 0) || //empty attribute
|
||||
truthy(scope.$eval(attr));
|
||||
}
|
||||
function removeMessageNode(parent, comment, key) {
|
||||
var messageNode = messages[key];
|
||||
|
||||
function truthy(val) {
|
||||
return isString(val) ? val.length : !!val;
|
||||
}
|
||||
}])
|
||||
var match = findPreviousMessage(parent, comment);
|
||||
if (match) {
|
||||
match.next = messageNode.next;
|
||||
} else {
|
||||
ctrl.head = messageNode.next;
|
||||
}
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMessagesInclude
|
||||
* @restrict AE
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessagesInclude` is a directive with the purpose to import existing ngMessage template
|
||||
* code from a remote template and place the downloaded template code into the exact spot
|
||||
* that the ngMessagesInclude directive is placed within the ngMessages container. This allows
|
||||
* for a series of pre-defined messages to be reused and also allows for the developer to
|
||||
* determine what messages are overridden due to the placement of the ngMessagesInclude directive.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression" role="alert">
|
||||
* <ANY ng-messages-include="remoteTplString">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression" role="alert">
|
||||
* <ng-messages-include src="expressionValue1">...</ng-messages-include>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
*
|
||||
* @param {string} ngMessagesInclude|src a string value corresponding to the remote template.
|
||||
*/
|
||||
.directive('ngMessagesInclude',
|
||||
['$templateRequest', '$document', '$compile', function($templateRequest, $document, $compile) {
|
||||
function isAttrTruthy(scope, attr) {
|
||||
return (isString(attr) && attr.length === 0) || //empty attribute
|
||||
truthy(scope.$eval(attr));
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'AE',
|
||||
require: '^^ngMessages', // we only require this for validation sake
|
||||
link: function($scope, element, attrs) {
|
||||
var src = attrs.ngMessagesInclude || attrs.src;
|
||||
$templateRequest(src).then(function(html) {
|
||||
$compile(html)($scope, function(contents) {
|
||||
element.after(contents);
|
||||
function truthy(val) {
|
||||
return isString(val) ? val.length : !!val;
|
||||
}
|
||||
}])
|
||||
|
||||
// the anchor is placed for debugging purposes
|
||||
var anchor = jqLite($document[0].createComment(' ngMessagesInclude: ' + src + ' '));
|
||||
element.after(anchor);
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMessagesInclude
|
||||
* @restrict AE
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessagesInclude` is a directive with the purpose to import existing ngMessage template
|
||||
* code from a remote template and place the downloaded template code into the exact spot
|
||||
* that the ngMessagesInclude directive is placed within the ngMessages container. This allows
|
||||
* for a series of pre-defined messages to be reused and also allows for the developer to
|
||||
* determine what messages are overridden due to the placement of the ngMessagesInclude directive.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression" role="alert">
|
||||
* <ANY ng-messages-include="remoteTplString">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression" role="alert">
|
||||
* <ng-messages-include src="expressionValue1">...</ng-messages-include>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
*
|
||||
* @param {string} ngMessagesInclude|src a string value corresponding to the remote template.
|
||||
*/
|
||||
.directive('ngMessagesInclude',
|
||||
['$templateRequest', '$document', '$compile', function($templateRequest, $document, $compile) {
|
||||
|
||||
// we don't want to pollute the DOM anymore by keeping an empty directive element
|
||||
element.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}])
|
||||
return {
|
||||
restrict: 'AE',
|
||||
require: '^^ngMessages', // we only require this for validation sake
|
||||
link: function($scope, element, attrs) {
|
||||
var src = attrs.ngMessagesInclude || attrs.src;
|
||||
$templateRequest(src).then(function(html) {
|
||||
if ($scope.$$destroyed) return;
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMessage
|
||||
* @restrict AE
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessage` is a directive with the purpose to show and hide a particular message.
|
||||
* For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element
|
||||
* must be situated since it determines which messages are visible based on the state
|
||||
* of the provided key/value map that `ngMessages` listens on.
|
||||
*
|
||||
* More information about using `ngMessage` can be found in the
|
||||
* {@link module:ngMessages `ngMessages` module documentation}.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression" role="alert">
|
||||
* <ANY ng-message="stringValue">...</ANY>
|
||||
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression" role="alert">
|
||||
* <ng-message when="stringValue">...</ng-message>
|
||||
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* @param {expression} ngMessage|when a string value corresponding to the message key.
|
||||
*/
|
||||
.directive('ngMessage', ngMessageDirectiveFactory('AE'))
|
||||
if (isString(html) && !html.trim()) {
|
||||
// Empty template - nothing to compile
|
||||
replaceElementWithMarker(element, src);
|
||||
} else {
|
||||
// Non-empty template - compile and link
|
||||
$compile(html)($scope, function(contents) {
|
||||
element.after(contents);
|
||||
replaceElementWithMarker(element, src);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Helpers
|
||||
function replaceElementWithMarker(element, src) {
|
||||
// A comment marker is placed for debugging purposes
|
||||
var comment = $compile.$$createComment ?
|
||||
$compile.$$createComment('ngMessagesInclude', src) :
|
||||
$document[0].createComment(' ngMessagesInclude: ' + src + ' ');
|
||||
var marker = jqLite(comment);
|
||||
element.after(marker);
|
||||
|
||||
// Don't pollute the DOM anymore by keeping an empty directive element
|
||||
element.remove();
|
||||
}
|
||||
}])
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMessage
|
||||
* @restrict AE
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessage` is a directive with the purpose to show and hide a particular message.
|
||||
* For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element
|
||||
* must be situated since it determines which messages are visible based on the state
|
||||
* of the provided key/value map that `ngMessages` listens on.
|
||||
*
|
||||
* More information about using `ngMessage` can be found in the
|
||||
* {@link module:ngMessages `ngMessages` module documentation}.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression" role="alert">
|
||||
* <ANY ng-message="stringValue">...</ANY>
|
||||
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression" role="alert">
|
||||
* <ng-message when="stringValue">...</ng-message>
|
||||
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* @param {expression} ngMessage|when a string value corresponding to the message key.
|
||||
*/
|
||||
.directive('ngMessage', ngMessageDirectiveFactory())
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMessageExp
|
||||
* @restrict AE
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessageExp` is a directive with the purpose to show and hide a particular message.
|
||||
* For `ngMessageExp` to operate, a parent `ngMessages` directive on a parent DOM element
|
||||
* must be situated since it determines which messages are visible based on the state
|
||||
* of the provided key/value map that `ngMessages` listens on.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression">
|
||||
* <ANY ng-message-exp="expressionValue">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression">
|
||||
* <ng-message when-exp="expressionValue">...</ng-message>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
*
|
||||
* @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key.
|
||||
*/
|
||||
.directive('ngMessageExp', ngMessageDirectiveFactory('A'));
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMessageExp
|
||||
* @restrict AE
|
||||
* @priority 1
|
||||
* @scope
|
||||
*
|
||||
* @description
|
||||
* `ngMessageExp` is a directive with the purpose to show and hide a particular message.
|
||||
* For `ngMessageExp` to operate, a parent `ngMessages` directive on a parent DOM element
|
||||
* must be situated since it determines which messages are visible based on the state
|
||||
* of the provided key/value map that `ngMessages` listens on.
|
||||
*
|
||||
* @usage
|
||||
* ```html
|
||||
* <!-- using attribute directives -->
|
||||
* <ANY ng-messages="expression">
|
||||
* <ANY ng-message-exp="expressionValue">...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
* <!-- or by using element directives -->
|
||||
* <ng-messages for="expression">
|
||||
* <ng-message when-exp="expressionValue">...</ng-message>
|
||||
* </ng-messages>
|
||||
* ```
|
||||
*
|
||||
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
|
||||
*
|
||||
* @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key.
|
||||
*/
|
||||
.directive('ngMessageExp', ngMessageDirectiveFactory());
|
||||
|
||||
function ngMessageDirectiveFactory(restrict) {
|
||||
function ngMessageDirectiveFactory() {
|
||||
return ['$animate', function($animate) {
|
||||
return {
|
||||
restrict: 'AE',
|
||||
transclude: 'element',
|
||||
priority: 1, // must run before ngBind, otherwise the text is set on the comment
|
||||
terminal: true,
|
||||
require: '^^ngMessages',
|
||||
link: function(scope, element, attrs, ngMessagesCtrl, $transclude) {
|
||||
@ -641,8 +673,8 @@ function ngMessageDirectiveFactory(restrict) {
|
||||
var assignRecords = function(items) {
|
||||
records = items
|
||||
? (isArray(items)
|
||||
? items
|
||||
: items.split(/[\s,]+/))
|
||||
? items
|
||||
: items.split(/[\s,]+/))
|
||||
: null;
|
||||
ngMessagesCtrl.reRender();
|
||||
};
|
||||
@ -661,7 +693,7 @@ function ngMessageDirectiveFactory(restrict) {
|
||||
},
|
||||
attach: function() {
|
||||
if (!currentElement) {
|
||||
$transclude(scope, function(elm) {
|
||||
$transclude(function(elm, newScope) {
|
||||
$animate.enter(elm, null, element);
|
||||
currentElement = elm;
|
||||
|
||||
@ -669,14 +701,15 @@ function ngMessageDirectiveFactory(restrict) {
|
||||
// when we are destroying the node later.
|
||||
var $$attachId = currentElement.$$attachId = ngMessagesCtrl.getAttachId();
|
||||
|
||||
// in the event that the parent element is destroyed
|
||||
// by any other structural directive then it's time
|
||||
// in the event that the element or a parent element is destroyed
|
||||
// by another structural directive then it's time
|
||||
// to deregister the message from the controller
|
||||
currentElement.on('$destroy', function() {
|
||||
if (currentElement && currentElement.$$attachId === $$attachId) {
|
||||
ngMessagesCtrl.deregister(commentNode);
|
||||
messageCtrl.detach();
|
||||
}
|
||||
newScope.$destroy();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
846
xstatic/pkg/angular/data/angular-mocks.js
vendored
846
xstatic/pkg/angular/data/angular-mocks.js
vendored
File diff suppressed because it is too large
Load Diff
1271
xstatic/pkg/angular/data/angular-parse-ext.js
vendored
Normal file
1271
xstatic/pkg/angular/data/angular-parse-ext.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
269
xstatic/pkg/angular/data/angular-resource.js
vendored
269
xstatic/pkg/angular/data/angular-resource.js
vendored
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
var $resourceMinErr = angular.$$minErr('$resource');
|
||||
|
||||
@ -61,13 +61,30 @@ function shallowClearAndCopy(src, dst) {
|
||||
*
|
||||
* <div doc-module-components="ngResource"></div>
|
||||
*
|
||||
* See {@link ngResource.$resource `$resource`} for usage.
|
||||
* See {@link ngResource.$resourceProvider} and {@link ngResource.$resource} for usage.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $resourceProvider
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Use `$resourceProvider` to change the default behavior of the {@link ngResource.$resource}
|
||||
* service.
|
||||
*
|
||||
* ## Dependencies
|
||||
* Requires the {@link ngResource } module to be installed.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $resource
|
||||
* @requires $http
|
||||
* @requires ng.$log
|
||||
* @requires $q
|
||||
* @requires ng.$timeout
|
||||
*
|
||||
* @description
|
||||
* A factory which creates a resource object that lets you interact with
|
||||
@ -102,8 +119,9 @@ function shallowClearAndCopy(src, dst) {
|
||||
* can escape it with `/\.`.
|
||||
*
|
||||
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
||||
* `actions` methods. If a parameter value is a function, it will be executed every time
|
||||
* when a param value needs to be obtained for a request (unless the param was overridden).
|
||||
* `actions` methods. If a parameter value is a function, it will be called every time
|
||||
* a param value needs to be obtained for a request (unless the param was overridden). The function
|
||||
* will be passed the current data value as an argument.
|
||||
*
|
||||
* Each key value in the parameter object is first bound to url template if present and then any
|
||||
* excess keys are appended to the url search query after the `?`.
|
||||
@ -111,10 +129,13 @@ function shallowClearAndCopy(src, dst) {
|
||||
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
|
||||
* URL `/path/greet?salutation=Hello`.
|
||||
*
|
||||
* If the parameter value is prefixed with `@` then the value for that parameter will be extracted
|
||||
* from the corresponding property on the `data` object (provided when calling an action method). For
|
||||
* example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam`
|
||||
* will be `data.someProp`.
|
||||
* If the parameter value is prefixed with `@`, then the value for that parameter will be
|
||||
* extracted from the corresponding property on the `data` object (provided when calling a
|
||||
* "non-GET" action method).
|
||||
* For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
|
||||
* `someParam` will be `data.someProp`.
|
||||
* Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
|
||||
* method that does not accept a request body)
|
||||
*
|
||||
* @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
|
||||
* the default set of resource actions. The declaration should be created in the format of {@link
|
||||
@ -131,8 +152,9 @@ function shallowClearAndCopy(src, dst) {
|
||||
* - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
|
||||
* `DELETE`, `JSONP`, etc).
|
||||
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
|
||||
* the parameter value is a function, it will be executed every time when a param value needs to
|
||||
* be obtained for a request (unless the param was overridden).
|
||||
* the parameter value is a function, it will be called every time when a param value needs to
|
||||
* be obtained for a request (unless the param was overridden). The function will be passed the
|
||||
* current data value as an argument.
|
||||
* - **`url`** – {string} – action specific `url` override. The url templating is supported just
|
||||
* like for the resource-level urls.
|
||||
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
|
||||
@ -148,9 +170,9 @@ function shallowClearAndCopy(src, dst) {
|
||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||
* transform function or an array of such functions. The transform function takes the http
|
||||
* response body and headers and returns its transformed (typically deserialized) version.
|
||||
* By default, transformResponse will contain one function that checks if the response looks like
|
||||
* a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
|
||||
* `transformResponse` to an empty array: `transformResponse: []`
|
||||
* By default, transformResponse will contain one function that checks if the response looks
|
||||
* like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
|
||||
* set `transformResponse` to an empty array: `transformResponse: []`
|
||||
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
|
||||
* GET request, otherwise if a cache instance built with
|
||||
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
||||
@ -158,8 +180,11 @@ function shallowClearAndCopy(src, dst) {
|
||||
* - **`timeout`** – `{number}` – timeout in milliseconds.<br />
|
||||
* **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
|
||||
* **not** supported in $resource, because the same value would be used for multiple requests.
|
||||
* If you need support for cancellable $resource actions, you should upgrade to version 1.5 or
|
||||
* higher.
|
||||
* If you are looking for a way to cancel requests, you should use the `cancellable` option.
|
||||
* - **`cancellable`** – `{boolean}` – if set to true, the request made by a "non-instance" call
|
||||
* will be cancelled (if not already completed) by calling `$cancelRequest()` on the call's
|
||||
* return value. Calling `$cancelRequest()` for a non-cancellable or an already
|
||||
* completed/cancelled request will have no effect.<br />
|
||||
* - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
|
||||
* XHR object. See
|
||||
* [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
|
||||
@ -171,12 +196,13 @@ function shallowClearAndCopy(src, dst) {
|
||||
* with `http response` object. See {@link ng.$http $http interceptors}.
|
||||
*
|
||||
* @param {Object} options Hash with custom settings that should extend the
|
||||
* default `$resourceProvider` behavior. The only supported option is
|
||||
*
|
||||
* Where:
|
||||
* default `$resourceProvider` behavior. The supported options are:
|
||||
*
|
||||
* - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
|
||||
* slashes from any calculated URL will be stripped. (Defaults to true.)
|
||||
* - **`cancellable`** – {boolean} – If true, the request made by a "non-instance" call will be
|
||||
* cancelled (if not already completed) by calling `$cancelRequest()` on the call's return value.
|
||||
* This can be overwritten per action. (Defaults to false.)
|
||||
*
|
||||
* @returns {Object} A resource "class" object with methods for the default set of resource actions
|
||||
* optionally extended with custom `actions`. The default set contains these actions:
|
||||
@ -224,7 +250,7 @@ function shallowClearAndCopy(src, dst) {
|
||||
* Class actions return empty instance (with additional properties below).
|
||||
* Instance actions return promise of the action.
|
||||
*
|
||||
* The Resource instances and collection have these additional properties:
|
||||
* The Resource instances and collections have these additional properties:
|
||||
*
|
||||
* - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
|
||||
* instance or collection.
|
||||
@ -244,6 +270,19 @@ function shallowClearAndCopy(src, dst) {
|
||||
* rejection), `false` before that. Knowing if the Resource has been resolved is useful in
|
||||
* data-binding.
|
||||
*
|
||||
* The Resource instances and collections have these additional methods:
|
||||
*
|
||||
* - `$cancelRequest`: If there is a cancellable, pending request related to the instance or
|
||||
* collection, calling this method will abort the request.
|
||||
*
|
||||
* The Resource instances have these additional methods:
|
||||
*
|
||||
* - `toJSON`: It returns a simple object without any of the extra properties added as part of
|
||||
* the Resource API. This object can be serialized through {@link angular.toJson} safely
|
||||
* without attaching Angular-specific fields. Notice that `JSON.stringify` (and
|
||||
* `angular.toJson`) automatically use this method when serializing a Resource instance
|
||||
* (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior)).
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # Credit card resource
|
||||
@ -288,6 +327,11 @@ function shallowClearAndCopy(src, dst) {
|
||||
*
|
||||
* Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
|
||||
* `headers`.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # User resource
|
||||
*
|
||||
* When the data is returned from the server then the object is an instance of the resource type and
|
||||
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
|
||||
* operations (create, read, update, delete) on server-side data.
|
||||
@ -306,10 +350,10 @@ function shallowClearAndCopy(src, dst) {
|
||||
*
|
||||
```js
|
||||
var User = $resource('/user/:userId', {userId:'@id'});
|
||||
User.get({userId:123}, function(u, getResponseHeaders){
|
||||
u.abc = true;
|
||||
u.$save(function(u, putResponseHeaders) {
|
||||
//u => saved user object
|
||||
User.get({userId:123}, function(user, getResponseHeaders){
|
||||
user.abc = true;
|
||||
user.$save(function(user, putResponseHeaders) {
|
||||
//user => saved user object
|
||||
//putResponseHeaders => $http header getter
|
||||
});
|
||||
});
|
||||
@ -324,8 +368,11 @@ function shallowClearAndCopy(src, dst) {
|
||||
$scope.user = user;
|
||||
});
|
||||
```
|
||||
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # Creating a custom 'PUT' request
|
||||
*
|
||||
* In this example we create a custom method on our resource to make a PUT request
|
||||
* ```js
|
||||
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
||||
@ -353,16 +400,112 @@ function shallowClearAndCopy(src, dst) {
|
||||
* // This will PUT /notes/ID with the note object in the request payload
|
||||
* }]);
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* # Cancelling requests
|
||||
*
|
||||
* If an action's configuration specifies that it is cancellable, you can cancel the request related
|
||||
* to an instance or collection (as long as it is a result of a "non-instance" call):
|
||||
*
|
||||
```js
|
||||
// ...defining the `Hotel` resource...
|
||||
var Hotel = $resource('/api/hotel/:id', {id: '@id'}, {
|
||||
// Let's make the `query()` method cancellable
|
||||
query: {method: 'get', isArray: true, cancellable: true}
|
||||
});
|
||||
|
||||
// ...somewhere in the PlanVacationController...
|
||||
...
|
||||
this.onDestinationChanged = function onDestinationChanged(destination) {
|
||||
// We don't care about any pending request for hotels
|
||||
// in a different destination any more
|
||||
this.availableHotels.$cancelRequest();
|
||||
|
||||
// Let's query for hotels in '<destination>'
|
||||
// (calls: /api/hotel?location=<destination>)
|
||||
this.availableHotels = Hotel.query({location: destination});
|
||||
};
|
||||
```
|
||||
*
|
||||
*/
|
||||
angular.module('ngResource', ['ng']).
|
||||
provider('$resource', function() {
|
||||
var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
|
||||
var provider = this;
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name $resourceProvider#defaults
|
||||
* @description
|
||||
* Object containing default options used when creating `$resource` instances.
|
||||
*
|
||||
* The default values satisfy a wide range of usecases, but you may choose to overwrite any of
|
||||
* them to further customize your instances. The available properties are:
|
||||
*
|
||||
* - **stripTrailingSlashes** – `{boolean}` – If true, then the trailing slashes from any
|
||||
* calculated URL will be stripped.<br />
|
||||
* (Defaults to true.)
|
||||
* - **cancellable** – `{boolean}` – If true, the request made by a "non-instance" call will be
|
||||
* cancelled (if not already completed) by calling `$cancelRequest()` on the call's return
|
||||
* value. For more details, see {@link ngResource.$resource}. This can be overwritten per
|
||||
* resource class or action.<br />
|
||||
* (Defaults to false.)
|
||||
* - **actions** - `{Object.<Object>}` - A hash with default actions declarations. Actions are
|
||||
* high-level methods corresponding to RESTful actions/methods on resources. An action may
|
||||
* specify what HTTP method to use, what URL to hit, if the return value will be a single
|
||||
* object or a collection (array) of objects etc. For more details, see
|
||||
* {@link ngResource.$resource}. The actions can also be enhanced or overwritten per resource
|
||||
* class.<br />
|
||||
* The default actions are:
|
||||
* ```js
|
||||
* {
|
||||
* get: {method: 'GET'},
|
||||
* save: {method: 'POST'},
|
||||
* query: {method: 'GET', isArray: true},
|
||||
* remove: {method: 'DELETE'},
|
||||
* delete: {method: 'DELETE'}
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* #### Example
|
||||
*
|
||||
* For example, you can specify a new `update` action that uses the `PUT` HTTP verb:
|
||||
*
|
||||
* ```js
|
||||
* angular.
|
||||
* module('myApp').
|
||||
* config(['resourceProvider', function ($resourceProvider) {
|
||||
* $resourceProvider.defaults.actions.update = {
|
||||
* method: 'PUT'
|
||||
* };
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Or you can even overwrite the whole `actions` list and specify your own:
|
||||
*
|
||||
* ```js
|
||||
* angular.
|
||||
* module('myApp').
|
||||
* config(['resourceProvider', function ($resourceProvider) {
|
||||
* $resourceProvider.defaults.actions = {
|
||||
* create: {method: 'POST'}
|
||||
* get: {method: 'GET'},
|
||||
* getAll: {method: 'GET', isArray:true},
|
||||
* update: {method: 'PUT'},
|
||||
* delete: {method: 'DELETE'}
|
||||
* };
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
this.defaults = {
|
||||
// Strip slashes by default
|
||||
stripTrailingSlashes: true,
|
||||
|
||||
// Make non-instance requests cancellable (via `$cancelRequest()`)
|
||||
cancellable: false,
|
||||
|
||||
// Default actions configuration
|
||||
actions: {
|
||||
'get': {method: 'GET'},
|
||||
@ -373,7 +516,7 @@ angular.module('ngResource', ['ng']).
|
||||
}
|
||||
};
|
||||
|
||||
this.$get = ['$http', '$log', '$q', function($http, $log, $q) {
|
||||
this.$get = ['$http', '$log', '$q', '$timeout', function($http, $log, $q, $timeout) {
|
||||
|
||||
var noop = angular.noop,
|
||||
forEach = angular.forEach,
|
||||
@ -441,7 +584,9 @@ angular.module('ngResource', ['ng']).
|
||||
}
|
||||
if (!(new RegExp("^\\d+$").test(param)) && param &&
|
||||
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
||||
urlParams[param] = true;
|
||||
urlParams[param] = {
|
||||
isQueryParamValue: (new RegExp("\\?.*=:" + param + "(?:\\W|$)")).test(url)
|
||||
};
|
||||
}
|
||||
});
|
||||
url = url.replace(/\\:/g, ':');
|
||||
@ -451,10 +596,14 @@ angular.module('ngResource', ['ng']).
|
||||
});
|
||||
|
||||
params = params || {};
|
||||
forEach(self.urlParams, function(_, urlParam) {
|
||||
forEach(self.urlParams, function(paramInfo, urlParam) {
|
||||
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
||||
if (angular.isDefined(val) && val !== null) {
|
||||
encodedVal = encodeUriSegment(val);
|
||||
if (paramInfo.isQueryParamValue) {
|
||||
encodedVal = encodeUriQuery(val, true);
|
||||
} else {
|
||||
encodedVal = encodeUriSegment(val);
|
||||
}
|
||||
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
|
||||
return encodedVal + p1;
|
||||
});
|
||||
@ -502,7 +651,7 @@ angular.module('ngResource', ['ng']).
|
||||
var ids = {};
|
||||
actionParams = extend({}, paramDefaults, actionParams);
|
||||
forEach(actionParams, function(value, key) {
|
||||
if (isFunction(value)) { value = value(); }
|
||||
if (isFunction(value)) { value = value(data); }
|
||||
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
|
||||
lookupDottedPath(data, value.substr(1)) : value;
|
||||
});
|
||||
@ -526,6 +675,20 @@ angular.module('ngResource', ['ng']).
|
||||
|
||||
forEach(actions, function(action, name) {
|
||||
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
|
||||
var numericTimeout = action.timeout;
|
||||
var cancellable = angular.isDefined(action.cancellable) ? action.cancellable :
|
||||
(options && angular.isDefined(options.cancellable)) ? options.cancellable :
|
||||
provider.defaults.cancellable;
|
||||
|
||||
if (numericTimeout && !angular.isNumber(numericTimeout)) {
|
||||
$log.debug('ngResource:\n' +
|
||||
' Only numeric values are allowed as `timeout`.\n' +
|
||||
' Promises are not supported in $resource, because the same value would ' +
|
||||
'be used for multiple requests. If you are looking for a way to cancel ' +
|
||||
'requests, you should use the `cancellable` option.');
|
||||
delete action.timeout;
|
||||
numericTimeout = null;
|
||||
}
|
||||
|
||||
Resource[name] = function(a1, a2, a3, a4) {
|
||||
var params = {}, data, success, error;
|
||||
@ -574,6 +737,8 @@ angular.module('ngResource', ['ng']).
|
||||
defaultResponseInterceptor;
|
||||
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
|
||||
undefined;
|
||||
var timeoutDeferred;
|
||||
var numericTimeoutPromise;
|
||||
|
||||
forEach(action, function(value, key) {
|
||||
switch (key) {
|
||||
@ -583,28 +748,27 @@ angular.module('ngResource', ['ng']).
|
||||
case 'params':
|
||||
case 'isArray':
|
||||
case 'interceptor':
|
||||
break;
|
||||
case 'timeout':
|
||||
if (value && !angular.isNumber(value)) {
|
||||
$log.debug('ngResource:\n' +
|
||||
' Only numeric values are allowed as `timeout`.\n' +
|
||||
' Promises are not supported in $resource, because the same value would ' +
|
||||
'be used for multiple requests.\n' +
|
||||
' If you need support for cancellable $resource actions, you should ' +
|
||||
'upgrade to version 1.5 or higher.');
|
||||
}
|
||||
case 'cancellable':
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isInstanceCall && cancellable) {
|
||||
timeoutDeferred = $q.defer();
|
||||
httpConfig.timeout = timeoutDeferred.promise;
|
||||
|
||||
if (numericTimeout) {
|
||||
numericTimeoutPromise = $timeout(timeoutDeferred.resolve, numericTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasBody) httpConfig.data = data;
|
||||
route.setUrlParams(httpConfig,
|
||||
extend({}, extractParams(data, action.params || {}), params),
|
||||
action.url);
|
||||
|
||||
var promise = $http(httpConfig).then(function(response) {
|
||||
var data = response.data,
|
||||
promise = value.$promise;
|
||||
var data = response.data;
|
||||
|
||||
if (data) {
|
||||
// Need to convert action.isArray to boolean in case it is undefined
|
||||
@ -629,24 +793,28 @@ angular.module('ngResource', ['ng']).
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var promise = value.$promise; // Save the promise
|
||||
shallowClearAndCopy(data, value);
|
||||
value.$promise = promise;
|
||||
value.$promise = promise; // Restore the promise
|
||||
}
|
||||
}
|
||||
|
||||
value.$resolved = true;
|
||||
|
||||
response.resource = value;
|
||||
|
||||
return response;
|
||||
}, function(response) {
|
||||
value.$resolved = true;
|
||||
|
||||
(error || noop)(response);
|
||||
|
||||
return $q.reject(response);
|
||||
});
|
||||
|
||||
promise['finally'](function() {
|
||||
value.$resolved = true;
|
||||
if (!isInstanceCall && cancellable) {
|
||||
value.$cancelRequest = angular.noop;
|
||||
$timeout.cancel(numericTimeoutPromise);
|
||||
timeoutDeferred = numericTimeoutPromise = httpConfig.timeout = null;
|
||||
}
|
||||
});
|
||||
|
||||
promise = promise.then(
|
||||
function(response) {
|
||||
var value = responseInterceptor(response);
|
||||
@ -661,6 +829,7 @@ angular.module('ngResource', ['ng']).
|
||||
// - return the instance / collection
|
||||
value.$promise = promise;
|
||||
value.$resolved = false;
|
||||
if (cancellable) value.$cancelRequest = timeoutDeferred.resolve;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
152
xstatic/pkg/angular/data/angular-route.js
vendored
152
xstatic/pkg/angular/data/angular-route.js
vendored
@ -1,9 +1,43 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
/* 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 shallowCopy: false */
|
||||
|
||||
// There 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;
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@ -40,6 +74,9 @@ var ngRouteModule = angular.module('ngRoute', ['ng']).
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*/
|
||||
function $RouteProvider() {
|
||||
isArray = angular.isArray;
|
||||
isObject = angular.isObject;
|
||||
|
||||
function inherit(parent, extra) {
|
||||
return angular.extend(Object.create(parent), extra);
|
||||
}
|
||||
@ -105,8 +142,17 @@ function $RouteProvider() {
|
||||
* 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. The map object
|
||||
* is:
|
||||
* {@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.<br />
|
||||
* <div class="alert alert-warning">
|
||||
* **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.
|
||||
* </div>
|
||||
* 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.
|
||||
@ -116,7 +162,10 @@ function $RouteProvider() {
|
||||
* `ngRoute.$routeParams` will still refer to the previous route within these resolve
|
||||
* functions. Use `$route.current.params` to access the new route parameters, instead.
|
||||
*
|
||||
* - `redirectTo` – {(string|function())=} – value to update
|
||||
* - `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:
|
||||
@ -129,13 +178,13 @@ function $RouteProvider() {
|
||||
* The custom `redirectTo` function is expected to return a string which will be used
|
||||
* to update `$location.path()` and `$location.search()`.
|
||||
*
|
||||
* - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
|
||||
* - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()`
|
||||
* or `$location.hash()` changes.
|
||||
*
|
||||
* If the option is set to `false` and url in the browser changes, then
|
||||
* `$routeUpdate` event is broadcasted on the root scope.
|
||||
*
|
||||
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
||||
* - `[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
|
||||
@ -147,7 +196,7 @@ function $RouteProvider() {
|
||||
*/
|
||||
this.when = function(path, route) {
|
||||
//copy original route object to preserve params inherited from proto chain
|
||||
var routeCopy = angular.copy(route);
|
||||
var routeCopy = shallowCopy(route);
|
||||
if (angular.isUndefined(routeCopy.reloadOnSearch)) {
|
||||
routeCopy.reloadOnSearch = true;
|
||||
}
|
||||
@ -265,7 +314,7 @@ function $RouteProvider() {
|
||||
* @property {Object} current Reference to the current route definition.
|
||||
* The route definition contains:
|
||||
*
|
||||
* - `controller`: The controller constructor as define in route definition.
|
||||
* - `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:
|
||||
@ -273,6 +322,10 @@ function $RouteProvider() {
|
||||
* - `$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
|
||||
@ -588,35 +641,7 @@ function $RouteProvider() {
|
||||
}
|
||||
|
||||
$q.when(nextRoute).
|
||||
then(function() {
|
||||
if (nextRoute) {
|
||||
var locals = angular.extend({}, nextRoute.resolve),
|
||||
template, templateUrl;
|
||||
|
||||
angular.forEach(locals, function(value, key) {
|
||||
locals[key] = angular.isString(value) ?
|
||||
$injector.get(value) : $injector.invoke(value, null, null, key);
|
||||
});
|
||||
|
||||
if (angular.isDefined(template = nextRoute.template)) {
|
||||
if (angular.isFunction(template)) {
|
||||
template = template(nextRoute.params);
|
||||
}
|
||||
} else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) {
|
||||
if (angular.isFunction(templateUrl)) {
|
||||
templateUrl = templateUrl(nextRoute.params);
|
||||
}
|
||||
if (angular.isDefined(templateUrl)) {
|
||||
nextRoute.loadedTemplateUrl = $sce.valueOf(templateUrl);
|
||||
template = $templateRequest(templateUrl);
|
||||
}
|
||||
}
|
||||
if (angular.isDefined(template)) {
|
||||
locals['$template'] = template;
|
||||
}
|
||||
return $q.all(locals);
|
||||
}
|
||||
}).
|
||||
then(resolveLocals).
|
||||
then(function(locals) {
|
||||
// after route change
|
||||
if (nextRoute == $route.current) {
|
||||
@ -634,6 +659,41 @@ function $RouteProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -733,11 +793,20 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* @animations
|
||||
* enter - animation is used to bring new content into the browser.
|
||||
* leave - animation is used to animate existing content away.
|
||||
* | 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.
|
||||
*
|
||||
* @knownIssue If `ngView` is contained in an asynchronously loaded template (e.g. in another
|
||||
* directive's templateUrl or in a template loaded using `ngInclude`), then you need to
|
||||
* make sure that `$route` is instantiated in time to capture the initial
|
||||
* `$locationChangeStart` event and load the appropriate view. One way to achieve this
|
||||
* is to have it as a dependency in a `.run` block:
|
||||
* `myModule.run(['$route', function() {}]);`
|
||||
*
|
||||
* @scope
|
||||
* @priority 400
|
||||
* @param {string=} onload Expression to evaluate whenever the view updates.
|
||||
@ -989,6 +1058,7 @@ function ngViewFillContentFactory($compile, $controller, $route) {
|
||||
$element.data('$ngControllerController', controller);
|
||||
$element.children().data('$ngControllerController', controller);
|
||||
}
|
||||
scope[current.resolveAs || '$resolve'] = locals;
|
||||
|
||||
link(scope);
|
||||
}
|
||||
|
873
xstatic/pkg/angular/data/angular-sanitize.js
vendored
873
xstatic/pkg/angular/data/angular-sanitize.js
vendored
@ -1,9 +1,9 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Any commits to this file should be reviewed with security in mind. *
|
||||
@ -17,6 +17,14 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
||||
var bind;
|
||||
var extend;
|
||||
var forEach;
|
||||
var isDefined;
|
||||
var lowercase;
|
||||
var noop;
|
||||
var htmlParser;
|
||||
var htmlSanitizeWriter;
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@ -33,36 +41,23 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
||||
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
|
||||
*/
|
||||
|
||||
/*
|
||||
* HTML Parser By Misko Hevery (misko@hevery.com)
|
||||
* based on: HTML Parser By John Resig (ejohn.org)
|
||||
* Original code by Erik Arvidsson, Mozilla Public License
|
||||
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
||||
*
|
||||
* // Use like so:
|
||||
* htmlParser(htmlString, {
|
||||
* start: function(tag, attrs, unary) {},
|
||||
* end: function(tag) {},
|
||||
* chars: function(text) {},
|
||||
* comment: function(text) {}
|
||||
* });
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @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 whitelist) are
|
||||
* then serialized back to properly escaped html string. This means that no unsafe input can make
|
||||
* it into the returned string, however, since our parser is more strict than a typical browser
|
||||
* parser, it's possible that some obscure input, which would be recognized as valid HTML by a
|
||||
* browser, won't make it through the sanitizer. The input may also contain SVG markup.
|
||||
* The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
|
||||
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
|
||||
* it into the returned string.
|
||||
*
|
||||
* The whitelist for URL sanitization of attribute values is configured using the functions
|
||||
* `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
|
||||
* `$compileProvider`}.
|
||||
*
|
||||
* The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
|
||||
*
|
||||
* @param {string} html HTML input.
|
||||
* @returns {string} Sanitized HTML.
|
||||
@ -148,401 +143,426 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $sanitizeProvider
|
||||
*
|
||||
* @description
|
||||
* Creates and configures {@link $sanitize} instance.
|
||||
*/
|
||||
function $SanitizeProvider() {
|
||||
var svgEnabled = false;
|
||||
|
||||
this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
|
||||
if (svgEnabled) {
|
||||
extend(validElements, svgElements);
|
||||
}
|
||||
return function(html) {
|
||||
var buf = [];
|
||||
htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
|
||||
return !/^unsafe/.test($$sanitizeUri(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.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg
|
||||
* tags within the sanitized content:</p>
|
||||
*
|
||||
* <br>
|
||||
*
|
||||
* <pre><code>
|
||||
* .rootOfTheIncludedContent svg {
|
||||
* overflow: hidden !important;
|
||||
* }
|
||||
* </code></pre>
|
||||
* </div>
|
||||
*
|
||||
* @param {boolean=} flag Enable or disable SVG support in the sanitizer.
|
||||
* @returns {boolean|ng.$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;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private stuff
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bind = angular.bind;
|
||||
extend = angular.extend;
|
||||
forEach = angular.forEach;
|
||||
isDefined = angular.isDefined;
|
||||
lowercase = angular.lowercase;
|
||||
noop = angular.noop;
|
||||
|
||||
htmlParser = htmlParserImpl;
|
||||
htmlSanitizeWriter = htmlSanitizeWriterImpl;
|
||||
|
||||
// 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 = toMap("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 = toMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
||||
optionalEndTagInlineElements = toMap("rp,rt"),
|
||||
optionalEndTagElements = extend({},
|
||||
optionalEndTagInlineElements,
|
||||
optionalEndTagBlockElements);
|
||||
|
||||
// Safe Block Elements - HTML5
|
||||
var blockElements = extend({}, optionalEndTagBlockElements, toMap("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, toMap("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 = toMap("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 = toMap("script,style");
|
||||
|
||||
var validElements = extend({},
|
||||
voidElements,
|
||||
blockElements,
|
||||
inlineElements,
|
||||
optionalEndTagElements);
|
||||
|
||||
//Attributes that have href and hence need to be sanitized
|
||||
var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href");
|
||||
|
||||
var htmlAttrs = toMap('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 = toMap('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 toMap(str, lowercaseKeys) {
|
||||
var obj = {}, items = str.split(','), i;
|
||||
for (i = 0; i < items.length; i++) {
|
||||
obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
var inertBodyElement;
|
||||
(function(window) {
|
||||
var doc;
|
||||
if (window.document && window.document.implementation) {
|
||||
doc = window.document.implementation.createHTMLDocument("inert");
|
||||
} else {
|
||||
throw $sanitizeMinErr('noinert', "Can't create an inert html document");
|
||||
}
|
||||
var docElement = doc.documentElement || doc.getDocumentElement();
|
||||
var bodyElements = docElement.getElementsByTagName('body');
|
||||
|
||||
// usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
|
||||
if (bodyElements.length === 1) {
|
||||
inertBodyElement = bodyElements[0];
|
||||
} else {
|
||||
var html = doc.createElement('html');
|
||||
inertBodyElement = doc.createElement('body');
|
||||
html.appendChild(inertBodyElement);
|
||||
doc.appendChild(html);
|
||||
}
|
||||
})(window);
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
inertBodyElement.innerHTML = html;
|
||||
|
||||
//mXSS protection
|
||||
var mXSSAttempts = 5;
|
||||
do {
|
||||
if (mXSSAttempts === 0) {
|
||||
throw $sanitizeMinErr('uinput', "Failed to sanitize html because the input is unstable");
|
||||
}
|
||||
mXSSAttempts--;
|
||||
|
||||
// strip custom-namespaced attributes on IE<=11
|
||||
if (window.document.documentMode) {
|
||||
stripCustomNsAttrs(inertBodyElement);
|
||||
}
|
||||
html = inertBodyElement.innerHTML; //trigger mXSS
|
||||
inertBodyElement.innerHTML = 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 = node.nextSibling;
|
||||
if (!nextNode) {
|
||||
while (nextNode == null) {
|
||||
node = node.parentNode;
|
||||
if (node === inertBodyElement) break;
|
||||
nextNode = node.nextSibling;
|
||||
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, '<').
|
||||
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('</');
|
||||
out(tag);
|
||||
out('>');
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
nextNode = node.nextSibling;
|
||||
if (nextNode) {
|
||||
stripCustomNsAttrs(nextNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeText(chars) {
|
||||
var buf = [];
|
||||
var writer = htmlSanitizeWriter(buf, angular.noop);
|
||||
var writer = htmlSanitizeWriter(buf, noop);
|
||||
writer.chars(chars);
|
||||
return buf.join('');
|
||||
}
|
||||
|
||||
|
||||
// Regular Expressions for parsing tags and attributes
|
||||
var START_TAG_REGEXP =
|
||||
/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,
|
||||
END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/,
|
||||
ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
|
||||
BEGIN_TAG_REGEXP = /^</,
|
||||
BEGING_END_TAGE_REGEXP = /^<\//,
|
||||
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
||||
DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
|
||||
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
||||
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 = makeMap("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 = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
||||
optionalEndTagInlineElements = makeMap("rp,rt"),
|
||||
optionalEndTagElements = angular.extend({},
|
||||
optionalEndTagInlineElements,
|
||||
optionalEndTagBlockElements);
|
||||
|
||||
// Safe Block Elements - HTML5
|
||||
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("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,script,section,table,ul"));
|
||||
|
||||
// Inline Elements - HTML5
|
||||
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("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 = makeMap("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,use");
|
||||
|
||||
// Special Elements (can contain anything)
|
||||
var specialElements = makeMap("script,style");
|
||||
|
||||
var validElements = angular.extend({},
|
||||
voidElements,
|
||||
blockElements,
|
||||
inlineElements,
|
||||
optionalEndTagElements,
|
||||
svgElements);
|
||||
|
||||
//Attributes that have href and hence need to be sanitized
|
||||
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href");
|
||||
|
||||
var htmlAttrs = makeMap('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 = makeMap('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 = angular.extend({},
|
||||
uriAttrs,
|
||||
svgAttrs,
|
||||
htmlAttrs);
|
||||
|
||||
function makeMap(str, lowercaseKeys) {
|
||||
var obj = {}, items = str.split(','), i;
|
||||
for (i = 0; i < items.length; i++) {
|
||||
obj[lowercaseKeys ? angular.lowercase(items[i]) : items[i]] = true;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @example
|
||||
* htmlParser(htmlString, {
|
||||
* start: function(tag, attrs, unary) {},
|
||||
* end: function(tag) {},
|
||||
* chars: function(text) {},
|
||||
* comment: function(text) {}
|
||||
* });
|
||||
*
|
||||
* @param {string} html string
|
||||
* @param {object} handler
|
||||
*/
|
||||
function htmlParser(html, handler) {
|
||||
if (typeof html !== 'string') {
|
||||
if (html === null || typeof html === 'undefined') {
|
||||
html = '';
|
||||
} else {
|
||||
html = '' + html;
|
||||
}
|
||||
}
|
||||
var index, chars, match, stack = [], last = html, text;
|
||||
stack.last = function() { return stack[stack.length - 1]; };
|
||||
|
||||
while (html) {
|
||||
text = '';
|
||||
chars = true;
|
||||
|
||||
// Make sure we're not in a script or style element
|
||||
if (!stack.last() || !specialElements[stack.last()]) {
|
||||
|
||||
// Comment
|
||||
if (html.indexOf("<!--") === 0) {
|
||||
// comments containing -- are not allowed unless they terminate the comment
|
||||
index = html.indexOf("--", 4);
|
||||
|
||||
if (index >= 0 && html.lastIndexOf("-->", index) === index) {
|
||||
if (handler.comment) handler.comment(html.substring(4, index));
|
||||
html = html.substring(index + 3);
|
||||
chars = false;
|
||||
}
|
||||
// DOCTYPE
|
||||
} else if (DOCTYPE_REGEXP.test(html)) {
|
||||
match = html.match(DOCTYPE_REGEXP);
|
||||
|
||||
if (match) {
|
||||
html = html.replace(match[0], '');
|
||||
chars = false;
|
||||
}
|
||||
// end tag
|
||||
} else if (BEGING_END_TAGE_REGEXP.test(html)) {
|
||||
match = html.match(END_TAG_REGEXP);
|
||||
|
||||
if (match) {
|
||||
html = html.substring(match[0].length);
|
||||
match[0].replace(END_TAG_REGEXP, parseEndTag);
|
||||
chars = false;
|
||||
}
|
||||
|
||||
// start tag
|
||||
} else if (BEGIN_TAG_REGEXP.test(html)) {
|
||||
match = html.match(START_TAG_REGEXP);
|
||||
|
||||
if (match) {
|
||||
// We only have a valid start-tag if there is a '>'.
|
||||
if (match[4]) {
|
||||
html = html.substring(match[0].length);
|
||||
match[0].replace(START_TAG_REGEXP, parseStartTag);
|
||||
}
|
||||
chars = false;
|
||||
} else {
|
||||
// no ending tag found --- this piece should be encoded as an entity.
|
||||
text += '<';
|
||||
html = html.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (chars) {
|
||||
index = html.indexOf("<");
|
||||
|
||||
text += index < 0 ? html : html.substring(0, index);
|
||||
html = index < 0 ? "" : html.substring(index);
|
||||
|
||||
if (handler.chars) handler.chars(decodeEntities(text));
|
||||
}
|
||||
|
||||
} else {
|
||||
// IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w].
|
||||
html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
||||
function(all, text) {
|
||||
text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
|
||||
|
||||
if (handler.chars) handler.chars(decodeEntities(text));
|
||||
|
||||
return "";
|
||||
});
|
||||
|
||||
parseEndTag("", stack.last());
|
||||
}
|
||||
|
||||
if (html == last) {
|
||||
throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
|
||||
"of html: {0}", html);
|
||||
}
|
||||
last = html;
|
||||
}
|
||||
|
||||
// Clean up any remaining tags
|
||||
parseEndTag();
|
||||
|
||||
function parseStartTag(tag, tagName, rest, unary) {
|
||||
tagName = angular.lowercase(tagName);
|
||||
if (blockElements[tagName]) {
|
||||
while (stack.last() && inlineElements[stack.last()]) {
|
||||
parseEndTag("", stack.last());
|
||||
}
|
||||
}
|
||||
|
||||
if (optionalEndTagElements[tagName] && stack.last() == tagName) {
|
||||
parseEndTag("", tagName);
|
||||
}
|
||||
|
||||
unary = voidElements[tagName] || !!unary;
|
||||
|
||||
if (!unary) {
|
||||
stack.push(tagName);
|
||||
}
|
||||
|
||||
var attrs = {};
|
||||
|
||||
rest.replace(ATTR_REGEXP,
|
||||
function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
|
||||
var value = doubleQuotedValue
|
||||
|| singleQuotedValue
|
||||
|| unquotedValue
|
||||
|| '';
|
||||
|
||||
attrs[name] = decodeEntities(value);
|
||||
});
|
||||
if (handler.start) handler.start(tagName, attrs, unary);
|
||||
}
|
||||
|
||||
function parseEndTag(tag, tagName) {
|
||||
var pos = 0, i;
|
||||
tagName = angular.lowercase(tagName);
|
||||
if (tagName) {
|
||||
// Find the closest opened tag of the same type
|
||||
for (pos = stack.length - 1; pos >= 0; pos--) {
|
||||
if (stack[pos] == tagName) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos >= 0) {
|
||||
// Close all the open elements, up the stack
|
||||
for (i = stack.length - 1; i >= pos; i--)
|
||||
if (handler.end) handler.end(stack[i]);
|
||||
|
||||
// Remove the open elements from the stack
|
||||
stack.length = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var hiddenPre=document.createElement("pre");
|
||||
/**
|
||||
* decodes all entities into regular string
|
||||
* @param value
|
||||
* @returns {string} A string with decoded entities.
|
||||
*/
|
||||
function decodeEntities(value) {
|
||||
if (!value) { return ''; }
|
||||
|
||||
hiddenPre.innerHTML = value.replace(/</g,"<");
|
||||
// innerText depends on styling as it doesn't display hidden elements.
|
||||
// Therefore, it's better to use textContent not to cause unnecessary reflows.
|
||||
return hiddenPre.textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, '<').
|
||||
replace(/>/g, '>');
|
||||
}
|
||||
|
||||
/**
|
||||
* create an HTML/XML writer which writes to buffer
|
||||
* @param {Array} buf use buf.jain('') to get out sanitized html string
|
||||
* @returns {object} in the form of {
|
||||
* start: function(tag, attrs, unary) {},
|
||||
* end: function(tag) {},
|
||||
* chars: function(text) {},
|
||||
* comment: function(text) {}
|
||||
* }
|
||||
*/
|
||||
function htmlSanitizeWriter(buf, uriValidator) {
|
||||
var ignore = false;
|
||||
var out = angular.bind(buf, buf.push);
|
||||
return {
|
||||
start: function(tag, attrs, unary) {
|
||||
tag = angular.lowercase(tag);
|
||||
if (!ignore && specialElements[tag]) {
|
||||
ignore = tag;
|
||||
}
|
||||
if (!ignore && validElements[tag] === true) {
|
||||
out('<');
|
||||
out(tag);
|
||||
angular.forEach(attrs, function(value, key) {
|
||||
var lkey=angular.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(unary ? '/>' : '>');
|
||||
}
|
||||
},
|
||||
end: function(tag) {
|
||||
tag = angular.lowercase(tag);
|
||||
if (!ignore && validElements[tag] === true) {
|
||||
out('</');
|
||||
out(tag);
|
||||
out('>');
|
||||
}
|
||||
if (tag == ignore) {
|
||||
ignore = false;
|
||||
}
|
||||
},
|
||||
chars: function(chars) {
|
||||
if (!ignore) {
|
||||
out(encodeEntities(chars));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// define ngSanitize module and register $sanitize service
|
||||
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
|
||||
/* global sanitizeText: false */
|
||||
|
||||
/**
|
||||
* @ngdoc filter
|
||||
* @name linky
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
||||
* Finds links in text input and turns them into html links. Supports `http/https/ftp/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.
|
||||
* @returns {string} Html-linkified 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
|
||||
<span ng-bind-html="linky_expression | linky"></span>
|
||||
@ -550,25 +570,13 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
* @example
|
||||
<example module="linkyExample" deps="angular-sanitize.js">
|
||||
<file name="index.html">
|
||||
<script>
|
||||
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.snippetWithTarget = 'http://angularjs.org/';
|
||||
}]);
|
||||
</script>
|
||||
<div ng-controller="ExampleController">
|
||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Filter</td>
|
||||
<td>Source</td>
|
||||
<td>Rendered</td>
|
||||
<th>Filter</th>
|
||||
<th>Source</th>
|
||||
<th>Rendered</th>
|
||||
</tr>
|
||||
<tr id="linky-filter">
|
||||
<td>linky filter</td>
|
||||
@ -582,10 +590,19 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
<tr id="linky-target">
|
||||
<td>linky target</td>
|
||||
<td>
|
||||
<pre><div ng-bind-html="snippetWithTarget | linky:'_blank'"><br></div></pre>
|
||||
<pre><div ng-bind-html="snippetWithSingleURL | linky:'_blank'"><br></div></pre>
|
||||
</td>
|
||||
<td>
|
||||
<div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
|
||||
<div ng-bind-html="snippetWithSingleURL | linky:'_blank'"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="linky-custom-attributes">
|
||||
<td>linky custom attributes</td>
|
||||
<td>
|
||||
<pre><div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"><br></div></pre>
|
||||
</td>
|
||||
<td>
|
||||
<div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="escaped-html">
|
||||
@ -595,6 +612,18 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
</tr>
|
||||
</table>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
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/';
|
||||
}]);
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should linkify the snippet with urls', function() {
|
||||
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
||||
@ -622,10 +651,17 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
|
||||
it('should work with the target property', function() {
|
||||
expect(element(by.id('linky-target')).
|
||||
element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
|
||||
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');
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
@ -634,8 +670,21 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
||||
/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
|
||||
MAILTO_REGEXP = /^mailto:/i;
|
||||
|
||||
return function(text, target) {
|
||||
if (!text) return text;
|
||||
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 = [];
|
||||
@ -664,8 +713,14 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
||||
}
|
||||
|
||||
function addLink(url, text) {
|
||||
var key, linkAttributes = attributesFn(url);
|
||||
html.push('<a ');
|
||||
if (angular.isDefined(target)) {
|
||||
|
||||
for (key in linkAttributes) {
|
||||
html.push(key + '="' + linkAttributes[key] + '" ');
|
||||
}
|
||||
|
||||
if (isDefined(target) && !('target' in linkAttributes)) {
|
||||
html.push('target="',
|
||||
target,
|
||||
'" ');
|
||||
|
10956
xstatic/pkg/angular/data/angular-scenario.js
vendored
10956
xstatic/pkg/angular/data/angular-scenario.js
vendored
File diff suppressed because it is too large
Load Diff
150
xstatic/pkg/angular/data/angular-touch.js
vendored
150
xstatic/pkg/angular/data/angular-touch.js
vendored
@ -1,9 +1,12 @@
|
||||
/**
|
||||
* @license AngularJS v1.4.10
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.5.8
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
(function(window, angular) {'use strict';
|
||||
|
||||
/* global ngTouchClickDirectiveFactory: false,
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
@ -27,10 +30,108 @@
|
||||
/* global -ngTouch */
|
||||
var ngTouch = angular.module('ngTouch', []);
|
||||
|
||||
ngTouch.provider('$touch', $TouchProvider);
|
||||
|
||||
function nodeName_(element) {
|
||||
return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc provider
|
||||
* @name $touchProvider
|
||||
*
|
||||
* @description
|
||||
* The `$touchProvider` allows enabling / disabling {@link ngTouch.ngClick ngTouch's ngClick directive}.
|
||||
*/
|
||||
$TouchProvider.$inject = ['$provide', '$compileProvider'];
|
||||
function $TouchProvider($provide, $compileProvider) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $touchProvider#ngClickOverrideEnabled
|
||||
*
|
||||
* @param {boolean=} enabled update the ngClickOverrideEnabled state if provided, otherwise just return the
|
||||
* current ngClickOverrideEnabled state
|
||||
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
||||
*
|
||||
* @kind function
|
||||
*
|
||||
* @description
|
||||
* Call this method to enable/disable {@link ngTouch.ngClick ngTouch's ngClick directive}. If enabled,
|
||||
* the default ngClick directive will be replaced by a version that eliminates the 300ms delay for
|
||||
* click events on browser for touch-devices.
|
||||
*
|
||||
* The default is `false`.
|
||||
*
|
||||
*/
|
||||
var ngClickOverrideEnabled = false;
|
||||
var ngClickDirectiveAdded = false;
|
||||
this.ngClickOverrideEnabled = function(enabled) {
|
||||
if (angular.isDefined(enabled)) {
|
||||
|
||||
if (enabled && !ngClickDirectiveAdded) {
|
||||
ngClickDirectiveAdded = true;
|
||||
|
||||
// Use this to identify the correct directive in the delegate
|
||||
ngTouchClickDirectiveFactory.$$moduleName = 'ngTouch';
|
||||
$compileProvider.directive('ngClick', ngTouchClickDirectiveFactory);
|
||||
|
||||
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
|
||||
if (ngClickOverrideEnabled) {
|
||||
// drop the default ngClick directive
|
||||
$delegate.shift();
|
||||
} else {
|
||||
// drop the ngTouch ngClick directive if the override has been re-disabled (because
|
||||
// we cannot de-register added directives)
|
||||
var i = $delegate.length - 1;
|
||||
while (i >= 0) {
|
||||
if ($delegate[i].$$moduleName === 'ngTouch') {
|
||||
$delegate.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
return $delegate;
|
||||
}]);
|
||||
}
|
||||
|
||||
ngClickOverrideEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
return ngClickOverrideEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $touch
|
||||
* @kind object
|
||||
*
|
||||
* @description
|
||||
* Provides the {@link ngTouch.$touch#ngClickOverrideEnabled `ngClickOverrideEnabled`} method.
|
||||
*
|
||||
*/
|
||||
this.$get = function() {
|
||||
return {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $touch#ngClickOverrideEnabled
|
||||
*
|
||||
* @returns {*} current value of `ngClickOverrideEnabled` set in the {@link ngTouch.$touchProvider $touchProvider},
|
||||
* i.e. if {@link ngTouch.ngClick ngTouch's ngClick} directive is enabled.
|
||||
*
|
||||
* @kind function
|
||||
*/
|
||||
ngClickOverrideEnabled: function() {
|
||||
return ngClickOverrideEnabled;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/* global ngTouch: false */
|
||||
|
||||
/**
|
||||
@ -66,6 +167,12 @@ ngTouch.factory('$swipe', [function() {
|
||||
move: 'touchmove',
|
||||
end: 'touchend',
|
||||
cancel: 'touchcancel'
|
||||
},
|
||||
'pointer': {
|
||||
start: 'pointerdown',
|
||||
move: 'pointermove',
|
||||
end: 'pointerup',
|
||||
cancel: 'pointercancel'
|
||||
}
|
||||
};
|
||||
|
||||
@ -100,15 +207,15 @@ ngTouch.factory('$swipe', [function() {
|
||||
* The main method of `$swipe`. It takes an element to be watched for swipe motions, and an
|
||||
* object containing event handlers.
|
||||
* The pointer types that should be used can be specified via the optional
|
||||
* third argument, which is an array of strings `'mouse'` and `'touch'`. By default,
|
||||
* `$swipe` will listen for `mouse` and `touch` events.
|
||||
* third argument, which is an array of strings `'mouse'`, `'touch'` and `'pointer'`. By default,
|
||||
* `$swipe` will listen for `mouse`, `touch` and `pointer` events.
|
||||
*
|
||||
* The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end`
|
||||
* receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }` and the raw
|
||||
* `event`. `cancel` receives the raw `event` as its single parameter.
|
||||
*
|
||||
* `start` is called on either `mousedown` or `touchstart`. After this event, `$swipe` is
|
||||
* watching for `touchmove` or `mousemove` events. These events are ignored until the total
|
||||
* `start` is called on either `mousedown`, `touchstart` or `pointerdown`. After this event, `$swipe` is
|
||||
* watching for `touchmove`, `mousemove` or `pointermove` events. These events are ignored until the total
|
||||
* distance moved in either dimension exceeds a small threshold.
|
||||
*
|
||||
* Once this threshold is exceeded, either the horizontal or vertical delta is greater.
|
||||
@ -116,12 +223,12 @@ ngTouch.factory('$swipe', [function() {
|
||||
* - If the vertical distance is greater, this is a scroll, and we let the browser take over.
|
||||
* A `cancel` event is sent.
|
||||
*
|
||||
* `move` is called on `mousemove` and `touchmove` after the above logic has determined that
|
||||
* `move` is called on `mousemove`, `touchmove` and `pointermove` after the above logic has determined that
|
||||
* a swipe is in progress.
|
||||
*
|
||||
* `end` is called when a swipe is successfully completed with a `touchend` or `mouseup`.
|
||||
* `end` is called when a swipe is successfully completed with a `touchend`, `mouseup` or `pointerup`.
|
||||
*
|
||||
* `cancel` is called either on a `touchcancel` from the browser, or when we begin scrolling
|
||||
* `cancel` is called either on a `touchcancel` or `pointercancel` from the browser, or when we begin scrolling
|
||||
* as described above.
|
||||
*
|
||||
*/
|
||||
@ -135,7 +242,7 @@ ngTouch.factory('$swipe', [function() {
|
||||
// Whether a swipe is active.
|
||||
var active = false;
|
||||
|
||||
pointerTypes = pointerTypes || ['mouse', 'touch'];
|
||||
pointerTypes = pointerTypes || ['mouse', 'touch', 'pointer'];
|
||||
element.on(getEvents(pointerTypes, 'start'), function(event) {
|
||||
startCoords = getCoordinates(event);
|
||||
active = true;
|
||||
@ -202,8 +309,17 @@ ngTouch.factory('$swipe', [function() {
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngClick
|
||||
* @deprecated
|
||||
*
|
||||
* @description
|
||||
* <div class="alert alert-danger">
|
||||
* **DEPRECATION NOTICE**: Beginning with Angular 1.5, this directive is deprecated and by default **disabled**.
|
||||
* The directive will receive no further support and might be removed from future releases.
|
||||
* If you need the directive, you can enable it with the {@link ngTouch.$touchProvider $touchProvider#ngClickOverrideEnabled}
|
||||
* function. We also recommend that you migrate to [FastClick](https://github.com/ftlabs/fastclick).
|
||||
* To learn more about the 300ms delay, this [Telerik article](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/)
|
||||
* gives a good overview.
|
||||
* </div>
|
||||
* A more powerful replacement for the default ngClick designed to be used on touchscreen
|
||||
* devices. Most mobile browsers wait about 300ms after a tap-and-release before sending
|
||||
* the click event. This version handles them immediately, and then prevents the
|
||||
@ -235,15 +351,7 @@ ngTouch.factory('$swipe', [function() {
|
||||
</example>
|
||||
*/
|
||||
|
||||
ngTouch.config(['$provide', function($provide) {
|
||||
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
|
||||
// drop the default ngClick directive
|
||||
$delegate.shift();
|
||||
return $delegate;
|
||||
}]);
|
||||
}]);
|
||||
|
||||
ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
||||
var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
|
||||
function($parse, $timeout, $rootElement) {
|
||||
var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
|
||||
var MOVE_TOLERANCE = 12; // 12px seems to work in most mobile browsers.
|
||||
@ -487,7 +595,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
||||
});
|
||||
|
||||
};
|
||||
}]);
|
||||
}];
|
||||
|
||||
/* global ngTouch: false */
|
||||
|
||||
|
4309
xstatic/pkg/angular/data/angular.js
vendored
4309
xstatic/pkg/angular/data/angular.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"raw":"v1.4.10","major":1,"minor":4,"patch":10,"prerelease":[],"build":[],"version":"1.4.10","codeName":"benignant-oscillation","full":"1.4.10","branch":"v1.4.x","cdn":{"raw":"v1.4.9","major":1,"minor":4,"patch":9,"prerelease":[],"build":[],"version":"1.4.9","docsUrl":"http://code.angularjs.org/1.4.9/docs"}}
|
||||
{"raw":"v1.5.8","major":1,"minor":5,"patch":8,"prerelease":[],"build":[],"version":"1.5.8","codeName":"arbitrary-fallbacks","full":"1.5.8","branch":"v1.5.x","cdn":{"raw":"v1.5.7","major":1,"minor":5,"patch":7,"prerelease":[],"build":[],"version":"1.5.7","docsUrl":"http://code.angularjs.org/1.5.7/docs"}}
|
@ -1 +1 @@
|
||||
1.4.10
|
||||
1.5.8
|
Loading…
Reference in New Issue
Block a user