diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Angular.js | 54 | ||||
| -rw-r--r-- | src/Resource.js | 117 | ||||
| -rw-r--r-- | src/Scope.js | 32 |
3 files changed, 172 insertions, 31 deletions
diff --git a/src/Angular.js b/src/Angular.js index 6cb3f602..9b3634be 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -20,22 +20,23 @@ if (typeof Node == 'undefined') { function noop() {} if (!window['console']) window['console']={'log':noop, 'error':noop}; -var consoleNode, msie, +var consoleNode, msie, jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy foreach = _.each, extend = _.extend, identity = _.identity, - angular = window['angular'] || (window['angular'] = {}), - angularValidator = angular['validator'] || (angular['validator'] = {}), - angularFilter = angular['filter'] || (angular['filter'] = {}), - angularFormatter = angular['formatter'] || (angular['formatter'] = {}), + angular = window['angular'] || (window['angular'] = {}), + angularValidator = angular['validator'] || (angular['validator'] = {}), + angularFilter = angular['filter'] || (angular['filter'] = {}), + angularFormatter = angular['formatter'] || (angular['formatter'] = {}), angularCallbacks = angular['callbacks'] || (angular['callbacks'] = {}), angularAlert = angular['alert'] || (angular['alert'] = function(){ - log(arguments); window.alert.apply(window, arguments); + log(arguments); window.alert.apply(window, arguments); }); +angular['copy'] = copy; var isVisible = isVisible || function (element) { - return jQuery(element).is(":visible"); + return jQuery(element).is(":visible"); } function log(a, b, c){ @@ -101,6 +102,29 @@ function isLeafNode (node) { } } +function copy(source, destination){ + if (!destination) { + if (!source) { + return source; + } else if (_.isArray(source)) { + return copy(source, []); + } else { + return copy(source, {}); + } + } else { + if (_.isArray(source)) { + while(destination.length) { + destination.pop(); + } + } else { + _(destination).each(function(value, key){ + delete destination[key]; + }); + } + return $.extend(true, destination, source); + } +}; + function setHtml(node, html) { if (isLeafNode(node)) { if (msie) { @@ -218,7 +242,7 @@ UrlWatcher.prototype = { }; pull(); }, - + set: function(url) { var existingURL = this.location.href; if (!existingURL.match(/#/)) @@ -227,7 +251,7 @@ UrlWatcher.prototype = { this.location.href = url; this.existingURL = url; }, - + get: function() { return window.location.href; } @@ -326,10 +350,10 @@ function wireAngular(element, config) { binder.entity(scope); binder.compile(); controlBar.bind(); - + //TODO: remove this code new PopUp(element).bind(); - + var self = _(exposeMethods(scope, { 'set': scope.set, 'get': scope.get, @@ -338,8 +362,8 @@ function wireAngular(element, config) { 'init':function(){ config['location']['listen'](_(binder.onUrlChange).bind(binder)); binder.parseAnchor(); - binder.executeInit(); - binder.updateView(); + binder.executeInit(); + binder.updateView(); return self; }, 'element':element[0], @@ -349,7 +373,7 @@ function wireAngular(element, config) { return self; } -angular['startUrlWatcher'] = function(){ +angular['startUrlWatcher'] = function(){ var watcher = new UrlWatcher(window['location']); watcher.watch(); return exposeMethods(watcher, {'listen':watcher.listen, 'set':watcher.set, 'get':watcher.get}); @@ -366,6 +390,6 @@ angular['compile'] = function(element, config) { configureLogging(config); configureJQueryPlugins(); - + return wireAngular(jQuery(element), config); }; diff --git a/src/Resource.js b/src/Resource.js new file mode 100644 index 00000000..c0c6d220 --- /dev/null +++ b/src/Resource.js @@ -0,0 +1,117 @@ +function Route(template, defaults) { + this.template = template = template + '#'; + this.defaults = defaults || {}; + var urlParams = this.urlParams = {}; + foreach(template.split(/\W/), function(param){ + if (param && template.match(new RegExp(":" + param + "\\W"))) { + urlParams[param] = true; + } + }); +} + +Route.prototype = { + url: function(params) { + var path = []; + var self = this; + var url = this.template; + params = params || {}; + foreach(this.urlParams, function(value, urlParam){ + var value = params[urlParam] || self.defaults[urlParam] || ""; + url = url.replace(new RegExp(":" + urlParam + "(\\W)"), value + "$1"); + }); + url = url.replace(/\/?#$/, ''); + var query = []; + foreach(params, function(value, key){ + if (!self.urlParams[key]) { + query.push(encodeURI(key) + '=' + encodeURI(value)); + } + }); + return url + (query.length ? '?' + query.join('&') : ''); + } +}; + +function ResourceFactory(xhr) { + this.xhr = xhr; +} + +ResourceFactory.DEFAULT_ACTIONS = { + 'get': {method:'GET'}, + 'save': {method:'POST'}, + 'query': {method:'GET', isArray:true}, + 'remove': {method:'DELETE'}, + 'delete': {method:'DELETE'} +}; + +ResourceFactory.prototype = { + route: function(url, idPaths, actions){ + var self = this; + var route = new Route(url); + actions = $.extend({}, ResourceFactory.DEFAULT_ACTIONS, actions); + function extractIds(data){ + var ids = {}; + foreach(idPaths, function(path, id){ + ids[id] = Scope.getter(data, path); + }); + return ids; + } + + function Resource(value){ + copy(value || {}, this); + }; + + foreach(actions, function(action, name){ + var isGet = action.method == 'GET'; + var isPost = action.method == 'POST'; + Resource[name] = function (a1, a2, a3) { + var params = {}; + var data; + var callback = noop; + switch(arguments.length) { + case 3: callback = a3; + case 2: + if (typeof a2 == 'function') { + callback = a2; + } else { + params = a1; + data = a2; + break; + } + case 1: if (isPost) data = a1; else params = a1; break; + case 0: break; + default: + throw "Expected between 0-3 arguments [params, data, callback], got " + arguments.length + " arguments." + } + + var value = action.isArray ? [] : new Resource(data); + self.xhr.method(action.method, route.url($.extend({}, action.params || {}, extractIds(data), params)), data, function(response) { + if (action.isArray) { + foreach(response, function(item){ + value.push(new Resource(item)); + }); + } else { + copy(response, value); + } + (callback||noop)(value); + }); + return value; + }; + + if (!isGet) { + Resource.prototype['$' + name] = function(a1, a2){ + var params = {}; + var callback = noop; + switch(arguments.length) { + case 2: params = a1, callback = a2; + case 1: if (typeof a1 == 'function') callback = a1; else params = a1; + case 0: break; + default: + throw "Expected between 1-3 arguments [params, data, callback], got " + arguments.length + " arguments." + } + Resource[name](params, this, callback); + }; + } + }); + return Resource; + } +}; + diff --git a/src/Scope.js b/src/Scope.js index 4de57dd2..daf4b36c 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -53,11 +53,11 @@ Scope.prototype = { }); }); }, - + addWidget: function(controller) { if (controller) this.widgets.push(controller); }, - + isProperty: function(exp) { for ( var i = 0; i < exp.length; i++) { var ch = exp.charAt(i); @@ -67,12 +67,12 @@ Scope.prototype = { } return true; }, - + get: function(path) { // log('SCOPE.get', path, Scope.getter(this.state, path)); return Scope.getter(this.state, path); }, - + set: function(path, value) { // log('SCOPE.set', path, value); var element = path.split('.'); @@ -89,11 +89,11 @@ Scope.prototype = { instance[element.shift()] = value; return value; }, - + setEval: function(expressionText, value) { this.eval(expressionText + "=" + toJson(value)); }, - + eval: function(expressionText, context) { // log('Scope.eval', expressionText); var expression = Scope.expressionCache[expressionText]; @@ -108,7 +108,7 @@ Scope.prototype = { context.self = this.state; return expression(context); }, - + //TODO: Refactor. This function needs to be an execution closure for widgets // move to widgets // remove expression, just have inner closure. @@ -126,8 +126,8 @@ Scope.prototype = { } return true; } catch (e){ - error('Eval Widget Error:', e); var jsonError = toJson(e, true); + error('Eval Widget Error:', jsonError); widget.hasError = true; jQuery(widget.view). addClass('ng-exception'). @@ -138,7 +138,7 @@ Scope.prototype = { return false; } }, - + validate: function(expressionText, value, element) { var expression = Scope.expressionCache[expressionText]; if (!expression) { @@ -148,21 +148,21 @@ Scope.prototype = { var self = {scope:this, self:this.state, '$element':element}; return expression(self)(self, value); }, - + entity: function(entityDeclaration, datastore) { var expression = new Parser(entityDeclaration).entityDeclaration(); return expression({scope:this, datastore:datastore}); }, - + clearInvalid: function() { var invalid = this.state['$invalidWidgets']; while(invalid.length > 0) {invalid.pop();} }, - + markInvalid: function(widget) { this.state['$invalidWidgets'].push(widget); }, - + watch: function(declaration) { var self = this; new Parser(declaration).watch()({ @@ -178,7 +178,7 @@ Scope.prototype = { } }); }, - + addWatchListener: function(watchExpression, listener) { var watcher = this.watchListeners[watchExpression]; if (!watcher) { @@ -187,7 +187,7 @@ Scope.prototype = { } watcher.listeners.push(listener); }, - + fireWatchers: function() { var self = this; var fired = false; @@ -203,4 +203,4 @@ Scope.prototype = { }); return fired; } -};
\ No newline at end of file +}; |
