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
|
# please use a all-lowercase valid python
|
||||||
# package name
|
# 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
|
# 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.
|
# with fixes for xstatic stuff.
|
||||||
PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi
|
PACKAGE_VERSION = VERSION + '.' + BUILD # version used for PyPi
|
||||||
|
|
||||||
|
355
xstatic/pkg/angular/data/angular-animate.js
vendored
355
xstatic/pkg/angular/data/angular-animate.js
vendored
@ -1,23 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @license AngularJS v1.4.10
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
(function(window, angular, undefined) {'use strict';
|
(function(window, angular) {'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;
|
|
||||||
|
|
||||||
var ELEMENT_NODE = 1;
|
var ELEMENT_NODE = 1;
|
||||||
var COMMENT_NODE = 8;
|
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
|
// 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:
|
// therefore there is no reason to test anymore for other vendor prefixes:
|
||||||
// http://caniuse.com/#search=transition
|
// http://caniuse.com/#search=transition
|
||||||
if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionend)) {
|
if ((window.ontransitionend === void 0) && (window.onwebkittransitionend !== void 0)) {
|
||||||
CSS_PREFIX = '-webkit-';
|
CSS_PREFIX = '-webkit-';
|
||||||
TRANSITION_PROP = 'WebkitTransition';
|
TRANSITION_PROP = 'WebkitTransition';
|
||||||
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
|
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
|
||||||
@ -52,7 +38,7 @@ if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionen
|
|||||||
TRANSITIONEND_EVENT = 'transitionend';
|
TRANSITIONEND_EVENT = 'transitionend';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUndefined(window.onanimationend) && isDefined(window.onwebkitanimationend)) {
|
if ((window.onanimationend === void 0) && (window.onwebkitanimationend !== void 0)) {
|
||||||
CSS_PREFIX = '-webkit-';
|
CSS_PREFIX = '-webkit-';
|
||||||
ANIMATION_PROP = 'WebkitAnimation';
|
ANIMATION_PROP = 'WebkitAnimation';
|
||||||
ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
|
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_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
|
||||||
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
|
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
|
||||||
|
|
||||||
var isPromiseLike = function(p) {
|
|
||||||
return p && p.then ? true : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
var ngMinErr = angular.$$minErr('ng');
|
var ngMinErr = angular.$$minErr('ng');
|
||||||
function assertArg(arg, name, reason) {
|
function assertArg(arg, name, reason) {
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
@ -132,8 +114,7 @@ function stripCommentsFromElement(element) {
|
|||||||
if (element instanceof jqLite) {
|
if (element instanceof jqLite) {
|
||||||
switch (element.length) {
|
switch (element.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return [];
|
return element;
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
// there is no point of stripping anything if the element
|
// there is no point of stripping anything if the element
|
||||||
@ -146,7 +127,6 @@ function stripCommentsFromElement(element) {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
return jqLite(extractElementNode(element));
|
return jqLite(extractElementNode(element));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +167,7 @@ function applyAnimationClassesFactory($$jqLite) {
|
|||||||
$$removeClass($$jqLite, element, options.removeClass);
|
$$removeClass($$jqLite, element, options.removeClass);
|
||||||
options.removeClass = null;
|
options.removeClass = null;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareAnimationOptions(options) {
|
function prepareAnimationOptions(options) {
|
||||||
@ -290,10 +270,10 @@ function resolveElementClasses(existing, toAdd, toRemove) {
|
|||||||
var prop, allow;
|
var prop, allow;
|
||||||
if (val === ADD_CLASS) {
|
if (val === ADD_CLASS) {
|
||||||
prop = 'addClass';
|
prop = 'addClass';
|
||||||
allow = !existing[klass];
|
allow = !existing[klass] || existing[klass + REMOVE_CLASS_SUFFIX];
|
||||||
} else if (val === REMOVE_CLASS) {
|
} else if (val === REMOVE_CLASS) {
|
||||||
prop = 'removeClass';
|
prop = 'removeClass';
|
||||||
allow = existing[klass];
|
allow = existing[klass] || existing[klass + ADD_CLASS_SUFFIX];
|
||||||
}
|
}
|
||||||
if (allow) {
|
if (allow) {
|
||||||
if (classes[prop].length) {
|
if (classes[prop].length) {
|
||||||
@ -323,7 +303,7 @@ function resolveElementClasses(existing, toAdd, toRemove) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDomNode(element) {
|
function getDomNode(element) {
|
||||||
return (element instanceof angular.element) ? element[0] : element;
|
return (element instanceof jqLite) ? element[0] : element;
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyGeneratedPreparationClasses(element, event, options) {
|
function applyGeneratedPreparationClasses(element, event, options) {
|
||||||
@ -396,7 +376,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
|
|||||||
queue = scheduler.queue = [];
|
queue = scheduler.queue = [];
|
||||||
|
|
||||||
/* waitUntilQuiet does two things:
|
/* 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.
|
* 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
|
* The motivation here is that animation code can request more time from the scheduler
|
||||||
@ -513,7 +493,7 @@ var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) {
|
|||||||
return {
|
return {
|
||||||
link: function(scope, element, attrs) {
|
link: function(scope, element, attrs) {
|
||||||
var val = attrs.ngAnimateChildren;
|
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);
|
element.data(NG_ANIMATE_CHILDREN_DATA, true);
|
||||||
} else {
|
} else {
|
||||||
// Interpolate and set the value, so that it is available to
|
// 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.
|
* 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
|
* 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.
|
* 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
|
* * `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.})
|
* ({@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
|
* * `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`)
|
* `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.)
|
* * `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
|
* * `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 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`.
|
* By default this value is set to `false`.
|
||||||
*
|
*
|
||||||
* @return {object} an object with start and end methods and details about the animation.
|
* @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
|
// 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.
|
// value for being greater than any other negative value.
|
||||||
if (val === 0) {
|
if (val === 0) {
|
||||||
val = null;
|
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
|
// 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);
|
gcsLookup.put(cacheKey, timings);
|
||||||
return 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
|
// 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
|
var maxStagger = itemIndex > 0
|
||||||
&& ((timings.transitionDuration && stagger.transitionDuration === 0) ||
|
&& ((timings.transitionDuration && stagger.transitionDuration === 0) ||
|
||||||
(timings.animationDuration && stagger.animationDuration === 0))
|
(timings.animationDuration && stagger.animationDuration === 0))
|
||||||
@ -1556,7 +1536,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
|||||||
|
|
||||||
var rootBodyElement = jqLite(
|
var rootBodyElement = jqLite(
|
||||||
// this is to avoid using something that exists outside of the body
|
// 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
|
// appends the $rootElement to the body after the app has been bootstrapped
|
||||||
isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
|
isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
|
||||||
);
|
);
|
||||||
@ -1656,7 +1636,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
|||||||
var coords = getDomNode(anchor).getBoundingClientRect();
|
var coords = getDomNode(anchor).getBoundingClientRect();
|
||||||
|
|
||||||
// we iterate directly since safari messes up and doesn't return
|
// 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) {
|
forEach(['width','height','top','left'], function(key) {
|
||||||
var value = coords[key];
|
var value = coords[key];
|
||||||
switch (key) {
|
switch (key) {
|
||||||
@ -2225,6 +2205,11 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rules.cancel.push(function(element, newAnimation, currentAnimation) {
|
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 nA = newAnimation.addClass;
|
||||||
var nR = newAnimation.removeClass;
|
var nR = newAnimation.removeClass;
|
||||||
var cA = currentAnimation.addClass;
|
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
|
// remember that the classNameFilter is set during the provider/config
|
||||||
// stage therefore we can optimize here and setup a helper function
|
// 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.
|
// 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
|
// jshint bitwise: false
|
||||||
return this === arg || !!(this.compareDocumentPosition(arg) & 16);
|
return this === arg || !!(this.compareDocumentPosition(arg) & 16);
|
||||||
// jshint bitwise: true
|
// jshint bitwise: true
|
||||||
@ -2337,24 +2322,6 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
on: function(event, container, callback) {
|
|
||||||
var node = extractElementNode(container);
|
|
||||||
callbackRegistry[event] = callbackRegistry[event] || [];
|
|
||||||
callbackRegistry[event].push({
|
|
||||||
node: node,
|
|
||||||
callback: callback
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
off: function(event, container, callback) {
|
|
||||||
var entries = callbackRegistry[event];
|
|
||||||
if (!entries) return;
|
|
||||||
|
|
||||||
callbackRegistry[event] = arguments.length === 1
|
|
||||||
? null
|
|
||||||
: filterFromRegistry(entries, container, callback);
|
|
||||||
|
|
||||||
function filterFromRegistry(list, matchContainer, matchCallback) {
|
function filterFromRegistry(list, matchContainer, matchCallback) {
|
||||||
var containerNode = extractElementNode(matchContainer);
|
var containerNode = extractElementNode(matchContainer);
|
||||||
return list.filter(function(entry) {
|
return list.filter(function(entry) {
|
||||||
@ -2363,6 +2330,53 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
return !isMatch;
|
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] || [];
|
||||||
|
callbackRegistry[event].push({
|
||||||
|
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);
|
||||||
},
|
},
|
||||||
|
|
||||||
pin: function(element, parentElement) {
|
pin: function(element, parentElement) {
|
||||||
@ -2396,11 +2410,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
bool = animationsEnabled = !!element;
|
bool = animationsEnabled = !!element;
|
||||||
} else {
|
} else {
|
||||||
var node = getDomNode(element);
|
var node = getDomNode(element);
|
||||||
var recordExists = disabledElementsLookup.get(node);
|
|
||||||
|
|
||||||
if (argCount === 1) {
|
if (argCount === 1) {
|
||||||
// (element) - Element getter
|
// (element) - Element getter
|
||||||
bool = !recordExists;
|
bool = !disabledElementsLookup.get(node);
|
||||||
} else {
|
} else {
|
||||||
// (element, bool) - Element setter
|
// (element, bool) - Element setter
|
||||||
disabledElementsLookup.put(node, !bool);
|
disabledElementsLookup.put(node, !bool);
|
||||||
@ -2412,6 +2425,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return $animate;
|
||||||
|
|
||||||
function queueAnimation(element, event, initialOptions) {
|
function queueAnimation(element, event, initialOptions) {
|
||||||
// we always make a copy of the options since
|
// we always make a copy of the options since
|
||||||
// there should never be any side effects on
|
// 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 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
|
// this is a hard disable of all animations for the application or on
|
||||||
// the element itself, therefore there is no need to continue further
|
// the element itself, therefore there is no need to continue further
|
||||||
// past this point if not enabled
|
// past this point if not enabled
|
||||||
// Animations are also disabled if the document is currently hidden (page is not visible
|
// 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
|
// 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 existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
|
||||||
var hasExistingAnimation = !!existingAnimation.state;
|
var hasExistingAnimation = !!existingAnimation.state;
|
||||||
|
|
||||||
@ -2490,7 +2507,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (skipAnimations) {
|
if (skipAnimations) {
|
||||||
|
// Callbacks should fire even if the document is hidden (regression fix for issue #14120)
|
||||||
|
if (documentHidden) notifyProgress(runner, event, 'start');
|
||||||
close();
|
close();
|
||||||
|
if (documentHidden) notifyProgress(runner, event, 'close');
|
||||||
return runner;
|
return runner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2640,6 +2660,11 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
markElementAnimationState(element, RUNNING_STATE);
|
markElementAnimationState(element, RUNNING_STATE);
|
||||||
var realRunner = $$animation(element, event, animationDetails.options);
|
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) {
|
realRunner.done(function(status) {
|
||||||
close(!status);
|
close(!status);
|
||||||
var animationDetails = activeAnimationsLookup.get(node);
|
var animationDetails = activeAnimationsLookup.get(node);
|
||||||
@ -2648,11 +2673,6 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
}
|
}
|
||||||
notifyProgress(runner, event, 'close', {});
|
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;
|
return runner;
|
||||||
@ -2669,7 +2689,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
forEach(callbacks, function(callback) {
|
forEach(callbacks, function(callback) {
|
||||||
callback(element, phase, data);
|
callback(element, phase, data);
|
||||||
});
|
});
|
||||||
|
cleanupEventListeners(phase, element);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
cleanupEventListeners(phase, element);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
runner.progress(event, phase, data);
|
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
|
// 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.
|
// the same animation driver and to properly sequence the anchor animation.
|
||||||
if (group.classes.length) {
|
if (group.classes.length) {
|
||||||
preparedAnimations.push(group);
|
preparedAnimations.push(group);
|
||||||
@ -3169,8 +3192,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
// may attempt more elements, but custom drivers are more particular
|
// may attempt more elements, but custom drivers are more particular
|
||||||
for (var i = drivers.length - 1; i >= 0; i--) {
|
for (var i = drivers.length - 1; i >= 0; i--) {
|
||||||
var driverName = drivers[i];
|
var driverName = drivers[i];
|
||||||
if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check
|
|
||||||
|
|
||||||
var factory = $injector.get(driverName);
|
var factory = $injector.get(driverName);
|
||||||
var driver = factory(animationDetails);
|
var driver = factory(animationDetails);
|
||||||
if (driver) {
|
if (driver) {
|
||||||
@ -3199,7 +3220,8 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function update(element) {
|
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,
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
$$AnimateAsyncRunFactory,
|
* @name ngAnimateSwap
|
||||||
$$rAFSchedulerFactory,
|
* @restrict A
|
||||||
$$AnimateChildrenDirective,
|
* @scope
|
||||||
$$AnimateQueueProvider,
|
*
|
||||||
$$AnimationProvider,
|
* @description
|
||||||
$AnimateCssProvider,
|
*
|
||||||
$$AnimateCssDriverProvider,
|
* ngAnimateSwap is a animation-oriented directive that allows for the container to
|
||||||
$$AnimateJsProvider,
|
* be removed and entered in whenever the associated expression changes. A
|
||||||
$$AnimateJsDriverProvider,
|
* 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
|
* @ngdoc module
|
||||||
@ -3358,7 +3482,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
* <div ng-show="bool" class="fade">
|
* <div ng-show="bool" class="fade">
|
||||||
* Show and hide me
|
* Show and hide me
|
||||||
* </div>
|
* </div>
|
||||||
* <button ng-click="bool=true">Toggle</button>
|
* <button ng-click="bool=!bool">Toggle</button>
|
||||||
*
|
*
|
||||||
* <style>
|
* <style>
|
||||||
* .fade.ng-hide {
|
* .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
|
* 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
|
* 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`:
|
* 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}.
|
* 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
|
* ## 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
|
* 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.)
|
* (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
|
* @ngdoc service
|
||||||
* @name $animate
|
* @name $animate
|
||||||
@ -3993,7 +4105,24 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
|||||||
*
|
*
|
||||||
* Click here {@link ng.$animate to learn more about animations with `$animate`}.
|
* 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)
|
.directive('ngAnimateChildren', $$AnimateChildrenDirective)
|
||||||
.factory('$$rAFScheduler', $$rAFSchedulerFactory)
|
.factory('$$rAFScheduler', $$rAFSchedulerFactory)
|
||||||
|
|
||||||
|
105
xstatic/pkg/angular/data/angular-aria.js
vendored
105
xstatic/pkg/angular/data/angular-aria.js
vendored
@ -1,9 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @license AngularJS v1.4.10
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
(function(window, angular, undefined) {'use strict';
|
(function(window, angular) {'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc module
|
* @ngdoc module
|
||||||
@ -21,18 +21,23 @@
|
|||||||
*
|
*
|
||||||
* For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
|
* For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
|
||||||
* directives are supported:
|
* 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:
|
* Below is a more detailed breakdown of the attributes handled by ngAria:
|
||||||
*
|
*
|
||||||
* | Directive | Supported Attributes |
|
* | 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: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:ngShow ngShow} | aria-hidden |
|
||||||
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
|
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
|
||||||
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
|
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
|
||||||
* | {@link module:ngMessages ngMessages} | aria-live |
|
* | {@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
|
* Find out more information about each directive by reading the
|
||||||
@ -92,10 +97,10 @@ function $AriaProvider() {
|
|||||||
var config = {
|
var config = {
|
||||||
ariaHidden: true,
|
ariaHidden: true,
|
||||||
ariaChecked: true,
|
ariaChecked: true,
|
||||||
|
ariaReadonly: true,
|
||||||
ariaDisabled: true,
|
ariaDisabled: true,
|
||||||
ariaRequired: true,
|
ariaRequired: true,
|
||||||
ariaInvalid: true,
|
ariaInvalid: true,
|
||||||
ariaMultiline: true,
|
|
||||||
ariaValue: true,
|
ariaValue: true,
|
||||||
tabindex: true,
|
tabindex: true,
|
||||||
bindKeypress: true,
|
bindKeypress: true,
|
||||||
@ -110,14 +115,14 @@ function $AriaProvider() {
|
|||||||
*
|
*
|
||||||
* - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
|
* - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
|
||||||
* - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
|
* - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
|
||||||
|
* - **ariaReadonly** – `{boolean}` – Enables/disables aria-readonly tags
|
||||||
* - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
|
* - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
|
||||||
* - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
|
* - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
|
||||||
* - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid 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
|
* - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags
|
||||||
* - **tabindex** – `{boolean}` – Enables/disables tabindex tags
|
* - **tabindex** – `{boolean}` – Enables/disables tabindex tags
|
||||||
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `<div>` and
|
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `div` and
|
||||||
* `<li>` elements with ng-click
|
* `li` elements with ng-click
|
||||||
* - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements like `div`
|
* - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements like `div`
|
||||||
* using ng-click, making them more accessible to users of assistive technologies
|
* using ng-click, making them more accessible to users of assistive technologies
|
||||||
*
|
*
|
||||||
@ -156,15 +161,15 @@ function $AriaProvider() {
|
|||||||
*
|
*
|
||||||
*```js
|
*```js
|
||||||
* ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
|
* 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
|
* 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
|
* traditional `ng-disabled` directive. But this ngAria version is dedicated to
|
||||||
* solely managing accessibility attributes. The internal `$aria` service is used to watch the
|
* solely managing accessibility attributes on custom elements. The internal `$aria` service is
|
||||||
* boolean attribute `ngDisabled`. If it has not been explicitly set by the developer,
|
* used to watch the boolean attribute `ngDisabled`. If it has not been explicitly set by the
|
||||||
* `aria-disabled` is injected as an attribute with its value synchronized to the value in
|
* developer, `aria-disabled` is injected as an attribute with its value synchronized to the
|
||||||
* `ngDisabled`.
|
* value in `ngDisabled`.
|
||||||
*
|
*
|
||||||
* Because ngAria hooks into the `ng-disabled` directive, developers do not have to do
|
* 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
|
* 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:
|
* The full list of directives that interface with ngAria:
|
||||||
* * **ngModel**
|
* * **ngModel**
|
||||||
|
* * **ngChecked**
|
||||||
|
* * **ngReadonly**
|
||||||
|
* * **ngRequired**
|
||||||
|
* * **ngDisabled**
|
||||||
|
* * **ngValue**
|
||||||
* * **ngShow**
|
* * **ngShow**
|
||||||
* * **ngHide**
|
* * **ngHide**
|
||||||
* * **ngClick**
|
* * **ngClick**
|
||||||
* * **ngDblclick**
|
* * **ngDblclick**
|
||||||
* * **ngMessages**
|
* * **ngMessages**
|
||||||
* * **ngDisabled**
|
|
||||||
*
|
*
|
||||||
* Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
|
* Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
|
||||||
* directive.
|
* directive.
|
||||||
@ -203,13 +212,28 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
|||||||
.directive('ngHide', ['$aria', function($aria) {
|
.directive('ngHide', ['$aria', function($aria) {
|
||||||
return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);
|
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) {
|
.directive('ngModel', ['$aria', function($aria) {
|
||||||
|
|
||||||
function shouldAttachAttr(attr, normalizedAttr, elem) {
|
function shouldAttachAttr(attr, normalizedAttr, elem, allowBlacklistEls) {
|
||||||
return $aria.config(normalizedAttr) && !elem.attr(attr);
|
return $aria.config(normalizedAttr) && !elem.attr(attr) && (allowBlacklistEls || !isNodeOneOf(elem, nodeBlackList));
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldAttachRole(role, elem) {
|
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');
|
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' :
|
return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' :
|
||||||
((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' :
|
((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' :
|
||||||
(type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' :
|
(type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' : '';
|
||||||
(type || role) === 'textbox' || elem[0].nodeName === 'TEXTAREA' ? 'multiline' : '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
restrict: 'A',
|
restrict: 'A',
|
||||||
require: '?ngModel',
|
require: 'ngModel',
|
||||||
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
|
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
|
||||||
compile: function(elem, attr) {
|
compile: function(elem, attr) {
|
||||||
var shape = getShape(attr, elem);
|
var shape = getShape(attr, elem);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pre: function(scope, elem, attr, ngModel) {
|
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
|
//Use the input[checkbox] $isEmpty implementation for elements with checkbox roles
|
||||||
ngModel.$isEmpty = function(value) {
|
ngModel.$isEmpty = function(value) {
|
||||||
return value === false;
|
return value === false;
|
||||||
@ -240,29 +263,18 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
post: function(scope, elem, attr, ngModel) {
|
post: function(scope, elem, attr, ngModel) {
|
||||||
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem)
|
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
|
||||||
&& !isNodeOneOf(elem, nodeBlackList);
|
|
||||||
|
|
||||||
function ngAriaWatchModelValue() {
|
function ngAriaWatchModelValue() {
|
||||||
return ngModel.$modelValue;
|
return ngModel.$modelValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRadioReaction() {
|
function getRadioReaction(newVal) {
|
||||||
if (needsTabIndex) {
|
|
||||||
needsTabIndex = false;
|
|
||||||
return function ngAriaRadioReaction(newVal) {
|
|
||||||
var boolVal = (attr.value == ngModel.$viewValue);
|
var boolVal = (attr.value == ngModel.$viewValue);
|
||||||
elem.attr('aria-checked', boolVal);
|
elem.attr('aria-checked', boolVal);
|
||||||
elem.attr('tabindex', 0 - !boolVal);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return function ngAriaRadioReaction(newVal) {
|
|
||||||
elem.attr('aria-checked', (attr.value == ngModel.$viewValue));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ngAriaCheckboxReaction() {
|
function getCheckboxReaction() {
|
||||||
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
|
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,9 +284,9 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
|||||||
if (shouldAttachRole(shape, elem)) {
|
if (shouldAttachRole(shape, elem)) {
|
||||||
elem.attr('role', shape);
|
elem.attr('role', shape);
|
||||||
}
|
}
|
||||||
if (shouldAttachAttr('aria-checked', 'ariaChecked', elem)) {
|
if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {
|
||||||
scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
|
scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
|
||||||
getRadioReaction() : ngAriaCheckboxReaction);
|
getRadioReaction : getCheckboxReaction);
|
||||||
}
|
}
|
||||||
if (needsTabIndex) {
|
if (needsTabIndex) {
|
||||||
elem.attr('tabindex', 0);
|
elem.attr('tabindex', 0);
|
||||||
@ -311,22 +323,17 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
|||||||
elem.attr('tabindex', 0);
|
elem.attr('tabindex', 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'multiline':
|
|
||||||
if (shouldAttachAttr('aria-multiline', 'ariaMultiline', elem)) {
|
|
||||||
elem.attr('aria-multiline', true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ngModel.$validators.required && shouldAttachAttr('aria-required', 'ariaRequired', elem)) {
|
if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required
|
||||||
scope.$watch(function ngAriaRequiredWatch() {
|
&& shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {
|
||||||
return ngModel.$error.required;
|
// ngModel.$error.required is undefined on custom controls
|
||||||
}, function ngAriaRequiredReaction(newVal) {
|
attr.$observe('required', function() {
|
||||||
elem.attr('aria-required', !!newVal);
|
elem.attr('aria-required', !!attr['required']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem)) {
|
if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {
|
||||||
scope.$watch(function ngAriaInvalidWatch() {
|
scope.$watch(function ngAriaInvalidWatch() {
|
||||||
return ngModel.$invalid;
|
return ngModel.$invalid;
|
||||||
}, function ngAriaInvalidReaction(newVal) {
|
}, function ngAriaInvalidReaction(newVal) {
|
||||||
@ -339,7 +346,7 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
|||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
.directive('ngDisabled', ['$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() {
|
.directive('ngMessages', function() {
|
||||||
return {
|
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
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
(function(window, angular, undefined) {'use strict';
|
(function(window, angular) {'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc module
|
* @ngdoc module
|
||||||
|
25
xstatic/pkg/angular/data/angular-loader.js
vendored
25
xstatic/pkg/angular/data/angular-loader.js
vendored
@ -1,13 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* @license AngularJS v1.4.10
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {'use strict';
|
(function() {'use strict';
|
||||||
function isFunction(value) {return typeof value === 'function';};
|
function isFunction(value) {return typeof value === 'function';};
|
||||||
|
|
||||||
/* global: toDebugString: true */
|
/* global toDebugString: true */
|
||||||
|
|
||||||
function serializeObject(obj) {
|
function serializeObject(obj) {
|
||||||
var seen = [];
|
var seen = [];
|
||||||
@ -87,7 +87,7 @@ function minErr(module, ErrorConstructor) {
|
|||||||
return match;
|
return match;
|
||||||
});
|
});
|
||||||
|
|
||||||
message += '\nhttp://errors.angularjs.org/1.4.10/' +
|
message += '\nhttp://errors.angularjs.org/1.5.8/' +
|
||||||
(module ? module + '/' : '') + code;
|
(module ? module + '/' : '') + code;
|
||||||
|
|
||||||
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
|
||||||
@ -296,8 +296,8 @@ function setupModuleLoader(window) {
|
|||||||
* @ngdoc method
|
* @ngdoc method
|
||||||
* @name angular.Module#decorator
|
* @name angular.Module#decorator
|
||||||
* @module ng
|
* @module ng
|
||||||
* @param {string} The name of the service to decorate.
|
* @param {string} name The name of the service to decorate.
|
||||||
* @param {Function} This function will be invoked when the service needs to be
|
* @param {Function} decorFn This function will be invoked when the service needs to be
|
||||||
* instantiated and should return the decorated service instance.
|
* instantiated and should return the decorated service instance.
|
||||||
* @description
|
* @description
|
||||||
* See {@link auto.$provide#decorator $provide.decorator()}.
|
* See {@link auto.$provide#decorator $provide.decorator()}.
|
||||||
@ -381,6 +381,19 @@ function setupModuleLoader(window) {
|
|||||||
*/
|
*/
|
||||||
directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
|
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
|
* @ngdoc method
|
||||||
* @name angular.Module#config
|
* @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
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
(function(window, angular, undefined) {'use strict';
|
(function(window, angular) {'use strict';
|
||||||
|
|
||||||
// NOTE: ADVANCED_OPTIMIZATIONS mode.
|
// NOTE: ADVANCED_OPTIMIZATIONS mode.
|
||||||
//
|
//
|
||||||
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
|
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
|
||||||
// constructs incompatible with that mode.
|
// constructs incompatible with that mode.
|
||||||
|
|
||||||
var $interpolateMinErr = window['angular']['$interpolateMinErr'];
|
/* global isFunction: false */
|
||||||
|
/* global noop: false */
|
||||||
var noop = window['angular']['noop'],
|
/* global toJson: false */
|
||||||
isFunction = window['angular']['isFunction'],
|
|
||||||
toJson = window['angular']['toJson'];
|
|
||||||
|
|
||||||
function stringify(value) {
|
function stringify(value) {
|
||||||
if (value == null /* null/undefined */) { return ''; }
|
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
|
// This file is compiled with Closure compiler's ADVANCED_OPTIMIZATIONS flag! Be wary of using
|
||||||
// constructs incompatible with that mode.
|
// constructs incompatible with that mode.
|
||||||
|
|
||||||
/* global $interpolateMinErr: false */
|
/* global $interpolateMinErr: true */
|
||||||
|
/* global isFunction: true */
|
||||||
|
/* global noop: true */
|
||||||
|
/* global toJson: true */
|
||||||
/* global MessageFormatParser: false */
|
/* global MessageFormatParser: false */
|
||||||
/* global stringify: false */
|
/* global stringify: false */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc service
|
* @ngdoc module
|
||||||
* @name $$messageFormat
|
* @name ngMessageFormat
|
||||||
|
* @packageName angular-message-format
|
||||||
*
|
*
|
||||||
* @description
|
* @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">
|
* <file name="index.html">
|
||||||
* <div ng-controller="AppController">
|
* <div ng-controller="AppController">
|
||||||
* <button ng-click="decreaseRecipients()" id="decreaseRecipients">decreaseRecipients</button><br>
|
* Select Recipient:<br>
|
||||||
* <span>{{recipients.length, plural, offset:1
|
<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="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 (\#=#)}
|
* =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 (\#=#)}
|
* 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 (\#=#)}
|
* other {{{sender.name}} gave {{recipients[0].name}} and # other people a gift (\#=#)}
|
||||||
* }}</span>
|
* }}</p>
|
||||||
* </div>
|
* </div>
|
||||||
* </file>
|
* </file>
|
||||||
*
|
*
|
||||||
@ -897,35 +954,79 @@ MessageFormatParser.prototype.ruleInAngularExpression = function ruleInAngularEx
|
|||||||
*
|
*
|
||||||
* var alice = new Person("Alice", "female"),
|
* var alice = new Person("Alice", "female"),
|
||||||
* bob = new Person("Bob", "male"),
|
* bob = new Person("Bob", "male"),
|
||||||
* charlie = new Person("Charlie", "male"),
|
* sarah = new Person("Sarah", "female"),
|
||||||
* harry = new Person("Harry Potter", "male");
|
* harry = new Person("Harry Potter", "male"),
|
||||||
|
* ashley = new Person("Ashley", "");
|
||||||
*
|
*
|
||||||
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
* angular.module('msgFmtExample', ['ngMessageFormat'])
|
||||||
* .controller('AppController', ['$scope', function($scope) {
|
* .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.sender = harry;
|
||||||
* $scope.decreaseRecipients = function() {
|
|
||||||
* --$scope.recipients.length;
|
|
||||||
* };
|
|
||||||
* }]);
|
* }]);
|
||||||
* </file>
|
* </file>
|
||||||
*
|
*
|
||||||
* <file name="protractor.js" type="protractor">
|
* <file name="protractor.js" type="protractor">
|
||||||
* describe('MessageFormat plural', function() {
|
* describe('MessageFormat plural', function() {
|
||||||
|
*
|
||||||
* it('should pluralize initial values', 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)');
|
* expect(messageElem.getText()).toEqual('Harry Potter gave Alice and 2 other people a gift (#=2)');
|
||||||
* decreaseRecipientsBtn.click();
|
* decreaseRecipientsBtn.click();
|
||||||
* expect(messageElem.getText()).toEqual('Harry Potter gave Alice and one other person a gift (#=1)');
|
* expect(messageElem.getText()).toEqual('Harry Potter gave Alice and one other person a gift (#=1)');
|
||||||
* decreaseRecipientsBtn.click();
|
* 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();
|
* decreaseRecipientsBtn.click();
|
||||||
* expect(messageElem.getText()).toEqual('Harry Potter gave no gifts (#=-1)');
|
* expect(messageElem.getText()).toEqual('Harry Potter gave no gifts (#=-1)');
|
||||||
* });
|
* });
|
||||||
* });
|
* });
|
||||||
* </file>
|
* </file>
|
||||||
* </example>
|
* </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(
|
var $$MessageFormatFactory = ['$parse', '$locale', '$sce', '$exceptionHandler', function $$messageFormat(
|
||||||
$parse, $locale, $sce, $exceptionHandler) {
|
$parse, $locale, $sce, $exceptionHandler) {
|
||||||
|
|
||||||
@ -963,16 +1064,19 @@ var $$interpolateDecorator = ['$$messageFormat', '$delegate', function $$interpo
|
|||||||
return interpolate;
|
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']);
|
var module = window['angular']['module']('ngMessageFormat', ['ng']);
|
||||||
module['factory']('$$messageFormat', $$MessageFormatFactory);
|
module['factory']('$$messageFormat', $$MessageFormatFactory);
|
||||||
module['config'](['$provide', function($provide) {
|
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);
|
$provide['decorator']('$interpolate', $$interpolateDecorator);
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
85
xstatic/pkg/angular/data/angular-messages.js
vendored
85
xstatic/pkg/angular/data/angular-messages.js
vendored
@ -1,17 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* @license AngularJS v1.4.10
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
(function(window, angular, undefined) {'use strict';
|
(function(window, angular) {'use strict';
|
||||||
|
|
||||||
/* jshint ignore:start */
|
var forEach;
|
||||||
// this code is in the core, but not in angular-messages.js
|
var isArray;
|
||||||
var isArray = angular.isArray;
|
var isString;
|
||||||
var forEach = angular.forEach;
|
var jqLite;
|
||||||
var isString = angular.isString;
|
|
||||||
var jqLite = angular.element;
|
|
||||||
/* jshint ignore:end */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc module
|
* @ngdoc module
|
||||||
@ -267,7 +264,14 @@ var jqLite = angular.element;
|
|||||||
*
|
*
|
||||||
* {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
|
* {@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
|
* @ngdoc directive
|
||||||
@ -415,6 +419,13 @@ angular.module('ngMessages', [])
|
|||||||
|
|
||||||
$scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
|
$scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
|
||||||
|
|
||||||
|
// If the element is destroyed, proactively destroy all the currently visible messages
|
||||||
|
$element.on('$destroy', function() {
|
||||||
|
forEach(messages, function(item) {
|
||||||
|
item.message.detach();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
this.reRender = function() {
|
this.reRender = function() {
|
||||||
if (!renderLater) {
|
if (!renderLater) {
|
||||||
renderLater = true;
|
renderLater = true;
|
||||||
@ -449,6 +460,7 @@ angular.module('ngMessages', [])
|
|||||||
function findPreviousMessage(parent, comment) {
|
function findPreviousMessage(parent, comment) {
|
||||||
var prevNode = comment;
|
var prevNode = comment;
|
||||||
var parentLookup = [];
|
var parentLookup = [];
|
||||||
|
|
||||||
while (prevNode && prevNode !== parent) {
|
while (prevNode && prevNode !== parent) {
|
||||||
var prevKey = prevNode.$$ngMessageNode;
|
var prevKey = prevNode.$$ngMessageNode;
|
||||||
if (prevKey && prevKey.length) {
|
if (prevKey && prevKey.length) {
|
||||||
@ -457,11 +469,14 @@ angular.module('ngMessages', [])
|
|||||||
|
|
||||||
// dive deeper into the DOM and examine its children for any ngMessage
|
// 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
|
// comments that may be in an element that appears deeper in the list
|
||||||
if (prevNode.childNodes.length && parentLookup.indexOf(prevNode) == -1) {
|
if (prevNode.childNodes.length && parentLookup.indexOf(prevNode) === -1) {
|
||||||
parentLookup.push(prevNode);
|
parentLookup.push(prevNode);
|
||||||
prevNode = prevNode.childNodes[prevNode.childNodes.length - 1];
|
prevNode = prevNode.childNodes[prevNode.childNodes.length - 1];
|
||||||
|
} else if (prevNode.previousSibling) {
|
||||||
|
prevNode = prevNode.previousSibling;
|
||||||
} else {
|
} else {
|
||||||
prevNode = prevNode.previousSibling || prevNode.parentNode;
|
prevNode = prevNode.parentNode;
|
||||||
|
parentLookup.push(prevNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -544,19 +559,34 @@ angular.module('ngMessages', [])
|
|||||||
link: function($scope, element, attrs) {
|
link: function($scope, element, attrs) {
|
||||||
var src = attrs.ngMessagesInclude || attrs.src;
|
var src = attrs.ngMessagesInclude || attrs.src;
|
||||||
$templateRequest(src).then(function(html) {
|
$templateRequest(src).then(function(html) {
|
||||||
|
if ($scope.$$destroyed) return;
|
||||||
|
|
||||||
|
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) {
|
$compile(html)($scope, function(contents) {
|
||||||
element.after(contents);
|
element.after(contents);
|
||||||
|
replaceElementWithMarker(element, src);
|
||||||
// the anchor is placed for debugging purposes
|
|
||||||
var anchor = jqLite($document[0].createComment(' ngMessagesInclude: ' + src + ' '));
|
|
||||||
element.after(anchor);
|
|
||||||
|
|
||||||
// we don't want to pollute the DOM anymore by keeping an empty directive element
|
|
||||||
element.remove();
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
}])
|
}])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -591,13 +621,14 @@ angular.module('ngMessages', [])
|
|||||||
*
|
*
|
||||||
* @param {expression} ngMessage|when a string value corresponding to the message key.
|
* @param {expression} ngMessage|when a string value corresponding to the message key.
|
||||||
*/
|
*/
|
||||||
.directive('ngMessage', ngMessageDirectiveFactory('AE'))
|
.directive('ngMessage', ngMessageDirectiveFactory())
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc directive
|
* @ngdoc directive
|
||||||
* @name ngMessageExp
|
* @name ngMessageExp
|
||||||
* @restrict AE
|
* @restrict AE
|
||||||
|
* @priority 1
|
||||||
* @scope
|
* @scope
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
@ -623,13 +654,14 @@ angular.module('ngMessages', [])
|
|||||||
*
|
*
|
||||||
* @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key.
|
* @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key.
|
||||||
*/
|
*/
|
||||||
.directive('ngMessageExp', ngMessageDirectiveFactory('A'));
|
.directive('ngMessageExp', ngMessageDirectiveFactory());
|
||||||
|
|
||||||
function ngMessageDirectiveFactory(restrict) {
|
function ngMessageDirectiveFactory() {
|
||||||
return ['$animate', function($animate) {
|
return ['$animate', function($animate) {
|
||||||
return {
|
return {
|
||||||
restrict: 'AE',
|
restrict: 'AE',
|
||||||
transclude: 'element',
|
transclude: 'element',
|
||||||
|
priority: 1, // must run before ngBind, otherwise the text is set on the comment
|
||||||
terminal: true,
|
terminal: true,
|
||||||
require: '^^ngMessages',
|
require: '^^ngMessages',
|
||||||
link: function(scope, element, attrs, ngMessagesCtrl, $transclude) {
|
link: function(scope, element, attrs, ngMessagesCtrl, $transclude) {
|
||||||
@ -661,7 +693,7 @@ function ngMessageDirectiveFactory(restrict) {
|
|||||||
},
|
},
|
||||||
attach: function() {
|
attach: function() {
|
||||||
if (!currentElement) {
|
if (!currentElement) {
|
||||||
$transclude(scope, function(elm) {
|
$transclude(function(elm, newScope) {
|
||||||
$animate.enter(elm, null, element);
|
$animate.enter(elm, null, element);
|
||||||
currentElement = elm;
|
currentElement = elm;
|
||||||
|
|
||||||
@ -669,14 +701,15 @@ function ngMessageDirectiveFactory(restrict) {
|
|||||||
// when we are destroying the node later.
|
// when we are destroying the node later.
|
||||||
var $$attachId = currentElement.$$attachId = ngMessagesCtrl.getAttachId();
|
var $$attachId = currentElement.$$attachId = ngMessagesCtrl.getAttachId();
|
||||||
|
|
||||||
// in the event that the parent element is destroyed
|
// in the event that the element or a parent element is destroyed
|
||||||
// by any other structural directive then it's time
|
// by another structural directive then it's time
|
||||||
// to deregister the message from the controller
|
// to deregister the message from the controller
|
||||||
currentElement.on('$destroy', function() {
|
currentElement.on('$destroy', function() {
|
||||||
if (currentElement && currentElement.$$attachId === $$attachId) {
|
if (currentElement && currentElement.$$attachId === $$attachId) {
|
||||||
ngMessagesCtrl.deregister(commentNode);
|
ngMessagesCtrl.deregister(commentNode);
|
||||||
messageCtrl.detach();
|
messageCtrl.detach();
|
||||||
}
|
}
|
||||||
|
newScope.$destroy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
830
xstatic/pkg/angular/data/angular-mocks.js
vendored
830
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
267
xstatic/pkg/angular/data/angular-resource.js
vendored
267
xstatic/pkg/angular/data/angular-resource.js
vendored
@ -1,9 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @license AngularJS v1.4.10
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
(function(window, angular, undefined) {'use strict';
|
(function(window, angular) {'use strict';
|
||||||
|
|
||||||
var $resourceMinErr = angular.$$minErr('$resource');
|
var $resourceMinErr = angular.$$minErr('$resource');
|
||||||
|
|
||||||
@ -61,13 +61,30 @@ function shallowClearAndCopy(src, dst) {
|
|||||||
*
|
*
|
||||||
* <div doc-module-components="ngResource"></div>
|
* <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
|
* @ngdoc service
|
||||||
* @name $resource
|
* @name $resource
|
||||||
* @requires $http
|
* @requires $http
|
||||||
|
* @requires ng.$log
|
||||||
|
* @requires $q
|
||||||
|
* @requires ng.$timeout
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* A factory which creates a resource object that lets you interact with
|
* A factory which creates a resource object that lets you interact with
|
||||||
@ -102,8 +119,9 @@ function shallowClearAndCopy(src, dst) {
|
|||||||
* can escape it with `/\.`.
|
* can escape it with `/\.`.
|
||||||
*
|
*
|
||||||
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
* @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
|
* `actions` methods. If a 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).
|
* 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
|
* 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 `?`.
|
* 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
|
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
|
||||||
* URL `/path/greet?salutation=Hello`.
|
* URL `/path/greet?salutation=Hello`.
|
||||||
*
|
*
|
||||||
* If the parameter value is prefixed with `@` then the value for that parameter will be extracted
|
* If the parameter value is prefixed with `@`, then the value for that parameter will be
|
||||||
* from the corresponding property on the `data` object (provided when calling an action method). For
|
* extracted from the corresponding property on the `data` object (provided when calling a
|
||||||
* example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam`
|
* "non-GET" action method).
|
||||||
* will be `data.someProp`.
|
* 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
|
* @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
|
* 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`,
|
* - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
|
||||||
* `DELETE`, `JSONP`, etc).
|
* `DELETE`, `JSONP`, etc).
|
||||||
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
|
* - **`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
|
* 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).
|
* 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
|
* - **`url`** – {string} – action specific `url` override. The url templating is supported just
|
||||||
* like for the resource-level urls.
|
* like for the resource-level urls.
|
||||||
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
|
* - **`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)>}` –
|
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||||
* transform function or an array of such functions. The transform function takes the http
|
* 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.
|
* 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
|
* By default, transformResponse will contain one function that checks if the response looks
|
||||||
* a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
|
* like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
|
||||||
* `transformResponse` to an empty array: `transformResponse: []`
|
* set `transformResponse` to an empty array: `transformResponse: []`
|
||||||
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
|
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
|
||||||
* GET request, otherwise if a cache instance built with
|
* GET request, otherwise if a cache instance built with
|
||||||
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
||||||
@ -158,8 +180,11 @@ function shallowClearAndCopy(src, dst) {
|
|||||||
* - **`timeout`** – `{number}` – timeout in milliseconds.<br />
|
* - **`timeout`** – `{number}` – timeout in milliseconds.<br />
|
||||||
* **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
|
* **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.
|
* **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
|
* If you are looking for a way to cancel requests, you should use the `cancellable` option.
|
||||||
* higher.
|
* - **`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
|
* - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
|
||||||
* XHR object. See
|
* XHR object. See
|
||||||
* [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
|
* [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}.
|
* with `http response` object. See {@link ng.$http $http interceptors}.
|
||||||
*
|
*
|
||||||
* @param {Object} options Hash with custom settings that should extend the
|
* @param {Object} options Hash with custom settings that should extend the
|
||||||
* default `$resourceProvider` behavior. The only supported option is
|
* default `$resourceProvider` behavior. The supported options are:
|
||||||
*
|
|
||||||
* Where:
|
|
||||||
*
|
*
|
||||||
* - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
|
* - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
|
||||||
* slashes from any calculated URL will be stripped. (Defaults to true.)
|
* 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
|
* @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:
|
* 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).
|
* Class actions return empty instance (with additional properties below).
|
||||||
* Instance actions return promise of the action.
|
* 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
|
* - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
|
||||||
* instance or collection.
|
* 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
|
* rejection), `false` before that. Knowing if the Resource has been resolved is useful in
|
||||||
* data-binding.
|
* 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
|
* @example
|
||||||
*
|
*
|
||||||
* # Credit card resource
|
* # 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
|
* Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
|
||||||
* `headers`.
|
* `headers`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* # User resource
|
||||||
|
*
|
||||||
* When the data is returned from the server then the object is an instance of the resource type and
|
* 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
|
* 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.
|
* operations (create, read, update, delete) on server-side data.
|
||||||
@ -306,10 +350,10 @@ function shallowClearAndCopy(src, dst) {
|
|||||||
*
|
*
|
||||||
```js
|
```js
|
||||||
var User = $resource('/user/:userId', {userId:'@id'});
|
var User = $resource('/user/:userId', {userId:'@id'});
|
||||||
User.get({userId:123}, function(u, getResponseHeaders){
|
User.get({userId:123}, function(user, getResponseHeaders){
|
||||||
u.abc = true;
|
user.abc = true;
|
||||||
u.$save(function(u, putResponseHeaders) {
|
user.$save(function(user, putResponseHeaders) {
|
||||||
//u => saved user object
|
//user => saved user object
|
||||||
//putResponseHeaders => $http header getter
|
//putResponseHeaders => $http header getter
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -324,8 +368,11 @@ function shallowClearAndCopy(src, dst) {
|
|||||||
$scope.user = user;
|
$scope.user = user;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
* # Creating a custom 'PUT' request
|
* # Creating a custom 'PUT' request
|
||||||
|
*
|
||||||
* In this example we create a custom method on our resource to make a PUT request
|
* In this example we create a custom method on our resource to make a PUT request
|
||||||
* ```js
|
* ```js
|
||||||
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
* 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
|
* // 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']).
|
angular.module('ngResource', ['ng']).
|
||||||
provider('$resource', function() {
|
provider('$resource', function() {
|
||||||
var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
|
var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
|
||||||
var provider = this;
|
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 = {
|
this.defaults = {
|
||||||
// Strip slashes by default
|
// Strip slashes by default
|
||||||
stripTrailingSlashes: true,
|
stripTrailingSlashes: true,
|
||||||
|
|
||||||
|
// Make non-instance requests cancellable (via `$cancelRequest()`)
|
||||||
|
cancellable: false,
|
||||||
|
|
||||||
// Default actions configuration
|
// Default actions configuration
|
||||||
actions: {
|
actions: {
|
||||||
'get': {method: 'GET'},
|
'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,
|
var noop = angular.noop,
|
||||||
forEach = angular.forEach,
|
forEach = angular.forEach,
|
||||||
@ -441,7 +584,9 @@ angular.module('ngResource', ['ng']).
|
|||||||
}
|
}
|
||||||
if (!(new RegExp("^\\d+$").test(param)) && param &&
|
if (!(new RegExp("^\\d+$").test(param)) && param &&
|
||||||
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
||||||
urlParams[param] = true;
|
urlParams[param] = {
|
||||||
|
isQueryParamValue: (new RegExp("\\?.*=:" + param + "(?:\\W|$)")).test(url)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
url = url.replace(/\\:/g, ':');
|
url = url.replace(/\\:/g, ':');
|
||||||
@ -451,10 +596,14 @@ angular.module('ngResource', ['ng']).
|
|||||||
});
|
});
|
||||||
|
|
||||||
params = params || {};
|
params = params || {};
|
||||||
forEach(self.urlParams, function(_, urlParam) {
|
forEach(self.urlParams, function(paramInfo, urlParam) {
|
||||||
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
||||||
if (angular.isDefined(val) && val !== null) {
|
if (angular.isDefined(val) && val !== null) {
|
||||||
|
if (paramInfo.isQueryParamValue) {
|
||||||
|
encodedVal = encodeUriQuery(val, true);
|
||||||
|
} else {
|
||||||
encodedVal = encodeUriSegment(val);
|
encodedVal = encodeUriSegment(val);
|
||||||
|
}
|
||||||
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
|
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
|
||||||
return encodedVal + p1;
|
return encodedVal + p1;
|
||||||
});
|
});
|
||||||
@ -502,7 +651,7 @@ angular.module('ngResource', ['ng']).
|
|||||||
var ids = {};
|
var ids = {};
|
||||||
actionParams = extend({}, paramDefaults, actionParams);
|
actionParams = extend({}, paramDefaults, actionParams);
|
||||||
forEach(actionParams, function(value, key) {
|
forEach(actionParams, function(value, key) {
|
||||||
if (isFunction(value)) { value = value(); }
|
if (isFunction(value)) { value = value(data); }
|
||||||
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
|
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
|
||||||
lookupDottedPath(data, value.substr(1)) : value;
|
lookupDottedPath(data, value.substr(1)) : value;
|
||||||
});
|
});
|
||||||
@ -526,6 +675,20 @@ angular.module('ngResource', ['ng']).
|
|||||||
|
|
||||||
forEach(actions, function(action, name) {
|
forEach(actions, function(action, name) {
|
||||||
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
|
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) {
|
Resource[name] = function(a1, a2, a3, a4) {
|
||||||
var params = {}, data, success, error;
|
var params = {}, data, success, error;
|
||||||
@ -574,6 +737,8 @@ angular.module('ngResource', ['ng']).
|
|||||||
defaultResponseInterceptor;
|
defaultResponseInterceptor;
|
||||||
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
|
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
|
||||||
undefined;
|
undefined;
|
||||||
|
var timeoutDeferred;
|
||||||
|
var numericTimeoutPromise;
|
||||||
|
|
||||||
forEach(action, function(value, key) {
|
forEach(action, function(value, key) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
@ -583,28 +748,27 @@ angular.module('ngResource', ['ng']).
|
|||||||
case 'params':
|
case 'params':
|
||||||
case 'isArray':
|
case 'isArray':
|
||||||
case 'interceptor':
|
case 'interceptor':
|
||||||
break;
|
case 'cancellable':
|
||||||
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.');
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!isInstanceCall && cancellable) {
|
||||||
|
timeoutDeferred = $q.defer();
|
||||||
|
httpConfig.timeout = timeoutDeferred.promise;
|
||||||
|
|
||||||
|
if (numericTimeout) {
|
||||||
|
numericTimeoutPromise = $timeout(timeoutDeferred.resolve, numericTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasBody) httpConfig.data = data;
|
if (hasBody) httpConfig.data = data;
|
||||||
route.setUrlParams(httpConfig,
|
route.setUrlParams(httpConfig,
|
||||||
extend({}, extractParams(data, action.params || {}), params),
|
extend({}, extractParams(data, action.params || {}), params),
|
||||||
action.url);
|
action.url);
|
||||||
|
|
||||||
var promise = $http(httpConfig).then(function(response) {
|
var promise = $http(httpConfig).then(function(response) {
|
||||||
var data = response.data,
|
var data = response.data;
|
||||||
promise = value.$promise;
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
// Need to convert action.isArray to boolean in case it is undefined
|
// Need to convert action.isArray to boolean in case it is undefined
|
||||||
@ -629,24 +793,28 @@ angular.module('ngResource', ['ng']).
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
var promise = value.$promise; // Save the promise
|
||||||
shallowClearAndCopy(data, value);
|
shallowClearAndCopy(data, value);
|
||||||
value.$promise = promise;
|
value.$promise = promise; // Restore the promise
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value.$resolved = true;
|
|
||||||
|
|
||||||
response.resource = value;
|
response.resource = value;
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}, function(response) {
|
}, function(response) {
|
||||||
value.$resolved = true;
|
|
||||||
|
|
||||||
(error || noop)(response);
|
(error || noop)(response);
|
||||||
|
|
||||||
return $q.reject(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(
|
promise = promise.then(
|
||||||
function(response) {
|
function(response) {
|
||||||
var value = responseInterceptor(response);
|
var value = responseInterceptor(response);
|
||||||
@ -661,6 +829,7 @@ angular.module('ngResource', ['ng']).
|
|||||||
// - return the instance / collection
|
// - return the instance / collection
|
||||||
value.$promise = promise;
|
value.$promise = promise;
|
||||||
value.$resolved = false;
|
value.$resolved = false;
|
||||||
|
if (cancellable) value.$cancelRequest = timeoutDeferred.resolve;
|
||||||
|
|
||||||
return value;
|
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
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* 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
|
* @ngdoc module
|
||||||
@ -40,6 +74,9 @@ var ngRouteModule = angular.module('ngRoute', ['ng']).
|
|||||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||||
*/
|
*/
|
||||||
function $RouteProvider() {
|
function $RouteProvider() {
|
||||||
|
isArray = angular.isArray;
|
||||||
|
isObject = angular.isObject;
|
||||||
|
|
||||||
function inherit(parent, extra) {
|
function inherit(parent, extra) {
|
||||||
return angular.extend(Object.create(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
|
* If all the promises are resolved successfully, the values of the resolved promises are
|
||||||
* injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
|
* injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
|
||||||
* fired. If any of the promises are rejected the
|
* fired. If any of the promises are rejected the
|
||||||
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
|
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired.
|
||||||
* is:
|
* 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.
|
* - `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.
|
* - `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
|
* `ngRoute.$routeParams` will still refer to the previous route within these resolve
|
||||||
* functions. Use `$route.current.params` to access the new route parameters, instead.
|
* 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.
|
* {@link ng.$location $location} path with and trigger route redirection.
|
||||||
*
|
*
|
||||||
* If `redirectTo` is a function, it will be called with the following parameters:
|
* 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
|
* The custom `redirectTo` function is expected to return a string which will be used
|
||||||
* to update `$location.path()` and `$location.search()`.
|
* 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.
|
* or `$location.hash()` changes.
|
||||||
*
|
*
|
||||||
* If the option is set to `false` and url in the browser changes, then
|
* If the option is set to `false` and url in the browser changes, then
|
||||||
* `$routeUpdate` event is broadcasted on the root scope.
|
* `$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
|
* If the option is set to `true`, then the particular route can be matched without being
|
||||||
* case sensitive
|
* case sensitive
|
||||||
@ -147,7 +196,7 @@ function $RouteProvider() {
|
|||||||
*/
|
*/
|
||||||
this.when = function(path, route) {
|
this.when = function(path, route) {
|
||||||
//copy original route object to preserve params inherited from proto chain
|
//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)) {
|
if (angular.isUndefined(routeCopy.reloadOnSearch)) {
|
||||||
routeCopy.reloadOnSearch = true;
|
routeCopy.reloadOnSearch = true;
|
||||||
}
|
}
|
||||||
@ -265,7 +314,7 @@ function $RouteProvider() {
|
|||||||
* @property {Object} current Reference to the current route definition.
|
* @property {Object} current Reference to the current route definition.
|
||||||
* The route definition contains:
|
* 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
|
* - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
|
||||||
* controller instantiation. The `locals` contain
|
* controller instantiation. The `locals` contain
|
||||||
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
||||||
@ -273,6 +322,10 @@ function $RouteProvider() {
|
|||||||
* - `$scope` - The current route scope.
|
* - `$scope` - The current route scope.
|
||||||
* - `$template` - The current route template HTML.
|
* - `$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.
|
* @property {Object} routes Object with all route configuration Objects as its properties.
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
@ -588,35 +641,7 @@ function $RouteProvider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$q.when(nextRoute).
|
$q.when(nextRoute).
|
||||||
then(function() {
|
then(resolveLocals).
|
||||||
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(function(locals) {
|
then(function(locals) {
|
||||||
// after route change
|
// after route change
|
||||||
if (nextRoute == $route.current) {
|
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
|
* @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.
|
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||||
*
|
*
|
||||||
* @animations
|
* @animations
|
||||||
* enter - animation is used to bring new content into the browser.
|
* | Animation | Occurs |
|
||||||
* leave - animation is used to animate existing content away.
|
* |----------------------------------|-------------------------------------|
|
||||||
|
* | {@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.
|
* 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
|
* @scope
|
||||||
* @priority 400
|
* @priority 400
|
||||||
* @param {string=} onload Expression to evaluate whenever the view updates.
|
* @param {string=} onload Expression to evaluate whenever the view updates.
|
||||||
@ -989,6 +1058,7 @@ function ngViewFillContentFactory($compile, $controller, $route) {
|
|||||||
$element.data('$ngControllerController', controller);
|
$element.data('$ngControllerController', controller);
|
||||||
$element.children().data('$ngControllerController', controller);
|
$element.children().data('$ngControllerController', controller);
|
||||||
}
|
}
|
||||||
|
scope[current.resolveAs || '$resolve'] = locals;
|
||||||
|
|
||||||
link(scope);
|
link(scope);
|
||||||
}
|
}
|
||||||
|
573
xstatic/pkg/angular/data/angular-sanitize.js
vendored
573
xstatic/pkg/angular/data/angular-sanitize.js
vendored
@ -1,9 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @license AngularJS v1.4.10
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* 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. *
|
* Any commits to this file should be reviewed with security in mind. *
|
||||||
@ -17,6 +17,14 @@
|
|||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
||||||
|
var bind;
|
||||||
|
var extend;
|
||||||
|
var forEach;
|
||||||
|
var isDefined;
|
||||||
|
var lowercase;
|
||||||
|
var noop;
|
||||||
|
var htmlParser;
|
||||||
|
var htmlSanitizeWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc module
|
* @ngdoc module
|
||||||
@ -33,36 +41,23 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
|||||||
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
|
* 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
|
* @ngdoc service
|
||||||
* @name $sanitize
|
* @name $sanitize
|
||||||
* @kind function
|
* @kind function
|
||||||
*
|
*
|
||||||
* @description
|
* @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
|
* 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
|
* 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
|
* it into the returned string.
|
||||||
* 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 for URL sanitization of attribute values is configured using the functions
|
||||||
* The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
|
* `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
|
||||||
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
|
* `$compileProvider`}.
|
||||||
|
*
|
||||||
|
* The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
|
||||||
*
|
*
|
||||||
* @param {string} html HTML input.
|
* @param {string} html HTML input.
|
||||||
* @returns {string} Sanitized HTML.
|
* @returns {string} Sanitized HTML.
|
||||||
@ -148,39 +143,89 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
|||||||
</file>
|
</file>
|
||||||
</example>
|
</example>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc provider
|
||||||
|
* @name $sanitizeProvider
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Creates and configures {@link $sanitize} instance.
|
||||||
|
*/
|
||||||
function $SanitizeProvider() {
|
function $SanitizeProvider() {
|
||||||
|
var svgEnabled = false;
|
||||||
|
|
||||||
this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
|
this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
|
||||||
|
if (svgEnabled) {
|
||||||
|
extend(validElements, svgElements);
|
||||||
|
}
|
||||||
return function(html) {
|
return function(html) {
|
||||||
var buf = [];
|
var buf = [];
|
||||||
htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
|
htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
|
||||||
return !/^unsafe/.test($$sanitizeUri(uri, isImage));
|
return !/^unsafe:/.test($$sanitizeUri(uri, isImage));
|
||||||
}));
|
}));
|
||||||
return buf.join('');
|
return buf.join('');
|
||||||
};
|
};
|
||||||
}];
|
}];
|
||||||
}
|
|
||||||
|
|
||||||
function sanitizeText(chars) {
|
|
||||||
var buf = [];
|
|
||||||
var writer = htmlSanitizeWriter(buf, angular.noop);
|
|
||||||
writer.chars(chars);
|
|
||||||
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
|
// Regular Expressions for parsing tags and attributes
|
||||||
var START_TAG_REGEXP =
|
var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
|
||||||
/^<((?:[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)
|
// Match everything outside of normal chars and " (quote character)
|
||||||
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
|
NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
|
||||||
|
|
||||||
|
|
||||||
// Good source of info about elements and attributes
|
// Good source of info about elements and attributes
|
||||||
@ -189,23 +234,23 @@ var START_TAG_REGEXP =
|
|||||||
|
|
||||||
// Safe Void Elements - HTML5
|
// Safe Void Elements - HTML5
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#void-elements
|
// http://dev.w3.org/html5/spec/Overview.html#void-elements
|
||||||
var voidElements = makeMap("area,br,col,hr,img,wbr");
|
var voidElements = toMap("area,br,col,hr,img,wbr");
|
||||||
|
|
||||||
// Elements that you can, intentionally, leave open (and which close themselves)
|
// Elements that you can, intentionally, leave open (and which close themselves)
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
||||||
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
var optionalEndTagBlockElements = toMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
||||||
optionalEndTagInlineElements = makeMap("rp,rt"),
|
optionalEndTagInlineElements = toMap("rp,rt"),
|
||||||
optionalEndTagElements = angular.extend({},
|
optionalEndTagElements = extend({},
|
||||||
optionalEndTagInlineElements,
|
optionalEndTagInlineElements,
|
||||||
optionalEndTagBlockElements);
|
optionalEndTagBlockElements);
|
||||||
|
|
||||||
// Safe Block Elements - HTML5
|
// Safe Block Elements - HTML5
|
||||||
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," +
|
var blockElements = extend({}, optionalEndTagBlockElements, toMap("address,article," +
|
||||||
"aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
|
"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"));
|
"h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul"));
|
||||||
|
|
||||||
// Inline Elements - HTML5
|
// Inline Elements - HTML5
|
||||||
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," +
|
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," +
|
"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"));
|
"samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
|
||||||
|
|
||||||
@ -213,24 +258,23 @@ var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a
|
|||||||
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
|
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
|
||||||
// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
|
// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
|
||||||
// They can potentially allow for arbitrary javascript to be executed. See #11290
|
// 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," +
|
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," +
|
"hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," +
|
||||||
"radialGradient,rect,stop,svg,switch,text,title,tspan,use");
|
"radialGradient,rect,stop,svg,switch,text,title,tspan");
|
||||||
|
|
||||||
// Special Elements (can contain anything)
|
// Blocked Elements (will be stripped)
|
||||||
var specialElements = makeMap("script,style");
|
var blockedElements = toMap("script,style");
|
||||||
|
|
||||||
var validElements = angular.extend({},
|
var validElements = extend({},
|
||||||
voidElements,
|
voidElements,
|
||||||
blockElements,
|
blockElements,
|
||||||
inlineElements,
|
inlineElements,
|
||||||
optionalEndTagElements,
|
optionalEndTagElements);
|
||||||
svgElements);
|
|
||||||
|
|
||||||
//Attributes that have href and hence need to be sanitized
|
//Attributes that have href and hence need to be sanitized
|
||||||
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href");
|
var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href");
|
||||||
|
|
||||||
var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
|
var htmlAttrs = toMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
|
||||||
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
|
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
|
||||||
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
|
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
|
||||||
'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
|
'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
|
||||||
@ -238,7 +282,7 @@ var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspac
|
|||||||
|
|
||||||
// SVG attributes (without "id" and "name" attributes)
|
// SVG attributes (without "id" and "name" attributes)
|
||||||
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
|
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
|
||||||
var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
|
var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
|
||||||
'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
|
'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,' +
|
'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,' +
|
'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
|
||||||
@ -254,24 +298,45 @@ var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form
|
|||||||
'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' +
|
'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);
|
'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true);
|
||||||
|
|
||||||
var validAttrs = angular.extend({},
|
var validAttrs = extend({},
|
||||||
uriAttrs,
|
uriAttrs,
|
||||||
svgAttrs,
|
svgAttrs,
|
||||||
htmlAttrs);
|
htmlAttrs);
|
||||||
|
|
||||||
function makeMap(str, lowercaseKeys) {
|
function toMap(str, lowercaseKeys) {
|
||||||
var obj = {}, items = str.split(','), i;
|
var obj = {}, items = str.split(','), i;
|
||||||
for (i = 0; i < items.length; i++) {
|
for (i = 0; i < items.length; i++) {
|
||||||
obj[lowercaseKeys ? angular.lowercase(items[i]) : items[i]] = true;
|
obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true;
|
||||||
}
|
}
|
||||||
return obj;
|
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
|
* @example
|
||||||
* htmlParser(htmlString, {
|
* htmlParser(htmlString, {
|
||||||
* start: function(tag, attrs, unary) {},
|
* start: function(tag, attrs) {},
|
||||||
* end: function(tag) {},
|
* end: function(tag) {},
|
||||||
* chars: function(text) {},
|
* chars: function(text) {},
|
||||||
* comment: function(text) {}
|
* comment: function(text) {}
|
||||||
@ -280,170 +345,75 @@ function makeMap(str, lowercaseKeys) {
|
|||||||
* @param {string} html string
|
* @param {string} html string
|
||||||
* @param {object} handler
|
* @param {object} handler
|
||||||
*/
|
*/
|
||||||
function htmlParser(html, handler) {
|
function htmlParserImpl(html, handler) {
|
||||||
if (typeof html !== 'string') {
|
if (html === null || html === undefined) {
|
||||||
if (html === null || typeof html === 'undefined') {
|
|
||||||
html = '';
|
html = '';
|
||||||
} else {
|
} else if (typeof html !== 'string') {
|
||||||
html = '' + html;
|
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");
|
||||||
}
|
}
|
||||||
var index, chars, match, stack = [], last = html, text;
|
mXSSAttempts--;
|
||||||
stack.last = function() { return stack[stack.length - 1]; };
|
|
||||||
|
|
||||||
while (html) {
|
// strip custom-namespaced attributes on IE<=11
|
||||||
text = '';
|
if (window.document.documentMode) {
|
||||||
chars = true;
|
stripCustomNsAttrs(inertBodyElement);
|
||||||
|
|
||||||
// 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
|
html = inertBodyElement.innerHTML; //trigger mXSS
|
||||||
} else if (DOCTYPE_REGEXP.test(html)) {
|
inertBodyElement.innerHTML = html;
|
||||||
match = html.match(DOCTYPE_REGEXP);
|
} while (html !== inertBodyElement.innerHTML);
|
||||||
|
|
||||||
if (match) {
|
var node = inertBodyElement.firstChild;
|
||||||
html = html.replace(match[0], '');
|
while (node) {
|
||||||
chars = false;
|
switch (node.nodeType) {
|
||||||
}
|
case 1: // ELEMENT_NODE
|
||||||
// end tag
|
handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes));
|
||||||
} else if (BEGING_END_TAGE_REGEXP.test(html)) {
|
break;
|
||||||
match = html.match(END_TAG_REGEXP);
|
case 3: // TEXT NODE
|
||||||
|
handler.chars(node.textContent);
|
||||||
if (match) {
|
break;
|
||||||
html = html.substring(match[0].length);
|
|
||||||
match[0].replace(END_TAG_REGEXP, parseEndTag);
|
|
||||||
chars = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// start tag
|
var nextNode;
|
||||||
} else if (BEGIN_TAG_REGEXP.test(html)) {
|
if (!(nextNode = node.firstChild)) {
|
||||||
match = html.match(START_TAG_REGEXP);
|
if (node.nodeType == 1) {
|
||||||
|
handler.end(node.nodeName.toLowerCase());
|
||||||
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;
|
nextNode = node.nextSibling;
|
||||||
} else {
|
if (!nextNode) {
|
||||||
// no ending tag found --- this piece should be encoded as an entity.
|
while (nextNode == null) {
|
||||||
text += '<';
|
node = node.parentNode;
|
||||||
html = html.substring(1);
|
if (node === inertBodyElement) break;
|
||||||
}
|
nextNode = node.nextSibling;
|
||||||
}
|
if (node.nodeType == 1) {
|
||||||
|
handler.end(node.nodeName.toLowerCase());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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
|
* Escapes all potentially dangerous characters, so that the
|
||||||
@ -469,28 +439,28 @@ function encodeEntities(value) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* create an HTML/XML writer which writes to buffer
|
* create an HTML/XML writer which writes to buffer
|
||||||
* @param {Array} buf use buf.jain('') to get out sanitized html string
|
* @param {Array} buf use buf.join('') to get out sanitized html string
|
||||||
* @returns {object} in the form of {
|
* @returns {object} in the form of {
|
||||||
* start: function(tag, attrs, unary) {},
|
* start: function(tag, attrs) {},
|
||||||
* end: function(tag) {},
|
* end: function(tag) {},
|
||||||
* chars: function(text) {},
|
* chars: function(text) {},
|
||||||
* comment: function(text) {}
|
* comment: function(text) {}
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
function htmlSanitizeWriter(buf, uriValidator) {
|
function htmlSanitizeWriterImpl(buf, uriValidator) {
|
||||||
var ignore = false;
|
var ignoreCurrentElement = false;
|
||||||
var out = angular.bind(buf, buf.push);
|
var out = bind(buf, buf.push);
|
||||||
return {
|
return {
|
||||||
start: function(tag, attrs, unary) {
|
start: function(tag, attrs) {
|
||||||
tag = angular.lowercase(tag);
|
tag = lowercase(tag);
|
||||||
if (!ignore && specialElements[tag]) {
|
if (!ignoreCurrentElement && blockedElements[tag]) {
|
||||||
ignore = tag;
|
ignoreCurrentElement = tag;
|
||||||
}
|
}
|
||||||
if (!ignore && validElements[tag] === true) {
|
if (!ignoreCurrentElement && validElements[tag] === true) {
|
||||||
out('<');
|
out('<');
|
||||||
out(tag);
|
out(tag);
|
||||||
angular.forEach(attrs, function(value, key) {
|
forEach(attrs, function(value, key) {
|
||||||
var lkey=angular.lowercase(key);
|
var lkey = lowercase(key);
|
||||||
var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
|
var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
|
||||||
if (validAttrs[lkey] === true &&
|
if (validAttrs[lkey] === true &&
|
||||||
(uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
|
(uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
|
||||||
@ -501,22 +471,22 @@ function htmlSanitizeWriter(buf, uriValidator) {
|
|||||||
out('"');
|
out('"');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
out(unary ? '/>' : '>');
|
out('>');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
end: function(tag) {
|
end: function(tag) {
|
||||||
tag = angular.lowercase(tag);
|
tag = lowercase(tag);
|
||||||
if (!ignore && validElements[tag] === true) {
|
if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) {
|
||||||
out('</');
|
out('</');
|
||||||
out(tag);
|
out(tag);
|
||||||
out('>');
|
out('>');
|
||||||
}
|
}
|
||||||
if (tag == ignore) {
|
if (tag == ignoreCurrentElement) {
|
||||||
ignore = false;
|
ignoreCurrentElement = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chars: function(chars) {
|
chars: function(chars) {
|
||||||
if (!ignore) {
|
if (!ignoreCurrentElement) {
|
||||||
out(encodeEntities(chars));
|
out(encodeEntities(chars));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -524,25 +494,75 @@ function htmlSanitizeWriter(buf, uriValidator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, noop);
|
||||||
|
writer.chars(chars);
|
||||||
|
return buf.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// define ngSanitize module and register $sanitize service
|
// define ngSanitize module and register $sanitize service
|
||||||
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||||
|
|
||||||
/* global sanitizeText: false */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc filter
|
* @ngdoc filter
|
||||||
* @name linky
|
* @name linky
|
||||||
* @kind function
|
* @kind function
|
||||||
*
|
*
|
||||||
* @description
|
* @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.
|
* plain email address links.
|
||||||
*
|
*
|
||||||
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
|
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
|
||||||
*
|
*
|
||||||
* @param {string} text Input text.
|
* @param {string} text Input text.
|
||||||
* @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
|
* @param {string} target Window (`_blank|_self|_parent|_top`) or named frame to open links in.
|
||||||
* @returns {string} Html-linkified text.
|
* @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
|
* @usage
|
||||||
<span ng-bind-html="linky_expression | linky"></span>
|
<span ng-bind-html="linky_expression | linky"></span>
|
||||||
@ -550,25 +570,13 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
|||||||
* @example
|
* @example
|
||||||
<example module="linkyExample" deps="angular-sanitize.js">
|
<example module="linkyExample" deps="angular-sanitize.js">
|
||||||
<file name="index.html">
|
<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">
|
<div ng-controller="ExampleController">
|
||||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Filter</td>
|
<th>Filter</th>
|
||||||
<td>Source</td>
|
<th>Source</th>
|
||||||
<td>Rendered</td>
|
<th>Rendered</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="linky-filter">
|
<tr id="linky-filter">
|
||||||
<td>linky filter</td>
|
<td>linky filter</td>
|
||||||
@ -582,10 +590,19 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
|||||||
<tr id="linky-target">
|
<tr id="linky-target">
|
||||||
<td>linky target</td>
|
<td>linky target</td>
|
||||||
<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>
|
||||||
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="escaped-html">
|
<tr id="escaped-html">
|
||||||
@ -595,6 +612,18 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</file>
|
</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">
|
<file name="protractor.js" type="protractor">
|
||||||
it('should linkify the snippet with urls', function() {
|
it('should linkify the snippet with urls', function() {
|
||||||
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
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() {
|
it('should work with the target property', function() {
|
||||||
expect(element(by.id('linky-target')).
|
expect(element(by.id('linky-target')).
|
||||||
element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
|
element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()).
|
||||||
toBe('http://angularjs.org/');
|
toBe('http://angularjs.org/');
|
||||||
expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
|
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>
|
</file>
|
||||||
</example>
|
</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,
|
/((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
|
||||||
MAILTO_REGEXP = /^mailto:/i;
|
MAILTO_REGEXP = /^mailto:/i;
|
||||||
|
|
||||||
return function(text, target) {
|
var linkyMinErr = angular.$$minErr('linky');
|
||||||
if (!text) return text;
|
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 match;
|
||||||
var raw = text;
|
var raw = text;
|
||||||
var html = [];
|
var html = [];
|
||||||
@ -664,8 +713,14 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addLink(url, text) {
|
function addLink(url, text) {
|
||||||
|
var key, linkAttributes = attributesFn(url);
|
||||||
html.push('<a ');
|
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="',
|
html.push('target="',
|
||||||
target,
|
target,
|
||||||
'" ');
|
'" ');
|
||||||
|
9860
xstatic/pkg/angular/data/angular-scenario.js
vendored
9860
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
|
* @license AngularJS v1.5.8
|
||||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/
|
*/
|
||||||
(function(window, angular, undefined) {'use strict';
|
(function(window, angular) {'use strict';
|
||||||
|
|
||||||
|
/* global ngTouchClickDirectiveFactory: false,
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc module
|
* @ngdoc module
|
||||||
@ -27,10 +30,108 @@
|
|||||||
/* global -ngTouch */
|
/* global -ngTouch */
|
||||||
var ngTouch = angular.module('ngTouch', []);
|
var ngTouch = angular.module('ngTouch', []);
|
||||||
|
|
||||||
|
ngTouch.provider('$touch', $TouchProvider);
|
||||||
|
|
||||||
function nodeName_(element) {
|
function nodeName_(element) {
|
||||||
return angular.lowercase(element.nodeName || (element[0] && element[0].nodeName));
|
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 */
|
/* global ngTouch: false */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +167,12 @@ ngTouch.factory('$swipe', [function() {
|
|||||||
move: 'touchmove',
|
move: 'touchmove',
|
||||||
end: 'touchend',
|
end: 'touchend',
|
||||||
cancel: 'touchcancel'
|
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
|
* The main method of `$swipe`. It takes an element to be watched for swipe motions, and an
|
||||||
* object containing event handlers.
|
* object containing event handlers.
|
||||||
* The pointer types that should be used can be specified via the optional
|
* 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,
|
* third argument, which is an array of strings `'mouse'`, `'touch'` and `'pointer'`. By default,
|
||||||
* `$swipe` will listen for `mouse` and `touch` events.
|
* `$swipe` will listen for `mouse`, `touch` and `pointer` events.
|
||||||
*
|
*
|
||||||
* The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end`
|
* 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
|
* 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.
|
* `event`. `cancel` receives the raw `event` as its single parameter.
|
||||||
*
|
*
|
||||||
* `start` is called on either `mousedown` or `touchstart`. After this event, `$swipe` is
|
* `start` is called on either `mousedown`, `touchstart` or `pointerdown`. After this event, `$swipe` is
|
||||||
* watching for `touchmove` or `mousemove` events. These events are ignored until the total
|
* watching for `touchmove`, `mousemove` or `pointermove` events. These events are ignored until the total
|
||||||
* distance moved in either dimension exceeds a small threshold.
|
* distance moved in either dimension exceeds a small threshold.
|
||||||
*
|
*
|
||||||
* Once this threshold is exceeded, either the horizontal or vertical delta is greater.
|
* 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.
|
* - If the vertical distance is greater, this is a scroll, and we let the browser take over.
|
||||||
* A `cancel` event is sent.
|
* 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.
|
* 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.
|
* as described above.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -135,7 +242,7 @@ ngTouch.factory('$swipe', [function() {
|
|||||||
// Whether a swipe is active.
|
// Whether a swipe is active.
|
||||||
var active = false;
|
var active = false;
|
||||||
|
|
||||||
pointerTypes = pointerTypes || ['mouse', 'touch'];
|
pointerTypes = pointerTypes || ['mouse', 'touch', 'pointer'];
|
||||||
element.on(getEvents(pointerTypes, 'start'), function(event) {
|
element.on(getEvents(pointerTypes, 'start'), function(event) {
|
||||||
startCoords = getCoordinates(event);
|
startCoords = getCoordinates(event);
|
||||||
active = true;
|
active = true;
|
||||||
@ -202,8 +309,17 @@ ngTouch.factory('$swipe', [function() {
|
|||||||
/**
|
/**
|
||||||
* @ngdoc directive
|
* @ngdoc directive
|
||||||
* @name ngClick
|
* @name ngClick
|
||||||
|
* @deprecated
|
||||||
*
|
*
|
||||||
* @description
|
* @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
|
* 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
|
* 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
|
* the click event. This version handles them immediately, and then prevents the
|
||||||
@ -235,15 +351,7 @@ ngTouch.factory('$swipe', [function() {
|
|||||||
</example>
|
</example>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ngTouch.config(['$provide', function($provide) {
|
var ngTouchClickDirectiveFactory = ['$parse', '$timeout', '$rootElement',
|
||||||
$provide.decorator('ngClickDirective', ['$delegate', function($delegate) {
|
|
||||||
// drop the default ngClick directive
|
|
||||||
$delegate.shift();
|
|
||||||
return $delegate;
|
|
||||||
}]);
|
|
||||||
}]);
|
|
||||||
|
|
||||||
ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
|
|
||||||
function($parse, $timeout, $rootElement) {
|
function($parse, $timeout, $rootElement) {
|
||||||
var TAP_DURATION = 750; // Shorter than 750ms is a tap, longer is a taphold or drag.
|
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.
|
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 */
|
/* global ngTouch: false */
|
||||||
|
|
||||||
|
4065
xstatic/pkg/angular/data/angular.js
vendored
4065
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…
x
Reference in New Issue
Block a user