PageRenderTime 62ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/libcommon/DTK1.7/dgrid/List.js

https://bitbucket.org/sasha.firsov/dojoplay2012
JavaScript | 694 lines | 462 code | 74 blank | 158 comment | 125 complexity | 2957843c5451099934065803e800cc63 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, Apache-2.0, MIT
  1. define(["dojo/_base/array","dojo/_base/kernel", "dojo/_base/declare", "dojo/on", "dojo/has", "./util/misc", "dojo/has!touch?./TouchScroll", "xstyle/has-class", "put-selector/put", "dojo/_base/sniff", "xstyle/css!./css/dgrid.css"],
  2. function(arrayUtil, kernel, declare, listen, has, miscUtil, TouchScroll, hasClass, put){
  3. // Add user agent/feature CSS classes
  4. hasClass("mozilla", "opera", "webkit", "ie", "ie-6", "ie-6-7", "quirks", "no-quirks", "touch");
  5. var scrollbarWidth;
  6. // establish an extra stylesheet which addCssRule calls will use,
  7. // plus an array to track actual indices in stylesheet for removal
  8. var
  9. extraSheet = put(document.getElementsByTagName("head")[0], "style"),
  10. extraRules = [],
  11. oddClass = "dgrid-row-odd",
  12. evenClass = "dgrid-row-even";
  13. // keep reference to actual StyleSheet object (.styleSheet for IE < 9)
  14. extraSheet = extraSheet.sheet || extraSheet.styleSheet;
  15. // functions for adding and removing extra style rules.
  16. // addExtraRule is exposed on the List prototype as addCssRule.
  17. function addExtraRule(selector, css){
  18. var index = extraRules.length;
  19. extraRules[index] = (extraSheet.cssRules || extraSheet.rules).length;
  20. extraSheet.addRule ?
  21. extraSheet.addRule(selector, css) :
  22. extraSheet.insertRule(selector + '{' + css + '}', extraRules[index]);
  23. return {
  24. remove: function(){ removeExtraRule(index); }
  25. };
  26. }
  27. function removeExtraRule(index){
  28. var
  29. realIndex = extraRules[index],
  30. i, l = extraRules.length;
  31. if (realIndex === undefined) { return; } // already removed
  32. // remove rule indicated in internal array at index
  33. extraSheet.deleteRule ?
  34. extraSheet.deleteRule(realIndex) :
  35. extraSheet.removeRule(realIndex); // IE < 9
  36. // Clear internal array item representing rule that was just deleted.
  37. // NOTE: we do NOT splice, since the point of this array is specifically
  38. // to negotiate the splicing that occurs in the stylesheet itself!
  39. extraRules[index] = undefined;
  40. // Then update array items as necessary to downshift remaining rule indices.
  41. // Can start at index, since array is sparse but strictly increasing.
  42. for(i = index; i < l; i++){
  43. if(extraRules[i] > realIndex){ extraRules[i]--; }
  44. }
  45. }
  46. function byId(id){
  47. return document.getElementById(id);
  48. }
  49. function move(item, steps, targetClass, visible){
  50. var nextSibling, current, element;
  51. element = current = item.element;
  52. steps = steps || 1;
  53. do{
  54. // move in the correct direction
  55. if(nextSibling = current[steps < 0 ? 'previousSibling' : 'nextSibling']){
  56. do{
  57. current = nextSibling;
  58. if(((current && current.className) + ' ').indexOf(targetClass + ' ') > -1){
  59. // it's an element with the correct class name, counts as a real move
  60. element = current;
  61. steps += steps < 0 ? 1 : -1;
  62. break;
  63. }
  64. // if the next sibling isn't a match, drill down to search
  65. }while(nextSibling = (!visible || !current.hidden) && current[steps < 0 ? 'lastChild' : 'firstChild']);
  66. }else if((current = current.parentNode) == this.domNode || (current.className + ' ').indexOf("dgrid-row ") > -1){ // intentional assignment
  67. // we stepped all the way out of the grid, given up now
  68. break;
  69. }
  70. }while(steps);
  71. return element;
  72. }
  73. // var and function for autogenerating ID when one isn't provided
  74. var autogen = 0;
  75. function generateId(){
  76. return "dgrid_" + autogen++;
  77. }
  78. // window resize event handler
  79. var winResizeHandler = has("ie") < 7 && !has("quirks") ? function(grid){
  80. // IE6 triggers window.resize on any element resize;
  81. // avoid useless calls (and infinite loop if height: auto).
  82. // The measurement logic here is based on dojo/window logic.
  83. var root, w, h, dims;
  84. if(!grid._started){ return; } // no sense calling resize yet
  85. root = document.documentElement;
  86. w = root.clientWidth;
  87. h = root.clientHeight;
  88. dims = grid._prevWinDims || [];
  89. if(dims[0] !== w || dims[1] !== h){
  90. grid.resize();
  91. grid._prevWinDims = [w, h];
  92. }
  93. } :
  94. function(grid){
  95. grid._started && grid.resize();
  96. };
  97. return declare(TouchScroll ? [TouchScroll] : [], {
  98. tabableHeader: false,
  99. // showHeader: Boolean
  100. // Whether to render header (sub)rows.
  101. showHeader: false,
  102. // showFooter: Boolean
  103. // Whether to render footer area. Extensions which display content
  104. // in the footer area should set this to true.
  105. showFooter: false,
  106. // maintainOddEven: Boolean
  107. // Indicates whether to maintain the odd/even classes when new rows are inserted.
  108. // This can be disabled to improve insertion performance if odd/even styling is not employed.
  109. maintainOddEven: true,
  110. postscript: function(params, srcNodeRef){
  111. // perform setup and invoke create in postScript to allow descendants to
  112. // perform logic before create/postCreate happen (a la dijit/_WidgetBase)
  113. var grid = this;
  114. (this._Row = function(id, object, element){
  115. this.id = id;
  116. this.data = object;
  117. this.element = element;
  118. }).prototype.remove = function(){
  119. grid.removeRow(this.element);
  120. };
  121. if(srcNodeRef){
  122. // normalize srcNodeRef and store on instance during create process.
  123. // Doing this in postscript is a bit earlier than dijit would do it,
  124. // but allows subclasses to access it pre-normalized during create.
  125. this.srcNodeRef = srcNodeRef =
  126. srcNodeRef.nodeType ? srcNodeRef : byId(srcNodeRef);
  127. }
  128. this.create(params, srcNodeRef);
  129. },
  130. listType: "list",
  131. create: function(params, srcNodeRef){
  132. // mix in params now, but wait until postScript to create
  133. if(params){
  134. this.params = params;
  135. declare.safeMixin(this, params);
  136. // handle sort param - TODO: revise @ 1.0 when _sort -> sort
  137. this._sort = params.sort || [];
  138. delete this.sort; // ensure back-compat method isn't shadowed
  139. }else{
  140. this._sort = [];
  141. }
  142. var domNode = this.domNode = srcNodeRef || put("div");
  143. // ensure arrays and hashes are initialized
  144. this.observers = [];
  145. this._listeners = [];
  146. this._rowIdToObject = {};
  147. this.postMixInProperties && this.postMixInProperties();
  148. // Apply id to widget and domNode,
  149. // from incoming node, widget params, or autogenerated.
  150. this.id = domNode.id = domNode.id || this.id || generateId();
  151. this.buildRendering();
  152. this.postCreate && this.postCreate();
  153. // remove srcNodeRef instance property post-create
  154. delete this.srcNodeRef;
  155. // to preserve "it just works" behavior, call startup if we're visible
  156. if(this.domNode.offsetHeight){
  157. this.startup();
  158. }
  159. },
  160. buildRendering: function(){
  161. var domNode = this.domNode,
  162. grid = this,
  163. headerNode, spacerNode, bodyNode, footerNode, isRTL;
  164. // Detect RTL on html/body nodes; taken from dojo/dom-geometry
  165. isRTL = this.isRTL = (document.body.dir || document.documentElement.dir ||
  166. document.body.style.direction).toLowerCase() == "rtl";
  167. put(domNode, "[role=grid].ui-widget.dgrid.dgrid-" + this.listType);
  168. headerNode = this.headerNode = put(domNode,
  169. "div.dgrid-header.dgrid-header-row.ui-widget-header" +
  170. (this.showHeader ? "" : ".dgrid-header-hidden"));
  171. if(has("quirks") || has("ie") < 8){
  172. spacerNode = put(domNode, "div.dgrid-spacer");
  173. }
  174. bodyNode = this.bodyNode = this.touchNode = put(domNode, "div.dgrid-scroller");
  175. // firefox 4 until at least 10 adds overflow: auto elements to the tab index by default for some
  176. // reason; force them to be not tabbable
  177. bodyNode.tabIndex = -1;
  178. this.headerScrollNode = put(domNode, "div.dgrid-header-scroll.dgrid-scrollbar-width.ui-widget-header");
  179. footerNode = this.footerNode = put("div.dgrid-footer");
  180. // hide unless showFooter is true (set by extensions which use footer)
  181. if (!this.showFooter) { footerNode.style.display = "none"; }
  182. put(domNode, footerNode);
  183. if(isRTL){
  184. domNode.className += " dgrid-rtl" + (has("webkit") ? "" : " dgrid-rtl-nonwebkit");
  185. }
  186. listen(bodyNode, "scroll", function(event){
  187. // keep the header aligned with the body
  188. headerNode.scrollLeft = bodyNode.scrollLeft;
  189. // re-fire, since browsers are not consistent about propagation here
  190. event.stopPropagation();
  191. listen.emit(domNode, "scroll", {scrollTarget: bodyNode});
  192. });
  193. this.configStructure();
  194. this.renderHeader();
  195. this.contentNode = put(this.bodyNode, "div.dgrid-content.ui-widget-content");
  196. // add window resize handler, with reference for later removal if needed
  197. this._listeners.push(this._resizeHandle = listen(window, "resize",
  198. miscUtil.debounce(winResizeHandler)));
  199. },
  200. startup: function(){
  201. // summary:
  202. // Called automatically after postCreate if the component is already
  203. // visible; otherwise, should be called manually once placed.
  204. this.inherited(arguments);
  205. if(this._started){ return; } // prevent double-triggering
  206. this._started = true;
  207. this.resize();
  208. // apply sort (and refresh) now that we're ready to render
  209. this.set("sort", this._sort);
  210. },
  211. configStructure: function(){
  212. // does nothing in List, this is more of a hook for the Grid
  213. },
  214. resize: function(){
  215. var
  216. bodyNode = this.bodyNode,
  217. headerNode = this.headerNode,
  218. footerNode = this.footerNode,
  219. headerHeight = headerNode.offsetHeight,
  220. footerHeight = this.showFooter ? footerNode.offsetHeight : 0,
  221. quirks = has("quirks") || has("ie") < 7;
  222. this.headerScrollNode.style.height = bodyNode.style.marginTop = headerHeight + "px";
  223. if(footerHeight){ bodyNode.style.marginBottom = footerHeight + "px"; }
  224. if(quirks){
  225. // in IE6 and quirks mode, the "bottom" CSS property is ignored.
  226. // We guard against negative values in case of issues with external CSS.
  227. bodyNode.style.height = ""; // reset first
  228. bodyNode.style.height =
  229. Math.max((this.domNode.offsetHeight - headerHeight - footerHeight), 0) + "px";
  230. if (footerHeight) {
  231. // Work around additional glitch where IE 6 / quirks fails to update
  232. // the position of the bottom-aligned footer; this jogs its memory.
  233. footerNode.style.bottom = '1px';
  234. setTimeout(function(){ footerNode.style.bottom = ''; }, 0);
  235. }
  236. }
  237. if(!scrollbarWidth){
  238. // Measure the browser's scrollbar width using a DIV we'll delete right away
  239. var scrollDiv = put(document.body, "div.dgrid-scrollbar-measure");
  240. scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  241. put(scrollDiv, "!");
  242. // avoid crazy issues in IE7 only, with certain widgets inside
  243. if(has("ie") === 7){ scrollbarWidth++; }
  244. // add rules that can be used where scrollbar width/height is needed
  245. this.addCssRule(".dgrid-scrollbar-width", "width: " + scrollbarWidth + "px");
  246. this.addCssRule(".dgrid-scrollbar-height", "height: " + scrollbarWidth + "px");
  247. if(scrollbarWidth != 17 && !quirks){
  248. // for modern browsers, we can perform a one-time operation which adds
  249. // a rule to account for scrollbar width in all grid headers.
  250. this.addCssRule(".dgrid-header", "right: " + scrollbarWidth + "px");
  251. // add another for RTL grids
  252. this.addCssRule(".dgrid-rtl-nonwebkit .dgrid-header", "left: " + scrollbarWidth + "px");
  253. }
  254. }
  255. if(quirks){
  256. // old IE doesn't support left + right + width:auto; set width directly
  257. headerNode.style.width = bodyNode.clientWidth + "px";
  258. setTimeout(function(){
  259. // sync up (after the browser catches up with the new width)
  260. headerNode.scrollLeft = bodyNode.scrollLeft;
  261. }, 0);
  262. }
  263. },
  264. addCssRule: addExtraRule,
  265. on: function(eventType, listener){
  266. // delegate events to the domNode
  267. var signal = listen(this.domNode, eventType, listener);
  268. if(!has("dom-addeventlistener")){
  269. this._listeners.push(signal);
  270. }
  271. return signal;
  272. },
  273. cleanup: function(){
  274. // summary:
  275. // Clears out all rows currently in the list.
  276. var observers = this.observers,
  277. i;
  278. for(i in this._rowIdToObject){
  279. if(this._rowIdToObject[i] != this.columns){
  280. var rowElement = byId(i);
  281. if(rowElement){
  282. this.removeRow(rowElement, true);
  283. }
  284. }
  285. }
  286. // remove any store observers
  287. for(i = 0;i < observers.length; i++){
  288. var observer = observers[i];
  289. observer && observer.cancel();
  290. }
  291. this.observers = [];
  292. this.preload = null;
  293. },
  294. destroy: function(){
  295. // summary:
  296. // Destroys this grid
  297. // remove any event listeners
  298. for(var i = this._listeners.length; i--;){
  299. this._listeners[i].remove();
  300. }
  301. delete this._listeners;
  302. this.cleanup();
  303. // destroy DOM
  304. put("!", this.domNode);
  305. },
  306. refresh: function(){
  307. // summary:
  308. // refreshes the contents of the grid
  309. this.cleanup();
  310. this._rowIdToObject = {};
  311. this._autoId = 0;
  312. // make sure all the content has been removed so it can be recreated
  313. this.contentNode.innerHTML = "";
  314. },
  315. newRow: function(object, before, to, options){
  316. if(before.parentNode){
  317. var i = options.start + to;
  318. var row = this.insertRow(object, before.parentNode, before, i, options);
  319. put(row, ".ui-state-highlight");
  320. setTimeout(function(){
  321. put(row, "!ui-state-highlight");
  322. }, 250);
  323. return row;
  324. }
  325. },
  326. adjustRowIndices: function(firstRow){
  327. if(this.maintainOddEven){
  328. // this traverses through rows to maintain odd/even classes on the rows when indexes shift;
  329. var next = firstRow;
  330. var rowIndex = next.rowIndex;
  331. do{
  332. if(next.rowIndex > -1){
  333. // skip non-numeric, non-rows
  334. put(next, '.' + (rowIndex % 2 == 1 ? oddClass : evenClass) + '!' + (rowIndex % 2 == 0 ? oddClass : evenClass));
  335. next.rowIndex = rowIndex++;
  336. }
  337. }while((next = next.nextSibling) && next.rowIndex != rowIndex);
  338. }
  339. },
  340. renderArray: function(results, beforeNode, options){
  341. // summary:
  342. // This renders an array or collection of objects as rows in the grid, before the
  343. // given node. This will listen for changes in the collection if an observe method
  344. // is available (as it should be if it comes from an Observable data store).
  345. options = options || {};
  346. var self = this,
  347. start = options.start || 0,
  348. row, rows, container;
  349. if(!beforeNode){
  350. this._lastCollection = results;
  351. }
  352. if(results.observe){
  353. // observe the results for changes
  354. var observerIndex = this.observers.push(results.observe(function(object, from, to){
  355. var firstRow;
  356. // a change in the data took place
  357. if(from > -1 && rows[from]){
  358. // remove from old slot
  359. row = rows.splice(from, 1)[0];
  360. // check to make the sure the node is still there before we try to remove it, (in case it was moved to a different place in the DOM)
  361. if(row.parentNode == container){
  362. firstRow = row.nextSibling;
  363. if(firstRow){ // it's possible for this to have been already removed if it is in overlapping query results
  364. firstRow.rowIndex--; // adjust the rowIndex so adjustRowIndices has the right starting point
  365. self.removeRow(row); // now remove
  366. }
  367. }
  368. // the removal of rows could cause us to need to page in more items
  369. if(self._processScroll){
  370. self._processScroll();
  371. }
  372. }
  373. if(to > -1){
  374. // add to new slot (either before an existing row, or at the end)
  375. row = self.newRow(object, rows[to] || (rows[to-1] && rows[to-1].nextSibling) || beforeNode, to, options);
  376. if(row){
  377. row.observerIndex = observerIndex;
  378. rows.splice(to, 0, row);
  379. if(!firstRow || to < firstRow.rowIndex){
  380. firstRow = row;
  381. }
  382. }
  383. options.count++;
  384. }
  385. from != to && firstRow && self.adjustRowIndices(firstRow);
  386. }, true)) - 1;
  387. }
  388. var rowsFragment = document.createDocumentFragment();
  389. // now render the results
  390. if(results.map){
  391. rows = results.map(mapEach, console.error);
  392. if(rows.then){
  393. return rows.then(whenDone);
  394. }
  395. }else{
  396. rows = [];
  397. for(var i = 0, l = results.length; i < l; i++){
  398. rows[i] = mapEach(results[i]);
  399. }
  400. }
  401. var lastRow;
  402. function mapEach(object){
  403. lastRow = self.insertRow(object, rowsFragment, null, start++, options);
  404. lastRow.observerIndex = observerIndex;
  405. return lastRow;
  406. }
  407. function whenDone(resolvedRows){
  408. container = beforeNode ? beforeNode.parentNode : self.contentNode;
  409. if(container){
  410. container.insertBefore(rowsFragment, beforeNode || null);
  411. lastRow = resolvedRows[resolvedRows.length - 1];
  412. lastRow && self.adjustRowIndices(lastRow);
  413. }
  414. return (rows = resolvedRows);
  415. }
  416. return whenDone(rows);
  417. },
  418. renderHeader: function(){
  419. // no-op in a plain list
  420. },
  421. _autoId: 0,
  422. insertRow: function(object, parent, beforeNode, i, options){
  423. // summary:
  424. // Creates a single row in the grid.
  425. var id = this.id + "-row-" + ((this.store && this.store.getIdentity) ?
  426. this.store.getIdentity(object) : this._autoId++);
  427. var row = byId(id);
  428. if(!row || // we must create a row if it doesn't exist, or if it previously belonged to a different container
  429. (beforeNode && row.parentNode != beforeNode.parentNode)){
  430. if(row){// if it existed elsewhere in the DOM, we will remove it, so we can recreate it
  431. this.removeRow(row);
  432. }
  433. row = this.renderRow(object, options);
  434. row.className = (row.className || "") + " ui-state-default dgrid-row " + (i % 2 == 1 ? oddClass : evenClass);
  435. // get the row id for easy retrieval
  436. this._rowIdToObject[row.id = id] = object;
  437. }
  438. parent.insertBefore(row, beforeNode);
  439. row.rowIndex = i;
  440. return row;
  441. },
  442. renderRow: function(value, options){
  443. // summary:
  444. // Responsible for returning the DOM for a single row in the grid.
  445. return put("div", "" + value);
  446. },
  447. removeRow: function(rowElement, justCleanup){
  448. // summary:
  449. // Simply deletes the node in a plain List.
  450. // Column plugins may aspect this to implement their own cleanup routines.
  451. // rowElement: Object|DOMNode
  452. // Object or element representing the row to be removed.
  453. // justCleanup: Boolean
  454. // If true, the row element will not be removed from the DOM; this can
  455. // be used by extensions/plugins in cases where the DOM will be
  456. // massively cleaned up at a later point in time.
  457. rowElement = rowElement.element || rowElement;
  458. delete this._rowIdToObject[rowElement.id];
  459. if(!justCleanup){
  460. put(rowElement, "!");
  461. }
  462. },
  463. row: function(target){
  464. // summary:
  465. // Get the row object by id, object, node, or event
  466. var id;
  467. if(target instanceof this._Row){ return target; } // no-op; already a row
  468. if(target.target && target.target.nodeType){
  469. // event
  470. target = target.target;
  471. }
  472. if(target.nodeType){
  473. var object;
  474. do{
  475. var rowId = target.id;
  476. if((object = this._rowIdToObject[rowId])){
  477. return new this._Row(rowId.substring(this.id.length + 5), object, target);
  478. }
  479. target = target.parentNode;
  480. }while(target && target != this.domNode);
  481. return;
  482. }
  483. if(typeof target == "object"){
  484. // assume target represents a store item
  485. id = this.store.getIdentity(target);
  486. }else{
  487. // assume target is a row ID
  488. id = target;
  489. target = this._rowIdToObject[this.id + "-row-" + id];
  490. }
  491. return new this._Row(id, target, byId(this.id + "-row-" + id));
  492. },
  493. cell: function(target){
  494. // this doesn't do much in a plain list
  495. return {
  496. row: this.row(target)
  497. };
  498. },
  499. _move: move,
  500. up: function(row, steps, visible){
  501. return this.row(move(row, -(steps || 1), "dgrid-row", visible));
  502. },
  503. down: function(row, steps, visible){
  504. return this.row(move(row, steps || 1, "dgrid-row", visible));
  505. },
  506. get: function(/*String*/ name /*, ... */){
  507. // summary:
  508. // Get a property on a List instance.
  509. // name:
  510. // The property to get.
  511. // returns:
  512. // The property value on this List instance.
  513. // description:
  514. // Get a named property on a List object. The property may
  515. // potentially be retrieved via a getter method in subclasses. In the base class
  516. // this just retrieves the object's property.
  517. var fn = "_get" + name.charAt(0).toUpperCase() + name.slice(1);
  518. if(typeof this[fn] === "function"){
  519. return this[fn].apply(this, [].slice.call(arguments, 1));
  520. }
  521. // Alert users that try to use Dijit-style getter/setters so they don’t get confused
  522. // if they try to use them and it does not work
  523. if(!has("dojo-built") && typeof this[fn + "Attr"] === "function"){
  524. console.warn("dgrid: Use " + fn + " instead of " + fn + "Attr for getting " + name);
  525. }
  526. return this[name];
  527. },
  528. set: function(/*String*/ name, /*Object*/ value /*, ... */){
  529. // summary:
  530. // Set a property on a List instance
  531. // name:
  532. // The property to set.
  533. // value:
  534. // The value to set in the property.
  535. // returns:
  536. // The function returns this List instance.
  537. // description:
  538. // Sets named properties on a List object.
  539. // A programmatic setter may be defined in subclasses.
  540. //
  541. // set() may also be called with a hash of name/value pairs, ex:
  542. // | myObj.set({
  543. // | foo: "Howdy",
  544. // | bar: 3
  545. // | })
  546. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  547. if(typeof name === "object"){
  548. for(var k in name){
  549. this.set(k, name[k]);
  550. }
  551. }else{
  552. var fn = "_set" + name.charAt(0).toUpperCase() + name.slice(1);
  553. if(typeof this[fn] === "function"){
  554. this[fn].apply(this, [].slice.call(arguments, 1));
  555. }else{
  556. // Alert users that try to use Dijit-style getter/setters so they don’t get confused
  557. // if they try to use them and it does not work
  558. if(!has("dojo-built") && typeof this[fn + "Attr"] === "function"){
  559. console.warn("dgrid: Use " + fn + " instead of " + fn + "Attr for setting " + name);
  560. }
  561. this[name] = value;
  562. }
  563. }
  564. return this;
  565. },
  566. _setSort: function(property, descending){
  567. // summary:
  568. // Sort the content
  569. // property: String|Array
  570. // String specifying field to sort by, or actual array of objects
  571. // with attribute and descending properties
  572. // descending: boolean
  573. // In the case where property is a string, this argument
  574. // specifies whether to sort ascending (false) or descending (true)
  575. this._sort = typeof property != "string" ? property :
  576. [{attribute: property, descending: descending}];
  577. this.refresh();
  578. if(this._lastCollection){
  579. if(property.length){
  580. // if an array was passed in, flatten to just first sort attribute
  581. // for default array sort logic
  582. if(typeof property != "string"){
  583. descending = property[0].descending;
  584. property = property[0].attribute;
  585. }
  586. this._lastCollection.sort(function(a,b){
  587. var aVal = a[property], bVal = b[property];
  588. // fall back undefined values to "" for more consistent behavior
  589. if(aVal === undefined){ aVal = ""; }
  590. if(bVal === undefined){ bVal = ""; }
  591. return aVal == bVal ? 0 : (aVal > bVal == !descending ? 1 : -1);
  592. });
  593. }
  594. this.renderArray(this._lastCollection);
  595. }
  596. },
  597. // TODO: remove the following two (and rename _sort to sort) in 1.0
  598. sort: function(property, descending){
  599. kernel.deprecated("sort(...)", 'use set("sort", ...) instead', "dgrid 1.0");
  600. this.set("sort", property, descending);
  601. },
  602. _getSort: function(){
  603. return this._sort;
  604. },
  605. _setShowHeader: function(show){
  606. // this is in List rather than just in Grid, primarily for two reasons:
  607. // (1) just in case someone *does* want to show a header in a List
  608. // (2) helps address IE < 8 header display issue in List
  609. this.showHeader = show;
  610. // add/remove class which has styles for "hiding" header
  611. put(this.headerNode, (show ? "!" : ".") + "dgrid-header-hidden");
  612. this.renderHeader();
  613. this.resize(); // to account for (dis)appearance of header
  614. },
  615. setShowHeader: function(show){
  616. kernel.deprecated("setShowHeader(...)", 'use set("showHeader", ...) instead', "dgrid 1.0");
  617. this.set("showHeader", show);
  618. }
  619. });
  620. });