Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
9.2 KiB

  1. /*!
  2. * Ext JS Library 3.2.0
  3. * Copyright(c) 2006-2010 Ext JS, Inc.
  4. * licensing@extjs.com
  5. * http://www.extjs.com/license
  6. */
  7. /**
  8. * @class Ext.data.GroupingStore
  9. * @extends Ext.data.Store
  10. * A specialized store implementation that provides for grouping records by one of the available fields. This
  11. * is usually used in conjunction with an {@link Ext.grid.GroupingView} to provide the data model for
  12. * a grouped GridPanel.
  13. *
  14. * Internally, GroupingStore is simply a normal Store with multi sorting enabled from the start. The grouping field
  15. * and direction are always injected as the first sorter pair. GroupingView picks up on the configured groupField and
  16. * builds grid rows appropriately.
  17. *
  18. * @constructor
  19. * Creates a new GroupingStore.
  20. * @param {Object} config A config object containing the objects needed for the Store to access data,
  21. * and read the data into Records.
  22. * @xtype groupingstore
  23. */
  24. Ext.data.GroupingStore = Ext.extend(Ext.data.Store, {
  25. //inherit docs
  26. constructor: function(config) {
  27. config = config || {};
  28. //We do some preprocessing here to massage the grouping + sorting options into a single
  29. //multi sort array. If grouping and sorting options are both presented to the constructor,
  30. //the sorters array consists of the grouping sorter object followed by the sorting sorter object
  31. //see Ext.data.Store's sorting functions for details about how multi sorting works
  32. this.hasMultiSort = true;
  33. this.multiSortInfo = this.multiSortInfo || {sorters: []};
  34. var sorters = this.multiSortInfo.sorters,
  35. groupField = config.groupField || this.groupField,
  36. sortInfo = config.sortInfo || this.sortInfo,
  37. groupDir = config.groupDir || this.groupDir;
  38. //add the grouping sorter object first
  39. if(groupField){
  40. sorters.push({
  41. field : groupField,
  42. direction: groupDir
  43. });
  44. }
  45. //add the sorting sorter object if it is present
  46. if (sortInfo) {
  47. sorters.push(sortInfo);
  48. }
  49. Ext.data.GroupingStore.superclass.constructor.call(this, config);
  50. this.addEvents(
  51. /**
  52. * @event groupchange
  53. * Fired whenever a call to store.groupBy successfully changes the grouping on the store
  54. * @param {Ext.data.GroupingStore} store The grouping store
  55. * @param {String} groupField The field that the store is now grouped by
  56. */
  57. 'groupchange'
  58. );
  59. this.applyGroupField();
  60. },
  61. /**
  62. * @cfg {String} groupField
  63. * The field name by which to sort the store's data (defaults to '').
  64. */
  65. /**
  66. * @cfg {Boolean} remoteGroup
  67. * True if the grouping should apply on the server side, false if it is local only (defaults to false). If the
  68. * grouping is local, it can be applied immediately to the data. If it is remote, then it will simply act as a
  69. * helper, automatically sending the grouping field name as the 'groupBy' param with each XHR call.
  70. */
  71. remoteGroup : false,
  72. /**
  73. * @cfg {Boolean} groupOnSort
  74. * True to sort the data on the grouping field when a grouping operation occurs, false to sort based on the
  75. * existing sort info (defaults to false).
  76. */
  77. groupOnSort:false,
  78. groupDir : 'ASC',
  79. /**
  80. * Clears any existing grouping and refreshes the data using the default sort.
  81. */
  82. clearGrouping : function(){
  83. this.groupField = false;
  84. if(this.remoteGroup){
  85. if(this.baseParams){
  86. delete this.baseParams.groupBy;
  87. delete this.baseParams.groupDir;
  88. }
  89. var lo = this.lastOptions;
  90. if(lo && lo.params){
  91. delete lo.params.groupBy;
  92. delete lo.params.groupDir;
  93. }
  94. this.reload();
  95. }else{
  96. this.sort();
  97. this.fireEvent('datachanged', this);
  98. }
  99. },
  100. /**
  101. * Groups the data by the specified field.
  102. * @param {String} field The field name by which to sort the store's data
  103. * @param {Boolean} forceRegroup (optional) True to force the group to be refreshed even if the field passed
  104. * in is the same as the current grouping field, false to skip grouping on the same field (defaults to false)
  105. */
  106. groupBy : function(field, forceRegroup, direction) {
  107. direction = direction ? (String(direction).toUpperCase() == 'DESC' ? 'DESC' : 'ASC') : this.groupDir;
  108. if (this.groupField == field && this.groupDir == direction && !forceRegroup) {
  109. return; // already grouped by this field
  110. }
  111. //check the contents of the first sorter. If the field matches the CURRENT groupField (before it is set to the new one),
  112. //remove the sorter as it is actually the grouper. The new grouper is added back in by this.sort
  113. sorters = this.multiSortInfo.sorters;
  114. if (sorters.length > 0 && sorters[0].field == this.groupField) {
  115. sorters.shift();
  116. }
  117. this.groupField = field;
  118. this.groupDir = direction;
  119. this.applyGroupField();
  120. var fireGroupEvent = function() {
  121. this.fireEvent('groupchange', this, this.getGroupState());
  122. };
  123. if (this.groupOnSort) {
  124. this.sort(field, direction);
  125. fireGroupEvent.call(this);
  126. return;
  127. }
  128. if (this.remoteGroup) {
  129. this.on('load', fireGroupEvent, this, {single: true});
  130. this.reload();
  131. } else {
  132. this.sort(sorters);
  133. fireGroupEvent.call(this);
  134. }
  135. },
  136. //GroupingStore always uses multisorting so we intercept calls to sort here to make sure that our grouping sorter object
  137. //is always injected first.
  138. sort : function(fieldName, dir) {
  139. if (this.remoteSort) {
  140. return Ext.data.GroupingStore.superclass.sort.call(this, fieldName, dir);
  141. }
  142. var sorters = [];
  143. //cater for any existing valid arguments to this.sort, massage them into an array of sorter objects
  144. if (Ext.isArray(arguments[0])) {
  145. sorters = arguments[0];
  146. } else if (fieldName == undefined) {
  147. //we preserve the existing sortInfo here because this.sort is called after
  148. //clearGrouping and there may be existing sorting
  149. sorters = [this.sortInfo];
  150. } else {
  151. //TODO: this is lifted straight from Ext.data.Store's singleSort function. It should instead be
  152. //refactored into a common method if possible
  153. var field = this.fields.get(fieldName);
  154. if (!field) return false;
  155. var name = field.name,
  156. sortInfo = this.sortInfo || null,
  157. sortToggle = this.sortToggle ? this.sortToggle[name] : null;
  158. if (!dir) {
  159. if (sortInfo && sortInfo.field == name) { // toggle sort dir
  160. dir = (this.sortToggle[name] || 'ASC').toggle('ASC', 'DESC');
  161. } else {
  162. dir = field.sortDir;
  163. }
  164. }
  165. this.sortToggle[name] = dir;
  166. this.sortInfo = {field: name, direction: dir};
  167. sorters = [this.sortInfo];
  168. }
  169. //add the grouping sorter object as the first multisort sorter
  170. if (this.groupField) {
  171. sorters.unshift({direction: this.groupDir, field: this.groupField});
  172. }
  173. return this.multiSort.call(this, sorters, dir);
  174. },
  175. /**
  176. * @private
  177. * Saves the current grouping field and direction to this.baseParams and this.lastOptions.params
  178. * if we're using remote grouping. Does not actually perform any grouping - just stores values
  179. */
  180. applyGroupField: function(){
  181. if (this.remoteGroup) {
  182. if(!this.baseParams){
  183. this.baseParams = {};
  184. }
  185. Ext.apply(this.baseParams, {
  186. groupBy : this.groupField,
  187. groupDir: this.groupDir
  188. });
  189. var lo = this.lastOptions;
  190. if (lo && lo.params) {
  191. lo.params.groupDir = this.groupDir;
  192. //this is deleted because of a bug reported at http://www.extjs.com/forum/showthread.php?t=82907
  193. delete lo.params.groupBy;
  194. }
  195. }
  196. },
  197. /**
  198. * @private
  199. * TODO: This function is apparently never invoked anywhere in the framework. It has no documentation
  200. * and should be considered for deletion
  201. */
  202. applyGrouping : function(alwaysFireChange){
  203. if(this.groupField !== false){
  204. this.groupBy(this.groupField, true, this.groupDir);
  205. return true;
  206. }else{
  207. if(alwaysFireChange === true){
  208. this.fireEvent('datachanged', this);
  209. }
  210. return false;
  211. }
  212. },
  213. /**
  214. * @private
  215. * Returns the grouping field that should be used. If groupOnSort is used this will be sortInfo's field,
  216. * otherwise it will be this.groupField
  217. * @return {String} The group field
  218. */
  219. getGroupState : function(){
  220. return this.groupOnSort && this.groupField !== false ?
  221. (this.sortInfo ? this.sortInfo.field : undefined) : this.groupField;
  222. }
  223. });
  224. Ext.reg('groupingstore', Ext.data.GroupingStore);