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 +};  | 
