-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
ui-grid-one-bind.js
348 lines (342 loc) · 17.8 KB
/
ui-grid-one-bind.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
(function(){
'use strict';
/**
* @ngdoc overview
* @name ui.grid.directive:uiGridOneBind
* @summary A group of directives that provide a one time bind to a dom element.
* @description A group of directives that provide a one time bind to a dom element.
* As one time bindings are not supported in Angular 1.2.* this directive provdes this capability.
* This is done to reduce the number of watchers on the dom.
* <br/>
* <h2>Short Example ({@link ui.grid.directive:uiGridOneBindSrc ui-grid-one-bind-src})</h2>
* <pre>
<div ng-init="imageName = 'myImageDir.jpg'">
<img ui-grid-one-bind-src="imageName"></img>
</div>
</pre>
* Will become:
* <pre>
<div ng-init="imageName = 'myImageDir.jpg'">
<img ui-grid-one-bind-src="imageName" src="myImageDir.jpg"></img>
</div>
</pre>
</br>
<h2>Short Example ({@link ui.grid.directive:uiGridOneBindText ui-grid-one-bind-text})</h2>
* <pre>
<div ng-init="text='Add this text'" ui-grid-one-bind-text="text"></div>
</pre>
* Will become:
* <pre>
<div ng-init="text='Add this text'" ui-grid-one-bind-text="text">Add this text</div>
</pre>
</br>
* <b>Note:</b> This behavior is slightly different for the {@link ui.grid.directive:uiGridOneBindIdGrid uiGridOneBindIdGrid}
* and {@link ui.grid.directive:uiGridOneBindAriaLabelledbyGrid uiGridOneBindAriaLabelledbyGrid} directives.
*
*/
//https://github.com/joshkurz/Black-Belt-AngularJS-Directives/blob/master/directives/Optimization/oneBind.js
var oneBinders = angular.module('ui.grid');
angular.forEach([
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindSrc
* @memberof ui.grid.directive:uiGridOneBind
* @element img
* @restrict A
* @param {String} uiGridOneBindSrc The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the src dom tag.
*
*/
{tag: 'Src', method: 'attr'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindText
* @element div
* @restrict A
* @param {String} uiGridOneBindText The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the text dom tag.
*/
{tag: 'Text', method: 'text'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindHref
* @element div
* @restrict A
* @param {String} uiGridOneBindHref The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the href dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Href', method: 'attr'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindClass
* @element div
* @restrict A
* @param {String} uiGridOneBindClass The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @param {Object} uiGridOneBindClass The object that you want to bind. At least one of the values in the object must be something other than null or undefined for the watcher to be removed.
* this is to prevent the watcher from being removed before the scope is initialized.
* @param {Array} uiGridOneBindClass An array of classes to bind to this element.
* @description One time binding for the class dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Class', method: 'addClass'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindHtml
* @element div
* @restrict A
* @param {String} uiGridOneBindHtml The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the html method on a dom element. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Html', method: 'html'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindAlt
* @element div
* @restrict A
* @param {String} uiGridOneBindAlt The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the alt dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Alt', method: 'attr'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindStyle
* @element div
* @restrict A
* @param {String} uiGridOneBindStyle The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the style dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Style', method: 'css'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindValue
* @element div
* @restrict A
* @param {String} uiGridOneBindValue The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the value dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Value', method: 'attr'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindId
* @element div
* @restrict A
* @param {String} uiGridOneBindId The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the value dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Id', method: 'attr'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindIdGrid
* @element div
* @restrict A
* @param {String} uiGridOneBindIdGrid The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the id dom tag.
* <h1>Important Note!</h1>
* If the id tag passed as a parameter does <b>not</b> contain the grid id as a substring
* then the directive will search the scope and the parent controller (if it is a uiGridController) for the grid.id value.
* If this value is found then it is appended to the begining of the id tag. If the grid is not found then the directive throws an error.
* This is done in order to ensure uniqueness of id tags across the grid.
* This is to prevent two grids in the same document having duplicate id tags.
*/
{tag: 'Id', directiveName:'IdGrid', method: 'attr', appendGridId: true},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindTitle
* @element div
* @restrict A
* @param {String} uiGridOneBindTitle The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the title dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*/
{tag: 'Title', method: 'attr'},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindAriaLabel
* @element div
* @restrict A
* @param {String} uiGridOneBindAriaLabel The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the aria-label dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*<br/>
* <pre>
<div ng-init="text='Add this text'" ui-grid-one-bind-aria-label="text"></div>
</pre>
* Will become:
* <pre>
<div ng-init="text='Add this text'" ui-grid-one-bind-aria-label="text" aria-label="Add this text"></div>
</pre>
*/
{tag: 'Label', method: 'attr', aria:true},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindAriaLabelledby
* @element div
* @restrict A
* @param {String} uiGridOneBindAriaLabelledby The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the aria-labelledby dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*<br/>
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby="anId"></div>
</pre>
* Will become:
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby="anId" aria-labelledby="gridID32"></div>
</pre>
*/
{tag: 'Labelledby', method: 'attr', aria:true},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindAriaLabelledbyGrid
* @element div
* @restrict A
* @param {String} uiGridOneBindAriaLabelledbyGrid The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the aria-labelledby dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
* Works somewhat like {@link ui.grid.directive:uiGridOneBindIdGrid} however this one supports a list of ids (seperated by a space) and will dynamically add the
* grid id to each one.
*<br/>
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby-grid="anId"></div>
</pre>
* Will become ([grid.id] will be replaced by the actual grid id):
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby-grid="anId" aria-labelledby-Grid="[grid.id]-gridID32"></div>
</pre>
*/
{tag: 'Labelledby', directiveName:'LabelledbyGrid', appendGridId:true, method: 'attr', aria:true},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindAriaDescribedby
* @element ANY
* @restrict A
* @param {String} uiGridOneBindAriaDescribedby The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the aria-describedby dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
*<br/>
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-describedby="anId"></div>
</pre>
* Will become:
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-describedby="anId" aria-describedby="gridID32"></div>
</pre>
*/
{tag: 'Describedby', method: 'attr', aria:true},
/**
* @ngdoc directive
* @name ui.grid.directive:uiGridOneBindAriaDescribedbyGrid
* @element ANY
* @restrict A
* @param {String} uiGridOneBindAriaDescribedbyGrid The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
* @description One time binding for the aria-labelledby dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
* Works somewhat like {@link ui.grid.directive:uiGridOneBindIdGrid} however this one supports a list of ids (seperated by a space) and will dynamically add the
* grid id to each one.
*<br/>
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-describedby-grid="anId"></div>
</pre>
* Will become ([grid.id] will be replaced by the actual grid id):
* <pre>
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-describedby-grid="anId" aria-describedby="[grid.id]-gridID32"></div>
</pre>
*/
{tag: 'Describedby', directiveName:'DescribedbyGrid', appendGridId:true, method: 'attr', aria:true}],
function(v){
var baseDirectiveName = 'uiGridOneBind';
//If it is an aria tag then append the aria label seperately
//This is done because the aria tags are formatted aria-* and the directive name can't have a '-' character in it.
//If the diretiveName has to be overridden then it does so here. This is because the tag being modified and the directive sometimes don't match up.
var directiveName = (v.aria ? baseDirectiveName + 'Aria' : baseDirectiveName) + (v.directiveName ? v.directiveName : v.tag);
oneBinders.directive(directiveName, ['gridUtil', function(gridUtil){
return {
restrict: 'A',
require: ['?uiGrid','?^uiGrid'],
link: function(scope, iElement, iAttrs, controllers){
/* Appends the grid id to the beginnig of the value. */
var appendGridId = function(val){
var grid; //Get an instance of the grid if its available
//If its available in the scope then we don't need to try to find it elsewhere
if (scope.grid) {
grid = scope.grid;
}
//Another possible location to try to find the grid
else if (scope.col && scope.col.grid){
grid = scope.col.grid;
}
//Last ditch effort: Search through the provided controllers.
else if (!controllers.some( //Go through the controllers till one has the element we need
function(controller){
if (controller && controller.grid) {
grid = controller.grid;
return true; //We've found the grid
}
})){
//We tried our best to find it for you
gridUtil.logError("["+directiveName+"] A valid grid could not be found to bind id. Are you using this directive " +
"within the correct scope? Trying to generate id: [gridID]-" + val);
throw new Error("No valid grid could be found");
}
if (grid){
var idRegex = new RegExp(grid.id.toString());
//If the grid id hasn't been appended already in the template declaration
if (!idRegex.test(val)){
val = grid.id.toString() + '-' + val;
}
}
return val;
};
// The watch returns a function to remove itself.
var rmWatcher = scope.$watch(iAttrs[directiveName], function(newV){
if (newV){
//If we are trying to add an id element then we also apply the grid id if it isn't already there
if (v.appendGridId) {
var newIdString = null;
//Append the id to all of the new ids.
angular.forEach( newV.split(' '), function(s){
newIdString = (newIdString ? (newIdString + ' ') : '') + appendGridId(s);
});
newV = newIdString;
}
// Append this newValue to the dom element.
switch (v.method) {
case 'attr': //The attr method takes two paraams the tag and the value
if (v.aria) {
//If it is an aria element then append the aria prefix
iElement[v.method]('aria-' + v.tag.toLowerCase(),newV);
} else {
iElement[v.method](v.tag.toLowerCase(),newV);
}
break;
case 'addClass':
//Pulled from https://github.com/Pasvaz/bindonce/blob/master/bindonce.js
if (angular.isObject(newV) && !angular.isArray(newV)) {
var results = [];
var nonNullFound = false; //We don't want to remove the binding unless the key is actually defined
angular.forEach(newV, function (value, index) {
if (value !== null && typeof(value) !== "undefined"){
nonNullFound = true; //A non null value for a key was found so the object must have been initialized
if (value) {results.push(index);}
}
});
//A non null value for a key wasn't found so assume that the scope values haven't been fully initialized
if (!nonNullFound){
return; // If not initialized then the watcher should not be removed yet.
}
newV = results;
}
if (newV) {
iElement.addClass(angular.isArray(newV) ? newV.join(' ') : newV);
} else {
return;
}
break;
default:
iElement[v.method](newV);
break;
}
//Removes the watcher on itself after the bind
rmWatcher();
}
// True ensures that equality is determined using angular.equals instead of ===
}, true); //End rm watchers
} //End compile function
}; //End directive return
} // End directive function
]); //End directive
}); // End angular foreach
})();