aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMisko Hevery2010-03-31 17:56:16 -0700
committerMisko Hevery2010-03-31 17:56:16 -0700
commit861bac1d2808b15abb867e761ded8144bf5f7e94 (patch)
treec7acd3aba0caeddf14a77c538487cf2baff9d96a /src
parent35a91085004e31f786df1e0011bc26ed0142ab4d (diff)
downloadangular.js-861bac1d2808b15abb867e761ded8144bf5f7e94.tar.bz2
started to add services
Diffstat (limited to 'src')
-rw-r--r--src/Angular.js71
-rw-r--r--src/Compiler.js1
-rw-r--r--src/Parser.js4
-rw-r--r--src/Scope.js55
-rw-r--r--src/UrlWatcher.js40
-rw-r--r--src/services.js34
6 files changed, 139 insertions, 66 deletions
diff --git a/src/Angular.js b/src/Angular.js
index db177082..8eef6ac0 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -4,6 +4,9 @@ if (typeof document.getAttribute == 'undefined')
if (!window['console']) window['console']={'log':noop, 'error':noop};
var consoleNode,
+ PRIORITY_FIRST = -99999;
+ PRIORITY_WATCH = -1000;
+ PRIORITY_LAST = 99999;
NOOP = 'noop',
NG_ERROR = 'ng-error',
NG_EXCEPTION = 'ng-exception',
@@ -21,11 +24,30 @@ var consoleNode,
angularValidator = extensionMap(angular, 'validator'),
angularFilter = extensionMap(angular, 'filter'),
angularFormatter = extensionMap(angular, 'formatter'),
+ angularService = extensionMap(angular, 'service'),
angularCallbacks = extensionMap(angular, 'callbacks'),
- angularAlert = angular['alert'] || (angular['alert'] = function(){
- log(arguments); window.alert.apply(window, arguments);
- });
-angular['copy'] = copy;
+ urlWatcher = new UrlWatcher(window.location);
+
+function angularAlert(){
+ log(arguments); window.alert.apply(window, arguments);
+};
+
+extend(angular, {
+ 'compile': compile,
+ 'startUrlWatch': bind(urlWatcher, urlWatcher.start),
+ 'copy': copy,
+ 'extend': extend,
+ 'foreach': foreach,
+ 'noop':noop,
+ 'identity':identity,
+ 'isUndefined': isUndefined,
+ 'isDefined': isDefined,
+ 'isString': isString,
+ 'isFunction': isFunction,
+ 'isNumber': isNumber,
+ 'isArray': isArray,
+ 'alert': angularAlert
+});
function foreach(obj, iterator, context) {
var key;
@@ -43,6 +65,17 @@ function foreach(obj, iterator, context) {
return obj;
}
+function foreachSorted(obj, iterator, context) {
+ var keys = [];
+ for (var key in obj) keys.push(key);
+ keys.sort();
+ for ( var i = 0; i < keys.length; i++) {
+ iterator.call(context, obj[keys[i]], keys[i]);
+ }
+ return keys;
+}
+
+
function extend(dst) {
foreach(arguments, function(obj){
if (obj !== dst) {
@@ -285,19 +318,21 @@ function merge(src, dst) {
}
}
-/////////////////////////////////////////////////
-
-angular['compile'] = function(element, config) {
- config = extend({
- 'onUpdateView': noop,
- 'server': "",
- 'location': {'get':noop, 'set':noop, 'listen':noop}
- }, config||{});
-
+function compile(element, config) {
var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget);
$element = jqLite(element),
- rootScope = {
- '$window': window
- };
- return rootScope['$root'] = compiler.compile($element)($element, rootScope);
-};
+ rootScope = createScope({
+ $element: $element,
+ $config: extend({
+ 'onUpdateView': noop,
+ 'server': "",
+ 'location': {
+ 'get':bind(urlWatcher, urlWatcher.get),
+ 'set':bind(urlWatcher, urlWatcher.set),
+ 'watch':bind(urlWatcher, urlWatcher.watch)
+ }
+ }, config || {})
+ }, serviceAdapter(angularService));
+ return compiler.compile($element)($element, rootScope);
+}
+/////////////////////////////////////////////////
diff --git a/src/Compiler.js b/src/Compiler.js
index 361d6946..c9039928 100644
--- a/src/Compiler.js
+++ b/src/Compiler.js
@@ -65,7 +65,6 @@ Compiler.prototype = {
element = jqLite(element);
parentScope = parentScope || {};
var scope = createScope(parentScope);
- parentScope.$root = parentScope.$root || scope;
return extend(scope, {
$element:element,
$init: function() {
diff --git a/src/Parser.js b/src/Parser.js
index ef1465a0..ec58295a 100644
--- a/src/Parser.js
+++ b/src/Parser.js
@@ -11,8 +11,8 @@ Lexer.OPERATORS = {
'true':function(self){return true;},
'false':function(self){return false;},
'undefined':noop,
- '+':function(self, a,b){return (a||0)+(b||0);},
- '-':function(self, a,b){return (a||0)-(b||0);},
+ '+':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;},
'/':function(self, a,b){return a/b;},
'%':function(self, a,b){return a%b;},
diff --git a/src/Scope.js b/src/Scope.js
index 4144d456..ba86e24f 100644
--- a/src/Scope.js
+++ b/src/Scope.js
@@ -89,7 +89,11 @@ function createScope(parent, Class) {
function API(){}
function Behavior(){}
- var instance, behavior, api, watchList = [], evalList = [];
+ var instance, behavior, api, evalLists = {};
+ if (isFunction(parent)) {
+ Class = parent;
+ parent = {};
+ }
Class = Class || noop;
parent = Parent.prototype = parent || {};
@@ -107,15 +111,10 @@ function createScope(parent, Class) {
if (isDefined(exp)) {
return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length));
} else {
- foreach(watchList, function(watch) {
- var value = instance.$tryEval(watch.watch, watch.handler);
- if (watch.last !== value) {
- instance.$tryEval(watch.listener, watch.handler, value, watch.last);
- watch.last = value;
- }
- });
- foreach(evalList, function(eval) {
- instance.$tryEval(eval.fn, eval.handler);
+ foreachSorted(evalLists, function(list) {
+ foreach(list, function(eval) {
+ instance.$tryEval(eval.fn, eval.handler);
+ });
});
}
},
@@ -134,16 +133,24 @@ function createScope(parent, Class) {
},
$watch: function(watchExp, listener, exceptionHandler) {
- var watch = expressionCompile(watchExp);
- watchList.push({
- watch: watch,
- last: watch.call(instance),
- handler: exceptionHandler,
- listener:expressionCompile(listener)
+ var watch = expressionCompile(watchExp),
+ last = watch.call(instance);
+ instance.$onEval(PRIORITY_WATCH, function(){
+ var value = watch.call(instance);
+ if (last !== value) {
+ instance.$tryEval(listener, exceptionHandler, value, last);
+ last = value;
+ }
});
},
- $onEval: function(expr, exceptionHandler){
+ $onEval: function(priority, expr, exceptionHandler){
+ if (!isNumber(priority)) {
+ exceptionHandler = expr;
+ expr = priority;
+ priority = 0;
+ }
+ var evalList = evalLists[priority] || (evalLists[priority] = []);
evalList.push({
fn: expressionCompile(expr),
handler: exceptionHandler
@@ -151,7 +158,21 @@ function createScope(parent, Class) {
}
});
+ if (isUndefined(instance.$root)) {
+ behavior.$root = instance;
+ behavior.$parent = instance;
+ }
+
Class.apply(instance, slice.call(arguments, 2, arguments.length));
return instance;
}
+
+function serviceAdapter(services) {
+ return function(){
+ var self = this;
+ foreach(services, function(service, name){
+ self[name] = service.call(self);
+ });
+ };
+};
diff --git a/src/UrlWatcher.js b/src/UrlWatcher.js
index 0892eb1a..1b2a9cf0 100644
--- a/src/UrlWatcher.js
+++ b/src/UrlWatcher.js
@@ -9,42 +9,26 @@ function UrlWatcher(location) {
this.setTimeout = function(fn, delay) {
window.setTimeout(fn, delay);
};
- this.listener = function(url) {
- return url;
- };
this.expectedUrl = location.href;
+ this.listeners = [];
}
UrlWatcher.prototype = {
- listen: function(fn){
- this.listener = fn;
+ watch: function(fn){
+ this.listeners.push(fn);
},
- watch: function() {
+
+ start: function() {
var self = this;
- var pull = function() {
+ (function pull () {
if (self.expectedUrl !== self.location.href) {
- var notify = self.location.hash.match(/^#\$iframe_notify=(.*)$/);
- if (notify) {
- if (!self.expectedUrl.match(/#/)) {
- self.expectedUrl += "#";
- }
- self.location.href = self.expectedUrl;
- var id = '_iframe_notify_' + notify[1];
- var notifyFn = angularCallbacks[id];
- delete angularCallbacks[id];
- try {
- (notifyFn||noop)();
- } catch (e) {
- alert(e);
- }
- } else {
- self.listener(self.location.href);
- self.expectedUrl = self.location.href;
- }
+ foreach(self.listeners, function(listener){
+ listener(self.location.href);
+ });
+ self.expectedUrl = self.location.href;
}
self.setTimeout(pull, self.delay);
- };
- pull();
+ })();
},
set: function(url) {
@@ -57,6 +41,6 @@ UrlWatcher.prototype = {
},
get: function() {
- return window.location.href;
+ return this.location.href;
}
};
diff --git a/src/services.js b/src/services.js
new file mode 100644
index 00000000..14c71363
--- /dev/null
+++ b/src/services.js
@@ -0,0 +1,34 @@
+angularService("$window", bind(window, identity, window));
+
+angularService("$anchor", function(){
+ var scope = this;
+ function anchor(url){
+ if (isDefined(url)) {
+ if (url.charAt(0) == '#') url = url.substr(1);
+ var pathQuery = url.split('?');
+ anchor.path = decodeURIComponent(pathQuery[0]);
+ anchor.param = {};
+ foreach((pathQuery[1] || "").split('&'), function(keyValue){
+ if (keyValue) {
+ var parts = keyValue.split('=');
+ var key = decodeURIComponent(parts[0]);
+ var value = parts[1];
+ if (!value) value = true;
+ anchor.param[key] = decodeURIComponent(value);
+ }
+ });
+ }
+ var params = [];
+ foreach(anchor.param, function(value, key){
+ params.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
+ });
+ return (anchor.path ? anchor.path : '') + (params.length ? '?' + params.join('&') : '');
+ };
+ this.$config.location.watch(function(url){
+ anchor(url);
+ });
+ this.$onEval(PRIORITY_LAST, function(){
+ scope.$config.location.set(anchor());
+ });
+ return anchor;
+});