]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/_PaletteMixin.js.uncompressed.js
update dojo to 1.7.3
[tt-rss.git] / lib / dijit / _PaletteMixin.js.uncompressed.js
1 define("dijit/_PaletteMixin", [
2 "dojo/_base/declare", // declare
3 "dojo/dom-attr", // domAttr.set
4 "dojo/dom-class", // domClass.add domClass.remove
5 "dojo/dom-construct", // domConstruct.create domConstruct.place
6 "dojo/_base/event", // event.stop
7 "dojo/keys", // keys
8 "dojo/_base/lang", // lang.getObject
9 "./_CssStateMixin",
10 "./focus",
11 "./typematic"
12 ], function(declare, domAttr, domClass, domConstruct, event, keys, lang, _CssStateMixin, focus, typematic){
13
14 /*=====
15 var _CssStateMixin = dijit._CssStateMixin;
16 =====*/
17
18 // module:
19 // dijit/_PaletteMixin
20 // summary:
21 // A keyboard accessible palette, for picking a color/emoticon/etc.
22
23 return declare("dijit._PaletteMixin", [_CssStateMixin], {
24 // summary:
25 // A keyboard accessible palette, for picking a color/emoticon/etc.
26 // description:
27 // A mixin for a grid showing various entities, so the user can pick a certain entity.
28
29 // defaultTimeout: Number
30 // Number of milliseconds before a held key or button becomes typematic
31 defaultTimeout: 500,
32
33 // timeoutChangeRate: Number
34 // Fraction of time used to change the typematic timer between events
35 // 1.0 means that each typematic event fires at defaultTimeout intervals
36 // < 1.0 means that each typematic event fires at an increasing faster rate
37 timeoutChangeRate: 0.90,
38
39 // value: String
40 // Currently selected color/emoticon/etc.
41 value: "",
42
43 // _selectedCell: [private] Integer
44 // Index of the currently selected cell. Initially, none selected
45 _selectedCell: -1,
46
47 /*=====
48 // _currentFocus: [private] DomNode
49 // The currently focused cell (if the palette itself has focus), or otherwise
50 // the cell to be focused when the palette itself gets focus.
51 // Different from value, which represents the selected (i.e. clicked) cell.
52 _currentFocus: null,
53 =====*/
54
55 /*=====
56 // _xDim: [protected] Integer
57 // This is the number of cells horizontally across.
58 _xDim: null,
59 =====*/
60
61 /*=====
62 // _yDim: [protected] Integer
63 // This is the number of cells vertically down.
64 _yDim: null,
65 =====*/
66
67 // tabIndex: String
68 // Widget tab index.
69 tabIndex: "0",
70
71 // cellClass: [protected] String
72 // CSS class applied to each cell in the palette
73 cellClass: "dijitPaletteCell",
74
75 // dyeClass: [protected] String
76 // Name of javascript class for Object created for each cell of the palette.
77 // dyeClass should implements dijit.Dye interface
78 dyeClass: '',
79
80 // summary: String
81 // Localized summary for the palette table
82 summary: '',
83 _setSummaryAttr: "paletteTableNode",
84
85 _dyeFactory: function(value /*===== , row, col =====*/){
86 // summary:
87 // Return instance of dijit.Dye for specified cell of palette
88 // tags:
89 // extension
90 var dyeClassObj = lang.getObject(this.dyeClass);
91 return new dyeClassObj(value);
92 },
93
94 _preparePalette: function(choices, titles) {
95 // summary:
96 // Subclass must call _preparePalette() from postCreate(), passing in the tooltip
97 // for each cell
98 // choices: String[][]
99 // id's for each cell of the palette, used to create Dye JS object for each cell
100 // titles: String[]
101 // Localized tooltip for each cell
102
103 this._cells = [];
104 var url = this._blankGif;
105
106 this.connect(this.gridNode, "ondijitclick", "_onCellClick");
107
108 for(var row=0; row < choices.length; row++){
109 var rowNode = domConstruct.create("tr", {tabIndex: "-1"}, this.gridNode);
110 for(var col=0; col < choices[row].length; col++){
111 var value = choices[row][col];
112 if(value){
113 var cellObject = this._dyeFactory(value, row, col);
114
115 var cellNode = domConstruct.create("td", {
116 "class": this.cellClass,
117 tabIndex: "-1",
118 title: titles[value],
119 role: "gridcell"
120 });
121
122 // prepare cell inner structure
123 cellObject.fillCell(cellNode, url);
124
125 domConstruct.place(cellNode, rowNode);
126
127 cellNode.index = this._cells.length;
128
129 // save cell info into _cells
130 this._cells.push({node:cellNode, dye:cellObject});
131 }
132 }
133 }
134 this._xDim = choices[0].length;
135 this._yDim = choices.length;
136
137 // Now set all events
138 // The palette itself is navigated to with the tab key on the keyboard
139 // Keyboard navigation within the Palette is with the arrow keys
140 // Spacebar selects the cell.
141 // For the up key the index is changed by negative the x dimension.
142
143 var keyIncrementMap = {
144 UP_ARROW: -this._xDim,
145 // The down key the index is increase by the x dimension.
146 DOWN_ARROW: this._xDim,
147 // Right and left move the index by 1.
148 RIGHT_ARROW: this.isLeftToRight() ? 1 : -1,
149 LEFT_ARROW: this.isLeftToRight() ? -1 : 1
150 };
151 for(var key in keyIncrementMap){
152 this._connects.push(
153 typematic.addKeyListener(
154 this.domNode,
155 {charOrCode:keys[key], ctrlKey:false, altKey:false, shiftKey:false},
156 this,
157 function(){
158 var increment = keyIncrementMap[key];
159 return function(count){ this._navigateByKey(increment, count); };
160 }(),
161 this.timeoutChangeRate,
162 this.defaultTimeout
163 )
164 );
165 }
166 },
167
168 postCreate: function(){
169 this.inherited(arguments);
170
171 // Set initial navigable node.
172 this._setCurrent(this._cells[0].node);
173 },
174
175 focus: function(){
176 // summary:
177 // Focus this widget. Puts focus on the most recently focused cell.
178
179 // The cell already has tabIndex set, just need to set CSS and focus it
180 focus.focus(this._currentFocus);
181 },
182
183 _onCellClick: function(/*Event*/ evt){
184 // summary:
185 // Handler for click, enter key & space key. Selects the cell.
186 // evt:
187 // The event.
188 // tags:
189 // private
190
191 var target = evt.target;
192
193 // Find TD associated with click event. For ColorPalette user likely clicked IMG inside of TD
194 while(target.tagName != "TD"){
195 if(!target.parentNode || target == this.gridNode){ // probably can never happen, but just in case
196 return;
197 }
198 target = target.parentNode;
199 }
200
201 var value = this._getDye(target).getValue();
202
203 // First focus the clicked cell, and then send onChange() notification.
204 // onChange() (via _setValueAttr) must be after the focus call, because
205 // it may trigger a refocus to somewhere else (like the Editor content area), and that
206 // second focus should win.
207 this._setCurrent(target);
208 focus.focus(target);
209 this._setValueAttr(value, true);
210
211 event.stop(evt);
212 },
213
214 _setCurrent: function(/*DomNode*/ node){
215 // summary:
216 // Sets which node is the focused cell.
217 // description:
218 // At any point in time there's exactly one
219 // cell with tabIndex != -1. If focus is inside the palette then
220 // focus is on that cell.
221 //
222 // After calling this method, arrow key handlers and mouse click handlers
223 // should focus the cell in a setTimeout().
224 // tags:
225 // protected
226 if("_currentFocus" in this){
227 // Remove tabIndex on old cell
228 domAttr.set(this._currentFocus, "tabIndex", "-1");
229 }
230
231 // Set tabIndex of new cell
232 this._currentFocus = node;
233 if(node){
234 domAttr.set(node, "tabIndex", this.tabIndex);
235 }
236 },
237
238 _setValueAttr: function(value, priorityChange){
239 // summary:
240 // This selects a cell. It triggers the onChange event.
241 // value: String value of the cell to select
242 // tags:
243 // protected
244 // priorityChange:
245 // Optional parameter used to tell the select whether or not to fire
246 // onChange event.
247
248 // clear old selected cell
249 if(this._selectedCell >= 0){
250 domClass.remove(this._cells[this._selectedCell].node, this.cellClass + "Selected");
251 }
252 this._selectedCell = -1;
253
254 // search for cell matching specified value
255 if(value){
256 for(var i = 0; i < this._cells.length; i++){
257 if(value == this._cells[i].dye.getValue()){
258 this._selectedCell = i;
259 domClass.add(this._cells[i].node, this.cellClass + "Selected");
260 break;
261 }
262 }
263 }
264
265 // record new value, or null if no matching cell
266 this._set("value", this._selectedCell >= 0 ? value : null);
267
268 if(priorityChange || priorityChange === undefined){
269 this.onChange(value);
270 }
271 },
272
273 onChange: function(/*===== value =====*/){
274 // summary:
275 // Callback when a cell is selected.
276 // value: String
277 // Value corresponding to cell.
278 },
279
280 _navigateByKey: function(increment, typeCount){
281 // summary:
282 // This is the callback for typematic.
283 // It changes the focus and the highlighed cell.
284 // increment:
285 // How much the key is navigated.
286 // typeCount:
287 // How many times typematic has fired.
288 // tags:
289 // private
290
291 // typecount == -1 means the key is released.
292 if(typeCount == -1){ return; }
293
294 var newFocusIndex = this._currentFocus.index + increment;
295 if(newFocusIndex < this._cells.length && newFocusIndex > -1){
296 var focusNode = this._cells[newFocusIndex].node;
297 this._setCurrent(focusNode);
298
299 // Actually focus the node, for the benefit of screen readers.
300 // Use setTimeout because IE doesn't like changing focus inside of an event handler
301 setTimeout(lang.hitch(dijit, "focus", focusNode), 0);
302 }
303 },
304
305 _getDye: function(/*DomNode*/ cell){
306 // summary:
307 // Get JS object for given cell DOMNode
308
309 return this._cells[cell.index].dye;
310 }
311 });
312
313 /*=====
314 declare("dijit.Dye",
315 null,
316 {
317 // summary:
318 // Interface for the JS Object associated with a palette cell (i.e. DOMNode)
319
320 constructor: function(alias, row, col){
321 // summary:
322 // Initialize according to value or alias like "white"
323 // alias: String
324 },
325
326 getValue: function(){
327 // summary:
328 // Return "value" of cell; meaning of "value" varies by subclass.
329 // description:
330 // For example color hex value, emoticon ascii value etc, entity hex value.
331 },
332
333 fillCell: function(cell, blankGif){
334 // summary:
335 // Add cell DOMNode inner structure
336 // cell: DomNode
337 // The surrounding cell
338 // blankGif: String
339 // URL for blank cell image
340 }
341 }
342 );
343 =====*/
344
345 });