aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Angular.js54
-rw-r--r--src/AngularPublic.js1
-rw-r--r--src/Browser.js54
-rw-r--r--src/Compiler.js2
-rw-r--r--src/JSON.js28
-rw-r--r--src/Parser.js345
-rw-r--r--src/Resource.js2
-rw-r--r--src/Scope.js42
-rw-r--r--src/apis.js44
-rw-r--r--src/directives.js18
-rw-r--r--src/filters.js2
-rw-r--r--src/formatters.js11
-rw-r--r--src/jqLite.js8
-rw-r--r--src/markups.js6
-rw-r--r--src/scenario/DSL.js4
-rw-r--r--src/scenario/Future.js2
-rw-r--r--src/scenario/Runner.js10
-rw-r--r--src/services.js90
-rw-r--r--src/validators.js26
-rw-r--r--src/widgets.js16
-rw-r--r--test/ApiTest.js2
-rw-r--r--test/BrowserSpecs.js210
-rw-r--r--test/ParserTest.js63
-rw-r--r--test/ResourceSpec.js12
-rw-r--r--test/angular-mocks.js20
-rw-r--r--test/scenario/DSLSpec.js24
-rw-r--r--test/scenario/RunnerSpec.js4
-rw-r--r--test/servicesSpec.js111
-rw-r--r--test/testabilityPatch.js17
-rw-r--r--test/widgetsSpec.js38
30 files changed, 797 insertions, 469 deletions
diff --git a/src/Angular.js b/src/Angular.js
index 3970f762..1c75a063 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -1,23 +1,42 @@
////////////////////////////////////
-if (typeof document.getAttribute == 'undefined')
+if (typeof document.getAttribute == $undefined)
document.getAttribute = function() {};
-var consoleNode,
+var _undefined = undefined,
+ _null = null,
+ $$element = '$element',
+ $angular = 'angular',
+ $array = 'array',
+ $boolean = 'boolean',
+ $console = 'console',
+ $date = 'date',
+ $display = 'display',
+ $element = 'element',
+ $function = 'function',
+ $length = 'length',
+ $name = 'name',
+ $none = 'none',
+ $noop = 'noop',
+ $null = 'null',
+ $number = 'number',
+ $object = 'object',
+ $string = 'string',
+ $undefined = 'undefined',
+ NG_EXCEPTION = 'ng-exception',
+ NG_VALIDATION_ERROR = 'ng-validation-error',
+ NOOP = 'noop',
PRIORITY_FIRST = -99999,
PRIORITY_WATCH = -1000,
PRIORITY_LAST = 99999,
PRIORITY = {'FIRST': PRIORITY_FIRST, 'LAST': PRIORITY_LAST, 'WATCH':PRIORITY_WATCH},
- NOOP = 'noop',
- NG_EXCEPTION = 'ng-exception',
- NG_VALIDATION_ERROR = 'ng-validation-error',
jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy
_ = window['_'],
msie = !!/(msie) ([\w.]+)/.exec(lowercase(navigator.userAgent)),
jqLite = jQuery || jqLiteWrap,
slice = Array.prototype.slice,
- error = window['console'] ? bind(window['console'], window['console']['error'] || noop) : noop,
- angular = window['angular'] || (window['angular'] = {}),
+ error = window[$console] ? bind(window[$console], window[$console]['error'] || noop) : noop,
+ angular = window[$angular] || (window[$angular] = {}),
angularTextMarkup = extensionMap(angular, 'markup'),
angularAttrMarkup = extensionMap(angular, 'attrMarkup'),
angularDirective = extensionMap(angular, 'directive'),
@@ -34,7 +53,7 @@ function foreach(obj, iterator, context) {
if (obj) {
if (isFunction(obj)){
for (key in obj) {
- if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
+ if (key != 'prototype' && key != $length && key != $name && obj.hasOwnProperty(key)) {
iterator.call(context, obj[key], key);
}
}
@@ -75,7 +94,7 @@ function extend(dst) {
function inherit(parent, extra) {
return extend(new (extend(function(){}, {prototype:parent}))(), extra);
-};
+}
function noop() {}
function identity($) {return $;}
@@ -91,7 +110,7 @@ function extensionMap(angular, name, transform) {
}
function jqLiteWrap(element) {
- // for some reasons the parentNode of an orphan looks like null but its typeof is object.
+ // for some reasons the parentNode of an orphan looks like _null but its typeof is object.
if (element) {
if (isString(element)) {
var div = document.createElement('div');
@@ -103,13 +122,13 @@ function jqLiteWrap(element) {
}
return element;
}
-function isUndefined(value){ return typeof value == 'undefined'; }
-function isDefined(value){ return typeof value != 'undefined'; }
-function isObject(value){ return typeof value == 'object';}
+function isUndefined(value){ return typeof value == $undefined; }
+function isDefined(value){ return typeof value != $undefined; }
+function isObject(value){ return value!=_null && typeof value == 'object';}
function isString(value){ return typeof value == 'string';}
function isNumber(value){ return typeof value == 'number';}
function isArray(value) { return value instanceof Array; }
-function isFunction(value){ return typeof value == 'function';}
+function isFunction(value){ return typeof value == $function;}
function isTextNode(node) { return nodeName(node) == '#text'; }
function lowercase(value){ return isString(value) ? value.toLowerCase() : value; }
function uppercase(value){ return isString(value) ? value.toUpperCase() : value; }
@@ -293,7 +312,7 @@ function escapeAttr(html) {
function bind(self, fn) {
var curryArgs = arguments.length > 2 ? slice.call(arguments, 2, arguments.length) : [];
- if (typeof fn == 'function') {
+ if (typeof fn == $function) {
return curryArgs.length ? function() {
return arguments.length ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0, arguments.length))) : fn.apply(self, curryArgs);
}: function() {
@@ -319,7 +338,7 @@ function merge(src, dst) {
for ( var key in src) {
var value = dst[key];
var type = typeof value;
- if (type == 'undefined') {
+ if (type == $undefined) {
dst[key] = fromJson(toJson(src[key]));
} else if (type == 'object' && value.constructor != array &&
key.substring(0, 1) != "$") {
@@ -331,7 +350,6 @@ function merge(src, dst) {
function compile(element, existingScope) {
var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget),
$element = jqLite(element);
- parent.$element = $element;
return compiler.compile($element)($element, existingScope);
}
/////////////////////////////////////////////////
@@ -359,7 +377,7 @@ function toKeyValue(obj) {
function angularInit(config){
if (config.autobind) {
// TODO default to the source of angular.js
- var scope = compile(window.document, null, {'$config':config});
+ var scope = compile(window.document, _null, {'$config':config});
if (config.css)
scope.$browser.addCss(config.base_url + config.css);
scope.$init();
diff --git a/src/AngularPublic.js b/src/AngularPublic.js
index 7b093f88..e9f20b59 100644
--- a/src/AngularPublic.js
+++ b/src/AngularPublic.js
@@ -6,6 +6,7 @@ angularService('$browser', function browserFactory(){
jqLite(window.document),
jqLite(window.document.getElementsByTagName('head')[0]));
browserSingleton.startUrlWatcher();
+ browserSingleton.startCookieWatcher();
browserSingleton.bind();
}
return browserSingleton;
diff --git a/src/Browser.js b/src/Browser.js
index b4314e2c..0dacf3c4 100644
--- a/src/Browser.js
+++ b/src/Browser.js
@@ -22,8 +22,50 @@ function Browser(location, document, head) {
this.location = location;
this.document = document;
+ var rawDocument = document[0];
this.head = head;
this.idCounter = 0;
+
+ this.cookies = cookies;
+ this.watchCookies = function(fn){ cookieListeners.push(fn); };
+
+ // functions
+ var lastCookies = {};
+ var lastCookieString = '';
+ var cookieListeners = [];
+ /**
+ * cookies() -> hash of all cookies
+ * cookies(name, value) -> set name to value
+ * if value is undefined delete it
+ * cookies(name) -> should get value, but deletes (no one calls it right now that way)
+ */
+ function cookies(name, value){
+ if (name) {
+ if (value === _undefined) {
+ delete lastCookies[name];
+ rawDocument.cookie = escape(name) + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ } else {
+ rawDocument.cookie = escape(name) + '=' + escape(lastCookies[name] = ''+value);
+ }
+ } else {
+ if (rawDocument.cookie !== lastCookieString) {
+ lastCookieString = rawDocument.cookie;
+ var cookieArray = lastCookieString.split("; ");
+ lastCookies = {};
+
+ for (var i = 0; i < cookieArray.length; i++) {
+ var keyValue = cookieArray[i].split("=");
+ if (keyValue.length === 2) { //ignore nameless cookies
+ lastCookies[unescape(keyValue[0])] = unescape(keyValue[1]);
+ }
+ }
+ foreach(cookieListeners, function(fn){
+ fn(lastCookies);
+ });
+ }
+ return lastCookies;
+ }
+ }
}
Browser.prototype = {
@@ -57,7 +99,7 @@ Browser.prototype = {
xhr: function(method, url, post, callback){
if (isFunction(post)) {
callback = post;
- post = null;
+ post = _null;
}
if (lowercase(method) == 'json') {
var callbackId = "angular_" + Math.random() + '_' + (this.idCounter++);
@@ -67,7 +109,7 @@ Browser.prototype = {
script.src = url.replace('JSON_CALLBACK', callbackId);
this.head.append(script);
window[callbackId] = function(data){
- window[callbackId] = undefined;
+ window[callbackId] = _undefined;
callback(200, data);
};
} else {
@@ -132,6 +174,14 @@ Browser.prototype = {
})();
},
+ startCookieWatcher: function() {
+ var self = this;
+ (function poll() {
+ self.cookies();
+ self.setTimeout(poll, self.delay);
+ })();
+ },
+
setUrl: function(url) {
var existingURL = this.location.href;
if (!existingURL.match(/#/)) existingURL += '#';
diff --git a/src/Compiler.js b/src/Compiler.js
index e09f1876..c45dd46e 100644
--- a/src/Compiler.js
+++ b/src/Compiler.js
@@ -181,7 +181,7 @@ Compiler.prototype = {
template.addChild(i, self.templatize(child, i, priority));
});
}
- return template.empty() ? null : template;
+ return template.empty() ? _null : template;
}
};
diff --git a/src/JSON.js b/src/JSON.js
index 49ed0b29..9fb325ef 100644
--- a/src/JSON.js
+++ b/src/JSON.js
@@ -2,7 +2,7 @@ var array = [].constructor;
function toJson(obj, pretty){
var buf = [];
- toJsonArray(buf, obj, pretty ? "\n " : null, []);
+ toJsonArray(buf, obj, pretty ? "\n " : _null, []);
return buf.join('');
}
@@ -31,21 +31,21 @@ function toJsonArray(buf, obj, pretty, stack){
stack.push(obj);
}
var type = typeof obj;
- if (obj === null) {
- buf.push("null");
- } else if (type === 'function') {
+ if (obj === _null) {
+ buf.push($null);
+ } else if (type === $function) {
return;
- } else if (type === 'boolean') {
+ } else if (type === $boolean) {
buf.push('' + obj);
- } else if (type === 'number') {
+ } else if (type === $number) {
if (isNaN(obj)) {
- buf.push('null');
+ buf.push($null);
} else {
buf.push('' + obj);
}
- } else if (type === 'string') {
+ } else if (type === $string) {
return buf.push(angular['String']['quoteUnicode'](obj));
- } else if (type === 'object') {
+ } else if (type === $object) {
if (obj instanceof Array) {
buf.push("[");
var len = obj.length;
@@ -53,8 +53,8 @@ function toJsonArray(buf, obj, pretty, stack){
for(var i=0; i<len; i++) {
var item = obj[i];
if (sep) buf.push(",");
- if (typeof item == 'function' || typeof item == 'undefined') {
- buf.push("null");
+ if (typeof item == $function || typeof item == $undefined) {
+ buf.push($null);
} else {
toJsonArray(buf, item, pretty, stack);
}
@@ -70,7 +70,7 @@ function toJsonArray(buf, obj, pretty, stack){
var childPretty = pretty ? pretty + " " : false;
var keys = [];
for(var k in obj) {
- if (!obj.hasOwnProperty(k) || k.indexOf('$$') === 0 || obj[k] === undefined)
+ if (!obj.hasOwnProperty(k) || k.indexOf('$$') === 0 || obj[k] === _undefined)
continue;
keys.push(k);
}
@@ -78,7 +78,7 @@ function toJsonArray(buf, obj, pretty, stack){
for ( var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
var key = keys[keyIndex];
var value = obj[key];
- if (typeof value != 'function') {
+ if (typeof value != $function) {
if (comma) {
buf.push(",");
if (pretty) buf.push(pretty);
@@ -92,7 +92,7 @@ function toJsonArray(buf, obj, pretty, stack){
buf.push("}");
}
}
- if (typeof obj == "object") {
+ if (typeof obj == $object) {
stack.pop();
}
}
diff --git a/src/Parser.js b/src/Parser.js
index 5eb75713..eacbf117 100644
--- a/src/Parser.js
+++ b/src/Parser.js
@@ -1,16 +1,8 @@
-function Lexer(text, parsStrings){
- this.text = text;
- // UTC dates have 20 characters, we send them through parser
- this.dateParseLength = parsStrings ? 20 : -1;
- this.tokens = [];
- this.index = 0;
-}
-
-Lexer.OPERATORS = {
- 'null':function(self){return null;},
+OPERATORS = {
+ 'null':function(self){return _null;},
'true':function(self){return true;},
'false':function(self){return false;},
- 'undefined':noop,
+ $undefined:noop,
'+':function(self, a,b){return (isDefined(a)?a:0)+(isDefined(b)?b:0);},
'-':function(self, a,b){return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
'*':function(self, a,b){return a*b;},
@@ -31,149 +23,138 @@ Lexer.OPERATORS = {
'|':function(self, a,b){return b(self, a);},
'!':function(self, a){return !a;}
};
-Lexer.ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
-
-Lexer.prototype = {
- peek: function() {
- if (this.index + 1 < this.text.length) {
- return this.text.charAt(this.index + 1);
+ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
+
+function lex(text, parseStrings){
+ var dateParseLength = parseStrings ? 20 : -1,
+ tokens = [],
+ index = 0,
+ canStartRegExp = true;
+
+ while (index < text.length) {
+ var ch = text.charAt(index);
+ if (ch == '"' || ch == "'") {
+ readString(ch);
+ canStartRegExp = true;
+ } else if (ch == '(' || ch == '[') {
+ tokens.push({index:index, text:ch});
+ index++;
+ } else if (ch == '{' ) {
+ var peekCh = peek();
+ if (peekCh == ':' || peekCh == '(') {
+ tokens.push({index:index, text:ch + peekCh});
+ index++;
+ } else {
+ tokens.push({index:index, text:ch});
+ }
+ index++;
+ canStartRegExp = true;
+ } else if (ch == ')' || ch == ']' || ch == '}' ) {
+ tokens.push({index:index, text:ch});
+ index++;
+ canStartRegExp = false;
+ } else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
+ tokens.push({index:index, text:ch});
+ index++;
+ canStartRegExp = true;
+ } else if ( canStartRegExp && ch == '/' ) {
+ readRegexp();
+ canStartRegExp = false;
+ } else if ( isNumber(ch) ) {
+ readNumber();
+ canStartRegExp = false;
+ } else if (isIdent(ch)) {
+ readIdent();
+ canStartRegExp = false;
+ } else if (isWhitespace(ch)) {
+ index++;
} else {
- return false;
- }
- },
-
- parse: function() {
- var tokens = this.tokens;
- var OPERATORS = Lexer.OPERATORS;
- var canStartRegExp = true;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '"' || ch == "'") {
- this.readString(ch);
- canStartRegExp = true;
- } else if (ch == '(' || ch == '[') {
- tokens.push({index:this.index, text:ch});
- this.index++;
- } else if (ch == '{' ) {
- var peekCh = this.peek();
- if (peekCh == ':' || peekCh == '(') {
- tokens.push({index:this.index, text:ch + peekCh});
- this.index++;
- } else {
- tokens.push({index:this.index, text:ch});
- }
- this.index++;
- canStartRegExp = true;
- } else if (ch == ')' || ch == ']' || ch == '}' ) {
- tokens.push({index:this.index, text:ch});
- this.index++;
- canStartRegExp = false;
- } else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
- tokens.push({index:this.index, text:ch});
- this.index++;
- canStartRegExp = true;
- } else if ( canStartRegExp && ch == '/' ) {
- this.readRegexp();
- canStartRegExp = false;
- } else if ( this.isNumber(ch) ) {
- this.readNumber();
- canStartRegExp = false;
- } else if (this.isIdent(ch)) {
- this.readIdent();
- canStartRegExp = false;
- } else if (this.isWhitespace(ch)) {
- this.index++;
+ var ch2 = ch + peek(),
+ fn = OPERATORS[ch],
+ fn2 = OPERATORS[ch2];
+ if (fn2) {
+ tokens.push({index:index, text:ch2, fn:fn2});
+ index += 2;
+ } else if (fn) {
+ tokens.push({index:index, text:ch, fn:fn});
+ index += 1;
} else {
- var ch2 = ch + this.peek();
- var fn = OPERATORS[ch];
- var fn2 = OPERATORS[ch2];
- if (fn2) {
- tokens.push({index:this.index, text:ch2, fn:fn2});
- this.index += 2;
- } else if (fn) {
- tokens.push({index:this.index, text:ch, fn:fn});
- this.index += 1;
- } else {
- throw "Lexer Error: Unexpected next character [" +
- this.text.substring(this.index) +
- "] in expression '" + this.text +
- "' at column '" + (this.index+1) + "'.";
- }
- canStartRegExp = true;
+ throw "Lexer Error: Unexpected next character [" +
+ text.substring(index) +
+ "] in expression '" + text +
+ "' at column '" + (index+1) + "'.";
}
+ canStartRegExp = true;
}
- return tokens;
- },
+ }
+ return tokens;
- isNumber: function(ch) {
+ function peek() {
+ return index + 1 < text.length ? text.charAt(index + 1) : false;
+ }
+ function isNumber(ch) {
return '0' <= ch && ch <= '9';
- },
-
- isWhitespace: function(ch) {
+ }
+ function isWhitespace(ch) {
return ch == ' ' || ch == '\r' || ch == '\t' ||
ch == '\n' || ch == '\v';
- },
-
- isIdent: function(ch) {
+ }
+ function isIdent(ch) {
return 'a' <= ch && ch <= 'z' ||
'A' <= ch && ch <= 'Z' ||
'_' == ch || ch == '$';
- },
-
- readNumber: function() {
+ }
+ function readNumber() {
var number = "";
- var start = this.index;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '.' || this.isNumber(ch)) {
+ var start = index;
+ while (index < text.length) {
+ var ch = text.charAt(index);
+ if (ch == '.' || isNumber(ch)) {
number += ch;
} else {
break;
}
- this.index++;
+ index++;
}
number = 1 * number;
- this.tokens.push({index:start, text:number,
+ tokens.push({index:start, text:number,
fn:function(){return number;}});
- },
-
- readIdent: function() {
+ }
+ function readIdent() {
var ident = "";
- var start = this.index;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- if (ch == '.' || this.isIdent(ch) || this.isNumber(ch)) {
+ var start = index;
+ while (index < text.length) {
+ var ch = text.charAt(index);
+ if (ch == '.' || isIdent(ch) || isNumber(ch)) {
ident += ch;
} else {
break;
}
- this.index++;
+ index++;
}
- var fn = Lexer.OPERATORS[ident];
+ var fn = OPERATORS[ident];
if (!fn) {
fn = getterFn(ident);
fn.isAssignable = ident;
}
- this.tokens.push({index:start, text:ident, fn:fn});
- },
-
- readString: function(quote) {
- var start = this.index;
- var dateParseLength = this.dateParseLength;
- this.index++;
+ tokens.push({index:start, text:ident, fn:fn});
+ }
+ function readString(quote) {
+ var start = index;
+ index++;
var string = "";
var rawString = quote;
var escape = false;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
+ while (index < text.length) {
+ var ch = text.charAt(index);
rawString += ch;
if (escape) {
if (ch == 'u') {
- var hex = this.text.substring(this.index + 1, this.index + 5);
- this.index += 4;
+ var hex = text.substring(index + 1, index + 5);
+ index += 4;
string += String.fromCharCode(parseInt(hex, 16));
} else {
- var rep = Lexer.ESCAPE[ch];
+ var rep = ESCAPE[ch];
if (rep) {
string += rep;
} else {
@@ -184,8 +165,8 @@ Lexer.prototype = {
} else if (ch == '\\') {
escape = true;
} else if (ch == quote) {
- this.index++;
- this.tokens.push({index:start, text:rawString, string:string,
+ index++;
+ tokens.push({index:start, text:rawString, string:string,
fn:function(){
return (string.length == dateParseLength) ?
angular['String']['toDate'](string) : string;
@@ -194,20 +175,19 @@ Lexer.prototype = {
} else {
string += ch;
}
- this.index++;
+ index++;
}
throw "Lexer Error: Unterminated quote [" +
- this.text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + this.text + "'.";
- },
-
- readRegexp: function(quote) {
- var start = this.index;
- this.index++;
+ text.substring(start) + "] starting at column '" +
+ (start+1) + "' in expression '" + text + "'.";
+ }
+ function readRegexp(quote) {
+ var start = index;
+ index++;
var regexp = "";
var escape = false;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
+ while (index < text.length) {
+ var ch = text.charAt(index);
if (escape) {
regexp += ch;
escape = false;
@@ -215,36 +195,36 @@ Lexer.prototype = {
regexp += ch;
escape = true;
} else if (ch === '/') {
- this.index++;
+ index++;
var flags = "";
- if (this.isIdent(this.text.charAt(this.index))) {
- this.readIdent();
- flags = this.tokens.pop().text;
+ if (isIdent(text.charAt(index))) {
+ readIdent();
+ flags = tokens.pop().text;
}
var compiledRegexp = new RegExp(regexp, flags);
- this.tokens.push({index:start, text:regexp, flags:flags,
+ tokens.push({index:start, text:regexp, flags:flags,
fn:function(){return compiledRegexp;}});
return;
} else {
regexp += ch;
}
- this.index++;
+ index++;
}
throw "Lexer Error: Unterminated RegExp [" +
- this.text.substring(start) + "] starting at column '" +
- (start+1) + "' in expression '" + this.text + "'.";
+ text.substring(start) + "] starting at column '" +
+ (start+1) + "' in expression '" + text + "'.";
}
-};
+}
/////////////////////////////////////////
function Parser(text, parseStrings){
this.text = text;
- this.tokens = new Lexer(text, parseStrings).parse();
+ this.tokens = lex(text, parseStrings);
this.index = 0;
}
-Parser.ZERO = function(){
+ZERO = function(){
return 0;
};
@@ -472,7 +452,7 @@ Parser.prototype = {
if (this.expect('+')) {
return this.primary();
} else if (token = this.expect('-')) {
- return this._binary(Parser.ZERO, token.fn, this.unary());
+ return this._binary(ZERO, token.fn, this.unary());
} else if (token = this.expect('!')) {
return this._unary(token.fn, this.unary());
} else {
@@ -490,7 +470,7 @@ Parser.prototype = {
if (instance)
instance = instance[key];
}
- if (typeof instance != 'function') {
+ if (typeof instance != $function) {
throw "Function '" + token.text + "' at column '" +
(token.index+1) + "' in '" + this.text + "' is not defined.";
}
@@ -507,10 +487,6 @@ Parser.prototype = {
primary = this.arrayDeclaration();
} else if (this.expect('{')) {
primary = this.object();
- } else if (this.expect('{:')) {
- primary = this.closure(false);
- } else if (this.expect('{(')) {
- primary = this.closure(true);
} else {
var token = this.expect();
primary = token.fn;
@@ -533,32 +509,6 @@ Parser.prototype = {
return primary;
},
- closure: function(hasArgs) {
- var args = [];
- if (hasArgs) {
- if (!this.expect(')')) {
- args.push(this.expect().text);
- while(this.expect(',')) {
- args.push(this.expect().text);
- }
- this.consume(')');
- }
- this.consume(":");
- }
- var statements = this.statements();
- this.consume("}");
- return function(self) {
- return function($){
- var scope = createScope(self);
- scope['$'] = $;
- for ( var i = 0; i < args.length; i++) {
- setter(scope, args[i], arguments[i]);
- }
- return statements(scope);
- };
- };
- },
-
fieldAccess: function(object) {
var field = this.expect().text;
var getter = getterFn(field);
@@ -581,7 +531,7 @@ Parser.prototype = {
return function (self){
var o = obj(self);
var i = indexFn(self);
- return (o) ? o[i] : undefined;
+ return (o) ? o[i] : _undefined;
};
}
},
@@ -601,8 +551,8 @@ Parser.prototype = {
}
var fnPtr = fn(self) || noop;
// IE stupidity!
- return fnPtr.apply ?
- fnPtr.apply(self, args) :
+ return fnPtr.apply ?
+ fnPtr.apply(self, args) :
fnPtr(args[0], args[1], args[2], args[3], args[4]);
};
},
@@ -648,51 +598,6 @@ Parser.prototype = {
};
},
- entityDeclaration: function () {
- var decl = [];
- while(this.hasTokens()) {
- decl.push(this.entityDecl());
- if (!this.expect(';')) {
- this.assertAllConsumed();
- }
- }
- return function (self){
- var code = "";
- for ( var i = 0; i < decl.length; i++) {
- code += decl[i](self);
- }
- return code;
- };
- },
-
- entityDecl: function () {
- var entity = this.expect().text;
- var instance;
- var defaults;
- if (this.expect('=')) {
- instance = entity;
- entity = this.expect().text;
- }
- if (this.expect(':')) {
- defaults = this.primary()(null);
- }
- return function(self) {
- var Entity = self.datastore.entity(entity, defaults);
- setter(self, entity, Entity);
- if (instance) {
- var document = Entity();
- document['$$anchor'] = instance;
- setter(self, instance, document);
- return "$anchor." + instance + ":{" +
- instance + "=" + entity + ".load($anchor." + instance + ");" +
- instance + ".$$anchor=" + angular['String']['quote'](instance) + ";" +
- "};";
- } else {
- return "";
- }
- };
- },
-
watch: function () {
var decl = [];
while(this.hasTokens()) {
diff --git a/src/Resource.js b/src/Resource.js
index f4f26ebd..03718b5e 100644
--- a/src/Resource.js
+++ b/src/Resource.js
@@ -124,7 +124,7 @@ ResourceFactory.prototype = {
var callback = noop;
switch(arguments.length) {
case 2: params = a1; callback = a2;
- case 1: if (typeof a1 == 'function') callback = a1; else params = a1;
+ case 1: if (typeof a1 == $function) callback = a1; else params = a1;
case 0: break;
default:
throw "Expected between 1-2 arguments [params, callback], got " + arguments.length + " arguments.";
diff --git a/src/Scope.js b/src/Scope.js
index 27fafc3a..c2a4f098 100644
--- a/src/Scope.js
+++ b/src/Scope.js
@@ -15,7 +15,7 @@ function getter(instance, path, unboundFn) {
if (isUndefined(instance) && key.charAt(0) == '$') {
var type = angular['Global']['typeOf'](lastInstance);
type = angular[type.charAt(0).toUpperCase()+type.substring(1)];
- var fn = type ? type[[key.substring(1)]] : undefined;
+ var fn = type ? type[[key.substring(1)]] : _undefined;
if (fn) {
instance = bind(lastInstance, fn, lastInstance);
return instance;
@@ -44,43 +44,43 @@ function setter(instance, path, value){
}
///////////////////////////////////
-var scopeId = 0;
+var scopeId = 0,
getterFnCache = {},
compileCache = {},
JS_KEYWORDS = {};
foreach(
["abstract", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default",
- "delete", "do", "double", "else", "enum", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto",
- "if", "implements", "import", "ininstanceof", "intinterface", "long", "native", "new", "null", "package", "private",
+ "delete", "do", "double", "else", "enum", "export", "extends", "false", "final", "finally", "float", "for", $function, "goto",
+ "if", "implements", "import", "ininstanceof", "intinterface", "long", "native", "new", $null, "package", "private",
"protected", "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws",
- "transient", "true", "try", "typeof", "var", "volatile", "void", "while", "with"],
+ "transient", "true", "try", "typeof", "var", "volatile", "void", $undefined, "while", "with"],
function(key){ JS_KEYWORDS[key] = true;}
);
function getterFn(path){
var fn = getterFnCache[path];
if (fn) return fn;
- var code = 'function (self){\n';
- code += ' var last, fn, type;\n';
+ var code = 'function (s){\n';
+ code += ' var l, fn, t;\n';
foreach(path.split('.'), function(key) {
key = (JS_KEYWORDS[key]) ? '["' + key + '"]' : '.' + key;
- code += ' if(!self) return self;\n';
- code += ' last = self;\n';
- code += ' self = self' + key + ';\n';
- code += ' if(typeof self == "function") \n';
- code += ' self = function(){ return last'+key+'.apply(last, arguments); };\n';
+ code += ' if(!s) return s;\n';
+ code += ' l = s;\n';
+ code += ' s = s' + key + ';\n';
+ code += ' if(typeof s == "'+$function+'") \n';
+ code += ' s = function(){ return l'+key+'.apply(l, arguments); };\n';
if (key.charAt(1) == '$') {
// special code for super-imposed functions
var name = key.substr(2);
- code += ' if(!self) {\n';
- code += ' type = angular.Global.typeOf(last);\n';
- code += ' fn = (angular[type.charAt(0).toUpperCase() + type.substring(1)]||{})["' + name + '"];\n';
+ code += ' if(!s) {\n';
+ code += ' t = angular.Global.typeOf(l);\n';
+ code += ' fn = (angular[t.charAt(0).toUpperCase() + t.substring(1)]||{})["' + name + '"];\n';
code += ' if (fn)\n';
- code += ' self = function(){ return fn.apply(last, [last].concat(Array.prototype.slice.call(arguments, 0, arguments.length))); };\n';
+ code += ' s = function(){ return fn.apply(l, [l].concat(Array.prototype.slice.call(arguments, 0, arguments.length))); };\n';
code += ' }\n';
}
});
- code += ' return self;\n}';
+ code += ' return s;\n}';
fn = eval('fn = ' + code);
fn["toString"] = function(){ return code; };
@@ -90,7 +90,7 @@ function getterFn(path){
///////////////////////////////////
function expressionCompile(exp){
- if (typeof exp === 'function') return exp;
+ if (typeof exp === $function) return exp;
var fn = compileCache[exp];
if (!fn) {
var parser = new Parser(exp);
@@ -130,7 +130,7 @@ function createScope(parent, services, existing) {
$eval: function $eval(exp) {
var type = typeof exp;
- if (type == 'undefined') {
+ if (type == $undefined) {
for ( var i = 0, iSize = evalLists.sorted.length; i < iSize; i++) {
for ( var queue = evalLists.sorted[i],
jSize = queue.length,
@@ -138,7 +138,7 @@ function createScope(parent, services, existing) {
instance.$tryEval(queue[j].fn, queue[j].handler);
}
}
- } else if (type === 'function') {
+ } else if (type === $function) {
return exp.call(instance);
} else if (type === 'string') {
return expressionCompile(exp).call(instance);
@@ -148,7 +148,7 @@ function createScope(parent, services, existing) {
$tryEval: function (expression, exceptionHandler) {
var type = typeof expression;
try {
- if (type == 'function') {
+ if (type == $function) {
return expression.call(instance);
} else if (type == 'string'){
return expressionCompile(expression).call(instance);
diff --git a/src/apis.js b/src/apis.js
index 0cf24016..764c35ea 100644
--- a/src/apis.js
+++ b/src/apis.js
@@ -1,11 +1,11 @@
var angularGlobal = {
'typeOf':function(obj){
- if (obj === null) return "null";
+ if (obj === _null) return $null;
var type = typeof obj;
- if (type == "object") {
- if (obj instanceof Array) return "array";
- if (obj instanceof Date) return "date";
- if (obj.nodeType == 1) return "element";
+ if (type == $object) {
+ if (obj instanceof Array) return $array;
+ if (obj instanceof Date) return $date;
+ if (obj.nodeType == 1) return $element;
}
return type;
}
@@ -102,7 +102,7 @@ var angularArray = {
}
}
break;
- case "function":
+ case $function:
predicates.push(expression);
break;
default:
@@ -236,34 +236,18 @@ var angularFunction = {
}
};
-function defineApi(dst, chain, underscoreNames){
- if (_) {
- var lastChain = _.last(chain);
- foreach(underscoreNames, function(name){
- lastChain[name] = _[name];
- });
- }
+function defineApi(dst, chain){
angular[dst] = angular[dst] || {};
foreach(chain, function(parent){
extend(angular[dst], parent);
});
}
-defineApi('Global', [angularGlobal],
- ['extend', 'clone','isEqual',
- 'isElement', 'isArray', 'isFunction', 'isUndefined']);
-defineApi('Collection', [angularGlobal, angularCollection],
- ['each', 'map', 'reduce', 'reduceRight', 'detect',
- 'select', 'reject', 'all', 'any', 'include',
- 'invoke', 'pluck', 'max', 'min', 'sortBy',
- 'sortedIndex', 'toArray', 'size']);
-defineApi('Array', [angularGlobal, angularCollection, angularArray],
- ['first', 'last', 'compact', 'flatten', 'without',
- 'uniq', 'intersect', 'zip', 'indexOf', 'lastIndexOf']);
-defineApi('Object', [angularGlobal, angularCollection, angularObject],
- ['keys', 'values']);
-defineApi('String', [angularGlobal, angularString], []);
-defineApi('Date', [angularGlobal, angularDate], []);
+defineApi('Global', [angularGlobal]);
+defineApi('Collection', [angularGlobal, angularCollection]);
+defineApi('Array', [angularGlobal, angularCollection, angularArray]);
+defineApi('Object', [angularGlobal, angularCollection, angularObject]);
+defineApi('String', [angularGlobal, angularString]);
+defineApi('Date', [angularGlobal, angularDate]);
//IE bug
angular['Date']['toString'] = angularDate['toString'];
-defineApi('Function', [angularGlobal, angularCollection, angularFunction],
- ['bind', 'bindAll', 'delay', 'defer', 'wrap', 'compose']);
+defineApi('Function', [angularGlobal, angularCollection, angularFunction]);
diff --git a/src/directives.js b/src/directives.js
index 9aadbd11..994ef90e 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -27,14 +27,14 @@ angularDirective("ng:bind", function(expression){
var lastValue = noop, lastError = noop;
this.$onEval(function() {
var error, value, isHtml, isDomElement,
- oldElement = this.hasOwnProperty('$element') ? this.$element : undefined;
+ oldElement = this.hasOwnProperty($$element) ? this.$element : _undefined;
this.$element = element;
value = this.$tryEval(expression, function(e){
error = toJson(e);
});
this.$element = oldElement;
if (lastValue === value && lastError == error) return;
- isHtml = value instanceof HTML,
+ isHtml = value instanceof HTML;
isDomElement = isElement(value);
if (!isHtml && !isDomElement && isObject(value)) {
value = toJson(value);
@@ -76,7 +76,7 @@ function compileBindTemplate(template){
});
bindTemplateCache[template] = fn = function(element){
var parts = [], self = this,
- oldElement = this.hasOwnProperty('$element') ? self.$element : undefined;
+ oldElement = this.hasOwnProperty($$element) ? self.$element : _undefined;
self.$element = element;
for ( var i = 0; i < bindings.length; i++) {
var value = bindings[i].call(self, element);
@@ -85,7 +85,7 @@ function compileBindTemplate(template){
else if (isObject(value))
value = toJson(value, true);
parts.push(value);
- };
+ }
self.$element = oldElement;
return parts.join('');
};
@@ -133,7 +133,7 @@ angularDirective("ng:bind-attr", function(expression){
element.attr(key, value);
}
}
- };
+ }
}, element);
};
});
@@ -187,7 +187,7 @@ angularWidget("@ng:repeat", function(expression, element){
lastElement = childScope.$element;
index ++;
}
- };
+ }
// shrink children
while(children.length > index) {
children.pop().$element.remove();
@@ -242,7 +242,7 @@ angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;}));
angularDirective("ng:show", function(expression, element){
return function(element){
this.$onEval(function(){
- element.css('display', toBoolean(this.$eval(expression)) ? '' : 'none');
+ element.css($display, toBoolean(this.$eval(expression)) ? '' : $none);
}, element);
};
});
@@ -250,7 +250,7 @@ angularDirective("ng:show", function(expression, element){
angularDirective("ng:hide", function(expression, element){
return function(element){
this.$onEval(function(){
- element.css('display', toBoolean(this.$eval(expression)) ? 'none' : '');
+ element.css($display, toBoolean(this.$eval(expression)) ? $none : '');
}, element);
};
});
@@ -261,7 +261,7 @@ angularDirective("ng:style", function(expression, element){
this.$onEval(function(){
var style = this.$eval(expression) || {}, key, mergedStyle = {};
for(key in style) {
- if (resetStyle[key] === undefined) resetStyle[key] = '';
+ if (resetStyle[key] === _undefined) resetStyle[key] = '';
mergedStyle[key] = style[key];
}
for(key in resetStyle) {
diff --git a/src/filters.js b/src/filters.js
index 27e3deca..f1fc89f1 100644
--- a/src/filters.js
+++ b/src/filters.js
@@ -7,7 +7,7 @@ angularFilter.number = function(amount, fractionSize){
if (isNaN(amount) || !isFinite(amount)) {
return '';
}
- fractionSize = typeof fractionSize == 'undefined' ? 2 : fractionSize;
+ fractionSize = typeof fractionSize == $undefined ? 2 : fractionSize;
var isNegative = amount < 0;
amount = Math.abs(amount);
var pow = Math.pow(10, fractionSize);
diff --git a/src/formatters.js b/src/formatters.js
index 9122489f..ba57a3ed 100644
--- a/src/formatters.js
+++ b/src/formatters.js
@@ -1,5 +1,7 @@
function formatter(format, parse) {return {'format':format, 'parse':parse || format};}
-function toString(obj) {return (isDefined(obj) && obj !== null) ? "" + obj : obj;}
+function toString(obj) {
+ return (isDefined(obj) && obj !== _null) ? "" + obj : obj;
+}
var NUMBER = /^\s*[-+]?\d*(\.\d*)?\s*$/;
@@ -7,10 +9,11 @@ angularFormatter.noop = formatter(identity, identity);
angularFormatter.json = formatter(toJson, fromJson);
angularFormatter['boolean'] = formatter(toString, toBoolean);
angularFormatter.number = formatter(toString, function(obj){
- if (isString(obj) && NUMBER.exec(obj)) {
- return obj ? 1*obj : null;
+ if (obj == _null || NUMBER.exec(obj)) {
+ return obj===_null || obj === '' ? _null : 1*obj;
+ } else {
+ throw "Not a number";
}
- throw "Not a number";
});
angularFormatter.list = formatter(
diff --git a/src/jqLite.js b/src/jqLite.js
index 1ad4d96d..5f1b9730 100644
--- a/src/jqLite.js
+++ b/src/jqLite.js
@@ -70,7 +70,7 @@ JQLite.prototype = {
}
cache[key] = value;
} else {
- return cache ? cache[key] : null;
+ return cache ? cache[key] : _null;
}
},
@@ -115,7 +115,7 @@ JQLite.prototype = {
trigger: function(type) {
var evnt = document.createEvent('MouseEvent');
- evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, _null);
this[0].dispatchEvent(evnt);
},
@@ -195,8 +195,8 @@ JQLite.prototype = {
e.setAttribute(name, value);
} else {
var attributes = e.attributes,
- item = attributes ? attributes.getNamedItem(name) : undefined;
- return item && item.specified ? item.value : undefined;
+ item = attributes ? attributes.getNamedItem(name) : _undefined;
+ return item && item.specified ? item.value : _undefined;
}
},
diff --git a/src/markups.js b/src/markups.js
index ac2b5636..27f74518 100644
--- a/src/markups.js
+++ b/src/markups.js
@@ -20,11 +20,11 @@ function parseBindings(string) {
function binding(string) {
var binding = string.replace(/\n/gm, ' ').match(/^\{\{(.*)\}\}$/);
- return binding ? binding[1] : null;
+ return binding ? binding[1] : _null;
}
function hasBindings(bindings) {
- return bindings.length > 1 || binding(bindings[0]) !== null;
+ return bindings.length > 1 || binding(bindings[0]) !== _null;
}
angularTextMarkup('{{}}', function(text, textNode, parentElement) {
@@ -61,7 +61,7 @@ angularTextMarkup('{{}}', function(text, textNode, parentElement) {
angularTextMarkup('OPTION', function(text, textNode, parentElement){
if (nodeName(parentElement) == "OPTION") {
var select = document.createElement('select');
- select.insertBefore(parentElement[0].cloneNode(true), null);
+ select.insertBefore(parentElement[0].cloneNode(true), _null);
if (!select.innerHTML.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) {
parentElement.attr('value', text);
}
diff --git a/src/scenario/DSL.js b/src/scenario/DSL.js
index 0607238c..dc85ea45 100644
--- a/src/scenario/DSL.js
+++ b/src/scenario/DSL.js
@@ -24,7 +24,7 @@ angular.scenario.dsl.browser = {
href: "",
hash: "",
toEqual: function(url) {
- return (this.hash == "" ? (url == this.href) :
+ return (this.hash === "" ? (url == this.href) :
(url == (this.href + "/#/" + this.hash)));
},
setLocation: function(url) {
@@ -56,7 +56,7 @@ angular.scenario.dsl.input = function(selector) {
});
}
};
-},
+};
angular.scenario.dsl.NG_BIND_PATTERN =/\{\{[^\}]+\}\}/;
diff --git a/src/scenario/Future.js b/src/scenario/Future.js
index d70e8e6e..cc40eff0 100644
--- a/src/scenario/Future.js
+++ b/src/scenario/Future.js
@@ -2,7 +2,7 @@ function Future(name, behavior) {
this.name = name;
this.behavior = behavior;
this.fulfilled = false;
- this.value = undefined;
+ this.value = _undefined;
}
Future.prototype = {
diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js
index ac32559c..77969618 100644
--- a/src/scenario/Runner.js
+++ b/src/scenario/Runner.js
@@ -42,7 +42,7 @@ angular.scenario.Runner = function(scope, jQuery){
} finally {
afterEach();
}
- self.currentSpec = null;
+ self.currentSpec = _null;
};
this.logger = function returnNoop(){
return extend(returnNoop, {close:noop, fail:noop});
@@ -107,7 +107,7 @@ angular.scenario.Runner.prototype = {
} else {
self.scope.$testrun.done = true;
}
- };
+ }
callback();
},
@@ -144,7 +144,7 @@ angular.scenario.Runner.prototype = {
function done() {
result.finished = true;
futureLogger.close();
- self.self = null;
+ self.self = _null;
(callback||noop).call(specThis);
}
function next(value){
@@ -153,7 +153,7 @@ angular.scenario.Runner.prototype = {
}
var future = spec.futures[spec.nextFutureIndex];
(result.log || {close:noop}).close();
- result.log = null;
+ result.log = _null;
if (future) {
spec.nextFutureIndex ++;
result.log = futureLogger('future', future.name);
@@ -176,7 +176,7 @@ angular.scenario.Runner.prototype = {
steps: futuresFulfilled});
done();
}
- };
+ }
next();
return specThis;
}
diff --git a/src/services.js b/src/services.js
index a5158149..31c5e7af 100644
--- a/src/services.js
+++ b/src/services.js
@@ -40,7 +40,7 @@ angularService("$location", function(browser){
}
function check(param) {
- return lastLocation[param] == location[param] ? undefined : location[param];
+ return lastLocation[param] == location[param] ? _undefined : location[param];
}
function checkProtocol(){
@@ -49,9 +49,9 @@ angularService("$location", function(browser){
lastLocation.port === location.port &&
lastLocation.path === location.path &&
equals(lastLocation.search, location.search))
- return undefined;
+ return _undefined;
var url = toKeyValue(location.search);
- var port = (location.port == DEFAULT_PORTS[location.protocol] ? null : location.port);
+ var port = (location.port == DEFAULT_PORTS[location.protocol] ? _null : location.port);
return location.protocol + '://' + location.host +
(port ? ':' + port : '') + location.path +
(url ? '?' + url : '');
@@ -60,7 +60,7 @@ angularService("$location", function(browser){
function checkHashPathSearch(){
if (lastLocation.hashPath === location.hashPath &&
equals(lastLocation.hashSearch, location.hashSearch) )
- return undefined;
+ return _undefined;
var url = toKeyValue(location.hashSearch);
return escape(location.hashPath) + (url ? '?' + url : '');
}
@@ -72,7 +72,7 @@ angularService("$location", function(browser){
location.href = url.replace('#$', '');
location.protocol = match[1];
location.host = match[3] || '';
- location.port = match[5] || DEFAULT_PORTS[location.protocol] || null;
+ location.port = match[5] || DEFAULT_PORTS[location.protocol] || _null;
location.path = match[6];
location.search = parseKeyValue(match[8]);
location.hash = match[10] || '';
@@ -109,7 +109,7 @@ angularService('$exceptionHandler', function($log){
}, {inject:['$log']});
angularService("$hover", function(browser, document) {
- var tooltip, self = this, error, width = 300, arrowWidth = 10, body = jqLite(document[0].body);;
+ var tooltip, self = this, error, width = 300, arrowWidth = 10, body = jqLite(document[0].body);
browser.hover(function(element, show){
if (show && (error = element.attr(NG_EXCEPTION) || element.attr(NG_VALIDATION_ERROR))) {
if (!tooltip) {
@@ -149,7 +149,7 @@ angularService("$hover", function(browser, document) {
}
} else if (tooltip) {
tooltip.callout.remove();
- tooltip = null;
+ tooltip = _null;
}
});
}, {inject:['$browser', '$document']});
@@ -211,7 +211,7 @@ function switchRouteMatcher(on, when, dstName) {
});
if (dstName) this.$set(dstName, dst);
}
- return match ? dst : null;
+ return match ? dst : _null;
}
angularService('$route', function(location){
@@ -234,7 +234,7 @@ angularService('$route', function(location){
};
function updateRoute(){
var childScope;
- $route.current = null;
+ $route.current = _null;
angular.foreach(routes, function(routeParams, route) {
if (!childScope) {
var pathParams = matcher(location.hashPath, route);
@@ -262,7 +262,7 @@ angularService('$xhr', function($browser, $error, $log){
return function(method, url, post, callback){
if (isFunction(post)) {
callback = post;
- post = null;
+ post = _null;
}
if (post && isObject(post)) {
post = toJson(post);
@@ -300,7 +300,7 @@ angularService('$xhr.bulk', function($xhr, $error, $log){
function bulkXHR(method, url, post, callback) {
if (isFunction(post)) {
callback = post;
- post = null;
+ post = _null;
}
var currentQueue;
foreach(bulkXHR.urls, function(queue){
@@ -345,11 +345,11 @@ angularService('$xhr.bulk', function($xhr, $error, $log){
}, {inject:['$xhr', '$xhr.error', '$log']});
angularService('$xhr.cache', function($xhr){
- var inflight = {}, self = this;;
+ var inflight = {}, self = this;
function cache(method, url, post, callback, verifyCache){
if (isFunction(post)) {
callback = post;
- post = null;
+ post = _null;
}
if (method == 'GET') {
var data;
@@ -392,3 +392,67 @@ angularService('$resource', function($xhr){
var resource = new ResourceFactory($xhr);
return bind(resource, resource.route);
}, {inject: ['$xhr.cache']});
+
+
+angularService('$cookies', function($browser) {
+ var cookies = {}, rootScope = this;
+ $browser.watchCookies(function(newCookies){
+ copy(newCookies, cookies);
+ rootScope.$eval();
+ });
+ this.$onEval(PRIORITY_FIRST, update);
+ this.$onEval(PRIORITY_LAST, update);
+ return cookies;
+
+ function update(){
+ var name, browserCookies = $browser.cookies();
+ for(name in cookies) {
+ if (browserCookies[name] !== cookies[name]) {
+ $browser.cookies(name, browserCookies[name] = cookies[name]);
+ }
+ }
+ for(name in browserCookies) {
+ if (browserCookies[name] !== cookies[name]) {
+ $browser.cookies(name, _undefined);
+ //TODO: write test for this delete
+ //delete cookies[name];
+ }
+ }
+ }
+}, {inject: ['$browser']});
+
+
+angularService('$sessionStore', function($store) {
+
+ function SessionStore() {}
+
+ SessionStore.prototype.get = function(key) {
+ return fromJson($store[key]);
+ };
+
+ SessionStore.prototype.getAll = function() {
+ var all = {},
+ key;
+
+ for (key in $store) {
+ if (!$store.hasOwnProperty(key)) continue;
+ all[key] = fromJson($store[key]);
+ }
+
+ return all;
+ };
+
+
+ SessionStore.prototype.put = function(key, value) {
+ $store[key] = toJson(value);
+ };
+
+
+ SessionStore.prototype.remove = function(key) {
+ delete $store[key];
+ };
+
+
+ return new SessionStore();
+
+}, {inject: ['$cookies']});
diff --git a/src/validators.js b/src/validators.js
index 5c7fc952..b99c8aa9 100644
--- a/src/validators.js
+++ b/src/validators.js
@@ -1,25 +1,25 @@
foreach({
- 'noop': function() { return null; },
+ 'noop': function() { return _null; },
'regexp': function(value, regexp, msg) {
if (!value.match(regexp)) {
return msg ||
"Value does not match expected format " + regexp + ".";
} else {
- return null;
+ return _null;
}
},
'number': function(value, min, max) {
var num = 1 * value;
if (num == value) {
- if (typeof min != 'undefined' && num < min) {
+ if (typeof min != $undefined && num < min) {
return "Value can not be less than " + min + ".";
}
- if (typeof min != 'undefined' && num > max) {
+ if (typeof min != $undefined && num > max) {
return "Value can not be greater than " + max + ".";
}
- return null;
+ return _null;
} else {
return "Not a number";
}
@@ -31,43 +31,43 @@ foreach({
if (!("" + value).match(/^\s*[\d+]*\s*$/) || value != Math.round(value)) {
return "Not a whole number";
}
- return null;
+ return _null;
},
'date': function(value, min, max) {
if (value.match(/^\d\d?\/\d\d?\/\d\d\d\d$/)) {
- return null;
+ return _null;
}
return "Value is not a date. (Expecting format: 12/31/2009).";
},
'ssn': function(value) {
if (value.match(/^\d\d\d-\d\d-\d\d\d\d$/)) {
- return null;
+ return _null;
}
return "SSN needs to be in 999-99-9999 format.";
},
'email': function(value) {
if (value.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)) {
- return null;
+ return _null;
}
return "Email needs to be in username@host.com format.";
},
'phone': function(value) {
if (value.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/)) {
- return null;
+ return _null;
}
if (value.match(/^\+\d{2,3} (\(\d{1,5}\))?[\d ]+\d$/)) {
- return null;
+ return _null;
}
return "Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationaly.";
},
'url': function(value) {
if (value.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/)) {
- return null;
+ return _null;
}
return "URL needs to be in http://server[:port]/path format.";
},
@@ -75,7 +75,7 @@ foreach({
'json': function(value) {
try {
fromJson(value);
- return null;
+ return _null;
} catch (e) {
return e.toString();
}
diff --git a/src/widgets.js b/src/widgets.js
index a3874a51..b70c4dcb 100644
--- a/src/widgets.js
+++ b/src/widgets.js
@@ -6,7 +6,7 @@ function modelAccessor(scope, element) {
return scope.$eval(expr);
},
set: function(value) {
- if (value !== undefined) {
+ if (value !== _undefined) {
return scope.$tryEval(expr + '=' + toJson(value), element);
}
}
@@ -57,7 +57,7 @@ function valueAccessor(scope, element) {
return {
get: function(){
if (lastError)
- elementError(element, NG_VALIDATION_ERROR, null);
+ elementError(element, NG_VALIDATION_ERROR, _null);
try {
var value = parse(element.val());
validate();
@@ -80,13 +80,13 @@ function valueAccessor(scope, element) {
function validate() {
var value = trim(element.val());
if (element[0].disabled || element[0].readOnly) {
- elementError(element, NG_VALIDATION_ERROR, null);
+ elementError(element, NG_VALIDATION_ERROR, _null);
invalidWidgets.markValid(element);
} else {
var error, validateScope = inherit(scope, {$element:element});
error = required && !value ?
'Required' :
- (value ? validator(validateScope, value) : null);
+ (value ? validator(validateScope, value) : _null);
elementError(element, NG_VALIDATION_ERROR, error);
lastError = error;
if (error) {
@@ -114,7 +114,7 @@ function radioAccessor(scope, element) {
var domElement = element[0];
return {
get: function(){
- return domElement.checked ? domElement.value : null;
+ return domElement.checked ? domElement.value : _null;
},
set: function(value){
domElement.checked = value == domElement.value;
@@ -157,7 +157,7 @@ var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, initW
'image': buttonWidget,
'checkbox': inputWidget('click', modelFormattedAccessor, checkedAccessor, initWidgetValue(false)),
'radio': inputWidget('click', modelFormattedAccessor, radioAccessor, radioInit),
- 'select-one': inputWidget('change', modelFormattedAccessor, valueAccessor, initWidgetValue(null)),
+ 'select-one': inputWidget('change', modelFormattedAccessor, valueAccessor, initWidgetValue(_null)),
'select-multiple': inputWidget('change', modelFormattedAccessor, optionsAccessor, initWidgetValue([]))
// 'file': fileWidget???
};
@@ -179,9 +179,9 @@ function radioInit(model, view, element) {
input.checked = false;
input.name = this.$id + '@' + input.name;
if (isUndefined(modelValue)) {
- model.set(modelValue = null);
+ model.set(modelValue = _null);
}
- if (modelValue == null && viewValue !== null) {
+ if (modelValue == _null && viewValue !== _null) {
model.set(viewValue);
}
view.set(modelValue);
diff --git a/test/ApiTest.js b/test/ApiTest.js
index 9f09773d..189e9ad6 100644
--- a/test/ApiTest.js
+++ b/test/ApiTest.js
@@ -8,7 +8,7 @@ ApiTest.prototype.testItShouldReturnTypeOf = function (){
assertEquals("string", angular.Object.typeOf(""));
assertEquals("date", angular.Object.typeOf(new Date()));
assertEquals("element", angular.Object.typeOf(document.body));
- assertEquals("function", angular.Object.typeOf(function(){}));
+ assertEquals($function, angular.Object.typeOf(function(){}));
};
ApiTest.prototype.testItShouldReturnSize = function(){
diff --git a/test/BrowserSpecs.js b/test/BrowserSpecs.js
index 99632928..4138a9d9 100644
--- a/test/BrowserSpecs.js
+++ b/test/BrowserSpecs.js
@@ -27,6 +27,25 @@ describe('browser', function(){
browser.startUrlWatcher();
});
+ it('should contain cookie cruncher', function() {
+ expect(browser.cookies).toBeDefined();
+ });
+
+ it('should be able to start cookie watcher', function() {
+ browser.delay = 1;
+ expectAsserts(2);
+ browser.watchCookies(function(cookies){
+ assertEquals({'foo':'bar'}, cookies);
+ });
+ browser.setTimeout = function(fn, delay){
+ assertEquals(1, delay);
+ document.cookie = 'foo=bar';
+ browser.setTimeout = function(fn, delay) {};
+ fn();
+ };
+ browser.startCookieWatcher();
+ });
+
describe('outstading requests', function(){
it('should process callbacks immedietly with no outstanding requests', function(){
var callback = jasmine.createSpy('callback');
@@ -59,7 +78,7 @@ describe('browser', function(){
expect(head.scripts.length).toEqual(1);
var url = head.scripts[0].src.split('?cb=');
expect(url[0]).toEqual('http://example.org/path');
- expect(typeof window[url[1]]).toEqual('function');
+ expect(typeof window[url[1]]).toEqual($function);
window[url[1]]('data');
expect(log).toEqual('200:data;');
expect(typeof window[url[1]]).toEqual('undefined');
@@ -67,4 +86,193 @@ describe('browser', function(){
});
});
+
+ describe('cookies', function() {
+
+ function deleteAllCookies() {
+ var cookies = document.cookie.split(";");
+
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = cookies[i];
+ var eqPos = cookie.indexOf("=");
+ var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
+ document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ }
+ }
+
+ var browser;
+
+ beforeEach(function() {
+ deleteAllCookies();
+ browser = new Browser({}, jqLite(document));
+ expect(document.cookie).toEqual('');
+ });
+
+
+ afterEach(function() {
+ deleteAllCookies();
+ expect(document.cookie).toEqual('');
+ });
+
+
+ describe('remove all via (null)', function() {
+
+ it('should do nothing when no cookies are set', function() {
+ browser.cookies(null);
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ });
+
+ });
+
+ describe('remove via (cookieName, undefined)', function() {
+
+ it('should remove a cookie when it is present', function() {
+ document.cookie = 'foo=bar';
+
+ browser.cookies('foo', undefined);
+
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ });
+
+
+ it('should do nothing when an nonexisting cookie is being removed', function() {
+ browser.cookies('doesntexist', undefined);
+ expect(document.cookie).toEqual('');
+ expect(browser.cookies()).toEqual({});
+ });
+ });
+
+
+ describe('put via (cookieName, string)', function() {
+
+ it('should create and store a cookie', function() {
+ browser.cookies('cookieName', 'cookieValue');
+ expect(document.cookie).toEqual('cookieName=cookieValue');
+ expect(browser.cookies()).toEqual({'cookieName':'cookieValue'});
+ });
+
+
+ it('should overwrite an existing unsynced cookie', function() {
+ document.cookie = "cookie=new";
+
+ var oldVal = browser.cookies('cookie', 'newer');
+
+ expect(document.cookie).toEqual('cookie=newer');
+ expect(browser.cookies()).toEqual({'cookie':'newer'});
+ expect(oldVal).not.toBeDefined();
+ });
+
+ it('should escape both name and value', function() {
+ browser.cookies('cookie1=', 'val;ue');
+ browser.cookies('cookie2=bar;baz', 'val=ue');
+
+ var rawCookies = document.cookie.split("; "); //order is not guaranteed, so we need to parse
+ expect(rawCookies.length).toEqual(2);
+ expect(rawCookies).toContain('cookie1%3D=val%3Bue');
+ expect(rawCookies).toContain('cookie2%3Dbar%3Bbaz=val%3Due');
+ });
+ });
+
+
+ describe('get via (cookieName)', function() {
+
+ it('should return undefined for nonexistent cookie', function() {
+ expect(browser.cookies('nonexistent')).not.toBeDefined();
+ });
+
+
+ it ('should return a value for an existing cookie', function() {
+ document.cookie = "foo=bar";
+ browser.cookies(true);
+ expect(browser.cookies().foo).toEqual('bar');
+ });
+
+
+ it ('should unescape cookie values that were escaped by puts', function() {
+ document.cookie = "cookie2%3Dbar%3Bbaz=val%3Due";
+ browser.cookies(true);
+ expect(browser.cookies()['cookie2=bar;baz']).toEqual('val=ue');
+ });
+
+
+ it('should preserve leading & trailing spaces in names and values', function() {
+ browser.cookies(' cookie name ', ' cookie value ');
+ expect(browser.cookies()[' cookie name ']).toEqual(' cookie value ');
+ expect(browser.cookies()['cookie name']).not.toBeDefined();
+ });
+ });
+
+
+ describe('getAll', function() {
+
+ it('should return cookies as hash', function() {
+ document.cookie = "foo1=bar1";
+ document.cookie = "foo2=bar2";
+ expect(browser.cookies()).toEqual({'foo1':'bar1', 'foo2':'bar2'});
+ });
+
+
+ it('should return empty hash if no cookies exist', function() {
+ expect(browser.cookies()).toEqual({});
+ });
+ });
+
+
+ describe('watch', function() {
+
+ it('should allow listeners to be registered', function() {
+ expectAsserts(1);
+
+ browser.watchCookies(function(cookies) {
+ assertEquals({'aaa':'bbb'}, cookies);
+ });
+
+ browser.cookies('aaa','bbb');
+ browser.cookies();
+ });
+
+
+ it('should fire listeners when cookie changes are discovered', function() {
+ expectAsserts(1);
+
+ browser.watchCookies(function(cookies) {
+ assertEquals({'foo':'bar'}, cookies);
+ });
+
+ document.cookie = 'foo=bar';
+ browser.cookies();
+ });
+
+
+ it('should not fire listeners when no cookies were changed', function() {
+ expectAsserts(0);
+
+ browser.cookies(function(cookies) {
+ assertEquals({'shouldnt':'fire'}, cookies);
+ });
+
+ browser.cookies(true);
+ });
+ });
+
+
+ it('should pick up external changes made to browser cookies', function() {
+ browser.cookies('oatmealCookie', 'drool');
+ expect(browser.cookies()).toEqual({'oatmealCookie':'drool'});
+
+ document.cookie = 'oatmealCookie=changed';
+ browser.cookies(true);
+ expect(browser.cookies().oatmealCookie).toEqual('changed');
+ });
+
+
+ it('should initialize cookie cache with existing cookies', function() {
+ document.cookie = "existingCookie=existingValue";
+ expect(browser.cookies()).toEqual({'existingCookie':'existingValue'});
+ });
+
+ });
});
+
diff --git a/test/ParserTest.js b/test/ParserTest.js
index d7fd2f94..6a70bce8 100644
--- a/test/ParserTest.js
+++ b/test/ParserTest.js
@@ -1,8 +1,7 @@
LexerTest = TestCase('LexerTest');
LexerTest.prototype.testTokenizeAString = function(){
- var lexer = new Lexer("a.bc[22]+1.3|f:'a\\\'c':\"d\\\"e\"");
- var tokens = lexer.parse();
+ var tokens = lex("a.bc[22]+1.3|f:'a\\\'c':\"d\\\"e\"");
var i = 0;
assertEquals(tokens[i].index, 0);
assertEquals(tokens[i].text, 'a.bc');
@@ -53,8 +52,7 @@ LexerTest.prototype.testTokenizeAString = function(){
};
LexerTest.prototype.testTokenizeUndefined = function(){
- var lexer = new Lexer("undefined");
- var tokens = lexer.parse();
+ var tokens = lex("undefined");
var i = 0;
assertEquals(tokens[i].index, 0);
assertEquals(tokens[i].text, 'undefined');
@@ -64,8 +62,7 @@ LexerTest.prototype.testTokenizeUndefined = function(){
LexerTest.prototype.testTokenizeRegExp = function(){
- var lexer = new Lexer("/r 1/");
- var tokens = lexer.parse();
+ var tokens = lex("/r 1/");
var i = 0;
assertEquals(tokens[i].index, 0);
assertEquals(tokens[i].text, 'r 1');
@@ -74,8 +71,7 @@ LexerTest.prototype.testTokenizeRegExp = function(){
LexerTest.prototype.testQuotedString = function(){
var str = "['\\'', \"\\\"\"]";
- var lexer = new Lexer(str);
- var tokens = lexer.parse();
+ var tokens = lex(str);
assertEquals(1, tokens[1].index);
assertEquals("'", tokens[1].string);
@@ -87,22 +83,19 @@ LexerTest.prototype.testQuotedString = function(){
LexerTest.prototype.testQuotedStringEscape = function(){
var str = '"\\"\\n\\f\\r\\t\\v\\u00A0"';
- var lexer = new Lexer(str);
- var tokens = lexer.parse();
+ var tokens = lex(str);
assertEquals('"\n\f\r\t\v\u00A0', tokens[0].string);
};
LexerTest.prototype.testTokenizeUnicode = function(){
- var lexer = new Lexer('"\\u00A0"');
- var tokens = lexer.parse();
+ var tokens = lex('"\\u00A0"');
assertEquals(1, tokens.length);
assertEquals('\u00a0', tokens[0].string);
};
LexerTest.prototype.testTokenizeRegExpWithOptions = function(){
- var lexer = new Lexer("/r/g");
- var tokens = lexer.parse();
+ var tokens = lex("/r/g");
var i = 0;
assertEquals(tokens[i].index, 0);
assertEquals(tokens[i].text, 'r');
@@ -111,8 +104,7 @@ LexerTest.prototype.testTokenizeRegExpWithOptions = function(){
};
LexerTest.prototype.testTokenizeRegExpWithEscape = function(){
- var lexer = new Lexer("/\\/\\d/");
- var tokens = lexer.parse();
+ var tokens = lex("/\\/\\d/");
var i = 0;
assertEquals(tokens[i].index, 0);
assertEquals(tokens[i].text, '\\/\\d');
@@ -120,15 +112,13 @@ LexerTest.prototype.testTokenizeRegExpWithEscape = function(){
};
LexerTest.prototype.testIgnoreWhitespace = function(){
- var lexer = new Lexer("a \t \n \r b");
- var tokens = lexer.parse();
+ var tokens = lex("a \t \n \r b");
assertEquals(tokens[0].text, 'a');
assertEquals(tokens[1].text, 'b');
};
LexerTest.prototype.testRelation = function(){
- var lexer = new Lexer("! == != < > <= >=");
- var tokens = lexer.parse();
+ var tokens = lex("! == != < > <= >=");
assertEquals(tokens[0].text, '!');
assertEquals(tokens[1].text, '==');
assertEquals(tokens[2].text, '!=');
@@ -139,8 +129,7 @@ LexerTest.prototype.testRelation = function(){
};
LexerTest.prototype.testStatements = function(){
- var lexer = new Lexer("a;b;");
- var tokens = lexer.parse();
+ var tokens = lex("a;b;");
assertEquals(tokens[0].text, 'a');
assertEquals(tokens[1].text, ';');
assertEquals(tokens[2].text, 'b');
@@ -148,7 +137,7 @@ LexerTest.prototype.testStatements = function(){
};
LexerTest.prototype.testNumber = function(){
- var tokens = new Lexer("0.5").parse();
+ var tokens = lex("0.5");
expect(tokens[0].text).toEqual(0.5);
};
@@ -409,34 +398,6 @@ ParserTest.prototype.testMissingThrowsError = function() {
}
};
-ParserTest.prototype.testItShouldCreateClosureFunctionWithNoArguments = function () {
- var scope = createScope();
- var fn = scope.$eval("{:value}");
- scope.$set("value", 1);
- assertEquals(1, fn());
- scope.$set("value", 2);
- assertEquals(2, fn());
- fn = scope.$eval("{():value}");
- assertEquals(2, fn());
-};
-
-ParserTest.prototype.testItShouldCreateClosureFunctionWithArguments = function () {
- var scope = createScope();
- scope.$set("value", 1);
- var fn = scope.$eval("{(a):value+a}");
- assertEquals(11, fn(10));
- scope.$set("value", 2);
- assertEquals(12, fn(10));
- fn = scope.$eval("{(a,b):value+a+b}");
- assertEquals(112, fn(10, 100));
-};
-
-ParserTest.prototype.testItShouldHaveDefaultArugument = function(){
- var scope = createScope();
- var fn = scope.$eval("{:$*2}");
- assertEquals(4, fn(2));
-};
-
ParserTest.prototype.testDoubleNegationBug = function (){
var scope = createScope();
assertEquals(true, scope.$eval('true'));
diff --git a/test/ResourceSpec.js b/test/ResourceSpec.js
index 546e9aec..1ac43d74 100644
--- a/test/ResourceSpec.js
+++ b/test/ResourceSpec.js
@@ -15,12 +15,12 @@ describe("resource", function() {
});
it("should build resource", function(){
- expect(typeof CreditCard).toBe('function');
- expect(typeof CreditCard.get).toBe('function');
- expect(typeof CreditCard.save).toBe('function');
- expect(typeof CreditCard.remove).toBe('function');
- expect(typeof CreditCard['delete']).toBe('function');
- expect(typeof CreditCard.query).toBe('function');
+ expect(typeof CreditCard).toBe($function);
+ expect(typeof CreditCard.get).toBe($function);
+ expect(typeof CreditCard.save).toBe($function);
+ expect(typeof CreditCard.remove).toBe($function);
+ expect(typeof CreditCard['delete']).toBe($function);
+ expect(typeof CreditCard.query).toBe($function);
});
it('should default to empty parameters', function(){
diff --git a/test/angular-mocks.js b/test/angular-mocks.js
index bac2e800..1e547f77 100644
--- a/test/angular-mocks.js
+++ b/test/angular-mocks.js
@@ -26,6 +26,7 @@ function MockBrowser() {
var self = this,
expectations = {},
requests = [];
+
this.isMock = true;
self.url = "http://server";
self.watches = [];
@@ -72,6 +73,8 @@ function MockBrowser() {
requests.pop()();
}
};
+
+ self.cookieHash = {};
}
MockBrowser.prototype = {
@@ -90,11 +93,28 @@ MockBrowser.prototype = {
this.watches.push(fn);
},
+ watchCookies: function(fn) {
+ this.watches.push(fn);
+ },
+
fireUrlWatchers: function() {
for(var i=0; i<this.watches.length; i++) {
this.watches[i](this.url);
}
+ },
+
+ cookies: function(name, value) {
+ if (name) {
+ if (value == undefined) {
+ delete this.cookieHash[name];
+ } else {
+ this.cookieHash[name] = ""+value;
+ }
+ } else {
+ return copy(this.cookieHash);
+ }
}
+
};
angular.service('$browser', function(){
diff --git a/test/scenario/DSLSpec.js b/test/scenario/DSLSpec.js
index f8606641..7a8e2e3b 100644
--- a/test/scenario/DSLSpec.js
+++ b/test/scenario/DSLSpec.js
@@ -43,33 +43,29 @@ describe("DSL", function() {
describe('browser', function() {
var browser = angular.scenario.dsl.browser;
- it('shoud return true if location with empty hash provided is same '
- + 'as location of the page', function() {
+ it('shoud return true if location with empty hash provided is same ' +
+ 'as location of the page', function() {
browser.location.href = "http://server";
expect(browser.location.toEqual("http://server")).toEqual(true);
});
- it('shoud return true if location with hash provided is same '
- + 'as location of the page', function() {
+ it('shoud return true if location with hash provided is same ' +
+ 'as location of the page', function() {
browser.location.href = "http://server";
browser.location.hash = "hashPath";
- expect(browser.location.toEqual("http://server/#/hashPath"))
- .toEqual(true);
+ expect(browser.location.toEqual("http://server/#/hashPath")).toEqual(true);
});
- it('should return true if the location provided is the same as which '
- + 'browser navigated to', function() {
+ it('should return true if the location provided is the same as which ' +
+ 'browser navigated to', function() {
var future = browser.navigateTo("http://server/#/hashPath");
expect(future.name).toEqual("Navigate to: http://server/#/hashPath");
executeFuture(future, '<input type="text" name="name" />');
- expect(browser.location.toEqual("http://server/#/hashPath"))
- .toEqual(true);
- expect(browser.location.toEqual("http://server/"))
- .toEqual(false);
+ expect(browser.location.toEqual("http://server/#/hashPath")).toEqual(true);
+ expect(browser.location.toEqual("http://server/")).toEqual(false);
future = browser.navigateTo("http://server/");
expect(future.name).toEqual("Navigate to: http://server/");
executeFuture(future, '<input type="text" name="name" />');
- expect(browser.location.toEqual("http://server/"))
- .toEqual(true);
+ expect(browser.location.toEqual("http://server/")).toEqual(true);
});
});
diff --git a/test/scenario/RunnerSpec.js b/test/scenario/RunnerSpec.js
index b12c43c6..2986add6 100644
--- a/test/scenario/RunnerSpec.js
+++ b/test/scenario/RunnerSpec.js
@@ -47,7 +47,7 @@ describe('Runner', function() {
fail();
} catch (e) {
expect(e.message).toEqual('blah');
- };
+ }
});
});
@@ -116,7 +116,7 @@ describe('Runner', function() {
describe('future building', function() {
it('should queue futures', function() {
- function behavior(){};
+ function behavior(){}
Describe('name', function() {
It('should', function() {
$scenario.addFuture('futureName', behavior);
diff --git a/test/servicesSpec.js b/test/servicesSpec.js
index ffd01267..b39e401c 100644
--- a/test/servicesSpec.js
+++ b/test/servicesSpec.js
@@ -34,11 +34,11 @@ describe("service", function(){
describe("$log", function(){
it('should use console if present', function(){
var logger = "";
- function log(){ logger+= 'log;'; };
- function warn(){ logger+= 'warn;'; };
- function info(){ logger+= 'info;'; };
- function error(){ logger+= 'error;'; };
- var scope = createScope(null, angularService, {$window: {console:{log:log, warn:warn, info:info, error:error}}, $document:[{}]});
+ function log(){ logger+= 'log;'; }
+ function warn(){ logger+= 'warn;'; }
+ function info(){ logger+= 'info;'; }
+ function error(){ logger+= 'error;'; }
+ var scope = createScope(null, angularService, {$window: {console:{log:log, warn:warn, info:info, error:error}}, $document:[{cookie:''}]});
scope.$log.log();
scope.$log.warn();
scope.$log.info();
@@ -48,8 +48,8 @@ describe("service", function(){
it('should use console.log if other not present', function(){
var logger = "";
- function log(){ logger+= 'log;'; };
- var scope = createScope(null, angularService, {$window: {console:{log:log}}, $document:[{}]});
+ function log(){ logger+= 'log;'; }
+ var scope = createScope(null, angularService, {$window: {console:{log:log}}, $document:[{cookie:''}]});
scope.$log.log();
scope.$log.warn();
scope.$log.info();
@@ -58,7 +58,7 @@ describe("service", function(){
});
it('should use noop if no console', function(){
- var scope = createScope(null, angularService, {$window: {}, $document:[{}]});
+ var scope = createScope(null, angularService, {$window: {}, $document:[{cookie:''}]});
scope.$log.log();
scope.$log.warn();
scope.$log.info();
@@ -247,7 +247,7 @@ describe("service", function(){
scope.$xhr('POST', '/req', 'MyData', callback);
xhr.flush();
var cb = $xhrError.mostRecentCall.args[0].callback;
- expect(typeof cb).toEqual('function');
+ expect(typeof cb).toEqual($function);
expect($xhrError).wasCalledWith(
{url:'/req', method:'POST', data:'MyData', callback:cb},
{status:500, body:'MyError'});
@@ -297,7 +297,7 @@ describe("service", function(){
expect($xhrError).wasCalled();
var cb = $xhrError.mostRecentCall.args[0].callback;
- expect(typeof cb).toEqual('function');
+ expect(typeof cb).toEqual($function);
expect($xhrError).wasCalledWith(
{url:'/req1', method:'GET', data:null, callback:cb},
{status:404, response:'NotFound'});
@@ -371,4 +371,95 @@ describe("service", function(){
});
+ describe('$cookies', function() {
+
+ it('should provide access to existing cookies via object properties', function(){
+ expect(scope.$cookies).toEqual({});
+
+ scope.$browser.cookies('brandNew', 'cookie');
+ //TODO: This is a hacky way of calling the watch function, once pooling is refactored, this will go away.
+ scope.$browser.watches[1](scope.$browser.cookies());
+
+ expect(scope.$cookies).toEqual({'brandNew':'cookie'});
+ });
+
+
+ it('should create or update a cookie when a value is assigned to a property', function() {
+ scope.$cookies.oatmealCookie = 'nom nom';
+ scope.$eval();
+
+ expect(scope.$browser.cookies()).toEqual({'oatmealCookie':'nom nom'});
+
+ scope.$cookies.oatmealCookie = 'gone';
+ scope.$eval();
+
+ expect(scope.$browser.cookies()).toEqual({'oatmealCookie':'gone'});
+ });
+
+
+ it('should turn non-string into String when creating a cookie', function() {
+ scope.$cookies.nonString = [1, 2, 3];
+ scope.$eval();
+ expect(scope.$browser.cookies()).toEqual({'nonString':'1,2,3'});
+ });
+
+
+ it('should drop any null or undefined properties', function() {
+ scope.$cookies.nullVal = null;
+ scope.$cookies.undefVal = undefined;
+ scope.$eval();
+
+ expect(scope.$browser.cookies()).toEqual({});
+ });
+
+
+ it('should remove a cookie when a $cookies property is deleted', function() {
+ scope.$cookies.oatmealCookie = 'nom nom';
+ scope.$eval();
+ expect(scope.$browser.cookies()).toEqual({'oatmealCookie':'nom nom'});
+
+ delete scope.$cookies.oatmealCookie;
+ scope.$eval();
+
+ expect(scope.$browser.cookies()).toEqual({});
+ });
+ });
+
+
+ describe('$sessionStore', function() {
+
+ it('should serialize objects to json', function() {
+ scope.$sessionStore.put('objectCookie', {id: 123, name: 'blah'});
+ scope.$eval();
+ expect(scope.$browser.cookies()).toEqual({'objectCookie': '{"id":123,"name":"blah"}'});
+ });
+
+
+ it('should return all persisted items as a has via getAll', function() {
+ expect(scope.$sessionStore.getAll()).toEqual({});
+
+ scope.$sessionStore.put('object1', {id:1,foo:'bar1'});
+ scope.$sessionStore.put('object2', {id:2,foo:'bar2'});
+
+ expect(scope.$sessionStore.getAll()).toEqual({'object1':{id:1,foo:'bar1'},
+ 'object2':{id:2,foo:'bar2'}});
+ });
+
+
+ it('should deserialize json to object', function() {
+ scope.$browser.cookies('objectCookie', '{"id":123,"name":"blah"}');
+ //TODO: This is a hacky way of calling the watch function, once pooling is refactored, this will go away.
+ scope.$browser.watches[1](scope.$browser.cookies());
+ expect(scope.$sessionStore.get('objectCookie')).toEqual({id: 123, name: 'blah'});
+ });
+
+
+ it('should delete objects from the store when remove is called', function() {
+ scope.$sessionStore.put('gonner', { "I'll":"Be Back"});
+ // TODO: Is this $eval necessary (why was it not here before?)
+ scope.$eval();
+ expect(scope.$browser.cookies()).toEqual({'gonner': '{"I\'ll":"Be Back"}'});
+ });
+
+ });
});
diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js
index e9a88b67..bbe2876e 100644
--- a/test/testabilityPatch.js
+++ b/test/testabilityPatch.js
@@ -178,9 +178,18 @@ error = noop;
function click(element) {
element = jqLite(element);
- if ( msie &&
- nodeName(element) == 'INPUT' && (lowercase(element.attr('type')) == 'radio' || lowercase(element.attr('type')) == 'checkbox')) {
- element[0].checked = ! element[0].checked;
+ var type = lowercase(element.attr('type'));
+ var name = lowercase(nodeName(element));
+ if (msie) {
+ if (name == 'input') {
+ if (type == 'radio' || type == 'checkbox') {
+ element[0].checked = ! element[0].checked;
+ }
+ }
+ }
+ if (name == 'option') {
+ JQLite.prototype.trigger.call(element.parent(), 'change');
+ } else {
+ JQLite.prototype.trigger.call(element, 'click');
}
- JQLite.prototype.trigger.call(element, 'click');
}
diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js
index 0e9b52ce..3861ef4f 100644
--- a/test/widgetsSpec.js
+++ b/test/widgetsSpec.js
@@ -338,17 +338,35 @@ describe("widget", function(){
});
- it('should support type="select-one"', function(){
- compile(
- '<select name="selection">' +
- '<option>A</option>' +
- '<option selected>B</option>' +
+ describe('select-one', function(){
+ it('should initialize to selected', function(){
+ compile(
+ '<select name="selection">' +
+ '<option>A</option>' +
+ '<option selected>B</option>' +
'</select>');
- expect(scope.selection).toEqual('B');
- scope.selection = 'A';
- scope.$eval();
- expect(scope.selection).toEqual('A');
- expect(element[0].childNodes[0].selected).toEqual(true);
+ expect(scope.selection).toEqual('B');
+ scope.selection = 'A';
+ scope.$eval();
+ expect(scope.selection).toEqual('A');
+ expect(element[0].childNodes[0].selected).toEqual(true);
+ });
+
+ it('should honor the value field in option', function(){
+ compile(
+ '<select name="selection" ng:format="number">' +
+ '<option value="{{$index}}" ng:repeat="name in [\'A\', \'B\']">{{name}}</option>' +
+ '</select>');
+ // childNodes[0] is repeater
+ expect(scope.selection).toEqual(undefined);
+
+ click(element[0].childNodes[1]);
+ expect(scope.selection).toEqual(0);
+
+ scope.selection = 1;
+ scope.$eval();
+ expect(element[0].childNodes[2].selected).toEqual(true);
+ });
});
it('should support type="select-multiple"', function(){