From 522ec1a9ec10e1fece3e5e855c1d7ef9770a8efc Mon Sep 17 00:00:00 2001
From: Igor Minar
Date: Wed, 17 Nov 2010 22:32:35 -0800
Subject: move attribute widgets to widgets.js file
- move @ng:repeat to widgets.js and its specs to widgetsSpecs.js
- move @ng:non-bindable to widgets.js and its specs to widgetsSpecs.js
- make widget.template suitable for attribute widgets
- fix up the js docs for attribute widgets
---
src/directives.js | 154 ----------------------------------------------------
src/widgets.js | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 158 insertions(+), 156 deletions(-)
(limited to 'src')
diff --git a/src/directives.js b/src/directives.js
index 2958773d..d47d993d 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -378,160 +378,6 @@ angularDirective("ng:bind-attr", function(expression){
};
});
-/**
- * @ngdoc directive
- * @name angular.directive.ng:non-bindable
- *
- * @description
- * Sometimes it is necessary to write code which looks like
- * bindings but which should be left alone by .
- * Use `ng:non-bindable` to ignore a chunk of HTML.
- *
- * @element ANY
- * @param {string} ignore
- *
- * @exampleDescription
- * In this example there are two location where
- * {{1 + 2}} is present, but the one
- * wrapped in `ng:non-bindable` is left alone
- * @example
-
Normal: {{1 + 2}}
- Ignored: {{1 + 2}}
- *
- * @scenario
- it('should check ng:non-bindable', function(){
- expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
- expect(using('.doc-example-live').element('div:last').text()).
- toMatch(/1 \+ 2/);
- });
- */
-angularWidget("@ng:non-bindable", noop);
-
-/**
- * @ngdoc directive
- * @name angular.directive.ng:repeat
- *
- * @description
- * `ng:repeat` instantiates a template once per item from a
- * collection. The collection is enumerated with
- * `ng:repeat-index` attribute starting from 0. Each template
- * instance gets its own scope where the given loop variable
- * is set to the current collection item and `$index` is set
- * to the item index or key.
- *
- * NOTE: `ng:repeat` looks like a directive, but is actually a
- * attribute widget.
- *
- * @element ANY
- * @param {repeat} repeat_expression to itterate over.
- *
- * * `variable in expression`, where variable is the user
- * defined loop variable and expression is a scope expression
- * giving the collection to enumerate. For example:
- * `track in cd.tracks`.
- * * `(key, value) in expression`, where key and value can
- * be any user defined identifiers, and expression is the
- * scope expression giving the collection to enumerate.
- * For example: `(name, age) in {'adam':10, 'amalie':12}`.
- *
- * Special properties set on the local scope:
- * * {number} $index - iterator offset of the repeated element (0..length-1)
- * * {string} $position - position of the repeated element in the iterator ('first', 'middle', 'last')
- *
- * @exampleDescription
- * This example initializes the scope to a list of names and
- * than uses `ng:repeat` to display every person.
- * @example
-
- I have {{friends.length}} friends. They are:
-
- -
- [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
-
-
-
- * @scenario
- it('should check ng:repeat', function(){
- var r = using('.doc-example-live').repeater('ul li');
- expect(r.count()).toBe(2);
- expect(r.row(0)).toEqual(["1","John","25"]);
- expect(r.row(1)).toEqual(["2","Mary","28"]);
- });
- */
-angularWidget("@ng:repeat", function(expression, element){
- element.removeAttr('ng:repeat');
- element.replaceWith(this.comment("ng:repeat: " + expression));
- var template = this.compile(element);
- return function(reference){
- var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
- lhs, rhs, valueIdent, keyIdent;
- if (! match) {
- throw Error("Expected ng:repeat in form of 'item in collection' but got '" +
- expression + "'.");
- }
- lhs = match[1];
- rhs = match[2];
- match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
- if (!match) {
- throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
- keyValue + "'.");
- }
- valueIdent = match[3] || match[1];
- keyIdent = match[2];
-
- var children = [], currentScope = this;
- this.$onEval(function(){
- var index = 0,
- childCount = children.length,
- lastElement = reference,
- collection = this.$tryEval(rhs, reference),
- is_array = isArray(collection),
- collectionLength = 0,
- childScope,
- key;
-
- if (is_array) {
- collectionLength = collection.length;
- } else {
- for (key in collection)
- if (collection.hasOwnProperty(key))
- collectionLength++;
- }
-
- for (key in collection) {
- if (!is_array || collection.hasOwnProperty(key)) {
- if (index < childCount) {
- // reuse existing child
- childScope = children[index];
- childScope[valueIdent] = collection[key];
- if (keyIdent) childScope[keyIdent] = key;
- } else {
- // grow children
- childScope = template(quickClone(element), createScope(currentScope));
- childScope[valueIdent] = collection[key];
- if (keyIdent) childScope[keyIdent] = key;
- lastElement.after(childScope.$element);
- childScope.$index = index;
- childScope.$position = index == 0 ?
- 'first' :
- (index == collectionLength - 1 ? 'last' : 'middle');
- childScope.$element.attr('ng:repeat-index', index);
- childScope.$init();
- children.push(childScope);
- }
- childScope.$eval();
- lastElement = childScope.$element;
- index ++;
- }
- }
- // shrink children
- while(children.length > index) {
- children.pop().$element.remove();
- }
- }, reference);
- };
-});
-
/**
* @ngdoc directive
diff --git a/src/widgets.js b/src/widgets.js
index 887b31ac..930a6788 100644
--- a/src/widgets.js
+++ b/src/widgets.js
@@ -691,7 +691,7 @@ var ngSwitch = angularWidget('ng:switch', function (element){
* changing the location or causing page reloads, e.g.:
* Save
*/
-angular.widget('a', function() {
+angularWidget('a', function() {
this.descend(true);
this.directives(true);
@@ -702,4 +702,160 @@ angular.widget('a', function() {
});
}
};
-});
\ No newline at end of file
+});
+
+
+/**
+ * @ngdoc widget
+ * @name angular.widget.@ng:repeat
+ *
+ * @description
+ * `ng:repeat` instantiates a template once per item from a collection. The collection is enumerated
+ * with `ng:repeat-index` attribute starting from 0. Each template instance gets its own scope where
+ * the given loop variable is set to the current collection item and `$index` is set to the item
+ * index or key.
+ *
+ * There are special properties exposed on the local scope of each template instance:
+ *
+ * * `$index` – `{number}` – iterator offset of the repeated element (0..length-1)
+ * * `$position` – {string} – position of the repeated element in the iterator. One of: `'first'`,
+ * `'middle'` or `'last'`.
+ *
+ * NOTE: `ng:repeat` looks like a directive, but is actually an attribute widget.
+ *
+ * @element ANY
+ * @param {string} repeat_expression The expression indicating how to enumerate a collection. Two
+ * formats are currently supported:
+ *
+ * * `variable in expression` – where variable is the user defined loop variable and `expression`
+ * is a scope expression giving the collection to enumerate.
+ *
+ * For example: `track in cd.tracks`.
+ * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
+ * and `expression` is the scope expression giving the collection to enumerate.
+ *
+ * For example: `(name, age) in {'adam':10, 'amalie':12}`.
+ *
+ * @exampleDescription
+ * This example initializes the scope to a list of names and
+ * than uses `ng:repeat` to display every person.
+ * @example
+
+ I have {{friends.length}} friends. They are:
+
+ -
+ [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
+
+
+
+ * @scenario
+ it('should check ng:repeat', function(){
+ var r = using('.doc-example-live').repeater('ul li');
+ expect(r.count()).toBe(2);
+ expect(r.row(0)).toEqual(["1","John","25"]);
+ expect(r.row(1)).toEqual(["2","Mary","28"]);
+ });
+ */
+angularWidget("@ng:repeat", function(expression, element){
+ element.removeAttr('ng:repeat');
+ element.replaceWith(this.comment("ng:repeat: " + expression));
+ var template = this.compile(element);
+ return function(reference){
+ var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
+ lhs, rhs, valueIdent, keyIdent;
+ if (! match) {
+ throw Error("Expected ng:repeat in form of 'item in collection' but got '" +
+ expression + "'.");
+ }
+ lhs = match[1];
+ rhs = match[2];
+ match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
+ if (!match) {
+ throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
+ keyValue + "'.");
+ }
+ valueIdent = match[3] || match[1];
+ keyIdent = match[2];
+
+ var children = [], currentScope = this;
+ this.$onEval(function(){
+ var index = 0,
+ childCount = children.length,
+ lastElement = reference,
+ collection = this.$tryEval(rhs, reference),
+ is_array = isArray(collection),
+ collectionLength = 0,
+ childScope,
+ key;
+
+ if (is_array) {
+ collectionLength = collection.length;
+ } else {
+ for (key in collection)
+ if (collection.hasOwnProperty(key))
+ collectionLength++;
+ }
+
+ for (key in collection) {
+ if (!is_array || collection.hasOwnProperty(key)) {
+ if (index < childCount) {
+ // reuse existing child
+ childScope = children[index];
+ childScope[valueIdent] = collection[key];
+ if (keyIdent) childScope[keyIdent] = key;
+ } else {
+ // grow children
+ childScope = template(quickClone(element), createScope(currentScope));
+ childScope[valueIdent] = collection[key];
+ if (keyIdent) childScope[keyIdent] = key;
+ lastElement.after(childScope.$element);
+ childScope.$index = index;
+ childScope.$position = index == 0 ?
+ 'first' :
+ (index == collectionLength - 1 ? 'last' : 'middle');
+ childScope.$element.attr('ng:repeat-index', index);
+ childScope.$init();
+ children.push(childScope);
+ }
+ childScope.$eval();
+ lastElement = childScope.$element;
+ index ++;
+ }
+ }
+ // shrink children
+ while(children.length > index) {
+ children.pop().$element.remove();
+ }
+ }, reference);
+ };
+});
+
+
+/**
+ * @ngdoc widget
+ * @name angular.widget.@ng:non-bindable
+ *
+ * @description
+ * Sometimes it is necessary to write code which looks like bindings but which should be left alone
+ * by angular. Use `ng:non-bindable` to make angular ignore a chunk of HTML.
+ *
+ * NOTE: `ng:non-bindable` looks like a directive, but is actually an attribute widget.
+ *
+ * @element ANY
+ *
+ * @exampleDescription
+ * In this example there are two location where a siple binding (`{{}}`) is present, but the one
+ * wrapped in `ng:non-bindable` is left alone.
+ *
+ * @example
+ Normal: {{1 + 2}}
+ Ignored: {{1 + 2}}
+ *
+ * @scenario
+ it('should check ng:non-bindable', function(){
+ expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
+ expect(using('.doc-example-live').element('div:last').text()).
+ toMatch(/1 \+ 2/);
+ });
+ */
+angularWidget("@ng:non-bindable", noop);
--
cgit v1.2.3