1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file.
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen/**
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * @fileoverview This is a table data model
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsencr.define('cr.ui.table', function() {
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const EventTarget = cr.EventTarget;
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const Event = cr.Event;
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const ArrayDataModel = cr.ui.ArrayDataModel;
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * A table data model that supports sorting by storing initial indexes of
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * elements for each position in sorted array.
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @param {!Array} items The underlying array.
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @constructor
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @extends {ArrayDataModel}
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function TableDataModel(items) {
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ArrayDataModel.apply(this, arguments);
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    this.indexes_ = [];
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (var i = 0; i < items.length; i++) {
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.indexes_.push(i);
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TableDataModel.prototype = {
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    __proto__: ArrayDataModel.prototype,
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Returns the item at the given index.
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * This implementation returns the item at the given index in the source
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * array before sort.
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} index The index of the element to get.
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {*} The element at the given index.
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    getItemByUnsortedIndex_: function(unsortedIndex) {
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return ArrayDataModel.prototype.item.call(this, unsortedIndex);
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Returns the item at the given index.
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * This implementation returns the item at the given index in the sorted
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * array.
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} index The index of the element to get.
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {*} The element at the given index.
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    item: function(index) {
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (index >= 0 && index < this.length)
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return this.getItemByUnsortedIndex_(this.indexes_[index]);
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return undefined;
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Returns compare function set for given field.
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field The field to get compare function for.
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {Function(*, *): number} Compare function set for given field.
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    compareFunction: function(field) {
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return this.compareFunctions_[field];
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Sets compare function for given field.
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field The field to set compare function.
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {Function(*, *): number} Compare function to set for given field.
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    setCompareFunction: function(field, compareFunction) {
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.compareFunctions_[field] = compareFunction;
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Returns current sort status.
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {!Object} Current sort status.
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    get sortStatus() {
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.sortStatus_) {
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return this.createSortStatus(
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            this.sortStatus_.field, this.sortStatus_.direction);
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return this.createSortStatus(null, null);
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * This removes and adds items to the model.
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * This dispatches a splice event.
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * This implementation runs sort after splice and creates permutation for
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * the whole change.
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} index The index of the item to update.
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} deleteCount The number of items to remove.
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {...*} The items to add.
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {!Array} An array with the removed items.
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    splice: function(index, deleteCount, var_args) {
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var addCount = arguments.length - 2;
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var newIndexes = [];
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var deletePermutation = [];
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var deleted = 0;
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.indexes_.length; i++) {
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var oldIndex = this.indexes_[i];
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (oldIndex < index) {
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          newIndexes.push(oldIndex);
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          deletePermutation.push(i - deleted);
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        } else if (oldIndex >= index + deleteCount) {
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          newIndexes.push(oldIndex - deleteCount + addCount);
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          deletePermutation.push(i - deleted);
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        } else {
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          deletePermutation.push(-1);
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          deleted++;
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < addCount; i++) {
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        newIndexes.push(index + i);
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.indexes_ = newIndexes;
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var rv = ArrayDataModel.prototype.splice.apply(this, arguments);
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var splicePermutation;
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.sortStatus.field) {
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var sortPermutation = this.doSort_(this.sortStatus.field,
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           this.sortStatus.direction);
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        splicePermutation = deletePermutation.map(function(element) {
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          return element != -1 ? sortPermutation[element] : -1;
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        });
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        splicePermutation = deletePermutation;
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.dispatchSortEvent_(splicePermutation);
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return rv;
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Use this to update a given item in the array. This does not remove and
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * reinsert a new item.
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * This dispatches a change event.
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * This implementation runs sort after updating.
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {number} index The index of the item to update.
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    updateIndex: function(index) {
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ArrayDataModel.prototype.updateIndex.apply(this, arguments);
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.sortStatus.field)
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        this.sort(this.sortStatus.field, this.sortStatus.direction);
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Creates sort status with given field and direction.
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field Sort field.
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} direction Sort direction.
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {!Object} Created sort status.
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    createSortStatus: function(field, direction) {
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return {
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        field: field,
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        direction: direction
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      };
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Called before a sort happens so that you may fetch additional data
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * required for the sort.
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *
167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field Sort field.
168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {function()} callback The function to invoke when preparation
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *     is complete.
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    prepareSort: function(field, callback) {
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      callback();
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Sorts data model according to given field and direction and dispathes
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * sorted event.
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field Sort field.
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} direction Sort direction.
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sort: function(field, direction) {
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var self = this;
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.prepareSort(field, function() {
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var sortPermutation = self.doSort_(field, direction);
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        self.dispatchSortEvent_(sortPermutation);
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      });
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Sorts data model according to given field and direction.
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field Sort field.
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} direction Sort direction.
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    doSort_: function(field, direction) {
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var compareFunction = this.sortFunction_(field, direction);
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var positions = [];
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.length; i++) {
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        positions[this.indexes_[i]] = i;
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.indexes_.sort(compareFunction);
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.sortStatus_ = this.createSortStatus(field, direction);
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var sortPermutation = [];
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < this.length; i++) {
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        sortPermutation[positions[this.indexes_[i]]] = i;
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return sortPermutation;
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    dispatchSortEvent_: function(sortPermutation) {
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var e = new Event('sorted');
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      e.sortPermutation = sortPermutation;
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.dispatchEvent(e);
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Creates compare function for the field.
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Returns the function set as sortFunction for given field
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * or default compare function
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field Sort field.
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {Function(*, *): number} Compare function.
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    createCompareFunction_: function(field) {
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var compareFunction =
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          this.compareFunctions_ ? this.compareFunctions_[field] : null;
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var defaultValuesCompareFunction = this.defaultValuesCompareFunction;
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (compareFunction) {
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return compareFunction;
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return function(a, b) {
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          return defaultValuesCompareFunction.call(null, a[field], b[field]);
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return compareFunction;
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Creates compare function for given field and direction.
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} field Sort field.
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} direction Sort direction.
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {Function(*, *): number} Compare function.
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sortFunction_: function(field, direction) {
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var compareFunction = this.createCompareFunction_(field);
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var dirMultiplier = direction == 'desc' ? -1 : 1;
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return function(index1, index2) {
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var item1 = this.getItemByUnsortedIndex_(index1);
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var item2 = this.getItemByUnsortedIndex_(index2);
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        var compareResult = compareFunction.call(null, item1, item2);
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (compareResult != 0)
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          return dirMultiplier * compareResult;
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return dirMultiplier * this.defaultValuesCompareFunction(index1,
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                                 index2);
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }.bind(this);
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Default compare function.
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    defaultValuesCompareFunction: function(a, b) {
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // We could insert i18n comparisons here.
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (a < b)
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return -1;
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (a > b)
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return 1;
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return 0;
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return {
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TableDataModel: TableDataModel
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen});
276