mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-01-13 08:59:54 +08:00
lots of small fixes
This commit is contained in:
223
angular-debug.js
vendored
223
angular-debug.js
vendored
@@ -62,6 +62,12 @@ function foreach(obj, iterator, context) {
|
||||
if (obj) {
|
||||
if (obj.forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (isFunction(obj)){
|
||||
for (key in obj) {
|
||||
if (key != 'prototype' && key != 'length' && key != 'name') {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
}
|
||||
} else if (isObject(obj) && isNumber(obj.length)) {
|
||||
for (key = 0; key < obj.length; key++)
|
||||
iterator.call(context, obj[key], key);
|
||||
@@ -137,7 +143,7 @@ function isElement(node) {
|
||||
|
||||
function isVisible(element) {
|
||||
var rect = element[0].getBoundingClientRect();
|
||||
return rect.width !=0 && rect.height !=0;
|
||||
return rect.width && rect.height;
|
||||
}
|
||||
|
||||
function map(obj, iterator, context) {
|
||||
@@ -771,7 +777,7 @@ function createScope(parent, services, existing) {
|
||||
function API(){}
|
||||
function Behavior(){}
|
||||
|
||||
var instance, behavior, api, evalLists = {}, servicesCache = extend({}, existing);
|
||||
var instance, behavior, api, evalLists = {sorted:[]}, servicesCache = extend({}, existing);
|
||||
|
||||
parent = Parent.prototype = (parent || {});
|
||||
api = API.prototype = new Parent();
|
||||
@@ -790,7 +796,7 @@ function createScope(parent, services, existing) {
|
||||
if (isDefined(exp)) {
|
||||
return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length));
|
||||
} else {
|
||||
foreachSorted(evalLists, function(list) {
|
||||
foreach(evalLists.sorted, function(list) {
|
||||
foreach(list, function(eval) {
|
||||
instance.$tryEval(eval.fn, eval.handler);
|
||||
});
|
||||
@@ -833,7 +839,13 @@ function createScope(parent, services, existing) {
|
||||
expr = priority;
|
||||
priority = 0;
|
||||
}
|
||||
var evalList = evalLists[priority] || (evalLists[priority] = []);
|
||||
var evalList = evalLists[priority];
|
||||
if (!evalList) {
|
||||
evalList = evalLists[priority] = [];
|
||||
evalList.priority = priority;
|
||||
evalLists.sorted.push(evalList);
|
||||
evalLists.sorted.sort(function(a,b){return a.priority-b.priority;});
|
||||
}
|
||||
evalList.push({
|
||||
fn: expressionCompile(expr),
|
||||
handler: exceptionHandler
|
||||
@@ -1820,10 +1832,11 @@ Browser.prototype = {
|
||||
|
||||
setUrl: function(url) {
|
||||
var existingURL = this.location.href;
|
||||
if (!existingURL.match(/#/))
|
||||
existingURL += '#';
|
||||
if (existingURL != url)
|
||||
this.location.href = url;
|
||||
if (!existingURL.match(/#/)) existingURL += '#';
|
||||
if (!url.match(/#/)) url += '#';
|
||||
if (existingURL != url) {
|
||||
this.location.href = this.expectedUrl = url;
|
||||
}
|
||||
},
|
||||
|
||||
getUrl: function() {
|
||||
@@ -2017,7 +2030,7 @@ JQLite.prototype = {
|
||||
} else if (isDefined(value)) {
|
||||
e.setAttribute(name, value);
|
||||
} else {
|
||||
return e.getAttribute(name);
|
||||
return e.getAttribute ? e.getAttribute(name) : undefined;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2790,33 +2803,52 @@ foreach({
|
||||
}
|
||||
},
|
||||
|
||||
'asynchronous': function(text, asynchronousFn) {
|
||||
var element = this['$element'];
|
||||
var cache = element.data('$validateState');
|
||||
/*
|
||||
* cache is attached to the element
|
||||
* cache: {
|
||||
* inputs : {
|
||||
* 'user input': {
|
||||
* response: server response,
|
||||
* error: validation error
|
||||
* },
|
||||
* current: 'current input'
|
||||
* }
|
||||
*
|
||||
*/
|
||||
'asynchronous': function(input, asynchronousFn, updateFn) {
|
||||
if (!input) return;
|
||||
var scope = this;
|
||||
var element = scope.$element;
|
||||
var cache = element.data('$asyncValidator');
|
||||
if (!cache) {
|
||||
cache = { state: {}};
|
||||
element.data('$validateState', cache);
|
||||
}
|
||||
var state = cache.state[text];
|
||||
cache.lastKey = text;
|
||||
if (state === undefined) {
|
||||
// we have never seen this before, Request it
|
||||
element.addClass('ng-input-indicator-wait');
|
||||
state = cache.state[text] = null;
|
||||
(asynchronousFn || noop)(text, function(error){
|
||||
state = cache.state[text] = error ? error : false;
|
||||
if (cache.state[cache.lastKey] !== null) {
|
||||
element.removeClass('ng-input-indicator-wait');
|
||||
}
|
||||
elementError(element, NG_VALIDATION_ERROR, error);
|
||||
});
|
||||
element.data('$asyncValidator', cache = {inputs:{}});
|
||||
}
|
||||
|
||||
if (state === null && this['$invalidWidgets']){
|
||||
cache.current = input;
|
||||
|
||||
var inputState = cache.inputs[input];
|
||||
if (!inputState) {
|
||||
cache.inputs[input] = inputState = { inFlight: true };
|
||||
scope.$invalidWidgets.markInvalid(scope.$element);
|
||||
element.addClass('ng-input-indicator-wait');
|
||||
asynchronousFn(input, function(error, data) {
|
||||
inputState.response = data;
|
||||
inputState.error = error;
|
||||
inputState.inFlight = false;
|
||||
if (cache.current == input) {
|
||||
element.removeClass('ng-input-indicator-wait');
|
||||
scope.$invalidWidgets.markValid(element);
|
||||
}
|
||||
element.data('$validate')(input);
|
||||
scope.$root.$eval();
|
||||
});
|
||||
} else if (inputState.inFlight) {
|
||||
// request in flight, mark widget invalid, but don't show it to user
|
||||
this['$invalidWidgets'].markInvalid(this.$element);
|
||||
scope.$invalidWidgets.markInvalid(scope.$element);
|
||||
} else {
|
||||
(updateFn||noop)(inputState.response);
|
||||
}
|
||||
return state;
|
||||
return inputState.error;
|
||||
}
|
||||
|
||||
}, function(v,k) {angularValidator[k] = v;});
|
||||
@@ -2924,8 +2956,13 @@ angularDirective("ng-bind-attr", function(expression){
|
||||
this.$onEval(function(){
|
||||
foreach(this.$eval(expression), function(bindExp, key) {
|
||||
var value = compileBindTemplate(bindExp).call(this, element);
|
||||
if (REMOVE_ATTRIBUTES[lowercase(key)] && !toBoolean(value)) {
|
||||
element.removeAttr('disabled');
|
||||
if (REMOVE_ATTRIBUTES[lowercase(key)]) {
|
||||
if (!toBoolean(value)) {
|
||||
element.removeAttr('disabled');
|
||||
} else {
|
||||
element.attr(key, value);
|
||||
}
|
||||
(element.data('$validate')||noop)();
|
||||
} else {
|
||||
element.attr(key, value);
|
||||
}
|
||||
@@ -3165,6 +3202,11 @@ function valueAccessor(scope, element) {
|
||||
required = required || required === '';
|
||||
if (!validator) throw "Validator named '" + validatorName + "' not found.";
|
||||
function validate(value) {
|
||||
if (element[0].disabled || isString(element.attr('readonly'))) {
|
||||
elementError(element, NG_VALIDATION_ERROR, null);
|
||||
invalidWidgets.markValid(element);
|
||||
return value;
|
||||
}
|
||||
var error,
|
||||
validateScope = extend(new (extend(function(){}, {prototype:scope}))(), {$element:element});
|
||||
error = required && !trim(value) ?
|
||||
@@ -3180,6 +3222,7 @@ function valueAccessor(scope, element) {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
element.data('$validate', validate);
|
||||
return {
|
||||
get: function(){ return validate(element.val()); },
|
||||
set: function(value){ element.val(validate(value)); }
|
||||
@@ -3305,20 +3348,31 @@ angularWidget('SELECT', function(element){
|
||||
|
||||
angularWidget('NG:INCLUDE', function(element){
|
||||
var compiler = this,
|
||||
src = element.attr("src");
|
||||
if (element.attr('switch-instance')) {
|
||||
srcExp = element.attr("src"),
|
||||
scopeExp = element.attr("scope") || '';
|
||||
if (element[0]['ng-compiled']) {
|
||||
this.descend(true);
|
||||
this.directives(true);
|
||||
} else {
|
||||
element[0]['ng-compiled'] = true;
|
||||
return function(element){
|
||||
var scope = this, childScope;
|
||||
element.attr('switch-instance', 'compiled');
|
||||
scope.$browser.xhr('GET', src, function(code, response){
|
||||
element.html(response);
|
||||
childScope = createScope(scope);
|
||||
compiler.compile(element)(element, childScope);
|
||||
childScope.$init();
|
||||
scope.$root.$eval();
|
||||
var changeCounter = 0;
|
||||
function incrementChange(){ changeCounter++;}
|
||||
this.$watch(srcExp, incrementChange);
|
||||
this.$watch(scopeExp, incrementChange);
|
||||
this.$watch(function(){return changeCounter;}, function(){
|
||||
var src = this.$eval(srcExp),
|
||||
useScope = this.$eval(scopeExp);
|
||||
if (src) {
|
||||
scope.$browser.xhr('GET', src, function(code, response){
|
||||
element.html(response);
|
||||
childScope = useScope || createScope(scope);
|
||||
compiler.compile(element)(element, childScope);
|
||||
childScope.$init();
|
||||
scope.$root.$eval();
|
||||
});
|
||||
}
|
||||
});
|
||||
scope.$onEval(function(){
|
||||
if (childScope) childScope.$eval();
|
||||
@@ -3405,12 +3459,13 @@ angularService("$document", function(window){
|
||||
return jqLite(window.document);
|
||||
}, {inject:['$window']});
|
||||
|
||||
var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.]*)(:([0-9]+))?([^\?#]+)(\?([^#]*))?((#([^\?]*))?(\?([^\?]*))?)$/;
|
||||
var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.]*)(:([0-9]+))?([^\?#]+)(\?([^#]*))?(#(.*))?$/;
|
||||
var HASH_MATCH = /^([^\?]*)?(\?([^\?]*))?$/;
|
||||
var DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21};
|
||||
angularService("$location", function(browser){
|
||||
var scope = this, location = {parse:parse, toString:toString};
|
||||
var lastHash;
|
||||
function parse(url){
|
||||
var scope = this, location = {parse:parseUrl, toString:toString};
|
||||
var lastHash, lastUrl;
|
||||
function parseUrl(url){
|
||||
if (isDefined(url)) {
|
||||
var match = URL_MATCH.exec(url);
|
||||
if (match) {
|
||||
@@ -3420,38 +3475,46 @@ angularService("$location", function(browser){
|
||||
location.port = match[5] || DEFAULT_PORTS[location.href] || null;
|
||||
location.path = match[6];
|
||||
location.search = parseKeyValue(match[8]);
|
||||
location.hash = match[9];
|
||||
location.hash = match[9] || '';
|
||||
if (location.hash)
|
||||
location.hash = location.hash.substr(1);
|
||||
lastHash = location.hash;
|
||||
location.hashPath = match[11] || '';
|
||||
location.hashSearch = parseKeyValue(match[13]);
|
||||
parseHash(location.hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
function parseHash(hash) {
|
||||
var match = HASH_MATCH.exec(hash);
|
||||
location.hashPath = match[1] || '';
|
||||
location.hashSearch = parseKeyValue(match[3]);
|
||||
lastHash = hash;
|
||||
}
|
||||
function toString() {
|
||||
if (lastHash === location.hash) {
|
||||
var hashKeyValue = toKeyValue(location.hashSearch),
|
||||
hash = (location.hashPath ? location.hashPath : '') + (hashKeyValue ? '?' + hashKeyValue : ''),
|
||||
url = location.href.split('#')[0] + '#' + (hash ? hash : '');
|
||||
if (url !== location.href) parse(url);
|
||||
if (url !== location.href) parseUrl(url);
|
||||
return url;
|
||||
} else {
|
||||
parse(location.href.split('#')[0] + '#' + location.hash);
|
||||
parseUrl(location.href.split('#')[0] + '#' + location.hash);
|
||||
return toString();
|
||||
}
|
||||
}
|
||||
browser.watchUrl(function(url){
|
||||
parse(url);
|
||||
parseUrl(url);
|
||||
scope.$root.$eval();
|
||||
});
|
||||
parse(browser.getUrl());
|
||||
var lastURL;
|
||||
parseUrl(browser.getUrl());
|
||||
this.$onEval(PRIORITY_FIRST, function(){
|
||||
if (location.hash != lastHash) {
|
||||
parseHash(location.hash);
|
||||
}
|
||||
});
|
||||
this.$onEval(PRIORITY_LAST, function(){
|
||||
var url = toString();
|
||||
if (lastURL != url) {
|
||||
if (lastUrl != url) {
|
||||
browser.setUrl(url);
|
||||
lastURL = url;
|
||||
lastUrl = url;
|
||||
}
|
||||
});
|
||||
return location;
|
||||
@@ -3539,6 +3602,51 @@ angularService("$invalidWidgets", function(){
|
||||
}
|
||||
return invalidWidgets;
|
||||
});
|
||||
|
||||
angularService('$route', function(location, params){
|
||||
var routes = {},
|
||||
onChange = [],
|
||||
matcher = angularWidget('NG:SWITCH').route,
|
||||
parentScope = this,
|
||||
$route = {
|
||||
routes: routes,
|
||||
onChange: bind(onChange, onChange.push),
|
||||
when:function (path, params){
|
||||
if (angular.isUndefined(path)) return routes;
|
||||
var route = routes[path];
|
||||
if (!route) route = routes[path] = {};
|
||||
if (params) angular.extend(route, params);
|
||||
if (matcher(location.hashPath, path)) updateRoute();
|
||||
return route;
|
||||
}
|
||||
};
|
||||
function updateRoute(){
|
||||
console.log('updating route');
|
||||
var childScope;
|
||||
$route.current = null;
|
||||
angular.foreach(routes, function(routeParams, route) {
|
||||
if (!childScope) {
|
||||
var pathParams = matcher(location.hashPath, route);
|
||||
if (pathParams) {
|
||||
console.log('new route', routeParams.template, location.hashPath, location.hash);
|
||||
childScope = angular.scope(parentScope);
|
||||
$route.current = angular.extend({}, routeParams, {
|
||||
scope: childScope,
|
||||
params: angular.extend({}, location.hashSearch, pathParams)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
angular.foreach(onChange, parentScope.$tryEval);
|
||||
if (childScope) {
|
||||
childScope.$become($route.current.controller);
|
||||
parentScope.$tryEval(childScope.init);
|
||||
}
|
||||
}
|
||||
this.$watch(function(){return location.hash;}, updateRoute);
|
||||
return $route;
|
||||
}, {inject: ['$location']});
|
||||
|
||||
var browserSingleton;
|
||||
angularService('$browser', function browserFactory(){
|
||||
if (!browserSingleton) {
|
||||
@@ -3557,6 +3665,7 @@ extend(angular, {
|
||||
'extend': extend,
|
||||
'foreach': foreach,
|
||||
'noop':noop,
|
||||
'bind':bind,
|
||||
'identity':identity,
|
||||
'isUndefined': isUndefined,
|
||||
'isDefined': isDefined,
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
<link rel="StyleSheet" type="text/css" href="../css/angular.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<input type="button" value="add" ng-action="add()"/>
|
||||
<input type="button" value="remove" ng-action="remove()"/>
|
||||
<input type="button" value="add" ng-click="add()"/>
|
||||
<input type="button" value="remove" ng-click="remove()"/>
|
||||
<div id="partial"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
<script type="text/javascript" src="../src/angular-bootstrap.js#autobind"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a href="#"> {{'first'}}<br/>{{'second'}}</a>
|
||||
<a href="#" ng-click="$window.location.hash='123'"> {{'first'}}<br/>{{'second'}}</a>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
[ Filter: <input type="text" name="userFilter"/>]
|
||||
<ul>
|
||||
<li ng-repeat="user in users.$filter(userFilter).$orderBy('screen_name')" ng-class-even="'even'" ng-class-odd="'odd'">
|
||||
<a href="" ng-action="$anchor.user=user.screen_name"><img src="{{user.profile_image_url}}"/></a>
|
||||
<a href="" ng-action="$anchor.user=user.screen_name">{{user.screen_name}}</a>
|
||||
<a href="" ng-click="$anchor.user=user.screen_name"><img src="{{user.profile_image_url}}"/></a>
|
||||
<a href="" ng-click="$anchor.user=user.screen_name">{{user.screen_name}}</a>
|
||||
as <span class="nickname">{{user.name}}</span>
|
||||
[ <a href="#" ng-action="$anchor.edituser=user.screen_name">edit</a>
|
||||
| <a href="#" ng-action="users.$remove(user)">X</a>
|
||||
| <a href="#" ng-action="mute[user.screen_name] = ! mute[user.screen_name]">mute</a>
|
||||
[ <a href="#" ng-click="$anchor.edituser=user.screen_name">edit</a>
|
||||
| <a href="#" ng-click="users.$remove(user)">X</a>
|
||||
| <a href="#" ng-click="mute[user.screen_name] = ! mute[user.screen_name]">mute</a>
|
||||
]
|
||||
<div class="notes">{{user.notes|linky}}</div>
|
||||
<div class="clrleft"></div>
|
||||
@@ -37,7 +37,7 @@
|
||||
<label>Notes:</label>
|
||||
<textarea type="text" name="user.notes"></textarea>
|
||||
|
||||
<input type="button" ng-action="$anchor.edituser=undefined" value="Close"/>
|
||||
<input type="button" ng-click="$anchor.edituser=undefined" value="Close"/>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
@@ -66,8 +66,8 @@ tweets={{tweets}}
|
||||
ng-class-even="'even'" ng-class-odd="'odd'"
|
||||
ng-eval="user = users.$find({: $.screen_name == tweet.user.screen_name}) || tweet.user">
|
||||
<img src="{{user.profile_image_url}}"/>
|
||||
[ <a href="" ng-action="$anchor.user=user.screen_name">{{user.nickname || user.name || user.screen_name }}</a>
|
||||
| <a href="" ng-action="users.$includeIf(user, true)">+</a>
|
||||
[ <a href="" ng-click="$anchor.user=user.screen_name">{{user.nickname || user.name || user.screen_name }}</a>
|
||||
| <a href="" ng-click="users.$includeIf(user, true)">+</a>
|
||||
]:
|
||||
{{tweet.text | linky}}
|
||||
<span class="notes">{{tweet.created_at}}</span>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<li Xng-repeat="tweet in tweets"
|
||||
ng-class-even="'even'" ng-class-odd="'odd'">
|
||||
<img src="{{tweet.user.profile_image_url}}"/>
|
||||
[ <a href="" Xng-action="$anchor.user=tweet.user.screen_name">{{tweet.user.nickname || tweet.user.name || tweet.user.screen_name }}</a>
|
||||
[ <a href="" Xng-click="$anchor.user=tweet.user.screen_name">{{tweet.user.nickname || tweet.user.name || tweet.user.screen_name }}</a>
|
||||
]:
|
||||
{{tweet.text}} (TODO: I want urls as links)
|
||||
<span class="notes">{{tweet.created_at}}</span>
|
||||
|
||||
@@ -38,6 +38,12 @@ function foreach(obj, iterator, context) {
|
||||
if (obj) {
|
||||
if (obj.forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (isFunction(obj)){
|
||||
for (key in obj) {
|
||||
if (key != 'prototype' && key != 'length' && key != 'name') {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
}
|
||||
} else if (isObject(obj) && isNumber(obj.length)) {
|
||||
for (key = 0; key < obj.length; key++)
|
||||
iterator.call(context, obj[key], key);
|
||||
@@ -113,7 +119,7 @@ function isElement(node) {
|
||||
|
||||
function isVisible(element) {
|
||||
var rect = element[0].getBoundingClientRect();
|
||||
return rect.width !=0 && rect.height !=0;
|
||||
return rect.width && rect.height;
|
||||
}
|
||||
|
||||
function map(obj, iterator, context) {
|
||||
|
||||
@@ -83,10 +83,11 @@ Browser.prototype = {
|
||||
|
||||
setUrl: function(url) {
|
||||
var existingURL = this.location.href;
|
||||
if (!existingURL.match(/#/))
|
||||
existingURL += '#';
|
||||
if (existingURL != url)
|
||||
this.location.href = url;
|
||||
if (!existingURL.match(/#/)) existingURL += '#';
|
||||
if (!url.match(/#/)) url += '#';
|
||||
if (existingURL != url) {
|
||||
this.location.href = this.expectedUrl = url;
|
||||
}
|
||||
},
|
||||
|
||||
getUrl: function() {
|
||||
|
||||
12
src/Scope.js
12
src/Scope.js
@@ -81,7 +81,7 @@ function createScope(parent, services, existing) {
|
||||
function API(){}
|
||||
function Behavior(){}
|
||||
|
||||
var instance, behavior, api, evalLists = {}, servicesCache = extend({}, existing);
|
||||
var instance, behavior, api, evalLists = {sorted:[]}, servicesCache = extend({}, existing);
|
||||
|
||||
parent = Parent.prototype = (parent || {});
|
||||
api = API.prototype = new Parent();
|
||||
@@ -100,7 +100,7 @@ function createScope(parent, services, existing) {
|
||||
if (isDefined(exp)) {
|
||||
return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length));
|
||||
} else {
|
||||
foreachSorted(evalLists, function(list) {
|
||||
foreach(evalLists.sorted, function(list) {
|
||||
foreach(list, function(eval) {
|
||||
instance.$tryEval(eval.fn, eval.handler);
|
||||
});
|
||||
@@ -143,7 +143,13 @@ function createScope(parent, services, existing) {
|
||||
expr = priority;
|
||||
priority = 0;
|
||||
}
|
||||
var evalList = evalLists[priority] || (evalLists[priority] = []);
|
||||
var evalList = evalLists[priority];
|
||||
if (!evalList) {
|
||||
evalList = evalLists[priority] = [];
|
||||
evalList.priority = priority;
|
||||
evalLists.sorted.push(evalList);
|
||||
evalLists.sorted.sort(function(a,b){return a.priority-b.priority;});
|
||||
}
|
||||
evalList.push({
|
||||
fn: expressionCompile(expr),
|
||||
handler: exceptionHandler
|
||||
|
||||
@@ -102,8 +102,13 @@ angularDirective("ng-bind-attr", function(expression){
|
||||
this.$onEval(function(){
|
||||
foreach(this.$eval(expression), function(bindExp, key) {
|
||||
var value = compileBindTemplate(bindExp).call(this, element);
|
||||
if (REMOVE_ATTRIBUTES[lowercase(key)] && !toBoolean(value)) {
|
||||
element.removeAttr('disabled');
|
||||
if (REMOVE_ATTRIBUTES[lowercase(key)]) {
|
||||
if (!toBoolean(value)) {
|
||||
element.removeAttr('disabled');
|
||||
} else {
|
||||
element.attr(key, value);
|
||||
}
|
||||
(element.data('$validate')||noop)();
|
||||
} else {
|
||||
element.attr(key, value);
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ JQLite.prototype = {
|
||||
} else if (isDefined(value)) {
|
||||
e.setAttribute(name, value);
|
||||
} else {
|
||||
return e.getAttribute(name);
|
||||
return e.getAttribute ? e.getAttribute(name) : undefined;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -3,12 +3,13 @@ angularService("$document", function(window){
|
||||
return jqLite(window.document);
|
||||
}, {inject:['$window']});
|
||||
|
||||
var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.]*)(:([0-9]+))?([^\?#]+)(\?([^#]*))?((#([^\?]*))?(\?([^\?]*))?)$/;
|
||||
var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.]*)(:([0-9]+))?([^\?#]+)(\?([^#]*))?(#(.*))?$/;
|
||||
var HASH_MATCH = /^([^\?]*)?(\?([^\?]*))?$/;
|
||||
var DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21};
|
||||
angularService("$location", function(browser){
|
||||
var scope = this, location = {parse:parse, toString:toString};
|
||||
var lastHash;
|
||||
function parse(url){
|
||||
var scope = this, location = {parse:parseUrl, toString:toString};
|
||||
var lastHash, lastUrl;
|
||||
function parseUrl(url){
|
||||
if (isDefined(url)) {
|
||||
var match = URL_MATCH.exec(url);
|
||||
if (match) {
|
||||
@@ -18,38 +19,46 @@ angularService("$location", function(browser){
|
||||
location.port = match[5] || DEFAULT_PORTS[location.href] || null;
|
||||
location.path = match[6];
|
||||
location.search = parseKeyValue(match[8]);
|
||||
location.hash = match[9];
|
||||
location.hash = match[9] || '';
|
||||
if (location.hash)
|
||||
location.hash = location.hash.substr(1);
|
||||
lastHash = location.hash;
|
||||
location.hashPath = match[11] || '';
|
||||
location.hashSearch = parseKeyValue(match[13]);
|
||||
parseHash(location.hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
function parseHash(hash) {
|
||||
var match = HASH_MATCH.exec(hash);
|
||||
location.hashPath = match[1] || '';
|
||||
location.hashSearch = parseKeyValue(match[3]);
|
||||
lastHash = hash;
|
||||
}
|
||||
function toString() {
|
||||
if (lastHash === location.hash) {
|
||||
var hashKeyValue = toKeyValue(location.hashSearch),
|
||||
hash = (location.hashPath ? location.hashPath : '') + (hashKeyValue ? '?' + hashKeyValue : ''),
|
||||
url = location.href.split('#')[0] + '#' + (hash ? hash : '');
|
||||
if (url !== location.href) parse(url);
|
||||
if (url !== location.href) parseUrl(url);
|
||||
return url;
|
||||
} else {
|
||||
parse(location.href.split('#')[0] + '#' + location.hash);
|
||||
parseUrl(location.href.split('#')[0] + '#' + location.hash);
|
||||
return toString();
|
||||
}
|
||||
}
|
||||
browser.watchUrl(function(url){
|
||||
parse(url);
|
||||
parseUrl(url);
|
||||
scope.$root.$eval();
|
||||
});
|
||||
parse(browser.getUrl());
|
||||
var lastURL;
|
||||
parseUrl(browser.getUrl());
|
||||
this.$onEval(PRIORITY_FIRST, function(){
|
||||
if (location.hash != lastHash) {
|
||||
parseHash(location.hash);
|
||||
}
|
||||
});
|
||||
this.$onEval(PRIORITY_LAST, function(){
|
||||
var url = toString();
|
||||
if (lastURL != url) {
|
||||
if (lastUrl != url) {
|
||||
browser.setUrl(url);
|
||||
lastURL = url;
|
||||
lastUrl = url;
|
||||
}
|
||||
});
|
||||
return location;
|
||||
@@ -142,6 +151,7 @@ angularService('$route', function(location, params){
|
||||
var routes = {},
|
||||
onChange = [],
|
||||
matcher = angularWidget('NG:SWITCH').route,
|
||||
parentScope = this,
|
||||
$route = {
|
||||
routes: routes,
|
||||
onChange: bind(onChange, onChange.push),
|
||||
@@ -150,16 +160,19 @@ angularService('$route', function(location, params){
|
||||
var route = routes[path];
|
||||
if (!route) route = routes[path] = {};
|
||||
if (params) angular.extend(route, params);
|
||||
if (matcher(location.hashPath, path)) updateRoute();
|
||||
return route;
|
||||
}
|
||||
};
|
||||
this.$watch(function(){return location.hash;}, function(hash){
|
||||
var parentScope = this, childScope;
|
||||
function updateRoute(){
|
||||
console.log('updating route');
|
||||
var childScope;
|
||||
$route.current = null;
|
||||
angular.foreach(routes, function(routeParams, route) {
|
||||
if (!childScope) {
|
||||
var pathParams = matcher(location.hashPath, route);
|
||||
if (pathParams) {
|
||||
console.log('new route', routeParams.template, location.hashPath, location.hash);
|
||||
childScope = angular.scope(parentScope);
|
||||
$route.current = angular.extend({}, routeParams, {
|
||||
scope: childScope,
|
||||
@@ -173,7 +186,8 @@ angularService('$route', function(location, params){
|
||||
childScope.$become($route.current.controller);
|
||||
parentScope.$tryEval(childScope.init);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.$watch(function(){return location.hash;}, updateRoute);
|
||||
return $route;
|
||||
}, {inject: ['$location']});
|
||||
|
||||
|
||||
@@ -81,33 +81,52 @@ foreach({
|
||||
}
|
||||
},
|
||||
|
||||
'asynchronous': function(text, asynchronousFn) {
|
||||
var element = this['$element'];
|
||||
var cache = element.data('$validateState');
|
||||
/*
|
||||
* cache is attached to the element
|
||||
* cache: {
|
||||
* inputs : {
|
||||
* 'user input': {
|
||||
* response: server response,
|
||||
* error: validation error
|
||||
* },
|
||||
* current: 'current input'
|
||||
* }
|
||||
*
|
||||
*/
|
||||
'asynchronous': function(input, asynchronousFn, updateFn) {
|
||||
if (!input) return;
|
||||
var scope = this;
|
||||
var element = scope.$element;
|
||||
var cache = element.data('$asyncValidator');
|
||||
if (!cache) {
|
||||
cache = { state: {}};
|
||||
element.data('$validateState', cache);
|
||||
}
|
||||
var state = cache.state[text];
|
||||
cache.lastKey = text;
|
||||
if (state === undefined) {
|
||||
// we have never seen this before, Request it
|
||||
element.addClass('ng-input-indicator-wait');
|
||||
state = cache.state[text] = null;
|
||||
(asynchronousFn || noop)(text, function(error){
|
||||
state = cache.state[text] = error ? error : false;
|
||||
if (cache.state[cache.lastKey] !== null) {
|
||||
element.removeClass('ng-input-indicator-wait');
|
||||
}
|
||||
elementError(element, NG_VALIDATION_ERROR, error);
|
||||
});
|
||||
element.data('$asyncValidator', cache = {inputs:{}});
|
||||
}
|
||||
|
||||
if (state === null && this['$invalidWidgets']){
|
||||
cache.current = input;
|
||||
|
||||
var inputState = cache.inputs[input];
|
||||
if (!inputState) {
|
||||
cache.inputs[input] = inputState = { inFlight: true };
|
||||
scope.$invalidWidgets.markInvalid(scope.$element);
|
||||
element.addClass('ng-input-indicator-wait');
|
||||
asynchronousFn(input, function(error, data) {
|
||||
inputState.response = data;
|
||||
inputState.error = error;
|
||||
inputState.inFlight = false;
|
||||
if (cache.current == input) {
|
||||
element.removeClass('ng-input-indicator-wait');
|
||||
scope.$invalidWidgets.markValid(element);
|
||||
}
|
||||
element.data('$validate')(input);
|
||||
scope.$root.$eval();
|
||||
});
|
||||
} else if (inputState.inFlight) {
|
||||
// request in flight, mark widget invalid, but don't show it to user
|
||||
this['$invalidWidgets'].markInvalid(this.$element);
|
||||
scope.$invalidWidgets.markInvalid(scope.$element);
|
||||
} else {
|
||||
(updateFn||noop)(inputState.response);
|
||||
}
|
||||
return state;
|
||||
return inputState.error;
|
||||
}
|
||||
|
||||
}, function(v,k) {angularValidator[k] = v;});
|
||||
|
||||
@@ -27,6 +27,11 @@ function valueAccessor(scope, element) {
|
||||
required = required || required === '';
|
||||
if (!validator) throw "Validator named '" + validatorName + "' not found.";
|
||||
function validate(value) {
|
||||
if (element[0].disabled || isString(element.attr('readonly'))) {
|
||||
elementError(element, NG_VALIDATION_ERROR, null);
|
||||
invalidWidgets.markValid(element);
|
||||
return value;
|
||||
}
|
||||
var error,
|
||||
validateScope = extend(new (extend(function(){}, {prototype:scope}))(), {$element:element});
|
||||
error = required && !trim(value) ?
|
||||
@@ -42,6 +47,7 @@ function valueAccessor(scope, element) {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
element.data('$validate', validate);
|
||||
return {
|
||||
get: function(){ return validate(element.val()); },
|
||||
set: function(value){ element.val(validate(value)); }
|
||||
@@ -167,20 +173,31 @@ angularWidget('SELECT', function(element){
|
||||
|
||||
angularWidget('NG:INCLUDE', function(element){
|
||||
var compiler = this,
|
||||
src = element.attr("src");
|
||||
if (element.attr('switch-instance')) {
|
||||
srcExp = element.attr("src"),
|
||||
scopeExp = element.attr("scope") || '';
|
||||
if (element[0]['ng-compiled']) {
|
||||
this.descend(true);
|
||||
this.directives(true);
|
||||
} else {
|
||||
element[0]['ng-compiled'] = true;
|
||||
return function(element){
|
||||
var scope = this, childScope;
|
||||
element.attr('switch-instance', 'compiled');
|
||||
scope.$browser.xhr('GET', src, function(code, response){
|
||||
element.html(response);
|
||||
childScope = createScope(scope);
|
||||
compiler.compile(element)(element, childScope);
|
||||
childScope.$init();
|
||||
scope.$root.$eval();
|
||||
var changeCounter = 0;
|
||||
function incrementChange(){ changeCounter++;}
|
||||
this.$watch(srcExp, incrementChange);
|
||||
this.$watch(scopeExp, incrementChange);
|
||||
this.$watch(function(){return changeCounter;}, function(){
|
||||
var src = this.$eval(srcExp),
|
||||
useScope = this.$eval(scopeExp);
|
||||
if (src) {
|
||||
scope.$browser.xhr('GET', src, function(code, response){
|
||||
element.html(response);
|
||||
childScope = useScope || createScope(scope);
|
||||
compiler.compile(element)(element, childScope);
|
||||
childScope.$init();
|
||||
scope.$root.$eval();
|
||||
});
|
||||
}
|
||||
});
|
||||
scope.$onEval(function(){
|
||||
if (childScope) childScope.$eval();
|
||||
|
||||
@@ -88,17 +88,16 @@ describe('Validator:asynchronous', function(){
|
||||
var value, fn;
|
||||
|
||||
beforeEach(function(){
|
||||
var invalidWidgets = [];
|
||||
invalidWidgets.markInvalid = function(element){
|
||||
invalidWidgets.push(element);
|
||||
};
|
||||
var invalidWidgets = angularService('$invalidWidgets')();
|
||||
value = null;
|
||||
fn = null;
|
||||
self = {
|
||||
$element:jqLite('<input />'),
|
||||
$invalidWidgets:invalidWidgets,
|
||||
$updateView: noop
|
||||
$eval: noop
|
||||
};
|
||||
self.$element.data('$validate', noop);
|
||||
self.$root = self;
|
||||
});
|
||||
|
||||
afterEach(function(){
|
||||
@@ -122,14 +121,14 @@ describe('Validator:asynchronous', function(){
|
||||
expect(input.hasClass('ng-input-indicator-wait')).toBeTruthy();
|
||||
fn("myError");
|
||||
expect(input.hasClass('ng-input-indicator-wait')).toBeFalsy();
|
||||
expect(input.attr('ng-validation-error')).toEqual("myError");
|
||||
expect(input.attr(NG_VALIDATION_ERROR)).toEqual("myError");
|
||||
scope.$element.remove();
|
||||
});
|
||||
|
||||
it("should not make second request to same value", function(){
|
||||
asynchronous.call(self, "kai", function(v,f){value=v; fn=f;});
|
||||
expect(value).toEqual('kai');
|
||||
expect(self.$invalidWidgets[0][0]).toEqual(self.$element[0]);
|
||||
expect(self.$invalidWidgets[0]).toEqual(self.$element);
|
||||
|
||||
var spy = jasmine.createSpy();
|
||||
asynchronous.call(self, "kai", spy);
|
||||
@@ -145,9 +144,26 @@ describe('Validator:asynchronous', function(){
|
||||
asynchronous.call(self, "second", function(v,f){value=v; secondCb=f;});
|
||||
|
||||
firstCb();
|
||||
expect(jqLite(self.$element).hasClass('ng-input-indicator-wait')).toBeTruthy();
|
||||
expect(self.$element.hasClass('ng-input-indicator-wait')).toBeTruthy();
|
||||
|
||||
secondCb();
|
||||
expect(jqLite(self.$element).hasClass('ng-input-indicator-wait')).toBeFalsy();
|
||||
expect(self.$element.hasClass('ng-input-indicator-wait')).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should handle update function", function(){
|
||||
var scope = angular.compile('<input name="name" ng-validate="asynchronous:asyncFn:updateFn"/>');
|
||||
scope.asyncFn = jasmine.createSpy();
|
||||
scope.updateFn = jasmine.createSpy();
|
||||
scope.name = 'misko';
|
||||
scope.$init();
|
||||
scope.$eval();
|
||||
expect(scope.asyncFn).wasCalledWith('misko', scope.asyncFn.mostRecentCall.args[1]);
|
||||
assertTrue(scope.$element.hasClass('ng-input-indicator-wait'));
|
||||
scope.asyncFn.mostRecentCall.args[1]('myError', {id: 1234, data:'data'});
|
||||
assertFalse(scope.$element.hasClass('ng-input-indicator-wait'));
|
||||
assertEquals('myError', scope.$element.attr('ng-validation-error'));
|
||||
expect(scope.updateFn.mostRecentCall.args[0]).toEqual({id: 1234, data:'data'});
|
||||
scope.$element.remove();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -57,6 +57,22 @@ describe("directives", function(){
|
||||
expect(element.attr('alt')).toEqual('myalt');
|
||||
});
|
||||
|
||||
it('should remove special attributes on false', function(){
|
||||
var scope = compile('<div disabled="{{disabled}}" readonly="{{readonly}}" checked="{{checked}}"/>');
|
||||
expect(scope.$element.attr('disabled')).toEqual(null);
|
||||
expect(scope.$element.attr('readonly')).toEqual(null);
|
||||
expect(scope.$element.attr('checked')).toEqual(null);
|
||||
|
||||
scope.disabled = true;
|
||||
scope.readonly = true;
|
||||
scope.checked = true;
|
||||
scope.$eval();
|
||||
|
||||
expect(scope.$element.attr('disabled')).not.toEqual(null);
|
||||
expect(scope.$element.attr('readonly')).not.toEqual(null);
|
||||
expect(scope.$element.attr('checked')).not.toEqual(null);
|
||||
});
|
||||
|
||||
it('should ng-non-bindable', function(){
|
||||
var scope = compile('<div ng-non-bindable><span ng-bind="name"></span></div>');
|
||||
scope.$set('name', 'misko');
|
||||
|
||||
@@ -9,53 +9,6 @@ describe("services", function(){
|
||||
expect(scope.$window).toEqual(window);
|
||||
});
|
||||
|
||||
it("should inject $location", function(){
|
||||
scope.$location.parse('http://host:123/p/a/t/h.html?query=value#path?key=value');
|
||||
expect(scope.$location.href).toEqual("http://host:123/p/a/t/h.html?query=value#path?key=value");
|
||||
expect(scope.$location.protocol).toEqual("http");
|
||||
expect(scope.$location.host).toEqual("host");
|
||||
expect(scope.$location.port).toEqual("123");
|
||||
expect(scope.$location.path).toEqual("/p/a/t/h.html");
|
||||
expect(scope.$location.search).toEqual({query:'value'});
|
||||
expect(scope.$location.hash).toEqual('path?key=value');
|
||||
expect(scope.$location.hashPath).toEqual('path');
|
||||
expect(scope.$location.hashSearch).toEqual({key:'value'});
|
||||
|
||||
scope.$location.hashPath = 'page=http://path';
|
||||
scope.$location.hashSearch = {k:'a=b'};
|
||||
|
||||
expect(scope.$location.toString()).toEqual('http://host:123/p/a/t/h.html?query=value#page=http://path?k=a%3Db');
|
||||
});
|
||||
|
||||
it('should parse file://', function(){
|
||||
scope.$location.parse('file:///Users/Shared/misko/work/angular.js/scenario/widgets.html');
|
||||
expect(scope.$location.href).toEqual("file:///Users/Shared/misko/work/angular.js/scenario/widgets.html");
|
||||
expect(scope.$location.protocol).toEqual("file");
|
||||
expect(scope.$location.host).toEqual("");
|
||||
expect(scope.$location.port).toEqual(null);
|
||||
expect(scope.$location.path).toEqual("/Users/Shared/misko/work/angular.js/scenario/widgets.html");
|
||||
expect(scope.$location.search).toEqual({});
|
||||
expect(scope.$location.hash).toEqual('');
|
||||
expect(scope.$location.hashPath).toEqual('');
|
||||
expect(scope.$location.hashSearch).toEqual({});
|
||||
|
||||
expect(scope.$location.toString()).toEqual('file:///Users/Shared/misko/work/angular.js/scenario/widgets.html#');
|
||||
});
|
||||
|
||||
it('should update url on hash change', function(){
|
||||
scope.$location.parse('http://server/#path?a=b');
|
||||
scope.$location.hash = '';
|
||||
expect(scope.$location.toString()).toEqual('http://server/#');
|
||||
expect(scope.$location.hashPath).toEqual('');
|
||||
});
|
||||
|
||||
it('should update url on hashPath change', function(){
|
||||
scope.$location.parse('http://server/#path?a=b');
|
||||
scope.$location.hashPath = '';
|
||||
expect(scope.$location.toString()).toEqual('http://server/#?a=b');
|
||||
expect(scope.$location.hash).toEqual('?a=b');
|
||||
});
|
||||
|
||||
xit('should add stylesheets', function(){
|
||||
scope.$document = {
|
||||
getElementsByTagName: function(name){
|
||||
@@ -64,9 +17,71 @@ describe("services", function(){
|
||||
}
|
||||
};
|
||||
scope.$document.addStyleSheet('css/angular.css');
|
||||
|
||||
});
|
||||
|
||||
describe("$location", function(){
|
||||
it("should inject $location", function(){
|
||||
scope.$location.parse('http://host:123/p/a/t/h.html?query=value#path?key=value');
|
||||
expect(scope.$location.href).toEqual("http://host:123/p/a/t/h.html?query=value#path?key=value");
|
||||
expect(scope.$location.protocol).toEqual("http");
|
||||
expect(scope.$location.host).toEqual("host");
|
||||
expect(scope.$location.port).toEqual("123");
|
||||
expect(scope.$location.path).toEqual("/p/a/t/h.html");
|
||||
expect(scope.$location.search).toEqual({query:'value'});
|
||||
expect(scope.$location.hash).toEqual('path?key=value');
|
||||
expect(scope.$location.hashPath).toEqual('path');
|
||||
expect(scope.$location.hashSearch).toEqual({key:'value'});
|
||||
|
||||
scope.$location.hashPath = 'page=http://path';
|
||||
scope.$location.hashSearch = {k:'a=b'};
|
||||
|
||||
expect(scope.$location.toString()).toEqual('http://host:123/p/a/t/h.html?query=value#page=http://path?k=a%3Db');
|
||||
});
|
||||
|
||||
it('should parse file://', function(){
|
||||
scope.$location.parse('file:///Users/Shared/misko/work/angular.js/scenario/widgets.html');
|
||||
expect(scope.$location.href).toEqual("file:///Users/Shared/misko/work/angular.js/scenario/widgets.html");
|
||||
expect(scope.$location.protocol).toEqual("file");
|
||||
expect(scope.$location.host).toEqual("");
|
||||
expect(scope.$location.port).toEqual(null);
|
||||
expect(scope.$location.path).toEqual("/Users/Shared/misko/work/angular.js/scenario/widgets.html");
|
||||
expect(scope.$location.search).toEqual({});
|
||||
expect(scope.$location.hash).toEqual('');
|
||||
expect(scope.$location.hashPath).toEqual('');
|
||||
expect(scope.$location.hashSearch).toEqual({});
|
||||
|
||||
expect(scope.$location.toString()).toEqual('file:///Users/Shared/misko/work/angular.js/scenario/widgets.html#');
|
||||
});
|
||||
|
||||
it('should update url on hash change', function(){
|
||||
scope.$location.parse('http://server/#path?a=b');
|
||||
scope.$location.hash = '';
|
||||
expect(scope.$location.toString()).toEqual('http://server/#');
|
||||
expect(scope.$location.hashPath).toEqual('');
|
||||
});
|
||||
|
||||
it('should update url on hashPath change', function(){
|
||||
scope.$location.parse('http://server/#path?a=b');
|
||||
scope.$location.hashPath = '';
|
||||
expect(scope.$location.toString()).toEqual('http://server/#?a=b');
|
||||
expect(scope.$location.hash).toEqual('?a=b');
|
||||
});
|
||||
|
||||
it('should update hash before any processing', function(){
|
||||
var scope = compile('<div>');
|
||||
var log = '';
|
||||
scope.$watch('$location.hash', function(){
|
||||
log += this.$location.hashPath + ';';
|
||||
});
|
||||
expect(log).toEqual(';');
|
||||
|
||||
log = '';
|
||||
scope.$location.hash = '/abc';
|
||||
scope.$eval();
|
||||
expect(log).toEqual('/abc;');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe("service $invalidWidgets", function(){
|
||||
@@ -135,5 +150,7 @@ describe("service $route", function(){
|
||||
expect(log).toEqual('onChange();');
|
||||
expect(scope.$route.current).toEqual(null);
|
||||
|
||||
scope.$route.when('/NONE', {template:'instant update'});
|
||||
expect(scope.$route.current.template).toEqual('instant update');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,6 +76,18 @@ describe("input widget", function(){
|
||||
expect(element.attr('ng-validation-error')).toEqual('Not a number');
|
||||
});
|
||||
|
||||
it("should ignore disabled widgets", function(){
|
||||
compile('<input type="text" name="price" ng-required disabled/>');
|
||||
expect(element.hasClass('ng-validation-error')).toBeFalsy();
|
||||
expect(element.attr('ng-validation-error')).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should ignore readonly widgets", function(){
|
||||
compile('<input type="text" name="price" ng-required readonly/>');
|
||||
expect(element.hasClass('ng-validation-error')).toBeFalsy();
|
||||
expect(element.attr('ng-validation-error')).toBeFalsy();
|
||||
});
|
||||
|
||||
it("should process ng-required", function(){
|
||||
compile('<input type="text" name="price" ng-required/>');
|
||||
expect(element.hasClass('ng-validation-error')).toBeTruthy();
|
||||
@@ -244,13 +256,15 @@ describe('ng:switch', function(){
|
||||
|
||||
describe('ng:include', function(){
|
||||
it('should include on external file', function() {
|
||||
var element = jqLite('<ng:include src="myUrl"></ng:include>');
|
||||
var element = jqLite('<ng:include src="url" scope="childScope"></ng:include>');
|
||||
var scope = compile(element);
|
||||
scope.$browser.xhr.expect('GET', 'myUrl').respond('{{1+2}}');
|
||||
scope.childScope = createScope();
|
||||
scope.childScope.name = 'misko';
|
||||
scope.url = 'myUrl';
|
||||
scope.$browser.xhr.expect('GET', 'myUrl').respond('{{name}}');
|
||||
scope.$init();
|
||||
expect(sortedHtml(element)).toEqual('<ng:include src="myUrl" switch-instance="compiled"></ng:include>');
|
||||
scope.$browser.xhr.flush();
|
||||
expect(element.text()).toEqual('3');
|
||||
expect(element.text()).toEqual('misko');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user