Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 309486d

Browse files
committed
Declared global vars, removed a lot of unnecessary code, got the $observe working, got karma working, started working on the tests.
1 parent 4b4bbfb commit 309486d

File tree

5 files changed

+87
-189
lines changed

5 files changed

+87
-189
lines changed

angularFiles.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ angularFiles = {
5353
'src/ng/directive/ngController.js',
5454
'src/ng/directive/ngCsp.js',
5555
'src/ng/directive/ngEventDirs.js',
56+
'src/ng/directive/ngId.js',
5657
'src/ng/directive/ngIf.js',
5758
'src/ng/directive/ngInclude.js',
5859
'src/ng/directive/ngInit.js',

src/AngularPublic.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
ngControllerDirective,
2727
ngFormDirective,
2828
ngHideDirective,
29+
ngIdDirective,
2930
ngIfDirective,
3031
ngIncludeDirective,
3132
ngIncludeFillContentDirective,
@@ -166,6 +167,7 @@ function publishExternalAPI(angular){
166167
ngController: ngControllerDirective,
167168
ngForm: ngFormDirective,
168169
ngHide: ngHideDirective,
170+
ngId: ngIdDirective,
169171
ngIf: ngIfDirective,
170172
ngInclude: ngIncludeDirective,
171173
ngInit: ngInitDirective,

src/ng/directive/ngId.js

Lines changed: 54 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,52 @@
11
'use strict';
22

3-
function idDirective(name, selector) {
4-
name = 'ngId' + name;
5-
return ['$animate', function($animate) {
3+
function idDirective() {
4+
return function() {
65
return {
7-
restrict: 'A',
86
link: function(scope, element, attr) {
9-
var oldVal;
7+
var oldVal = attr['id'] ? attr['id'] : null ;
108

11-
scope.$watch(attr[name], ngIdWatchAction, true);
9+
scope.$watch(attr['ngId'], ngIdWatchAction, true);
1210

1311
attr.$observe('id', function(value) {
14-
ngIdWatchAction(scope.$eval(attr[name]));
12+
ngIdWatchAction(scope.$eval(attr['ngId']));
1513
});
1614

1715

18-
if (name !== 'ngId') {
19-
scope.$watch('$index', function($index, old$index) {
20-
// jshint bitwise: false
21-
var mod = $index & 1;
22-
if (mod !== old$index & 1) {
23-
var id = typeofId(scope.$eval(attr[name]));
24-
if (mod === selector) {
25-
replaceId(id);
26-
}
27-
}
28-
});
29-
}
30-
31-
// Used in place of addClass and removeClass, as it must be unique.
32-
function replaceId(id) {
33-
attr.$attr('id', id)
34-
}
35-
36-
// New
37-
function uniqueId(id) {
38-
/* Check if the id is unique throughout the view
39-
* Should search $index for the ID.
40-
*/
41-
}
42-
43-
// This is the joining function. This shouldn't exist
44-
// function digestIdCounts (ids, count) {
45-
// var idCounts = element.data('$idCounts') || {};
46-
// var idsToUpdate = [];
47-
// forEach(ids, function (idName) {
48-
// if (count > 0 || idCounts[idName]) {
49-
// idCounts[idName] = (idCounts[idName] || 0) + count;
50-
// if (idCounts[idName] === +(count > 0)) {
51-
// idsToUpdate.push(idName);
52-
// }
53-
// }
54-
// });
55-
// element.data('$idCounts', idCounts);
56-
// return idsToUpdate.join(' ');
57-
// }
58-
59-
//function updateClasses (oldClasses, newClasses) {
60-
// var toAdd = arrayDifference(newClasses, oldClasses);
61-
// var toRemove = arrayDifference(oldClasses, newClasses);
62-
// toRemove = digestClassCounts(toRemove, -1);
63-
// toAdd = digestClassCounts(toAdd, 1);
64-
65-
// if (toAdd.length === 0) {
66-
// $animate.removeClass(element, toRemove);
67-
// } else if (toRemove.length === 0) {
68-
// $animate.addClass(element, toAdd);
69-
// } else {
70-
// $animate.setClass(element, toAdd, toRemove);
71-
// }
72-
// }
73-
7416
function ngIdWatchAction(newVal) {
75-
if (selector === true || scope.$index % 2 === selector) {
76-
var newId = typeofId(newVal || []);
77-
if (!oldVal) {
78-
addId(newId);
79-
} else if (!equals(newVal,oldVal)) {
80-
var oldId = typeofId(oldVal);
81-
updateId(oldId, newId);
82-
}
17+
var newId = typeofId(newVal || []);
18+
if (!newId && !oldVal) {
19+
console.log('Removing id');
20+
element.removeAttr('id');
21+
} else if (!newId && oldVal) {
22+
console.log('Setting to old id:', oldVal, typeof(oldVal));
23+
element.attr('id', oldVal);
24+
} else {
25+
console.log('Setting to newId:', newVal, typeof(newVal))
26+
element.attr('id', newId);
8327
}
84-
oldVal = copy(newVal);
85-
}
28+
};
8629
}
8730
};
8831

89-
function arrayDifference(tokens1, tokens2) {
90-
var values = [];
91-
92-
outer:
93-
for(var i = 0; i < tokens1.length; i++) {
94-
var token = tokens1[i];
95-
for(var j = 0; j < tokens2.length; j++) {
96-
if(token == tokens2[j]) continue outer;
97-
}
98-
values.push(token);
99-
}
100-
return values;
101-
}
102-
10332
function typeofId (idVal) {
104-
//if (isArray(classVal)) {
105-
// return classVal;
106-
//} else if (isString(classVal)) {
10733
if (isString(idVal)) {
34+
if (idVal.split(' ').length > 0) {
35+
return idVal.split(' ')[0];
36+
}
10837
return idVal;
10938
} else if (isObject(idVal)) {
11039
var ids = [], i = 0;
11140
forEach(idVal, function(v, k) {
112-
// This should push for all classes. That isn't ideal.
113-
// We want it to only push for one.
11441
if (v) {
11542
ids.push(k);
116-
// This should make it break after the first truthy value.
117-
return ids;
11843
}
11944
});
120-
return ids;
45+
return ids[0];
12146
}
12247
return idVal;
123-
}
124-
}];
48+
};
49+
};
12550
}
12651

12752
/**
@@ -136,139 +61,79 @@ function idDirective(name, selector) {
13661
* The directive operates in two different ways, depending on which of two types the expression
13762
* evaluates to:
13863
*
139-
* 1. If the expression evaluates to a string, the string should be one, unique id.
64+
* 1. If the expression evaluates to a string, the string should be one id. If the string has multiple
65+
* space-delimited ids, the first id is returned.
14066
*
141-
* 2. If the expression evaluates to an object, then for each key-value pair of the
142-
* object with a truthy value the corresponding key is used as an id.
67+
* 2. If the expression evaluates to an object, then the key for the first key-value pair in the object
68+
* to evaluate with a truthy value is used as an id.
14369
*
144-
* If the specified value evaluates as truthy, and there is already an existing id on that element,
145-
* it will overwrite that id.
70+
* If there is already an existing id on that element, it will overwrite that id (if the specified key
71+
* value pair is truthy, or if a valid string is used). When the expression changes, the previous id is
72+
* set as the element attribute again. If there was no original id, and the expression does not evaluate
73+
* as truthy, the id attribute is removed.
14674
*
147-
* If the specified value evaluates as truthy, but there is already an id or name set elsewhere with the same
148-
* value, it will not apply the id attribute, unless the name attribute is in the same element, and the element
149-
* in question is either: `A`, `APPLET`, `FORM`, `FRAME`, `IFRAME`, `IMG`, or `MAP`.
150-
*
151-
* When the expression changes, the previously added id is removed and only then is the
152-
* new id added.
153-
*
154-
* @animations
155-
* add - happens just before the class is applied to the element
156-
* remove - happens just before the class is removed from the element
75+
* If there is already an id or name set elsewhere with the same value, it will apply the id attribute,
76+
* which may result in invalid HTML.
15777
*
15878
* @element ANY
15979
* @param {expression} ngId {@link guide/expression Expression} to eval. The result
160-
* of the evaluation can be a string with a single id name, or a map of unique id names
161-
* to boolean values. In the case of a map, the names of the property whose value
162-
* is truthy will be added as css id to the element.
163-
*
164-
* // Edited up to here.
80+
* of the evaluation can be a string with a single id name, or a map of id names
81+
* to boolean values. In the case of a map, the name of the first property whose value
82+
* to evaluate as truthy will be added as css id to the element.
16583
*
16684
* @example Example that demonstrates basic bindings via ngClass directive.
16785
<example>
16886
<file name="index.html">
169-
<p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
170-
<input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
171-
<input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
172-
<input type="checkbox" ng-model="error"> error (apply "red" class)
87+
<p ng-id="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
88+
<input type="checkbox" ng-model="deleted"> deleted (apply "strike" id)<br>
89+
<input type="checkbox" ng-model="important"> important (apply "bold" id)<br>
90+
<input type="checkbox" ng-model="error"> error (apply "red" id)
17391
<hr>
174-
<p ng-class="style">Using String Syntax</p>
92+
<p ng-id="style">Using String Syntax</p>
17593
<input type="text" ng-model="style" placeholder="Type: bold strike red">
176-
<hr>
177-
<p ng-class="[style1, style2, style3]">Using Array Syntax</p>
178-
<input ng-model="style1" placeholder="Type: bold, strike or red"><br>
179-
<input ng-model="style2" placeholder="Type: bold, strike or red"><br>
180-
<input ng-model="style3" placeholder="Type: bold, strike or red"><br>
18194
</file>
18295
<file name="style.css">
183-
.strike {
96+
#strike {
18497
text-decoration: line-through;
18598
}
186-
.bold {
187-
font-weight: bold;
99+
#bold {
100+
font-weight: bold;
188101
}
189-
.red {
190-
color: red;
102+
#red {
103+
color: red;
191104
}
192105
</file>
193106
<file name="protractor.js" type="protractor">
194107
var ps = element.all(by.css('p'));
195108
196-
it('should let you toggle the class', function() {
109+
it('should let you toggle the id', function() {
197110
198-
expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
199-
expect(ps.first().getAttribute('class')).not.toMatch(/red/);
111+
expect(ps.first().getAttribute('id')).not.toMatch(/bold/);
112+
expect(ps.first().getAttribute('id')).not.toMatch(/red/);
200113
201114
element(by.model('important')).click();
202-
expect(ps.first().getAttribute('class')).toMatch(/bold/);
115+
expect(ps.first().getAttribute('id')).toMatch(/bold/);
203116
204117
element(by.model('error')).click();
205-
expect(ps.first().getAttribute('class')).toMatch(/red/);
118+
expect(ps.first().getAttribute('id')).toMatch(/red/);
206119
});
207120
208121
it('should let you toggle string example', function() {
209-
expect(ps.get(1).getAttribute('class')).toBe('');
122+
expect(ps.get(1).getAttribute('id')).toBe('');
210123
element(by.model('style')).clear();
211124
element(by.model('style')).sendKeys('red');
212-
expect(ps.get(1).getAttribute('class')).toBe('red');
125+
expect(ps.get(1).getAttribute('id')).toBe('red');
213126
});
214127
215128
it('array example should have 3 classes', function() {
216129
expect(ps.last().getAttribute('class')).toBe('');
217130
element(by.model('style1')).sendKeys('bold');
218131
element(by.model('style2')).sendKeys('strike');
219132
element(by.model('style3')).sendKeys('red');
220-
expect(ps.last().getAttribute('class')).toBe('bold strike red');
133+
expect(ps.last().getAttribute('id')).toBe('bold');
221134
});
222135
</file>
223136
</example>
224-
225-
## Animations
226-
227-
The example below demonstrates how to perform animations using ngClass.
228-
229-
<example module="ngAnimate" deps="angular-animate.js" animations="true">
230-
<file name="index.html">
231-
<input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
232-
<input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
233-
<br>
234-
<span class="base-class" ng-class="myVar">Sample Text</span>
235-
</file>
236-
<file name="style.css">
237-
.base-class {
238-
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
239-
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
240-
}
241-
242-
.base-class.my-class {
243-
color: red;
244-
font-size:3em;
245-
}
246-
</file>
247-
<file name="protractor.js" type="protractor">
248-
it('should check ng-class', function() {
249-
expect(element(by.css('.base-class')).getAttribute('class')).not.
250-
toMatch(/my-class/);
251-
252-
element(by.id('setbtn')).click();
253-
254-
expect(element(by.css('.base-class')).getAttribute('class')).
255-
toMatch(/my-class/);
256-
257-
element(by.id('clearbtn')).click();
258-
259-
expect(element(by.css('.base-class')).getAttribute('class')).not.
260-
toMatch(/my-class/);
261-
});
262-
</file>
263-
</example>
264-
265-
266-
## ngClass and pre-existing CSS3 Transitions/Animations
267-
The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
268-
Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
269-
any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
270-
to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
271-
{@link ngAnimate.$animate#removeclass $animate.removeClass}.
272137
*/
273-
var ngIdDirective = idDirective('', true);
138+
var ngIdDirective = idDirective();
274139

test/ng/directive/ngIdSpec.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict';
2+
3+
describe('ngId', function() {
4+
var element;
5+
6+
afterEach(function() {
7+
dealoc(element);
8+
});
9+
10+
it('should add new and remove old ids dynamically', inject(function($rootScope, $compile) {
11+
element = $compile('<div id="existing" ng-id="dynId"></div>')($rootScope);
12+
$rootScope.dynId = 'A';
13+
$rootScope.$digest();
14+
expect(element.attr('id') === 'existing').toBe(false);
15+
expect(element.attr('id') === 'A').toBe(true);
16+
17+
// $rootScope.dynClass = 'B';
18+
// $rootScope.$digest();
19+
// expect(element.hasClass('existing')).toBe(true);
20+
// expect(element.hasClass('A')).toBe(false);
21+
// expect(element.hasClass('B')).toBe(true);
22+
23+
// delete $rootScope.dynClass;
24+
// $rootScope.$digest();
25+
// expect(element.hasClass('existing')).toBe(true);
26+
// expect(element.hasClass('A')).toBe(false);
27+
// expect(element.hasClass('B')).toBe(false);
28+
}));
29+
30+
});

test/ng/directive/ngIfSpec.js

100755100644
File mode changed.

0 commit comments

Comments
 (0)