diff options
| author | Misko Hevery | 2010-04-02 11:10:36 -0700 |
|---|---|---|
| committer | Misko Hevery | 2010-04-02 11:10:36 -0700 |
| commit | d717020911a350a5ea3c0a985c57d56c8fcad607 (patch) | |
| tree | 0b0a9f14cdfdcdf0dfb4c3fd607daf5ab9f9901d /src | |
| parent | 85f13d602e31424b2e2d18172872f14a24c31135 (diff) | |
| download | angular.js-d717020911a350a5ea3c0a985c57d56c8fcad607.tar.bz2 | |
widgets now work properly
Diffstat (limited to 'src')
| -rw-r--r-- | src/Angular.js | 8 | ||||
| -rw-r--r-- | src/Scope.js | 3 | ||||
| -rw-r--r-- | src/Widgets.js | 78 | ||||
| -rw-r--r-- | src/services.js | 42 |
4 files changed, 100 insertions, 31 deletions
diff --git a/src/Angular.js b/src/Angular.js index 5b5aa87b..4e3266eb 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -398,6 +398,14 @@ function parseKeyValue(keyValue) { return obj; } +function toKeyValue(obj) { + var parts = []; + foreach(obj, function(value, key){ + parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); + }); + return parts.length ? parts.join('&') : ''; +}; + function angularInit(config){ if (config.autobind) { compile(window.document, config).$init(); diff --git a/src/Scope.js b/src/Scope.js index ba86e24f..ae5bd384 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -102,6 +102,7 @@ function createScope(parent, Class) { instance = new Behavior(); extend(api, { + 'this': instance, $parent: parent, $bind: bind(instance, bind, instance), $get: bind(instance, getter, instance), @@ -162,7 +163,7 @@ function createScope(parent, Class) { behavior.$root = instance; behavior.$parent = instance; } - + (parent.$onEval || noop)(instance.$eval); Class.apply(instance, slice.call(arguments, 2, arguments.length)); return instance; diff --git a/src/Widgets.js b/src/Widgets.js index f172eae2..e42d981c 100644 --- a/src/Widgets.js +++ b/src/Widgets.js @@ -85,8 +85,8 @@ function optionsAccessor(scope, element) { function noopAccessor() { return { get: noop, set: noop }; } -var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, ''), - buttonWidget = inputWidget('click', noopAccessor, noopAccessor, undefined), +var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, initWidgetValue('')), + buttonWidget = inputWidget('click', noopAccessor, noopAccessor, noop), INPUT_TYPE = { 'text': textWidget, 'textarea': textWidget, @@ -96,29 +96,42 @@ var textWidget = inputWidget('keyup change', modelAccessor, valueAccessor, ''), 'submit': buttonWidget, 'reset': buttonWidget, 'image': buttonWidget, - 'checkbox': inputWidget('click', modelAccessor, checkedAccessor, false), - 'radio': inputWidget('click', modelAccessor, radioAccessor, undefined), - 'select-one': inputWidget('click', modelAccessor, valueAccessor, null), - 'select-multiple': inputWidget('click', modelAccessor, optionsAccessor, []) + 'checkbox': inputWidget('click', modelAccessor, checkedAccessor, initWidgetValue(false)), + 'radio': inputWidget('click', modelAccessor, radioAccessor, radioInit), + 'select-one': inputWidget('change', modelAccessor, valueAccessor, initWidgetValue(null)), + 'select-multiple': inputWidget('change', modelAccessor, optionsAccessor, initWidgetValue([])) // 'file': fileWidget??? }; -function inputWidget(events, modelAccessor, viewAccessor, initValue) { +function initWidgetValue(initValue) { + return function (model, view) { + var value = view.get() || copy(initValue); + if (isUndefined(model.get()) && isDefined(value)) + model.set(value); + }; +} + +function radioInit(model, view) { + var modelValue = model.get(), viewValue = view.get(); + if (isUndefined(modelValue)) model.set(null); + if (viewValue != null) model.set(viewValue); +} + +function inputWidget(events, modelAccessor, viewAccessor, initFn) { return function(element) { var scope = this, model = modelAccessor(scope, element), view = viewAccessor(scope, element), - action = element.attr('ng-change') || '', - value = view.get() || copy(initValue); - if (isUndefined(model.get()) && isDefined(value)) model.set(value); + action = element.attr('ng-change') || ''; + initFn(model, view); this.$eval(element.attr('ng-init')||''); element.bind(events, function(){ model.set(view.get()); scope.$tryEval(action, element); scope.$root.$eval(); - // if we have no initValue than we are just a button, + // if we have noop initFn than we are just a button, // therefore we want to prevent default action - return isDefined(initValue); + return initFn != noop; }); view.set(model.get()); scope.$watch(model.get, view.set); @@ -137,3 +150,44 @@ angularWidget('SELECT', function(element){ this.descend(true); return inputWidgetSelector.call(this, element); }); + + +angularWidget('INLINE', function(element){ + element.replaceWith(this.element("div")); + var compiler = this, + behavior = element.attr("behavior"), + template = element.attr("template"), + initExpr = element.attr("init"); + return function(boundElement){ + var scope = this; + boundElement.load(template, function(){ + var templateScope = compiler.compile(boundElement)(boundElement, scope); + templateScope.$tryEval(initExpr, boundElement); + templateScope.$init(); + }); + }; +}); + +angularWidget('INCLUDE', function(element){ + element.replaceWith(this.element("div")); + var matches = []; + element.find("INLINE").each(function(){ + matches.push({match: jQuery(this).attr("match"), element: jQuery(this)}); + }); + var compiler = this, + watchExpr = element.attr("watch"); + return function(boundElement){ + var scope = this; + this.$watch(watchExpr, function(value){ + foreach(matches, function(inline){ + if(inline.match == value) { + var template = inline.element.attr("template"); + boundElement.load(template, function(){ + var templateScope = compiler.compile(boundElement)(boundElement, scope); + templateScope.$init(); + }); + } + }); + }); + }; +}); diff --git a/src/services.js b/src/services.js index 5d235b32..fc12b22b 100644 --- a/src/services.js +++ b/src/services.js @@ -1,34 +1,40 @@ angularService("$window", bind(window, identity, window)); -var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.]+)(:([0-9]+))?([^\?#]+)?(\?([^#]*))((#([^\?]*))(\?([^\?]*))?)$/; +var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.]*)(:([0-9]+))?([^\?#]+)(\?([^#]*))?((#([^\?]*))?(\?([^\?]*))?)$/; +var DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21}; angularService("$location", function(){ var scope = this; function location(url){ if (isDefined(url)) { var match = URL_MATCH.exec(url); - dump(match); - location.href = url; - location.protocol = match[1]; - location.host = match[3]; - location.port = match[5]; - location.path = match[6]; - location.search = parseKeyValue(match[8]); - location.hash = match[9]; - location.hashPath = match[11]; - location.hashSearch = parseKeyValue(match[13]); - foreach(location, dump); + if (match) { + location.href = url; + location.protocol = match[1]; + location.host = match[3] || ''; + location.port = match[5] || DEFAULT_PORTS[location.href] || null; + location.path = match[6]; + location.search = parseKeyValue(match[8]); + location.hash = match[9]; + if (location.hash) location.hash = location.hash.substr(1); + location.hashPath = match[11] || ''; + location.hashSearch = parseKeyValue(match[13]); + } } - var params = []; - foreach(location.param, function(value, key){ - params.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); - }); - return (location.path ? location.path : '') + (params.length ? '?' + params.join('&') : ''); + var hashKeyValue = toKeyValue(location.hashSearch); + return location.href + + (location.hashPath ? location.hashPath : '') + + (hashKeyValue ? '?' + hashKeyValue : ''); }; this.$config.location.watch(function(url){ location(url); }); + location(this.$config.location.get()); this.$onEval(PRIORITY_LAST, function(){ - scope.$config.location.set(location()); + var href = location(); + if (href != location.href) { + scope.$config.location.set(location()); + location.href = href; + } }); return location; }); |
