_PaletteMixin.js.uncompressed.js 9.4 KB

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