Skip to content

Commit ce65ca1

Browse files
committed
Adds ui-grid-one-bind directive set to core
Adds a series of one bind directives that allow simple bindings that reduce the number of watchers on the dom. This is primaraly implemented so that the accessibility aria roles wont increase the number of watchers. Directives added: - uiGridOneBindAlt - uiGridOneBindAriaLabel - uiGridOneBindAriaLabelledby - uiGridOneBindAriaLabelledbyGrid - uiGridOneBindClass - uiGridOneBindHref - uiGridOneBindHtml - uiGridOneBindId - uiGridOneBindIdGrid - uiGridOneBindSrc - uiGridOneBindStyle - uiGridOneBindText - uiGridOneBindTitle - uiGridOneBindValue
1 parent 9ee59b2 commit ce65ca1

File tree

2 files changed

+421
-0
lines changed

2 files changed

+421
-0
lines changed
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
(function(){
2+
'use strict';
3+
/**
4+
* @ngdoc overview
5+
* @name ui.grid.directive:uiGridOneBind
6+
* @summary A group of directives that provide a one time bind to a dom element.
7+
* @description A group of directives that provide a one time bind to a dom element.
8+
* As one time bindings are not supported in Angular 1.2.* this directive provdes this capability.
9+
* This is done to reduce the number of watchers on the dom.
10+
* <br/>
11+
* <h2>Short Example ({@link ui.grid.directive:uiGridOneBindSrc ui-grid-one-bind-src})</h2>
12+
* <pre>
13+
<div ng-init="imageName = 'myImageDir.jpg'">
14+
<img ui-grid-one-bind-src="imageName"></img>
15+
</div>
16+
</pre>
17+
* Will become:
18+
* <pre>
19+
<div ng-init="imageName = 'myImageDir.jpg'">
20+
<img ui-grid-one-bind-src="imageName" src="myImageDir.jpg"></img>
21+
</div>
22+
</pre>
23+
</br>
24+
<h2>Short Example ({@link ui.grid.directive:uiGridOneBindText ui-grid-one-bind-text})</h2>
25+
* <pre>
26+
<div ng-init="text='Add this text'" ui-grid-one-bind-text="text"></div>
27+
</pre>
28+
* Will become:
29+
* <pre>
30+
<div ng-init="text='Add this text'" ui-grid-one-bind-text="text">Add this text</div>
31+
</pre>
32+
</br>
33+
* <b>Note:</b> This behavior is slightly different for the {@link ui.grid.directive:uiGridOneBindIdGrid uiGridOneBindIdGrid}
34+
* and {@link ui.grid.directive:uiGridOneBindAriaLabelledbyGrid uiGridOneBindAriaLabelledbyGrid} directives.
35+
*
36+
*/
37+
//https://github.com/joshkurz/Black-Belt-AngularJS-Directives/blob/master/directives/Optimization/oneBind.js
38+
var oneBinders = angular.module('ui.grid');
39+
angular.forEach([
40+
/**
41+
* @ngdoc directive
42+
* @name ui.grid.directive:uiGridOneBindSrc
43+
* @memberof ui.grid.directive:uiGridOneBind
44+
* @element img
45+
* @restrict A
46+
* @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>.
47+
* @description One time binding for the src dom tag.
48+
*
49+
*/
50+
{tag: 'Src', method: 'attr'},
51+
/**
52+
* @ngdoc directive
53+
* @name ui.grid.directive:uiGridOneBindText
54+
* @element div
55+
* @restrict A
56+
* @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>.
57+
* @description One time binding for the text dom tag.
58+
*/
59+
{tag: 'Text', method: 'text'},
60+
/**
61+
* @ngdoc directive
62+
* @name ui.grid.directive:uiGridOneBindHref
63+
* @element div
64+
* @restrict A
65+
* @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>.
66+
* @description One time binding for the href dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
67+
*/
68+
{tag: 'Href', method: 'attr'},
69+
/**
70+
* @ngdoc directive
71+
* @name ui.grid.directive:uiGridOneBindClass
72+
* @element div
73+
* @restrict A
74+
* @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>.
75+
* @description One time binding for the class dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
76+
*/
77+
{tag: 'Class', method: 'addClass'},
78+
/**
79+
* @ngdoc directive
80+
* @name ui.grid.directive:uiGridOneBindHtml
81+
* @element div
82+
* @restrict A
83+
* @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>.
84+
* @description One time binding for the html method on a dom element. For more information see {@link ui.grid.directive:uiGridOneBind}.
85+
*/
86+
{tag: 'Html', method: 'html'},
87+
/**
88+
* @ngdoc directive
89+
* @name ui.grid.directive:uiGridOneBindAlt
90+
* @element div
91+
* @restrict A
92+
* @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>.
93+
* @description One time binding for the alt dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
94+
*/
95+
{tag: 'Alt', method: 'attr'},
96+
/**
97+
* @ngdoc directive
98+
* @name ui.grid.directive:uiGridOneBindStyle
99+
* @element div
100+
* @restrict A
101+
* @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>.
102+
* @description One time binding for the style dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
103+
*/
104+
{tag: 'Style', method: 'css'},
105+
/**
106+
* @ngdoc directive
107+
* @name ui.grid.directive:uiGridOneBindValue
108+
* @element div
109+
* @restrict A
110+
* @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>.
111+
* @description One time binding for the value dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
112+
*/
113+
{tag: 'Value', method: 'attr'},
114+
/**
115+
* @ngdoc directive
116+
* @name ui.grid.directive:uiGridOneBindId
117+
* @element div
118+
* @restrict A
119+
* @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>.
120+
* @description One time binding for the value dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
121+
*/
122+
{tag: 'Id', method: 'attr'},
123+
/**
124+
* @ngdoc directive
125+
* @name ui.grid.directive:uiGridOneBindIdGrid
126+
* @element div
127+
* @restrict A
128+
* @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>.
129+
* @description One time binding for the id dom tag.
130+
* <h1>Important Note!</h1>
131+
* If the id tag passed as a parameter does <b>not</b> contain the grid id as a substring
132+
* then the directive will search the scope and the parent controller (if it is a uiGridController) for the grid.id value.
133+
* 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.
134+
* This is done in order to ensure uniqueness of id tags across the grid.
135+
* This is to prevent two grids in the same document having duplicate id tags.
136+
*/
137+
{tag: 'Id', directiveName:'IdGrid', method: 'attr', appendGridId: true},
138+
/**
139+
* @ngdoc directive
140+
* @name ui.grid.directive:uiGridOneBindTitle
141+
* @element div
142+
* @restrict A
143+
* @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>.
144+
* @description One time binding for the title dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
145+
*/
146+
{tag: 'Title', method: 'attr'},
147+
/**
148+
* @ngdoc directive
149+
* @name ui.grid.directive:uiGridOneBindAriaLabel
150+
* @element div
151+
* @restrict A
152+
* @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>.
153+
* @description One time binding for the aria-label dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
154+
*<br/>
155+
* <pre>
156+
<div ng-init="text='Add this text'" ui-grid-one-bind-aria-label="text"></div>
157+
</pre>
158+
* Will become:
159+
* <pre>
160+
<div ng-init="text='Add this text'" ui-grid-one-bind-aria-label="text" aria-label="Add this text"></div>
161+
</pre>
162+
*/
163+
{tag: 'Label', method: 'attr', aria:true},
164+
/**
165+
* @ngdoc directive
166+
* @name ui.grid.directive:uiGridOneBindAriaLabelledby
167+
* @element div
168+
* @restrict A
169+
* @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>.
170+
* @description One time binding for the aria-labelledby dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
171+
*<br/>
172+
* <pre>
173+
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby="anId"></div>
174+
</pre>
175+
* Will become:
176+
* <pre>
177+
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby="anId" aria-labelledby="gridID32"></div>
178+
</pre>
179+
*/
180+
{tag: 'Labelledby', method: 'attr', aria:true},
181+
/**
182+
* @ngdoc directive
183+
* @name ui.grid.directive:uiGridOneBindAriaLabelledbyGrid
184+
* @element div
185+
* @restrict A
186+
* @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>.
187+
* @description One time binding for the aria-labelledby dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
188+
* 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
189+
* grid id to each one.
190+
*<br/>
191+
* <pre>
192+
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby-grid="anId"></div>
193+
</pre>
194+
* Will become ([grid.id] will be replaced by the actual grid id):
195+
* <pre>
196+
<div ng-init="anId = 'gridID32'" ui-grid-one-bind-aria-labelledby-grid="anId" aria-labelledby-Grid="[grid.id]-gridID32"></div>
197+
</pre>
198+
*/
199+
{tag: 'Labelledby', directiveName:'LabelledbyGrid', appendGridId:true, method: 'attr', aria:true}],
200+
function(v){
201+
202+
var baseDirectiveName = 'uiGridOneBind';
203+
//If it is an aria tag then append the aria label seperately
204+
//This is done because the aria tags are formatted aria-* and the directive name can't have a '-' character in it.
205+
//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.
206+
var directiveName = (v.aria ? baseDirectiveName + 'Aria' : baseDirectiveName) + (v.directiveName ? v.directiveName : v.tag);
207+
oneBinders.directive(directiveName, ['gridUtil', function(gridUtil){
208+
return {
209+
restrict: 'A',
210+
require: ['?uiGrid','?^uiGrid'],
211+
compile: function compile(tElement, tAttrs, transclude) {
212+
return {
213+
post: function(scope, iElement, iAttrs, controllers){
214+
/* Appends the grid id to the beginnig of the value. */
215+
var appendGridId = function(val){
216+
var grid; //Get an instance of the grid if its available
217+
//If its available in the scope then we don't need to try to find it elsewhere
218+
if (scope.grid) {
219+
grid = scope.grid;
220+
}
221+
//Another possible location to try to find the grid
222+
else if (scope.col && scope.col.grid){
223+
grid = scope.col.grid;
224+
}
225+
//Last ditch effort: Search through the provided controllers.
226+
else if (!controllers.some( //Go through the controllers till one has the element we need
227+
function(controller){
228+
if (controller && controller.grid) {
229+
grid = controller.grid;
230+
return true; //We've found the grid
231+
}
232+
})){
233+
//We tried our best to find it for you
234+
gridUtil.logError("["+directiveName+"] A valid grid could not be found to bind id. Are you using this directive " +
235+
"within the correct scope? Trying to generate id: [gridID]-" + val);
236+
throw new Error("No valid grid could be found");
237+
}
238+
239+
if (grid){
240+
var idRegex = new RegExp(grid.id.toString());
241+
//If the grid id hasn't been appended already in the template declaration
242+
if (!idRegex.test(val)){
243+
val = grid.id.toString() + '-' + val;
244+
}
245+
}
246+
return val;
247+
};
248+
249+
250+
var rmWatcher = scope.$watch(iAttrs[directiveName], function(newV,oldV){
251+
if (newV) {
252+
//If we are trying to add an id element then we also apply the grid id if it isn't already there
253+
if (v.appendGridId) {
254+
var newIdString = null;
255+
//Append the id to all of the new ids.
256+
angular.forEach( newV.split(' '), function(s){
257+
newIdString = (newIdString ? (newIdString + ' ') : '') + appendGridId(s);
258+
});
259+
newV = newIdString;
260+
}
261+
262+
// Append this newValue to the dom element.
263+
if (v.method === 'attr') {
264+
//The attr method takes two paraams the tag and the value
265+
if (v.aria) {
266+
//If it is an aria element then append the aria prefix
267+
iElement[v.method]('aria-' + v.tag.toLowerCase(),newV);
268+
} else {
269+
iElement[v.method](v.tag.toLowerCase(),newV);
270+
}
271+
} else {
272+
iElement[v.method](newV);
273+
}
274+
//Removes the watcher on itself after the bind
275+
rmWatcher();
276+
}
277+
}); //End rm watchers
278+
} // End post function
279+
}; // End compile return
280+
} //End compile function
281+
}; //End directive return
282+
} // End directive function
283+
]); //End directive
284+
}); // End angular foreach
285+
})();

0 commit comments

Comments
 (0)