pushpop-rails 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +42 -0
- data/Rakefile +29 -0
- data/lib/generators/pushpop/install/install_generator.rb +17 -0
- data/lib/pushpop-rails.rb +4 -0
- data/lib/pushpop/rails.rb +8 -0
- data/lib/pushpop/rails/engine.rb +7 -0
- data/lib/pushpop/rails/version.rb +5 -0
- data/vendor/assets/Pushpop/background.png +0 -0
- data/vendor/assets/Pushpop/background@2x.png +0 -0
- data/vendor/assets/Pushpop/externals/scrollkit/background.png +0 -0
- data/vendor/assets/Pushpop/externals/scrollkit/scrollkit.css +202 -0
- data/vendor/assets/Pushpop/externals/scrollkit/scrollkit.js +924 -0
- data/vendor/assets/Pushpop/font/pushpop-glyphs-webfont.eot +0 -0
- data/vendor/assets/Pushpop/font/pushpop-glyphs-webfont.svg +57 -0
- data/vendor/assets/Pushpop/font/pushpop-glyphs-webfont.ttf +0 -0
- data/vendor/assets/Pushpop/font/pushpop-glyphs-webfont.woff +0 -0
- data/vendor/assets/Pushpop/pushpop-modal-view-stack/pushpop-modal-view-stack.css +148 -0
- data/vendor/assets/Pushpop/pushpop-modal-view-stack/pushpop-modal-view-stack.js +306 -0
- data/vendor/assets/Pushpop/pushpop-popover-view-stack/pushpop-popover-view-stack.css +170 -0
- data/vendor/assets/Pushpop/pushpop-popover-view-stack/pushpop-popover-view-stack.js +278 -0
- data/vendor/assets/Pushpop/pushpop-split-view/pushpop-split-view.css +38 -0
- data/vendor/assets/Pushpop/pushpop-split-view/pushpop-split-view.js +33 -0
- data/vendor/assets/Pushpop/pushpop-tab-view/pushpop-tab-view.css +130 -0
- data/vendor/assets/Pushpop/pushpop-tab-view/pushpop-tab-view.js +298 -0
- data/vendor/assets/Pushpop/pushpop-table-view/pushpop-table-view.css +1273 -0
- data/vendor/assets/Pushpop/pushpop-table-view/pushpop-table-view.js +2275 -0
- data/vendor/assets/Pushpop/pushpop.css +2243 -0
- data/vendor/assets/Pushpop/pushpop.js +1554 -0
- data/vendor/assets/javascripts/pushpop_rails.js +7 -0
- data/vendor/assets/stylesheets/pushpop_rails.css +9 -0
- metadata +92 -0
@@ -0,0 +1,2275 @@
|
|
1
|
+
;'use strict';
|
2
|
+
|
3
|
+
// The base Pushpop object.
|
4
|
+
var Pushpop = window['Pushpop'] || {};
|
5
|
+
|
6
|
+
/**
|
7
|
+
Creates a new TableView.
|
8
|
+
@param {HTMLUListElement} element The UL element to initialize as a new TableView.
|
9
|
+
@constructor
|
10
|
+
*/
|
11
|
+
Pushpop.TableView = function TableView(element) {
|
12
|
+
if (!element) return;
|
13
|
+
|
14
|
+
var $element = this.$element = $(element);
|
15
|
+
element = this.element = $element[0];
|
16
|
+
|
17
|
+
var tableView = element.tableView;
|
18
|
+
if (tableView) return tableView;
|
19
|
+
|
20
|
+
var self = element.tableView = this;
|
21
|
+
|
22
|
+
// Make sure this table view has a scroll view, otherwise, stop initialization.
|
23
|
+
var view = this.getView();
|
24
|
+
if (!view) return;
|
25
|
+
|
26
|
+
var scrollView = this.scrollView = view.getScrollView();
|
27
|
+
if (!scrollView) return;
|
28
|
+
|
29
|
+
// Determine if a search bar should be added to this table view.
|
30
|
+
var containsSearchBar = $element.attr('data-contains-search-bar') || 'false';
|
31
|
+
if ((containsSearchBar = containsSearchBar !== 'false')) this.setSearchBar(new Pushpop.TableViewSearchBar(this));
|
32
|
+
|
33
|
+
// Set up the loading message element for this table view.
|
34
|
+
var $loadingMessageElement = this._$loadingMessageElement = $('<div class="pp-table-view-loading-message pp-hidden"/>').insertBefore(scrollView.$content);
|
35
|
+
var $loadingSpinnerElement = this._$loadingSpinnerElement = $('<div class="pp-table-view-loading-spinner"/>');
|
36
|
+
var loadingSpinner = this._loadingSpinner = new Spinner({
|
37
|
+
lines: 12, // The number of lines to draw
|
38
|
+
length: 6, // The length of each line
|
39
|
+
width: 4, // The line thickness
|
40
|
+
radius: 8, // The radius of the inner circle
|
41
|
+
corners: 1, // Corner roundness (0..1)
|
42
|
+
color: '#111', // #rgb or #rrggbb
|
43
|
+
speed: 1, // Rounds per second
|
44
|
+
trail: 60, // Afterglow percentage
|
45
|
+
hwaccel: true // Whether to use hardware acceleration
|
46
|
+
}).spin($loadingSpinnerElement[0]);
|
47
|
+
|
48
|
+
this.setLoadingMessageHtml(this.getLoadingMessageHtml());
|
49
|
+
|
50
|
+
// Instantiate instance variables.
|
51
|
+
this._renderedCells = [];
|
52
|
+
this._reusableCells = {};
|
53
|
+
this._selectedRowIndexes = [];
|
54
|
+
|
55
|
+
// Determine if this is running on a device with touch support.
|
56
|
+
var isTouchSupported = !!('ontouchstart' in window);
|
57
|
+
|
58
|
+
// Handle virtual rendering of table view cells when the table view is scrolled.
|
59
|
+
scrollView.$bind('scroll', function(evt) {
|
60
|
+
if (self.getDrawing()) return;
|
61
|
+
|
62
|
+
var minimumScrollPositionThreshold = self.getMinimumScrollPositionThreshold();
|
63
|
+
var maximumScrollPositionThreshold = self.getMaximumScrollPositionThreshold();
|
64
|
+
var scrollPosition = self.getScrollPosition();
|
65
|
+
|
66
|
+
if ((minimumScrollPositionThreshold !== -1 && scrollPosition < minimumScrollPositionThreshold) ||
|
67
|
+
(maximumScrollPositionThreshold !== -1 && scrollPosition >= maximumScrollPositionThreshold)) self.draw();
|
68
|
+
});
|
69
|
+
|
70
|
+
// Force a redraw when the DidScrollToTop event occurs on the scroll view.
|
71
|
+
scrollView.$bind(ScrollKit.ScrollView.EventType.DidScrollToTop, function(evt) { self.draw(); });
|
72
|
+
|
73
|
+
// Handle mouse/touch events to allow the user to tap accessory buttons.
|
74
|
+
var isPendingAccessoryButtonTap = false;
|
75
|
+
|
76
|
+
$element.delegate('.pp-table-view-cell-accessory', isTouchSupported ? 'touchstart' : 'mousedown', function(evt) {
|
77
|
+
isPendingAccessoryButtonTap = true;
|
78
|
+
});
|
79
|
+
$element.delegate('.pp-table-view-cell-accessory', isTouchSupported ? 'touchend' : 'mouseup', function(evt) {
|
80
|
+
if (!isPendingAccessoryButtonTap) return;
|
81
|
+
isPendingAccessoryButtonTap = false;
|
82
|
+
|
83
|
+
var tableViewCell = $(this).parent()[0].tableViewCell;
|
84
|
+
if (!tableViewCell) return;
|
85
|
+
|
86
|
+
var index = tableViewCell.getIndex();
|
87
|
+
|
88
|
+
// Trigger the AccessoryButtonTappedForRowWithIndex event on this and all parent table view elements.
|
89
|
+
self.triggerEventOnParentTableViews($.Event(Pushpop.TableView.EventType.AccessoryButtonTappedForRowWithIndex, {
|
90
|
+
tableView: self,
|
91
|
+
tableViewCell: tableViewCell,
|
92
|
+
index: index,
|
93
|
+
item: self.getDataSource().getFilteredItemAtIndex(index),
|
94
|
+
element: this
|
95
|
+
}), true);
|
96
|
+
});
|
97
|
+
|
98
|
+
// Handle mouse/touch events to allow the user to tap editing accessory buttons.
|
99
|
+
var isPendingEditingAccessoryButtonTap = false;
|
100
|
+
|
101
|
+
$element.delegate('.pp-table-view-cell-editing-accessory', isTouchSupported ? 'touchstart' : 'mousedown', function(evt) {
|
102
|
+
isPendingEditingAccessoryButtonTap = true;
|
103
|
+
});
|
104
|
+
$element.delegate('.pp-table-view-cell-editing-accessory', isTouchSupported ? 'touchend' : 'mouseup', function(evt) {
|
105
|
+
if (!isPendingEditingAccessoryButtonTap) return;
|
106
|
+
isPendingEditingAccessoryButtonTap = false;
|
107
|
+
|
108
|
+
var tableViewCell = $(this).parent()[0].tableViewCell;
|
109
|
+
if (!tableViewCell) return;
|
110
|
+
|
111
|
+
var index = tableViewCell.getIndex();
|
112
|
+
|
113
|
+
// Trigger the EditingAccessoryButtonTappedForRowWithIndex event on this and all parent table view elements.
|
114
|
+
self.triggerEventOnParentTableViews($.Event(Pushpop.TableView.EventType.EditingAccessoryButtonTappedForRowWithIndex, {
|
115
|
+
tableView: self,
|
116
|
+
tableViewCell: tableViewCell,
|
117
|
+
index: index,
|
118
|
+
item: self.getDataSource().getFilteredItemAtIndex(index),
|
119
|
+
element: this
|
120
|
+
}), true);
|
121
|
+
});
|
122
|
+
|
123
|
+
// Handle mouse/touch events to allow the user to make row selections.
|
124
|
+
var isPendingSelection = false, selectionTimeout = null;
|
125
|
+
|
126
|
+
$element.delegate('li', isTouchSupported ? 'touchstart' : 'mousedown', function(evt) {
|
127
|
+
var tableViewCell = this.tableViewCell;
|
128
|
+
if (!tableViewCell) return;
|
129
|
+
|
130
|
+
// Don't allow row to be selected if an accessory button is pending a tap.
|
131
|
+
if (isPendingAccessoryButtonTap || isPendingEditingAccessoryButtonTap) return;
|
132
|
+
|
133
|
+
isPendingSelection = true;
|
134
|
+
|
135
|
+
selectionTimeout = window.setTimeout(function() {
|
136
|
+
if (!isPendingSelection) return;
|
137
|
+
isPendingSelection = false;
|
138
|
+
|
139
|
+
tableViewCell.didReceiveTap();
|
140
|
+
self.selectRowAtIndex(tableViewCell.getIndex());
|
141
|
+
}, self.getSelectionTimeoutDuration());
|
142
|
+
});
|
143
|
+
$element.delegate('li', isTouchSupported ? 'touchend' : 'mouseup', function(evt) {
|
144
|
+
var tableViewCell = this.tableViewCell;
|
145
|
+
if (!tableViewCell || !isPendingSelection) return;
|
146
|
+
|
147
|
+
isPendingSelection = false;
|
148
|
+
|
149
|
+
window.clearTimeout(selectionTimeout);
|
150
|
+
|
151
|
+
tableViewCell.didReceiveTap();
|
152
|
+
self.selectRowAtIndex(this.tableViewCell.getIndex());
|
153
|
+
evt.preventDefault();
|
154
|
+
});
|
155
|
+
|
156
|
+
// Cancel any pending accessory, editing accessory or row selections if a mouse or touch move occurs.
|
157
|
+
$element.bind(isTouchSupported ? 'touchmove' : 'mousemove', function(evt) {
|
158
|
+
if (isPendingAccessoryButtonTap) isPendingAccessoryButtonTap = false;
|
159
|
+
else if (isPendingEditingAccessoryButtonTap) isPendingEditingAccessoryButtonTap = false;
|
160
|
+
else if (isPendingSelection) {
|
161
|
+
isPendingSelection = false;
|
162
|
+
window.clearTimeout(selectionTimeout);
|
163
|
+
}
|
164
|
+
});
|
165
|
+
|
166
|
+
// Create a new data source from a data set URL.
|
167
|
+
var dataSetUrl = $element.attr('data-set-url');
|
168
|
+
if (dataSetUrl) $.getJSON(dataSetUrl, function(dataSet) {
|
169
|
+
$element.html(null);
|
170
|
+
self.setDataSource(new Pushpop.TableViewDataSource(dataSet));
|
171
|
+
});
|
172
|
+
|
173
|
+
// Create a new data source from existing <li/> elements.
|
174
|
+
else (function(self, $element) {
|
175
|
+
var dataSet = [];
|
176
|
+
var dashAlpha = /-([a-z]|[0-9])/ig;
|
177
|
+
var camelCase = function(string) { return string.replace(dashAlpha, function(all, letter) { return (letter + '').toUpperCase(); }); };
|
178
|
+
|
179
|
+
$element.children('li').each(function(index, element) {
|
180
|
+
var data = { title: $(element).html() };
|
181
|
+
var attributes = element.attributes;
|
182
|
+
var attribute, attributeName, attributeValue;
|
183
|
+
for (var i = 0, length = attributes.length; i < length; i++) {
|
184
|
+
attribute = attributes[i];
|
185
|
+
attributeName = attribute.name;
|
186
|
+
attributeValue = attribute.value;
|
187
|
+
|
188
|
+
try { attributeValue = JSON.parse(attributeValue); } catch (ex) {}
|
189
|
+
|
190
|
+
if (attributeName.indexOf('data-') === 0) data[camelCase(attributeName.substring(5))] = attributeValue;
|
191
|
+
}
|
192
|
+
|
193
|
+
data.reuseIdentifier = data.reuseIdentifier || 'pp-table-view-cell-default';
|
194
|
+
|
195
|
+
dataSet.push(data);
|
196
|
+
});
|
197
|
+
|
198
|
+
$element.html(null);
|
199
|
+
self.setDataSource(new Pushpop.TableViewDataSource(dataSet));
|
200
|
+
})(self, $element);
|
201
|
+
};
|
202
|
+
|
203
|
+
/**
|
204
|
+
Event types for Pushpop.TableView.
|
205
|
+
*/
|
206
|
+
Pushpop.TableView.EventType = {
|
207
|
+
DidSelectRowAtIndex: 'Pushpop:TableView:DidSelectRowAtIndex',
|
208
|
+
DidDeselectRowAtIndex: 'Pushpop:TableView:DidDeselectRowAtIndex',
|
209
|
+
AccessoryButtonTappedForRowWithIndex: 'Pushpop:TableView:AccessoryButtonTappedForRowWithIndex',
|
210
|
+
EditingAccessoryButtonTappedForRowWithIndex: 'Pushpop:TableView:EditingAccessoryButtonTappedForRowWithIndex',
|
211
|
+
DidReloadData: 'Pushpop:TableView:DidReloadData',
|
212
|
+
DidDrawRowsWithIndexes: 'Pushpop:TableView:DidDrawRowsWithIndexes',
|
213
|
+
DidChangeValueForItemInDataSource: 'Pushpop:TableView:DidChangeValueForItemInDataSource',
|
214
|
+
DidChangeDataSource: 'Pushpop:TableView:DidChangeDataSource'
|
215
|
+
};
|
216
|
+
|
217
|
+
Pushpop.TableView._reusableCellPrototypes = {};
|
218
|
+
Pushpop.TableView.getReusableCellPrototypes = function() {
|
219
|
+
var reusableCellPrototypes = Pushpop.TableView._reusableCellPrototypes, items = [];
|
220
|
+
for (var reusableCellPrototype in reusableCellPrototypes) items.push(reusableCellPrototypes[reusableCellPrototype]);
|
221
|
+
return items;
|
222
|
+
};
|
223
|
+
|
224
|
+
Pushpop.TableView.getReusableCellPrototypeWithIdentifier = function(reuseIdentifier) { return Pushpop.TableView._reusableCellPrototypes[reuseIdentifier]; };
|
225
|
+
|
226
|
+
Pushpop.TableView.registerReusableCellPrototype = function(cellPrototype) {
|
227
|
+
var reuseIdentifier;
|
228
|
+
if (!cellPrototype || !(reuseIdentifier = cellPrototype.getReuseIdentifier())) return;
|
229
|
+
Pushpop.TableView._reusableCellPrototypes[reuseIdentifier] = cellPrototype;
|
230
|
+
};
|
231
|
+
|
232
|
+
Pushpop.TableView.prototype = {
|
233
|
+
constructor: Pushpop.TableView,
|
234
|
+
|
235
|
+
element: null,
|
236
|
+
$element: null,
|
237
|
+
|
238
|
+
scrollView: null,
|
239
|
+
|
240
|
+
/**
|
241
|
+
|
242
|
+
*/
|
243
|
+
getVisibleHeight: function() { return this.scrollView.getSize().height; },
|
244
|
+
|
245
|
+
/**
|
246
|
+
|
247
|
+
*/
|
248
|
+
getTotalHeight: function() { return this.getDataSource().getNumberOfRows() * this.getRowHeight(); },
|
249
|
+
|
250
|
+
/**
|
251
|
+
|
252
|
+
*/
|
253
|
+
getScrollPosition: function() { return this.scrollView.getScrollPosition().y; },
|
254
|
+
|
255
|
+
_minimumScrollPositionThreshold: -1,
|
256
|
+
|
257
|
+
/**
|
258
|
+
|
259
|
+
*/
|
260
|
+
getMinimumScrollPositionThreshold: function() { return this._minimumScrollPositionThreshold; },
|
261
|
+
|
262
|
+
_maximumScrollPositionThreshold: -1,
|
263
|
+
|
264
|
+
/**
|
265
|
+
|
266
|
+
*/
|
267
|
+
getMaximumScrollPositionThreshold: function() { return this._maximumScrollPositionThreshold; },
|
268
|
+
|
269
|
+
/**
|
270
|
+
|
271
|
+
*/
|
272
|
+
getMinimumVisibleRowIndex: function() { return Math.min(Math.floor(this.getScrollPosition() / this.getRowHeight()), this.getDataSource().getNumberOfRows() - 1); },
|
273
|
+
|
274
|
+
/**
|
275
|
+
|
276
|
+
*/
|
277
|
+
getMaximumVisibleRowIndex: function() { return Math.min(this.getMinimumVisibleRowIndex() + this.getNumberOfVisibleRows(), this.getDataSource().getNumberOfRows()) - 1; },
|
278
|
+
|
279
|
+
/**
|
280
|
+
|
281
|
+
*/
|
282
|
+
getNumberOfVisibleRows: function() { return Math.min(Math.ceil(this.getVisibleHeight() / this.getRowHeight()), this.getDataSource().getNumberOfRows()); },
|
283
|
+
|
284
|
+
_renderedCells: null, // []
|
285
|
+
|
286
|
+
/**
|
287
|
+
|
288
|
+
*/
|
289
|
+
getRenderedCells: function() { return this._renderedCells; },
|
290
|
+
|
291
|
+
/**
|
292
|
+
|
293
|
+
*/
|
294
|
+
getRenderedCellAtIndex: function(index) {
|
295
|
+
var renderedCells = this.getRenderedCells();
|
296
|
+
for (var i = 0, length = renderedCells.length, renderedCell; i < length; i++) if ((renderedCell = renderedCells[i]).getIndex() === index) return renderedCell;
|
297
|
+
return null;
|
298
|
+
},
|
299
|
+
|
300
|
+
_minimumRenderedRowIndex: -1,
|
301
|
+
|
302
|
+
/**
|
303
|
+
|
304
|
+
*/
|
305
|
+
getMinimumRenderedRowIndex: function() { return this._minimumRenderedRowIndex; },
|
306
|
+
|
307
|
+
_maximumRenderedRowIndex: -1,
|
308
|
+
|
309
|
+
/**
|
310
|
+
|
311
|
+
*/
|
312
|
+
getMaximumRenderedRowIndex: function() { return this._maximumRenderedRowIndex; },
|
313
|
+
|
314
|
+
_reusableCells: null, // {}
|
315
|
+
|
316
|
+
/**
|
317
|
+
|
318
|
+
*/
|
319
|
+
getReusableCells: function() { return this._reusableCells; },
|
320
|
+
|
321
|
+
/**
|
322
|
+
|
323
|
+
*/
|
324
|
+
getReusableCellsWithIdentifier: function(reuseIdentifier) {
|
325
|
+
var reusableCells = this.getReusableCells();
|
326
|
+
return reusableCells[reuseIdentifier] || (reusableCells[reuseIdentifier] = []);
|
327
|
+
},
|
328
|
+
|
329
|
+
/**
|
330
|
+
Returns a new or recycled TableViewCell with the specified reuse identifier.
|
331
|
+
@description This method will first attempt to reuse a recycled TableViewCell
|
332
|
+
with the specified reuse identifier. If no recycled TableViewCells with that
|
333
|
+
reuse identifier are available, a new one will be instantiated and returned.
|
334
|
+
The TableViewCell that is returned is always added to the |renderedCells| array.
|
335
|
+
@type Pushpop.TableViewCell
|
336
|
+
*/
|
337
|
+
dequeueReusableCellWithIdentifier: function(reuseIdentifier) {
|
338
|
+
var renderedCells = this.getRenderedCells();
|
339
|
+
var reusableCells = this.getReusableCellsWithIdentifier(reuseIdentifier);
|
340
|
+
|
341
|
+
var cell = null, cellPrototype = null;
|
342
|
+
|
343
|
+
if (reusableCells.length > 0) {
|
344
|
+
cell = reusableCells.pop();
|
345
|
+
} else {
|
346
|
+
cellPrototype = Pushpop.TableView.getReusableCellPrototypeWithIdentifier(reuseIdentifier);
|
347
|
+
cell = (cellPrototype) ? new cellPrototype.constructor(reuseIdentifier) : new Pushpop.TableViewCell(reuseIdentifier);
|
348
|
+
}
|
349
|
+
|
350
|
+
renderedCells.push(cell);
|
351
|
+
cell.tableView = this;
|
352
|
+
|
353
|
+
return cell;
|
354
|
+
},
|
355
|
+
|
356
|
+
_drawing: false,
|
357
|
+
|
358
|
+
getDrawing: function() { return this._drawing; },
|
359
|
+
|
360
|
+
/**
|
361
|
+
|
362
|
+
*/
|
363
|
+
draw: function() {
|
364
|
+
if (this._drawing) return;
|
365
|
+
this._drawing = true;
|
366
|
+
|
367
|
+
var dataSource = this.getDataSource();
|
368
|
+
|
369
|
+
var minimumVisibleRowIndex = this.getMinimumVisibleRowIndex();
|
370
|
+
var maximumVisibleRowIndex = this.getMaximumVisibleRowIndex();
|
371
|
+
|
372
|
+
var numberOfRows = dataSource.getNumberOfRows();
|
373
|
+
var numberOfVisibleRows = this.getNumberOfVisibleRows();
|
374
|
+
var numberOfLeadingRows = Math.min(numberOfVisibleRows, minimumVisibleRowIndex);
|
375
|
+
var numberOfTrailingRows = Math.min(numberOfVisibleRows, numberOfRows - maximumVisibleRowIndex - 1);
|
376
|
+
|
377
|
+
var lastMinimumRenderedRowIndex = this.getMinimumRenderedRowIndex();
|
378
|
+
var lastMaximumRenderedRowIndex = this.getMaximumRenderedRowIndex();
|
379
|
+
|
380
|
+
var minimumRenderedRowIndex = this._minimumRenderedRowIndex = minimumVisibleRowIndex - numberOfLeadingRows;
|
381
|
+
var maximumRenderedRowIndex = this._maximumRenderedRowIndex = maximumVisibleRowIndex + numberOfTrailingRows;
|
382
|
+
|
383
|
+
var lastMinimumScrollPositionThreshold = this._minimumScrollPositionThreshold;
|
384
|
+
var lastMaximumScrollPositionThreshold = this._maximumScrollPositionThreshold;
|
385
|
+
|
386
|
+
var scrollPosition = this.getScrollPosition();
|
387
|
+
|
388
|
+
var visibleHeight = this.getVisibleHeight();
|
389
|
+
var totalHeight = this.getTotalHeight();
|
390
|
+
var rowHeight = this.getRowHeight();
|
391
|
+
|
392
|
+
var scrollView = this.scrollView;
|
393
|
+
var lastScrollViewMargin = scrollView.getMargin();
|
394
|
+
var scrollViewMarginTop = minimumRenderedRowIndex * rowHeight;
|
395
|
+
var scrollViewMarginBottom = (numberOfRows - maximumRenderedRowIndex - 1) * rowHeight;
|
396
|
+
|
397
|
+
scrollView.setMargin(scrollViewMarginTop, lastScrollViewMargin.right, scrollViewMarginBottom, lastScrollViewMargin.left);
|
398
|
+
|
399
|
+
var $element = this.$element;
|
400
|
+
var minimumRowIndexToRender, maximumRowIndexToRender;
|
401
|
+
var minimumRowIndexToRemove, maximumRowIndexToRemove;
|
402
|
+
var i, cellToAdd, renderedCellToRemove;
|
403
|
+
|
404
|
+
// Render higher-indexed rows.
|
405
|
+
if (minimumRenderedRowIndex > lastMinimumRenderedRowIndex || maximumRenderedRowIndex > lastMaximumRenderedRowIndex) {
|
406
|
+
minimumRowIndexToRender = lastMaximumRenderedRowIndex + 1;
|
407
|
+
maximumRowIndexToRender = maximumRenderedRowIndex;
|
408
|
+
minimumRowIndexToRemove = lastMinimumRenderedRowIndex;
|
409
|
+
maximumRowIndexToRemove = minimumRenderedRowIndex - 1;
|
410
|
+
|
411
|
+
for (i = minimumRowIndexToRender; i <= maximumRowIndexToRender; i++) {
|
412
|
+
cellToAdd = dataSource.getCellForRowAtIndex(this, i);
|
413
|
+
cellToAdd.setSelected(this.isRowSelectedAtIndex(i));
|
414
|
+
$element.append(cellToAdd.$element);
|
415
|
+
}
|
416
|
+
}
|
417
|
+
|
418
|
+
// Render lower-indexed rows.
|
419
|
+
else if (minimumRenderedRowIndex < lastMinimumRenderedRowIndex || maximumRenderedRowIndex < lastMaximumRenderedRowIndex) {
|
420
|
+
minimumRowIndexToRender = minimumRenderedRowIndex;
|
421
|
+
maximumRowIndexToRender = lastMinimumRenderedRowIndex - 1;
|
422
|
+
minimumRowIndexToRemove = maximumRenderedRowIndex + 1;
|
423
|
+
maximumRowIndexToRemove = lastMaximumRenderedRowIndex;
|
424
|
+
|
425
|
+
for (i = maximumRowIndexToRender; i >= minimumRowIndexToRender; i--) {
|
426
|
+
cellToAdd = dataSource.getCellForRowAtIndex(this, i);
|
427
|
+
cellToAdd.setSelected(this.isRowSelectedAtIndex(i));
|
428
|
+
$element.prepend(cellToAdd.$element);
|
429
|
+
}
|
430
|
+
}
|
431
|
+
|
432
|
+
for (i = minimumRowIndexToRemove; i <= maximumRowIndexToRemove; i++) if ((renderedCellToRemove = this.getRenderedCellAtIndex(i))) renderedCellToRemove.prepareForReuse();
|
433
|
+
|
434
|
+
var minimumScrollPositionThreshold = this._minimumScrollPositionThreshold = (minimumRenderedRowIndex > 0) ? scrollPosition - visibleHeight : -1;
|
435
|
+
var maximumScrollPositionThreshold = this._maximumScrollPositionThreshold = (maximumRenderedRowIndex < numberOfRows - 1) ? scrollPosition + visibleHeight : -1;
|
436
|
+
|
437
|
+
// console.log('Minimum Visible Index: ' + minimumVisibleRowIndex + ', Maximum Visible Index: ' + maximumVisibleRowIndex);
|
438
|
+
// console.log('Visible Rows: ' + numberOfVisibleRows + ', Leading Rows: ' + numberOfLeadingRows + ', Trailing Rows: ' + numberOfTrailingRows);
|
439
|
+
// console.log(lastMinimumRenderedRowIndex + ' -> ' + minimumRenderedRowIndex + ', ' + lastMaximumRenderedRowIndex + ' -> ' + maximumRenderedRowIndex);
|
440
|
+
// console.log('Row Indexes To Render: ' + minimumRowIndexToRender + ' - ' + maximumRowIndexToRender);
|
441
|
+
// console.log('Row Indexes To Remove: ' + minimumRowIndexToRemove + ' - ' + maximumRowIndexToRemove);
|
442
|
+
// console.log('================================================================');
|
443
|
+
|
444
|
+
this._drawing = false;
|
445
|
+
|
446
|
+
this.$trigger($.Event(Pushpop.TableView.EventType.DidDrawRowsWithIndexes, {
|
447
|
+
tableView: this,
|
448
|
+
dataSource: dataSource,
|
449
|
+
minimumRowIndex: minimumRenderedRowIndex,
|
450
|
+
maximumRowIndex: maximumRenderedRowIndex
|
451
|
+
}));
|
452
|
+
},
|
453
|
+
|
454
|
+
/**
|
455
|
+
|
456
|
+
*/
|
457
|
+
reloadData: function() {
|
458
|
+
var scrollView = this.scrollView;
|
459
|
+
var scrollPosition = $.extend({}, scrollView.getScrollPosition());
|
460
|
+
var renderedCells = this.getRenderedCells();
|
461
|
+
var renderedCellsToReuse = [];
|
462
|
+
|
463
|
+
var i, length;
|
464
|
+
for (i = 0, length = renderedCells.length; i < length; i++) renderedCellsToReuse.push(renderedCells[i]);
|
465
|
+
for (i = 0, length = renderedCellsToReuse.length; i < length; i++) renderedCellsToReuse[i].prepareForReuse();
|
466
|
+
|
467
|
+
this._minimumScrollPositionThreshold = -1;
|
468
|
+
this._maximumScrollPositionThreshold = -1;
|
469
|
+
this._minimumRenderedRowIndex = -1;
|
470
|
+
this._maximumRenderedRowIndex = -1;
|
471
|
+
|
472
|
+
this.draw();
|
473
|
+
|
474
|
+
scrollView.setScrollPosition(scrollPosition.x, scrollPosition.y);
|
475
|
+
},
|
476
|
+
|
477
|
+
_$loadingMessageElement: null,
|
478
|
+
|
479
|
+
_loadingMessageHtml: 'Loading...',
|
480
|
+
|
481
|
+
/**
|
482
|
+
|
483
|
+
*/
|
484
|
+
getLoadingMessageHtml: function() { return this._loadingMessageHtml; },
|
485
|
+
|
486
|
+
/**
|
487
|
+
|
488
|
+
*/
|
489
|
+
setLoadingMessageHtml: function(loadingMessageHtml) { this._$loadingMessageElement.html(this._loadingMessageHtml = loadingMessageHtml).append(this._$loadingSpinnerElement); },
|
490
|
+
|
491
|
+
_$loadingSpinnerElement: null,
|
492
|
+
|
493
|
+
_loadingSpinner: null,
|
494
|
+
|
495
|
+
/**
|
496
|
+
|
497
|
+
*/
|
498
|
+
getLoadingSpinner: function() { return this._loadingSpinner; },
|
499
|
+
|
500
|
+
_loadingMessageHidden: true,
|
501
|
+
|
502
|
+
/**
|
503
|
+
|
504
|
+
*/
|
505
|
+
getLoadingMessageHidden: function() { return this._loadingMessageHidden; },
|
506
|
+
|
507
|
+
/**
|
508
|
+
|
509
|
+
*/
|
510
|
+
setLoadingMessageHidden: function(loadingMessageHidden) {
|
511
|
+
if ((this._loadingMessageHidden = loadingMessageHidden)) {
|
512
|
+
this._$loadingMessageElement.addClass('pp-hidden');
|
513
|
+
} else {
|
514
|
+
this._$loadingMessageElement.removeClass('pp-hidden');
|
515
|
+
}
|
516
|
+
},
|
517
|
+
|
518
|
+
_dataSource: null,
|
519
|
+
|
520
|
+
/**
|
521
|
+
Returns the TableViewDataSource for this TableView.
|
522
|
+
@type Pushpop.TableViewDataSource
|
523
|
+
*/
|
524
|
+
getDataSource: function() { return this._dataSource; },
|
525
|
+
|
526
|
+
/**
|
527
|
+
Sets a TableViewDataSource for this TableView and reloads the data.
|
528
|
+
@param {Pushpop.TableViewDataSource} dataSource The TableViewDataSource to bind
|
529
|
+
to this TableView.
|
530
|
+
*/
|
531
|
+
setDataSource: function(dataSource) {
|
532
|
+
var previousDataSource = this.getDataSource();
|
533
|
+
|
534
|
+
this._dataSource = dataSource;
|
535
|
+
dataSource.setTableView(this);
|
536
|
+
|
537
|
+
this.$trigger($.Event(Pushpop.TableView.EventType.DidChangeDataSource, {
|
538
|
+
tableView: this,
|
539
|
+
dataSource: dataSource,
|
540
|
+
previousDataSource: previousDataSource
|
541
|
+
}));
|
542
|
+
|
543
|
+
this.reloadData();
|
544
|
+
},
|
545
|
+
|
546
|
+
_searchBar: null,
|
547
|
+
|
548
|
+
/**
|
549
|
+
Returns the TableViewSearchBar for this TableView if it contains one.
|
550
|
+
@type Pushpop.TableViewSearchBar
|
551
|
+
*/
|
552
|
+
getSearchBar: function() { return this._searchBar; },
|
553
|
+
|
554
|
+
/**
|
555
|
+
Sets a TableViewSearchBar for this TableView.
|
556
|
+
@param {Pushpop.TableViewSearchBar} searchBar The TableViewSearchBar to attach
|
557
|
+
to this TableView.
|
558
|
+
*/
|
559
|
+
setSearchBar: function(searchBar) { this._searchBar = searchBar; },
|
560
|
+
|
561
|
+
_rowHeight: 44,
|
562
|
+
|
563
|
+
/**
|
564
|
+
|
565
|
+
*/
|
566
|
+
getRowHeight: function() { return this._rowHeight; },
|
567
|
+
|
568
|
+
/**
|
569
|
+
|
570
|
+
*/
|
571
|
+
setRowHeight: function(rowHeight) { this._rowHeight = rowHeight; },
|
572
|
+
|
573
|
+
_editing: false,
|
574
|
+
|
575
|
+
/**
|
576
|
+
Determines if this TableView is in editing mode.
|
577
|
+
@type Boolean
|
578
|
+
*/
|
579
|
+
getEditing: function() { return this._editing; },
|
580
|
+
|
581
|
+
/**
|
582
|
+
Used for setting the table view in or out of editing mode.
|
583
|
+
@param {Boolean} editing A flag indicating if the TableView should be in editing mode.
|
584
|
+
@param {Boolean} [animated] An optional flag indicating if the transition in or out of
|
585
|
+
editing mode should be animated (default: true).
|
586
|
+
*/
|
587
|
+
setEditing: function(editing, animated) {
|
588
|
+
if ((this._editing = editing)) {
|
589
|
+
this.$element.addClass('pp-table-view-editing');
|
590
|
+
} else {
|
591
|
+
this.$element.removeClass('pp-table-view-editing');
|
592
|
+
}
|
593
|
+
},
|
594
|
+
|
595
|
+
_selectionTimeoutDuration: 250,
|
596
|
+
|
597
|
+
/**
|
598
|
+
|
599
|
+
*/
|
600
|
+
getSelectionTimeoutDuration: function() { return this._selectionTimeoutDuration; },
|
601
|
+
|
602
|
+
/**
|
603
|
+
|
604
|
+
*/
|
605
|
+
setSelectionTimeoutDuration: function(selectionTimeoutDuration) { this._selectionTimeoutDuration = selectionTimeoutDuration; },
|
606
|
+
|
607
|
+
_selectedRowIndexes: null, // []
|
608
|
+
|
609
|
+
/**
|
610
|
+
Returns the index in for the first selected row.
|
611
|
+
@description NOTE: This is an index of a row in the data source, NOT an index
|
612
|
+
of a cell in the DOM. If no rows are selected, this method will return -1.
|
613
|
+
@type Number
|
614
|
+
*/
|
615
|
+
getIndexForSelectedRow: function() {
|
616
|
+
var selectedRowIndexes = this._selectedRowIndexes;
|
617
|
+
return (selectedRowIndexes && selectedRowIndexes.length > 0) ? selectedRowIndexes[0] : -1;
|
618
|
+
},
|
619
|
+
|
620
|
+
/**
|
621
|
+
Returns the indexes in for the selected rows.
|
622
|
+
@description NOTE: The array contains indexes of rows in the data source, NOT
|
623
|
+
indexes of cells in the DOM. If no rows are selected, this array will be empty.
|
624
|
+
@type Array
|
625
|
+
*/
|
626
|
+
getIndexesForSelectedRows: function() {
|
627
|
+
return this._selectedRowIndexes;
|
628
|
+
},
|
629
|
+
|
630
|
+
/**
|
631
|
+
Determines if the specified index is a selected row.
|
632
|
+
@description NOTE: This is an index of a row in the data source, NOT an index
|
633
|
+
of a cell in the DOM.
|
634
|
+
@type Boolean
|
635
|
+
*/
|
636
|
+
isRowSelectedAtIndex: function(index) {
|
637
|
+
var selectedRowIndexes = this._selectedRowIndexes;
|
638
|
+
for (var i = 0, length = selectedRowIndexes.length; i < length; i++) if (selectedRowIndexes[i] === index) return true;
|
639
|
+
return false;
|
640
|
+
},
|
641
|
+
|
642
|
+
/**
|
643
|
+
Selects the row at the specified index and triggers the DidSelectRowAtIndex event on
|
644
|
+
this and all parent table view elements.
|
645
|
+
@description NOTE: If the row contains a child data source, this method will automatically
|
646
|
+
push a dynamic table view using the child data source. The DidSelectRowAtIndex event contains
|
647
|
+
a flag |hasChildDataSource| to indicate whether or not a new dynamic table view was pushed
|
648
|
+
prior to the event.
|
649
|
+
@param {Number} index The index of a row in the data source to select.
|
650
|
+
@param {Boolean} [animated] A flag indicating if the selection should be animated
|
651
|
+
if the row is currently visible.
|
652
|
+
*/
|
653
|
+
selectRowAtIndex: function(index, animated) {
|
654
|
+
var dataSource = this.getDataSource();
|
655
|
+
var shouldSelectRowAtIndex = dataSource.shouldSelectRowAtIndex(index);
|
656
|
+
if (!shouldSelectRowAtIndex) return;
|
657
|
+
|
658
|
+
this.deselectAllRows();
|
659
|
+
|
660
|
+
var $element = this.$element;
|
661
|
+
this._selectedRowIndexes.push(index);
|
662
|
+
|
663
|
+
var tableViewCell, $cells = this.$element.children();
|
664
|
+
for (var i = 0, length = $cells.length; i < length; i++) {
|
665
|
+
tableViewCell = $cells[i].tableViewCell;
|
666
|
+
if (tableViewCell.getIndex() === index) {
|
667
|
+
tableViewCell.setSelected(true);
|
668
|
+
tableViewCell.forceReflow();
|
669
|
+
break;
|
670
|
+
}
|
671
|
+
}
|
672
|
+
|
673
|
+
var self = this;
|
674
|
+
|
675
|
+
// If this row contains a child data source, automatically push a new dynamic table view with it.
|
676
|
+
if (dataSource.rowHasChildDataSourceAtIndex(index)) {
|
677
|
+
var childDataSource = dataSource.getChildDataSourceForRowAtIndex(index);
|
678
|
+
var viewStack = this.getViewStack();
|
679
|
+
|
680
|
+
if (childDataSource && viewStack) {
|
681
|
+
viewStack.pushNewTableView(function(childTableView) {
|
682
|
+
if (self.getSearchBar()) childTableView.setSearchBar(new Pushpop.TableViewSearchBar(childTableView));
|
683
|
+
childTableView.setDataSource(childDataSource);
|
684
|
+
childTableView.setParentTableView(self);
|
685
|
+
});
|
686
|
+
|
687
|
+
// Trigger the DidSelectRowAtIndex event on this and all parent table view elements.
|
688
|
+
window.setTimeout(function() {
|
689
|
+
self.triggerEventOnParentTableViews($.Event(Pushpop.TableView.EventType.DidSelectRowAtIndex, {
|
690
|
+
tableView: self,
|
691
|
+
index: index,
|
692
|
+
item: dataSource.getFilteredItemAtIndex(index),
|
693
|
+
hasChildDataSource: true
|
694
|
+
}), true);
|
695
|
+
}, 1);
|
696
|
+
|
697
|
+
return;
|
698
|
+
}
|
699
|
+
}
|
700
|
+
|
701
|
+
// Trigger the DidSelectRowAtIndex event on this and all parent table view elements.
|
702
|
+
window.setTimeout(function() {
|
703
|
+
self.triggerEventOnParentTableViews($.Event(Pushpop.TableView.EventType.DidSelectRowAtIndex, {
|
704
|
+
tableView: self,
|
705
|
+
index: index,
|
706
|
+
item: dataSource.getFilteredItemAtIndex(index),
|
707
|
+
hasChildDataSource: false
|
708
|
+
}), true);
|
709
|
+
}, 1);
|
710
|
+
},
|
711
|
+
|
712
|
+
/**
|
713
|
+
De-selects the row at the specified index and optionally animates the de-selection
|
714
|
+
if the row is currently visible.
|
715
|
+
@description NOTE: This method will not modify any other existing selections.
|
716
|
+
@param {Number} index The index of a row in the data source to de-select.
|
717
|
+
@param {Boolean} [animated] A flag indicating if the de-selection should be
|
718
|
+
animated if the row is currently visible.
|
719
|
+
*/
|
720
|
+
deselectRowAtIndex: function(index, animated) {
|
721
|
+
var $element = this.$element;
|
722
|
+
var selectedRowIndexes = this._selectedRowIndexes;
|
723
|
+
var i, length;
|
724
|
+
for (i = 0, length = selectedRowIndexes.length; i < length; i++) {
|
725
|
+
if (selectedRowIndexes[i] === index) {
|
726
|
+
selectedRowIndexes.splice(i, 1);
|
727
|
+
break;
|
728
|
+
}
|
729
|
+
}
|
730
|
+
|
731
|
+
var tableViewCell, $selectedCells = $element.children('.pp-table-view-selected-state');
|
732
|
+
for (i = 0, length = $selectedCells.length; i < length; i++) {
|
733
|
+
tableViewCell = $selectedCells[i].tableViewCell;
|
734
|
+
if (tableViewCell.getIndex() === index) {
|
735
|
+
tableViewCell.setSelected(false);
|
736
|
+
break;
|
737
|
+
}
|
738
|
+
}
|
739
|
+
|
740
|
+
$element.trigger($.Event(Pushpop.TableView.EventType.DidDeselectRowAtIndex, {
|
741
|
+
tableView: this,
|
742
|
+
index: index
|
743
|
+
}));
|
744
|
+
},
|
745
|
+
|
746
|
+
/**
|
747
|
+
De-selects all rows in the table.
|
748
|
+
*/
|
749
|
+
deselectAllRows: function() {
|
750
|
+
var $element = this.$element;
|
751
|
+
var selectedRowIndexes = this._selectedRowIndexes;
|
752
|
+
for (var i = 0, length = selectedRowIndexes.length; i < length; i++) {
|
753
|
+
$element.trigger($.Event(Pushpop.TableView.EventType.DidDeselectRowAtIndex, {
|
754
|
+
tableView: this,
|
755
|
+
index: selectedRowIndexes[i]
|
756
|
+
}));
|
757
|
+
}
|
758
|
+
|
759
|
+
selectedRowIndexes.length = 0;
|
760
|
+
|
761
|
+
$element.children('.pp-table-view-selected-state').each(function(index, element) {
|
762
|
+
element.tableViewCell.setSelected(false);
|
763
|
+
});
|
764
|
+
},
|
765
|
+
|
766
|
+
_parentTableView: null,
|
767
|
+
|
768
|
+
/**
|
769
|
+
Returns the parent table view if this table view has one.
|
770
|
+
@type Pushpop.TableView
|
771
|
+
*/
|
772
|
+
getParentTableView: function() { return this._parentTableView; },
|
773
|
+
|
774
|
+
/**
|
775
|
+
Sets the parent table view for this table view.
|
776
|
+
@param {Pushpop.TableView} parentTableView The table view to set as the parent for this table view.
|
777
|
+
@description NOTE: To remove this table view from its parent, call this method
|
778
|
+
and pass in a |null| value.
|
779
|
+
*/
|
780
|
+
setParentTableView: function(parentTableView) { this._parentTableView = parentTableView; },
|
781
|
+
|
782
|
+
/**
|
783
|
+
Traverses the parent table views up the chain until it encounters a table view
|
784
|
+
with no parent then returns an array of Pushpop.TableView objects.
|
785
|
+
@type Array
|
786
|
+
*/
|
787
|
+
getParentTableViews: function() {
|
788
|
+
var parentTableViews = [];
|
789
|
+
var currentParentTableView = this.getParentTableView();
|
790
|
+
|
791
|
+
while (currentParentTableView) {
|
792
|
+
parentTableViews.push(currentParentTableView);
|
793
|
+
currentParentTableView = currentParentTableView.getParentTableView();
|
794
|
+
}
|
795
|
+
|
796
|
+
return parentTableViews;
|
797
|
+
},
|
798
|
+
|
799
|
+
/**
|
800
|
+
Triggers the specified event on the parent table view elements and optionally
|
801
|
+
also on this own table view's element.
|
802
|
+
@param {$.Event|String} evt The event to be triggered on the table view element(s).
|
803
|
+
@param {Boolean} [includeSelf] A flag indicating whether or not the event should
|
804
|
+
also be triggered on this table view's element.
|
805
|
+
*/
|
806
|
+
triggerEventOnParentTableViews: function(evt, includeSelf) {
|
807
|
+
var parentTableViews = this.getParentTableViews();
|
808
|
+
for (var i = 0, length = parentTableViews.length; i < length; i++) parentTableViews[i].$trigger(evt);
|
809
|
+
if (includeSelf) this.$trigger(evt);
|
810
|
+
},
|
811
|
+
|
812
|
+
/**
|
813
|
+
Returns the view that contains this table view.
|
814
|
+
@description NOTE: If this table view is not contained within a view, this method will return null.
|
815
|
+
@type Pushpop.View
|
816
|
+
*/
|
817
|
+
getView: function() {
|
818
|
+
var parents = this.$element.parents();
|
819
|
+
var view;
|
820
|
+
for (var i = 0, length = parents.length; i < length; i++) if ((view = parents[i].view)) return view;
|
821
|
+
return null;
|
822
|
+
},
|
823
|
+
|
824
|
+
/**
|
825
|
+
Returns the view stack that contains this table view.
|
826
|
+
@description NOTE: If this table view is not contained within a view stack, this method will return null.
|
827
|
+
@type Pushpop.ViewStack
|
828
|
+
*/
|
829
|
+
getViewStack: function() {
|
830
|
+
var parents = this.$element.parents();
|
831
|
+
var viewStack;
|
832
|
+
for (var i = 0, length = parents.length; i < length; i++) if ((viewStack = parents[i].viewStack)) return viewStack;
|
833
|
+
return null;
|
834
|
+
},
|
835
|
+
|
836
|
+
/**
|
837
|
+
Convenience accessor for jQuery's .bind() method.
|
838
|
+
*/
|
839
|
+
$bind: function() { this.$element.bind.apply(this.$element, arguments); },
|
840
|
+
|
841
|
+
/**
|
842
|
+
Convenience accessor for jQuery's .unbind() method.
|
843
|
+
*/
|
844
|
+
$unbind: function() { this.$element.unbind.apply(this.$element, arguments); },
|
845
|
+
|
846
|
+
/**
|
847
|
+
Convenience accessor for jQuery's .delegate() method.
|
848
|
+
*/
|
849
|
+
$delegate: function() { this.$element.delegate.apply(this.$element, arguments); },
|
850
|
+
|
851
|
+
/**
|
852
|
+
Convenience accessor for jQuery's .undelegate() method.
|
853
|
+
*/
|
854
|
+
$undelegate: function() { this.$element.undelegate.apply(this.$element, arguments); },
|
855
|
+
|
856
|
+
/**
|
857
|
+
Convenience accessor for jQuery's .trigger() method.
|
858
|
+
*/
|
859
|
+
$trigger: function() { this.$element.trigger.apply(this.$element, arguments); }
|
860
|
+
};
|
861
|
+
|
862
|
+
/**
|
863
|
+
Creates a new data source for a TableView.
|
864
|
+
@param {Array} [dataSet] An optional array of data to initialize a default data source.
|
865
|
+
@param {Array} [dataSet.id] The unique identifier for a specific record.
|
866
|
+
@param {Array} [dataSet.value] The (sometimes) hidden value for a specific record.
|
867
|
+
@param {Array} [dataSet.title] The title to be displayed in a TableViewCell for a specific record.
|
868
|
+
@param {String} [defaultReuseIdentifier] The optional reuse identifier to be used for rows that do
|
869
|
+
not specify a specific reuse identifier.
|
870
|
+
@constructor
|
871
|
+
*/
|
872
|
+
Pushpop.TableViewDataSource = function TableViewDataSource(dataSet, defaultReuseIdentifier) {
|
873
|
+
this.setDataSet(dataSet || []);
|
874
|
+
this.setDefaultReuseIdentifier(defaultReuseIdentifier || this.getDefaultReuseIdentifier());
|
875
|
+
};
|
876
|
+
|
877
|
+
Pushpop.TableViewDataSource.prototype = {
|
878
|
+
constructor: Pushpop.TableViewDataSource,
|
879
|
+
|
880
|
+
/**
|
881
|
+
Returns the number of rows provided by this data source.
|
882
|
+
@description NOTE: This is the default implementation and should be overridden for data
|
883
|
+
sources that are not driven directly from an in-memory data set.
|
884
|
+
@type Number
|
885
|
+
*/
|
886
|
+
getNumberOfRows: function() { return this.getNumberOfFilteredItems(); },
|
887
|
+
|
888
|
+
/**
|
889
|
+
Returns a TableViewCell for the specified index.
|
890
|
+
@description NOTE: This is the default implementation and should be overridden for data
|
891
|
+
sources that are not driven directly from an in-memory data set.
|
892
|
+
@param {Pushpop.TableView} tableView The TableView the TableViewCell should be returned for.
|
893
|
+
@param {Number} index The index of the data to be used when populating the TableViewCell.
|
894
|
+
@type Pushpop.TableViewCell
|
895
|
+
*/
|
896
|
+
getCellForRowAtIndex: function(tableView, index) {
|
897
|
+
var item = this.getFilteredItemAtIndex(index);
|
898
|
+
var reuseIdentifier = item.reuseIdentifier || this.getDefaultReuseIdentifier();
|
899
|
+
var accessoryType = item.accessoryType || this.getDefaultAccessoryType();
|
900
|
+
var editingAccessoryType = item.editingAccessoryType || this.getDefaultEditingAccessoryType();
|
901
|
+
var cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier);
|
902
|
+
|
903
|
+
cell.setIndex(index);
|
904
|
+
cell.setAccessoryType(accessoryType);
|
905
|
+
cell.setEditingAccessoryType(editingAccessoryType);
|
906
|
+
cell.setData(item);
|
907
|
+
|
908
|
+
return cell;
|
909
|
+
},
|
910
|
+
|
911
|
+
/**
|
912
|
+
Returns an array containing the key/value pairs for all "values" contained within the data
|
913
|
+
source. This is typically used for retrieving form fields stored within a table view and
|
914
|
+
behaves similarly to jQuery's .serializeArray() function.
|
915
|
+
@param {String} [keyFieldName] The name of the field in the data source containing the
|
916
|
+
values' keys. If not specified, the default value is 'name'.
|
917
|
+
@param {String} [valueFieldName] The name of the field in the data source containing the
|
918
|
+
values' values. If not specified, the default value is 'value.
|
919
|
+
@type Array
|
920
|
+
*/
|
921
|
+
getValuesArray: function(keyFieldName, valueFieldName) {
|
922
|
+
keyFieldName = keyFieldName || 'name';
|
923
|
+
valueFieldName = valueFieldName || 'value';
|
924
|
+
|
925
|
+
var numberOfItems = this.getNumberOfItems();
|
926
|
+
var valuesArray = [];
|
927
|
+
var item, name, value;
|
928
|
+
|
929
|
+
for (var i = 0; i < numberOfItems; i++) {
|
930
|
+
item = this.getItemAtIndex(i);
|
931
|
+
name = item[keyFieldName];
|
932
|
+
value = item[valueFieldName];
|
933
|
+
|
934
|
+
if (value !== undefined) valuesArray.push({
|
935
|
+
name: item[keyFieldName] || keyFieldName,
|
936
|
+
value: item[valueFieldName]
|
937
|
+
});
|
938
|
+
}
|
939
|
+
|
940
|
+
return valuesArray;
|
941
|
+
},
|
942
|
+
|
943
|
+
/**
|
944
|
+
Returns an object containing the data for all "values" contained within the data source.
|
945
|
+
This is typically used for retrieving form fields stored within a table view.
|
946
|
+
@description NOTE: If a field name occurs more than once, its values will be put into an
|
947
|
+
array.
|
948
|
+
@param {String} [keyFieldName] The name of the field in the data source containing the
|
949
|
+
values' keys. If not specified, the default value is 'name'.
|
950
|
+
@param {String} [valueFieldName] The name of the field in the data source containing the
|
951
|
+
values' values. If not specified, the default value is 'value.
|
952
|
+
@type Object
|
953
|
+
*/
|
954
|
+
getValuesObject: function(keyFieldName, valueFieldName) {
|
955
|
+
var valuesArray = this.getValuesArray(keyFieldName, valueFieldName);
|
956
|
+
var valuesObject = {};
|
957
|
+
|
958
|
+
var value;
|
959
|
+
for (var i = 0, length = valuesArray.length; i < length; i++) {
|
960
|
+
value = valuesArray[i];
|
961
|
+
|
962
|
+
if (valuesObject[value.name] !== undefined) {
|
963
|
+
if (!valuesObject[value.name].push) valuesObject[value.name] = [valuesObject[value.name]];
|
964
|
+
valuesObject[value.name].push(value.value);
|
965
|
+
} else {
|
966
|
+
valuesObject[value.name] = value.value;
|
967
|
+
}
|
968
|
+
}
|
969
|
+
|
970
|
+
return valuesObject;
|
971
|
+
},
|
972
|
+
|
973
|
+
/**
|
974
|
+
Sets the "values" for the items contained within the data source from an object containing
|
975
|
+
key/value pairs.
|
976
|
+
@param {Object} object The object to map key/value pairs from.
|
977
|
+
@param {String} [keyFieldName] The name of the field in the data source containing the
|
978
|
+
values' keys. If not specified, the default value is 'name'.
|
979
|
+
@param {String} [valueFieldName] The name of the field in the data source containing the
|
980
|
+
values' values. If not specified, the default value is 'value.
|
981
|
+
*/
|
982
|
+
setValuesFromObject: function(object, keyFieldName, valueFieldName) {
|
983
|
+
if (!object) return;
|
984
|
+
|
985
|
+
keyFieldName = keyFieldName || 'name';
|
986
|
+
valueFieldName = valueFieldName || 'value';
|
987
|
+
|
988
|
+
var numberOfItems = this.getNumberOfItems();
|
989
|
+
var i, item;
|
990
|
+
|
991
|
+
for (var key in object) {
|
992
|
+
for (i = 0; i < numberOfItems; i++) {
|
993
|
+
item = this.getItemAtIndex(i);
|
994
|
+
|
995
|
+
if (item[keyFieldName] === key) {
|
996
|
+
item[valueFieldName] = object[key];
|
997
|
+
break;
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
var tableView = this.getTableView();
|
1003
|
+
if (tableView) tableView.reloadData();
|
1004
|
+
},
|
1005
|
+
|
1006
|
+
clearValues: function(valueFieldName, defaultValueFieldName) {
|
1007
|
+
valueFieldName = valueFieldName || 'value';
|
1008
|
+
defaultValueFieldName = defaultValueFieldName || 'defaultValue';
|
1009
|
+
|
1010
|
+
var numberOfItems = this.getNumberOfItems();
|
1011
|
+
var item, value, defaultValue;
|
1012
|
+
|
1013
|
+
for (var i = 0; i < numberOfItems; i++) {
|
1014
|
+
item = this.getItemAtIndex(i);
|
1015
|
+
value = item[valueFieldName];
|
1016
|
+
defaultValue = item[defaultValueFieldName] || null;
|
1017
|
+
|
1018
|
+
if (value !== undefined || defaultValue) item[valueFieldName] = defaultValue;
|
1019
|
+
}
|
1020
|
+
|
1021
|
+
var tableView = this.getTableView();
|
1022
|
+
if (tableView) tableView.reloadData();
|
1023
|
+
},
|
1024
|
+
|
1025
|
+
/**
|
1026
|
+
Determines if the table should be reloaded following a change in the search string.
|
1027
|
+
@description The default implementation assumes that the data set is fully loaded into
|
1028
|
+
memory and executes the current filter function against each item in the data set. If the
|
1029
|
+
filtered data set has changed since the last reload, it will return |true| which will force
|
1030
|
+
the associated TableViewSearchBar to reload the data for the TableView. In a custom data
|
1031
|
+
source that does not use an in-memory data set (e.g.: WebSQL or HTML5 LocalStorage), it is
|
1032
|
+
recommended to override this method to perform any necessary queries asynchronously and
|
1033
|
+
immediately return |false|. Once the asynchronous queries have completed, the application
|
1034
|
+
should then manually call .reloadData() on the TableView to force an update (See the WebSQL
|
1035
|
+
demo for an example on this implementation).
|
1036
|
+
@param {String} searchString The search string to be used for matching items in the data set.
|
1037
|
+
@param {Boolean} [isCaseSensitive] An optional boolean flag for forcing a case-sensitive search.
|
1038
|
+
@type Boolean
|
1039
|
+
*/
|
1040
|
+
shouldReloadTableForSearchString: function(searchString, isCaseSensitive) {
|
1041
|
+
var dataSet = this.getDataSet();
|
1042
|
+
if (!dataSet) return false;
|
1043
|
+
|
1044
|
+
var filterFunction = this.getFilterFunction();
|
1045
|
+
if (!filterFunction || typeof filterFunction !== 'function' || !searchString) {
|
1046
|
+
this._lastSearchString = null;
|
1047
|
+
|
1048
|
+
if (this._filteredDataSet !== dataSet) {
|
1049
|
+
this._filteredDataSet = dataSet;
|
1050
|
+
return true;
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
return false;
|
1054
|
+
}
|
1055
|
+
|
1056
|
+
var filteredDataSet = [];
|
1057
|
+
var regExp = new RegExp(searchString + '+', (!isCaseSensitive ? 'i' : '') + 'm');
|
1058
|
+
var item, i, length;
|
1059
|
+
|
1060
|
+
// The search string is a continuation of the last search string (e.g.: 'ab' -> 'abc').
|
1061
|
+
if (searchString.indexOf(this._lastSearchString) === 0) {
|
1062
|
+
|
1063
|
+
// Search the previous filtered data set instead of the whole data set.
|
1064
|
+
var lastFilteredDataSet = this._filteredDataSet;
|
1065
|
+
for (i = 0, length = lastFilteredDataSet.length; i < length; i++) if (filterFunction(regExp, item = lastFilteredDataSet[i])) filteredDataSet.push(item);
|
1066
|
+
}
|
1067
|
+
|
1068
|
+
// The search string is NOT a contination of the last search string (e.g.: 'abc' -> 'ab').
|
1069
|
+
else {
|
1070
|
+
|
1071
|
+
// Search the whole data set.
|
1072
|
+
for (i = 0, length = dataSet.length; i < length; i++) if (filterFunction(regExp, item = dataSet[i])) filteredDataSet.push(item);
|
1073
|
+
}
|
1074
|
+
|
1075
|
+
this._filteredDataSet = filteredDataSet;
|
1076
|
+
this._lastSearchString = searchString;
|
1077
|
+
return true;
|
1078
|
+
},
|
1079
|
+
|
1080
|
+
_lastSearchString: null,
|
1081
|
+
|
1082
|
+
/**
|
1083
|
+
Returns a flag indicating whether or not the row at the specified index should be able
|
1084
|
+
to be selected.
|
1085
|
+
@description NOTE: This is the default implementation and should be overridden if certain
|
1086
|
+
rows should not be able to be selected.
|
1087
|
+
@param {Number} index The index of the row to determine whether or not it should be selectable.
|
1088
|
+
@type Boolean
|
1089
|
+
*/
|
1090
|
+
shouldSelectRowAtIndex: function(index) { return true; },
|
1091
|
+
|
1092
|
+
/**
|
1093
|
+
Returns a flag indicating whether or not the row at the specified index contains a child
|
1094
|
+
data source.
|
1095
|
+
@description NOTE: This is the default implementation and should be overridden for data
|
1096
|
+
sources that are not driven directly from an in-memory data set. In the default implementation,
|
1097
|
+
the |dataSourceKey| that is set using the setDataSourceKey() method is used to determine if an
|
1098
|
+
array of objects exists for that key on the item at the specified index.
|
1099
|
+
@param {Number} index The index of the row to determine whether or not it contains a child data source.
|
1100
|
+
@type Boolean
|
1101
|
+
*/
|
1102
|
+
rowHasChildDataSourceAtIndex: function(index) {
|
1103
|
+
var key = this.getChildDataSourceKey();
|
1104
|
+
if (!key) return;
|
1105
|
+
|
1106
|
+
var item = this.getFilteredItemAtIndex(index);
|
1107
|
+
return !!(item && item[key] && item[key] instanceof Array);
|
1108
|
+
},
|
1109
|
+
|
1110
|
+
/**
|
1111
|
+
Creates and returns a new data source for the row at the specified index if the item at
|
1112
|
+
that index contains a child data source as determined by the rowHadChildDataSourceAtIndex()
|
1113
|
+
method.
|
1114
|
+
@description NOTE: This is the default implementation and should be overridden for data
|
1115
|
+
sources that are not driven directly from an in-memory data set. In the default implementation,
|
1116
|
+
the |dataSourceKey| that is set using the setDataSourceKey() method is used to retrieve the
|
1117
|
+
array of objects for that key on the item at the specified index. The array of child objects are
|
1118
|
+
then used to create a new data source. The new data source is automatically given the same child
|
1119
|
+
data source key in order to continue chaining nested data n-levels deep.
|
1120
|
+
@param {Number} index The index of the row to retrieve a child data source for.
|
1121
|
+
@type Pushpop.TableViewDataSource
|
1122
|
+
*/
|
1123
|
+
getChildDataSourceForRowAtIndex: function(index) {
|
1124
|
+
var key = this.getChildDataSourceKey();
|
1125
|
+
if (!key) return null;
|
1126
|
+
|
1127
|
+
var item = this.getFilteredItemAtIndex(index);
|
1128
|
+
var childDataSet = item[key];
|
1129
|
+
if (!childDataSet) return null;
|
1130
|
+
|
1131
|
+
var childDataSource = new Pushpop.TableViewDataSource(childDataSet, this.getDefaultReuseIdentifier());
|
1132
|
+
childDataSource.setChildDataSourceKey(key);
|
1133
|
+
|
1134
|
+
// Inherit properties from this parent data source for the new child data source.
|
1135
|
+
childDataSource.shouldSelectRowAtIndex = this.shouldSelectRowAtIndex;
|
1136
|
+
childDataSource.shouldReloadTableForSearchString = this.shouldReloadTableForSearchString;
|
1137
|
+
|
1138
|
+
childDataSource.setFilterFunction(this.getFilterFunction());
|
1139
|
+
|
1140
|
+
return childDataSource;
|
1141
|
+
},
|
1142
|
+
|
1143
|
+
_tableView: null,
|
1144
|
+
|
1145
|
+
/**
|
1146
|
+
Returns the TableView this data source is bound to.
|
1147
|
+
@type Pushpop.TableView
|
1148
|
+
*/
|
1149
|
+
getTableView: function() { return this._tableView; },
|
1150
|
+
|
1151
|
+
/**
|
1152
|
+
Sets the TableView this data source should be bound to.
|
1153
|
+
@param {Pushpop.TableView} tableView The TableView to bind this data source to.
|
1154
|
+
*/
|
1155
|
+
setTableView: function(tableView) {
|
1156
|
+
this._tableView = tableView;
|
1157
|
+
|
1158
|
+
var searchBar = tableView.getSearchBar();
|
1159
|
+
if (searchBar) searchBar.setSearchString(this._lastSearchString);
|
1160
|
+
},
|
1161
|
+
|
1162
|
+
_defaultReuseIdentifier: 'pp-table-view-cell-default',
|
1163
|
+
|
1164
|
+
/**
|
1165
|
+
Returns the default reuse identifier that this data source will use when a
|
1166
|
+
reuse identifier is not specified for a particular item.
|
1167
|
+
@type String
|
1168
|
+
*/
|
1169
|
+
getDefaultReuseIdentifier: function() { return this._defaultReuseIdentifier; },
|
1170
|
+
|
1171
|
+
/**
|
1172
|
+
Sets the default reuse identifier that this data source will use when a
|
1173
|
+
reuse identifier is not specified for a particular item.
|
1174
|
+
@param {String} defaultReuseIdentifier The reuse identifier to set as default.
|
1175
|
+
*/
|
1176
|
+
setDefaultReuseIdentifier: function(defaultReuseIdentifier) { this._defaultReuseIdentifier = defaultReuseIdentifier; },
|
1177
|
+
|
1178
|
+
_defaultAccessoryType: 'pp-table-view-cell-accessory-none',
|
1179
|
+
|
1180
|
+
/**
|
1181
|
+
Returns the default accessory type that this data source will use when an
|
1182
|
+
accessory type is not specified for a particular item.
|
1183
|
+
@description NOTE: The available accessory types are defined by the
|
1184
|
+
Pushpop.TableViewCell.AccessoryType singleton.
|
1185
|
+
@type String
|
1186
|
+
*/
|
1187
|
+
getDefaultAccessoryType: function() { return this._defaultAccessoryType; },
|
1188
|
+
|
1189
|
+
/**
|
1190
|
+
Sets the default accessory type that this data source will use when an
|
1191
|
+
accessory type is not specified for a particular item.
|
1192
|
+
@description NOTE: The available accessory types are defined by the
|
1193
|
+
Pushpop.TableViewCell.AccessoryType singleton.
|
1194
|
+
@param {String} defaultAccessoryType The accessory type to set as default.
|
1195
|
+
*/
|
1196
|
+
setDefaultAccessoryType: function(defaultAccessoryType) { this._defaultAccessoryType = defaultAccessoryType; },
|
1197
|
+
|
1198
|
+
_defaultEditingAccessoryType: 'pp-table-view-cell-editing-accessory-none',
|
1199
|
+
|
1200
|
+
/**
|
1201
|
+
Returns the default editing accessory type that this data source will use when an
|
1202
|
+
editing accessory type is not specified for a particular item.
|
1203
|
+
@description NOTE: The available editing accessory types are defined by the
|
1204
|
+
Pushpop.TableViewCell.EditingAccessoryType singleton.
|
1205
|
+
@type String
|
1206
|
+
*/
|
1207
|
+
getDefaultEditingAccessoryType: function() { return this._defaultEditingAccessoryType; },
|
1208
|
+
|
1209
|
+
/**
|
1210
|
+
Sets the default editing accessory type that this data source will use when an
|
1211
|
+
editing accessory type is not specified for a particular item.
|
1212
|
+
@description NOTE: The available editing accessory types are defined by the
|
1213
|
+
Pushpop.TableViewCell.EditingAccessoryType singleton.
|
1214
|
+
@param {String} defaultEditingAccessoryType The editing accessory type to set as default.
|
1215
|
+
*/
|
1216
|
+
setDefaultEditingAccessoryType: function(defaultEditingAccessoryType) { this._defaultEditingAccessoryType = defaultEditingAccessoryType; },
|
1217
|
+
|
1218
|
+
_dataSet: null,
|
1219
|
+
|
1220
|
+
/**
|
1221
|
+
Returns the in-memory data set this data source will provide to the table view.
|
1222
|
+
@description NOTE: This may not be utilized by a custom data source.
|
1223
|
+
@type Array
|
1224
|
+
*/
|
1225
|
+
getDataSet: function() { return this._dataSet; },
|
1226
|
+
|
1227
|
+
/**
|
1228
|
+
Sets the in-memory data set this data source should provide to the table view.
|
1229
|
+
@description NOTE: This may not be utilized by a custom data source.
|
1230
|
+
@param {Array} dataSet The set of data that this data source should provide to the table view.
|
1231
|
+
*/
|
1232
|
+
setDataSet: function(dataSet) {
|
1233
|
+
this._dataSet = dataSet;
|
1234
|
+
this.shouldReloadTableForSearchString('');
|
1235
|
+
|
1236
|
+
var tableView = this.getTableView();
|
1237
|
+
if (tableView) tableView.reloadData();
|
1238
|
+
},
|
1239
|
+
|
1240
|
+
_childDataSourceKey: null,
|
1241
|
+
|
1242
|
+
/**
|
1243
|
+
Returns a string that specifies a key on this data source's objects that may contain
|
1244
|
+
an array of data for a child data source.
|
1245
|
+
@type String
|
1246
|
+
*/
|
1247
|
+
getChildDataSourceKey: function() { return this._childDataSourceKey; },
|
1248
|
+
|
1249
|
+
/**
|
1250
|
+
Sets a string that specifies a key on this data source's objects that may contain
|
1251
|
+
an array of data for a child data source.
|
1252
|
+
@param {String} childDataSourceKey A string containing a key on this data source's
|
1253
|
+
objects that may contain a child data source.
|
1254
|
+
*/
|
1255
|
+
setChildDataSourceKey: function(childDataSourceKey) { this._childDataSourceKey = childDataSourceKey; },
|
1256
|
+
|
1257
|
+
_filteredDataSet: null,
|
1258
|
+
|
1259
|
+
/**
|
1260
|
+
Returns the filtered in-memory data set this data source will provide to the table view.
|
1261
|
+
@description NOTE: This may not be utilized by a custom data source.
|
1262
|
+
@type Array
|
1263
|
+
*/
|
1264
|
+
getFilteredDataSet: function() { return this._filteredDataSet; },
|
1265
|
+
|
1266
|
+
/**
|
1267
|
+
Returns the total number of items contained within this data source.
|
1268
|
+
@description NOTE: This method is not typically used during the table view's rendering
|
1269
|
+
process. It is intended more for data-centric operations on this data source
|
1270
|
+
(e.g.: searching, filtering).
|
1271
|
+
IMPORTANT: When working with a data source that is driven from an in-memory data set,
|
1272
|
+
this method should ALWAYS be used to determine the length of the complete data set. It is
|
1273
|
+
NOT RECOMMENDED that the |length| property be accessed on the data set's array directly.
|
1274
|
+
@type Number
|
1275
|
+
*/
|
1276
|
+
getNumberOfItems: function() { return this.getDataSet().length; },
|
1277
|
+
|
1278
|
+
/**
|
1279
|
+
Returns the item at the specified index of the complete data set contained within this
|
1280
|
+
data source.
|
1281
|
+
@description NOTE: This method is not typically used during the table view's rendering
|
1282
|
+
process. It is intended more for data-centric operations on this data source
|
1283
|
+
(e.g.: searching, filtering).
|
1284
|
+
IMPORTANT: When working with a data source that is driven from an in-memory data set,
|
1285
|
+
this method should ALWAYS be used to access elements from the complete data set. It is NOT
|
1286
|
+
RECOMMENDED that the elements be accessed using "[ ]" notation on the complete data set's
|
1287
|
+
array directly.
|
1288
|
+
@param {Number} index The index of the item in the complete data set to retrieve within
|
1289
|
+
this data source.
|
1290
|
+
@type Object
|
1291
|
+
*/
|
1292
|
+
getItemAtIndex: function(index) { return this.getDataSet()[index]; },
|
1293
|
+
|
1294
|
+
/**
|
1295
|
+
Returns the number of filtered items contained within this data source.
|
1296
|
+
@description NOTE: This method is called directly by the table view's rendering process.
|
1297
|
+
It should yield the same result as the getNumberOfRows method in most cases.
|
1298
|
+
IMPORTANT: When working with a data source that is driven from an in-memory data set,
|
1299
|
+
this method should ALWAYS be used to determine the length of the filtered data set. It is
|
1300
|
+
NOT RECOMMENDED that the |length| property be accessed on the filtered data set's array
|
1301
|
+
directly.
|
1302
|
+
@type Number
|
1303
|
+
*/
|
1304
|
+
getNumberOfFilteredItems: function() { return this.getFilteredDataSet().length; },
|
1305
|
+
|
1306
|
+
/**
|
1307
|
+
Returns the item at the specified index of the filtered data set contained within this
|
1308
|
+
data source.
|
1309
|
+
@description NOTE: This method is called directly by the table view's rendering process.
|
1310
|
+
It should yield the same data that is used by the getCellForRowAtIndex method in most cases.
|
1311
|
+
IMPORTANT: When working with a data source that is driven from an in-memory data set,
|
1312
|
+
this method should ALWAYS be used to access elements from the filtered data set. It is NOT
|
1313
|
+
RECOMMENDED that the elements be accessed using "[ ]" notation on the filtered data set's
|
1314
|
+
array directly.
|
1315
|
+
@param {Number} index The index of the item in the filtered data set to retrieve within
|
1316
|
+
this data source.
|
1317
|
+
@type Object
|
1318
|
+
*/
|
1319
|
+
getFilteredItemAtIndex: function(index) { return this.getFilteredDataSet()[index]; },
|
1320
|
+
|
1321
|
+
setValueForKeyOnItem: function(item, key, value) {
|
1322
|
+
if (!item || !key) return;
|
1323
|
+
|
1324
|
+
var previousValue = item[key];
|
1325
|
+
if (previousValue === value) return;
|
1326
|
+
|
1327
|
+
item[key] = value;
|
1328
|
+
|
1329
|
+
var tableView = this.getTableView();
|
1330
|
+
tableView.$trigger($.Event(Pushpop.TableView.EventType.DidChangeValueForItemInDataSource, {
|
1331
|
+
tableView: tableView,
|
1332
|
+
dataSource: this,
|
1333
|
+
item: item,
|
1334
|
+
key: key,
|
1335
|
+
value: value,
|
1336
|
+
previousValue: previousValue
|
1337
|
+
}));
|
1338
|
+
},
|
1339
|
+
|
1340
|
+
_filterFunction: function(regExp, item) {
|
1341
|
+
|
1342
|
+
// Default filter function implementation that searches an item's title.
|
1343
|
+
return regExp.test(item.title);
|
1344
|
+
},
|
1345
|
+
|
1346
|
+
/**
|
1347
|
+
Returns the current filter function for searching this TableView.
|
1348
|
+
@description NOTE: This may not be utilized by a custom data source.
|
1349
|
+
@type Function
|
1350
|
+
*/
|
1351
|
+
getFilterFunction: function() { return this._filterFunction; },
|
1352
|
+
|
1353
|
+
/**
|
1354
|
+
Sets a filter function to be used when searching this TableView.
|
1355
|
+
@param {Function} filterFunction The filter function to be used when searching this TableView.
|
1356
|
+
@description The filter function gets called for each item in the data set during a search. A
|
1357
|
+
valid filter function must take two parameters (regExp, item) and return a Boolean value. The
|
1358
|
+
|regExp| parameter contains a RegExp object based on the search string to be used to match items
|
1359
|
+
in the data set. The |item| parameter contains an item from the data set that the search string
|
1360
|
+
in the RegExp should be tested against. The provided filter function should return a Boolean
|
1361
|
+
value: |true| if the item should match the search string or |false| if it should be filtered out.
|
1362
|
+
NOTE: This may not be utilized by a custom data source.
|
1363
|
+
*/
|
1364
|
+
setFilterFunction: function(filterFunction) { this._filterFunction = filterFunction; }
|
1365
|
+
};
|
1366
|
+
|
1367
|
+
/**
|
1368
|
+
Creates a new search bar for a TableView.
|
1369
|
+
@param {Pushpop.TableView} tableView The TableView this search bar should be attached to.
|
1370
|
+
@constructor
|
1371
|
+
*/
|
1372
|
+
Pushpop.TableViewSearchBar = function TableViewSearchBar(tableView) {
|
1373
|
+
var $element = this.$element = $('<div class="pp-table-view-search-bar"/>');
|
1374
|
+
var element = this.element = $element[0];
|
1375
|
+
|
1376
|
+
var self = element.tableViewSearchBar = this;
|
1377
|
+
|
1378
|
+
var $input = this.$input = $('<input type="text" placeholder="Search"/>').appendTo($element);
|
1379
|
+
var $cancelButton = this.$cancelButton = $('<a class="pp-table-view-search-bar-button" href="#">Cancel</a>').appendTo($element);
|
1380
|
+
var $clearButton = this.$clearButton = $('<a class="pp-table-view-search-bar-clear-button" href="#"/>').appendTo($element);
|
1381
|
+
var $overlay = this.$overlay = $('<div class="pp-table-view-search-bar-overlay"/>');
|
1382
|
+
|
1383
|
+
var willClickCancel = false;
|
1384
|
+
var willClickClear = false;
|
1385
|
+
var willFocus = false;
|
1386
|
+
|
1387
|
+
$element.delegate('a', 'click', function(evt) { evt.preventDefault(); });
|
1388
|
+
$element.delegate('a', !!('ontouchstart' in window) ? 'touchstart' : 'mousedown', function(evt) {
|
1389
|
+
evt.stopImmediatePropagation();
|
1390
|
+
evt.preventDefault();
|
1391
|
+
|
1392
|
+
var $button = $(this);
|
1393
|
+
if ($button.hasClass('pp-table-view-search-bar-button')) willClickCancel = true;
|
1394
|
+
else if ($button.hasClass('pp-table-view-search-bar-clear-button')) willClickClear = true;
|
1395
|
+
});
|
1396
|
+
$element.delegate('a', !!('ontouchmove' in window) ? 'touchmove' : 'mousemove', function(evt) {
|
1397
|
+
if (willClickCancel || willClickClear) willClickCancel = willClickClear = false;
|
1398
|
+
});
|
1399
|
+
$element.delegate('a', !!('ontouchend' in window) ? 'touchend' : 'mouseup', function(evt) {
|
1400
|
+
if (willClickCancel) {
|
1401
|
+
willClickCancel = false;
|
1402
|
+
$input.val(null).trigger('keyup').trigger('blur');
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
else if (willClickClear) {
|
1406
|
+
willClickClear = false;
|
1407
|
+
$input.val(null).trigger('keyup');
|
1408
|
+
}
|
1409
|
+
});
|
1410
|
+
$input.bind('mousedown touchstart', function(evt) {
|
1411
|
+
if ($input.is(':focus')) {
|
1412
|
+
evt.stopPropagation();
|
1413
|
+
return;
|
1414
|
+
}
|
1415
|
+
|
1416
|
+
evt.preventDefault();
|
1417
|
+
willFocus = true;
|
1418
|
+
});
|
1419
|
+
$input.bind('mousemove touchmove', function(evt) { willFocus = false; });
|
1420
|
+
$input.bind('mouseup touchend', function(evt) {
|
1421
|
+
if ($input.is(':focus')) {
|
1422
|
+
evt.stopPropagation();
|
1423
|
+
return;
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
evt.preventDefault();
|
1427
|
+
if (willFocus) $input.trigger('focus');
|
1428
|
+
});
|
1429
|
+
$input.bind('focus', function(evt) {
|
1430
|
+
if (!willFocus) {
|
1431
|
+
$input.trigger('blur');
|
1432
|
+
return false;
|
1433
|
+
}
|
1434
|
+
|
1435
|
+
willFocus = false;
|
1436
|
+
|
1437
|
+
window.setTimeout(function() {
|
1438
|
+
$overlay.addClass('pp-active');
|
1439
|
+
if ($input.val()) $clearButton.addClass('pp-active');
|
1440
|
+
}, 1);
|
1441
|
+
|
1442
|
+
self.getTableView().scrollView.scrollToTop();
|
1443
|
+
});
|
1444
|
+
$input.bind('blur', function(evt) { $overlay.removeClass('pp-active'); $clearButton.removeClass('pp-active'); });
|
1445
|
+
$overlay.bind('mousedown touchstart', function(evt) { evt.stopPropagation(); evt.preventDefault(); });
|
1446
|
+
$overlay.bind('mouseup touchend', function(evt) { $input.trigger('blur'); });
|
1447
|
+
$input.bind('keyup', function(evt) {
|
1448
|
+
|
1449
|
+
// If 'ESC' key was pressed, cancel the search.
|
1450
|
+
if (evt.keyCode === 27) {
|
1451
|
+
$input.val(null).trigger('keyup').trigger('blur');
|
1452
|
+
return;
|
1453
|
+
}
|
1454
|
+
|
1455
|
+
var searchString = $input.val();
|
1456
|
+
var tableView = self._tableView;
|
1457
|
+
|
1458
|
+
if (!searchString) {
|
1459
|
+
$overlay.addClass('pp-active');
|
1460
|
+
$clearButton.removeClass('pp-active');
|
1461
|
+
} else {
|
1462
|
+
$overlay.removeClass('pp-active');
|
1463
|
+
$clearButton.addClass('pp-active');
|
1464
|
+
}
|
1465
|
+
|
1466
|
+
if (tableView.getDataSource().shouldReloadTableForSearchString(searchString)) tableView.reloadData();
|
1467
|
+
});
|
1468
|
+
|
1469
|
+
this.attachToTableView(tableView);
|
1470
|
+
};
|
1471
|
+
|
1472
|
+
Pushpop.TableViewSearchBar.prototype = {
|
1473
|
+
constructor: Pushpop.TableViewSearchBar,
|
1474
|
+
|
1475
|
+
element: null,
|
1476
|
+
$element: null,
|
1477
|
+
$input: null,
|
1478
|
+
$cancelButton: null,
|
1479
|
+
$clearButton: null,
|
1480
|
+
$overlay: null,
|
1481
|
+
|
1482
|
+
_tableView: null,
|
1483
|
+
|
1484
|
+
/**
|
1485
|
+
|
1486
|
+
*/
|
1487
|
+
getTableView: function() { return this._tableView; },
|
1488
|
+
|
1489
|
+
/**
|
1490
|
+
Attaches this TableViewSearchBar to a TableView.
|
1491
|
+
@param {Pushpop.TableView} tableView A TableView to attach this search bar to.
|
1492
|
+
*/
|
1493
|
+
attachToTableView: function(tableView) {
|
1494
|
+
this._tableView = tableView;
|
1495
|
+
this.$overlay.appendTo(tableView.scrollView.$element);
|
1496
|
+
tableView.$element.before(this.$element);
|
1497
|
+
},
|
1498
|
+
|
1499
|
+
/**
|
1500
|
+
Returns the current search string entered in the search bar.
|
1501
|
+
@type String
|
1502
|
+
*/
|
1503
|
+
getSearchString: function() { return this.$input.val(); },
|
1504
|
+
|
1505
|
+
/**
|
1506
|
+
Sets the current search string that should appear in the search bar.
|
1507
|
+
@param {String} searchString The search string that should appear in the search bar.
|
1508
|
+
*/
|
1509
|
+
setSearchString: function(searchString) { this.$input.val(searchString); }
|
1510
|
+
};
|
1511
|
+
|
1512
|
+
/**
|
1513
|
+
Creates a new default table view cell for a TableView with bold black title text.
|
1514
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
1515
|
+
to the group of cells that this cell should belong to. This reuse identifier is
|
1516
|
+
used by the TableView to recycle TableViewCells of the same style and type.
|
1517
|
+
@constructor
|
1518
|
+
*/
|
1519
|
+
Pushpop.TableViewCell = function TableViewCell(reuseIdentifier) {
|
1520
|
+
reuseIdentifier = this._reuseIdentifier = reuseIdentifier || this._reuseIdentifier;
|
1521
|
+
|
1522
|
+
var $element = this.$element = $('<li data-reuse-identifier="' + reuseIdentifier + '"/>');
|
1523
|
+
var element = this.element = $element[0];
|
1524
|
+
|
1525
|
+
element.tableViewCell = this;
|
1526
|
+
|
1527
|
+
$element.addClass(reuseIdentifier);
|
1528
|
+
};
|
1529
|
+
|
1530
|
+
Pushpop.TableViewCell.AccessoryType = {
|
1531
|
+
None: 'pp-table-view-cell-accessory-none',
|
1532
|
+
DisclosureIndicator: 'pp-table-view-cell-accessory-disclosure-indicator',
|
1533
|
+
DetailDisclosureButton: 'pp-table-view-cell-accessory-detail-disclosure-button',
|
1534
|
+
Checkmark: 'pp-table-view-cell-accessory-checkmark',
|
1535
|
+
ConfirmDeleteButton: 'pp-table-view-cell-accessory-confirm-delete-button'
|
1536
|
+
};
|
1537
|
+
|
1538
|
+
Pushpop.TableViewCell.EditingAccessoryType = {
|
1539
|
+
None: 'pp-table-view-cell-editing-accessory-none',
|
1540
|
+
AddButton: 'pp-table-view-cell-editing-accessory-add-button',
|
1541
|
+
DeleteButton: 'pp-table-view-cell-editing-accessory-delete-button'
|
1542
|
+
};
|
1543
|
+
|
1544
|
+
Pushpop.TableViewCell.prototype = {
|
1545
|
+
constructor: Pushpop.TableViewCell,
|
1546
|
+
|
1547
|
+
element: null,
|
1548
|
+
$element: null,
|
1549
|
+
|
1550
|
+
tableView: null,
|
1551
|
+
|
1552
|
+
_reuseIdentifier: 'pp-table-view-cell-default',
|
1553
|
+
|
1554
|
+
/**
|
1555
|
+
Returns a string containing this cell's reuse identifier.
|
1556
|
+
@type String
|
1557
|
+
*/
|
1558
|
+
getReuseIdentifier: function() { return this._reuseIdentifier; },
|
1559
|
+
|
1560
|
+
/**
|
1561
|
+
Returns a string containing HTML to be used to render the cell's contents based
|
1562
|
+
on the cell's data.
|
1563
|
+
@description NOTE: When creating a custom cell class, this method should be
|
1564
|
+
overridden to provide the appropriate HTML markup for the cell.
|
1565
|
+
@type String
|
1566
|
+
*/
|
1567
|
+
getHtml: function() {
|
1568
|
+
var data = this.getData();
|
1569
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
1570
|
+
return '<h1>' + title + '</h1>';
|
1571
|
+
},
|
1572
|
+
|
1573
|
+
/**
|
1574
|
+
Returns a string containing HTML to be used to render the cell's accessories
|
1575
|
+
based on the cell's accessory type.
|
1576
|
+
@type String
|
1577
|
+
*/
|
1578
|
+
getEditingAccessoryHtml: function() {
|
1579
|
+
var editingAccessoryType = this.getEditingAccessoryType();
|
1580
|
+
if (!editingAccessoryType || editingAccessoryType === Pushpop.TableViewCell.EditingAccessoryType.None) return '';
|
1581
|
+
return '<span class="pp-table-view-cell-editing-accessory ' + editingAccessoryType + '"/>';
|
1582
|
+
},
|
1583
|
+
|
1584
|
+
/**
|
1585
|
+
Returns a string containing HTML to be used to render the cell's accessories
|
1586
|
+
based on the cell's accessory type.
|
1587
|
+
@type String
|
1588
|
+
*/
|
1589
|
+
getAccessoryHtml: function() {
|
1590
|
+
var accessoryType = this.getAccessoryType();
|
1591
|
+
if (!accessoryType || accessoryType === Pushpop.TableViewCell.AccessoryType.None) return '';
|
1592
|
+
return '<span class="pp-table-view-cell-accessory ' + accessoryType + '"/>';
|
1593
|
+
},
|
1594
|
+
|
1595
|
+
/**
|
1596
|
+
Renders the cell using HTML provided by the getHtml() and getAccessoryHtml()
|
1597
|
+
methods.
|
1598
|
+
@description NOTE: In most circumstances, this method shouldn't need to be
|
1599
|
+
overridden when creating a custom cell class. Typically, when creating a custom
|
1600
|
+
cell class, only the getHtml() method should need to be overridden.
|
1601
|
+
*/
|
1602
|
+
draw: function() {
|
1603
|
+
this.$element.html(this.getEditingAccessoryHtml() + this.getHtml() + this.getAccessoryHtml());
|
1604
|
+
},
|
1605
|
+
|
1606
|
+
forceReflow: function() { var doNothing = this.element.offsetWidth; },
|
1607
|
+
|
1608
|
+
/**
|
1609
|
+
Performs any necessary actions when this cell has been tapped.
|
1610
|
+
@description NOTE: The default implementation does nothing. This method is
|
1611
|
+
intended to be overridden by custom table view cells that require an action
|
1612
|
+
to be taken upon tapping the cell (e.g.: pushing a new view).
|
1613
|
+
*/
|
1614
|
+
didReceiveTap: function() {},
|
1615
|
+
|
1616
|
+
/**
|
1617
|
+
Removes this TableViewCell from the TableView's visible cells, resets its
|
1618
|
+
data and prepares it to be reused by the TableView by placing it in the
|
1619
|
+
reusable cells queue.
|
1620
|
+
*/
|
1621
|
+
prepareForReuse: function() {
|
1622
|
+
|
1623
|
+
// Detach the TableViewCell from the DOM.
|
1624
|
+
// NOTE: Using .detach() will preserve any attached event handlers.
|
1625
|
+
this.$element.detach();
|
1626
|
+
|
1627
|
+
var tableView = this.tableView;
|
1628
|
+
var reuseIdentifier = this.getReuseIdentifier();
|
1629
|
+
var renderedCells = tableView.getRenderedCells();
|
1630
|
+
var reusableCells = tableView.getReusableCells();
|
1631
|
+
reusableCells = reusableCells[reuseIdentifier] || (reusableCells[reuseIdentifier] = []);
|
1632
|
+
|
1633
|
+
reusableCells.push(this);
|
1634
|
+
|
1635
|
+
for (var i = 0, length = renderedCells.length; i < length; i++) {
|
1636
|
+
if (renderedCells[i] === this) {
|
1637
|
+
renderedCells.splice(i, 1);
|
1638
|
+
break;
|
1639
|
+
}
|
1640
|
+
}
|
1641
|
+
|
1642
|
+
this.setSelected(false);
|
1643
|
+
this.setIndex(-1);
|
1644
|
+
this.setAccessoryType(null);
|
1645
|
+
this.setEditingAccessoryType(null);
|
1646
|
+
this.setData(null);
|
1647
|
+
},
|
1648
|
+
|
1649
|
+
_data: null,
|
1650
|
+
|
1651
|
+
/**
|
1652
|
+
Returns the data of the item in the data source that corresponds to this cell.
|
1653
|
+
@type Object
|
1654
|
+
*/
|
1655
|
+
getData: function() { return this._data; },
|
1656
|
+
|
1657
|
+
/**
|
1658
|
+
Sets the data of this cell that corresponds to an item in the data source.
|
1659
|
+
@description NOTE: This method will set the cell's value to the |value| property
|
1660
|
+
of the provided data.
|
1661
|
+
@param {Object} data The data of an item in the data source to assign to this cell.
|
1662
|
+
*/
|
1663
|
+
setData: function(data) {
|
1664
|
+
this._data = data;
|
1665
|
+
if (!data) return;
|
1666
|
+
if (data.value) {
|
1667
|
+
this.setValue(data.value);
|
1668
|
+
return;
|
1669
|
+
}
|
1670
|
+
|
1671
|
+
this.draw();
|
1672
|
+
},
|
1673
|
+
|
1674
|
+
_accessoryType: null,
|
1675
|
+
|
1676
|
+
/**
|
1677
|
+
Returns the type of accessory to render for this cell. The types of available
|
1678
|
+
accessories are specified in Pushpop.TableViewCell.AccessoryType.
|
1679
|
+
@description NOTE: Table view cell accessories are rendered on the right-hand
|
1680
|
+
side of the cell.
|
1681
|
+
@type String
|
1682
|
+
*/
|
1683
|
+
getAccessoryType: function() { return this._accessoryType; },
|
1684
|
+
|
1685
|
+
/**
|
1686
|
+
Sets the type of accessory to render for this cell. The types of available
|
1687
|
+
accessories are specified in Pushpop.TableViewCell.AccessoryType.
|
1688
|
+
@description NOTE: Table view cell accessories are rendered on the right-hand
|
1689
|
+
side of the cell.
|
1690
|
+
@param {String} accessoryType The type of accessory to render for this cell.
|
1691
|
+
*/
|
1692
|
+
setAccessoryType: function(accessoryType) { this._accessoryType = (accessoryType !== Pushpop.TableViewCell.AccessoryType.None) ? accessoryType : null; },
|
1693
|
+
|
1694
|
+
_editingAccessoryType: null,
|
1695
|
+
|
1696
|
+
/**
|
1697
|
+
Returns the type of editing accessory to render for this cell. The types of available
|
1698
|
+
editing accessories are specified in Pushpop.TableViewCell.EditingAccessoryType.
|
1699
|
+
@description NOTE: Table view cell editing accessories are rendered on the left-hand
|
1700
|
+
side of the cell.
|
1701
|
+
@type String
|
1702
|
+
*/
|
1703
|
+
getEditingAccessoryType: function() { return this._editingAccessoryType; },
|
1704
|
+
|
1705
|
+
/**
|
1706
|
+
Sets the type of editing accessory to render for this cell. The types of available
|
1707
|
+
editing accessories are specified in Pushpop.TableViewCell.EditingAccessoryType.
|
1708
|
+
@description NOTE: Table view cell editing accessories are rendered on the left-hand
|
1709
|
+
side of the cell.
|
1710
|
+
@param {String} editingAccessoryType The type of editing accessory to render for this cell.
|
1711
|
+
*/
|
1712
|
+
setEditingAccessoryType: function(editingAccessoryType) { this._editingAccessoryType = (editingAccessoryType !== Pushpop.TableViewCell.EditingAccessoryType.None) ? editingAccessoryType : null; },
|
1713
|
+
|
1714
|
+
_value: null,
|
1715
|
+
|
1716
|
+
/**
|
1717
|
+
Returns the value of the item in the data source that corresponds to this cell.
|
1718
|
+
@description NOTE: This method is typically only used by "input" cell types. When
|
1719
|
+
setData() is called, the cell's value will be set to the |value| property of the
|
1720
|
+
cell's data (e.g.: this.getData().value). The value that is returned by this method
|
1721
|
+
originates from the |value| property of the cell's data.
|
1722
|
+
@type Number|String|Object
|
1723
|
+
*/
|
1724
|
+
getValue: function() { return this._value; },
|
1725
|
+
|
1726
|
+
/**
|
1727
|
+
Sets the value of this cell that corresponds to an item in the data source.
|
1728
|
+
@description NOTE: This method is typically only used by "input" cell types. When
|
1729
|
+
setData() is called, this method is called to set the |value| property of the
|
1730
|
+
cell's data (e.g.: this.getData().value). The value that is set by this method
|
1731
|
+
will also replace the value of the |value| property of the cell's data.
|
1732
|
+
@param {Number|String|Object} value The value of an item in the data source to assign to this cell.
|
1733
|
+
*/
|
1734
|
+
setValue: function(value) {
|
1735
|
+
var data = this.getData();
|
1736
|
+
var dataSource = this.tableView.getDataSource();
|
1737
|
+
dataSource.setValueForKeyOnItem(data, 'value', value);
|
1738
|
+
|
1739
|
+
this._value = value;
|
1740
|
+
this.draw();
|
1741
|
+
},
|
1742
|
+
|
1743
|
+
_index: -1,
|
1744
|
+
|
1745
|
+
/**
|
1746
|
+
Returns the index of the item in the data source that corresponds to this cell.
|
1747
|
+
@type Number
|
1748
|
+
*/
|
1749
|
+
getIndex: function() { return this._index; },
|
1750
|
+
|
1751
|
+
/**
|
1752
|
+
Sets the index of this cell that corresponds to an item in the data source.
|
1753
|
+
@param {Number} index The index of an item in the data source to assign to this cell.
|
1754
|
+
*/
|
1755
|
+
setIndex: function(index) { this._index = index; },
|
1756
|
+
|
1757
|
+
_isSelected: false,
|
1758
|
+
|
1759
|
+
/**
|
1760
|
+
Returns a flag indicating whether or not this TableViewCell is currently selected.
|
1761
|
+
@type Boolean
|
1762
|
+
*/
|
1763
|
+
getSelected: function() { return this._isSelected; },
|
1764
|
+
|
1765
|
+
/**
|
1766
|
+
Sets a flag to indicate if this TableViewCell should be selected.
|
1767
|
+
@param {Boolean} value A boolean value to determine if this cell should be selected.
|
1768
|
+
*/
|
1769
|
+
setSelected: function(value) {
|
1770
|
+
if ((this._isSelected = value)) {
|
1771
|
+
this.$element.addClass('pp-table-view-selected-state');
|
1772
|
+
} else {
|
1773
|
+
this.$element.removeClass('pp-table-view-selected-state');
|
1774
|
+
}
|
1775
|
+
}
|
1776
|
+
};
|
1777
|
+
|
1778
|
+
// Register the prototype for Pushpop.TableViewCell as a reusable cell type.
|
1779
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.TableViewCell.prototype);
|
1780
|
+
|
1781
|
+
/**
|
1782
|
+
Creates a new table view cell for a TableView with bold black title text and grey
|
1783
|
+
subtitle text.
|
1784
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
1785
|
+
to the group of cells that this cell should belong to.
|
1786
|
+
@constructor
|
1787
|
+
@extends Pushpop.TableViewCell
|
1788
|
+
*/
|
1789
|
+
Pushpop.SubtitleTableViewCell = function SubtitleTableViewCell(reuseIdentifier) {
|
1790
|
+
|
1791
|
+
// Call the "super" constructor.
|
1792
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
1793
|
+
};
|
1794
|
+
|
1795
|
+
Pushpop.SubtitleTableViewCell.prototype = new Pushpop.TableViewCell('pp-subtitle-table-view-cell');
|
1796
|
+
Pushpop.SubtitleTableViewCell.prototype.constructor = Pushpop.SubtitleTableViewCell;
|
1797
|
+
|
1798
|
+
Pushpop.SubtitleTableViewCell.prototype.getHtml = function() {
|
1799
|
+
var data = this.getData();
|
1800
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
1801
|
+
var subtitle = $.trim((data && data.subtitle) ? data.subtitle : ' ');
|
1802
|
+
return '<h1>' + title + '</h1><h2>' + subtitle + '</h2>';
|
1803
|
+
};
|
1804
|
+
|
1805
|
+
// Register the prototype for Pushpop.SubtitleTableViewCell as a reusable cell type.
|
1806
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.SubtitleTableViewCell.prototype);
|
1807
|
+
|
1808
|
+
/**
|
1809
|
+
Creates a new table view cell for a TableView with a bold black text label and a
|
1810
|
+
blue text value.
|
1811
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
1812
|
+
to the group of cells that this cell should belong to.
|
1813
|
+
@constructor
|
1814
|
+
@extends Pushpop.TableViewCell
|
1815
|
+
*/
|
1816
|
+
Pushpop.ValueTableViewCell = function ValueTableViewCell(reuseIdentifier) {
|
1817
|
+
|
1818
|
+
// Call the "super" constructor.
|
1819
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
1820
|
+
};
|
1821
|
+
|
1822
|
+
Pushpop.ValueTableViewCell.prototype = new Pushpop.TableViewCell('pp-value-table-view-cell');
|
1823
|
+
Pushpop.ValueTableViewCell.prototype.constructor = Pushpop.ValueTableViewCell;
|
1824
|
+
|
1825
|
+
Pushpop.ValueTableViewCell.prototype.getHtml = function() {
|
1826
|
+
var data = this.getData();
|
1827
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
1828
|
+
var value = $.trim((data && data.value) ? data.value : ' ');
|
1829
|
+
return '<h1>' + title + '</h1><h2>' + value + '</h2>';
|
1830
|
+
};
|
1831
|
+
|
1832
|
+
// Register the prototype for Pushpop.ValueTableViewCell as a reusable cell type.
|
1833
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.ValueTableViewCell.prototype);
|
1834
|
+
|
1835
|
+
/**
|
1836
|
+
Creates a new table view cell for a TableView with a small bold blue text label
|
1837
|
+
and a long black bold text value.
|
1838
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
1839
|
+
to the group of cells that this cell should belong to.
|
1840
|
+
@constructor
|
1841
|
+
@extends Pushpop.TableViewCell
|
1842
|
+
*/
|
1843
|
+
Pushpop.Value2TableViewCell = function Value2TableViewCell(reuseIdentifier) {
|
1844
|
+
|
1845
|
+
// Call the "super" constructor.
|
1846
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
1847
|
+
};
|
1848
|
+
|
1849
|
+
Pushpop.Value2TableViewCell.prototype = new Pushpop.TableViewCell('pp-value2-table-view-cell');
|
1850
|
+
Pushpop.Value2TableViewCell.prototype.constructor = Pushpop.Value2TableViewCell;
|
1851
|
+
|
1852
|
+
Pushpop.Value2TableViewCell.prototype.getHtml = function() {
|
1853
|
+
var data = this.getData();
|
1854
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
1855
|
+
var value = $.trim((data && data.value) ? data.value : ' ');
|
1856
|
+
return '<h1>' + title + '</h1><h2>' + value + '</h2>';
|
1857
|
+
};
|
1858
|
+
|
1859
|
+
// Register the prototype for Pushpop.Value2TableViewCell as a reusable cell type.
|
1860
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.Value2TableViewCell.prototype);
|
1861
|
+
|
1862
|
+
/**
|
1863
|
+
Creates a new table view cell for a TableView with a small bold blue text label
|
1864
|
+
and an inline text input field.
|
1865
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
1866
|
+
to the group of cells that this cell should belong to.
|
1867
|
+
@constructor
|
1868
|
+
@extends Pushpop.TableViewCell
|
1869
|
+
*/
|
1870
|
+
Pushpop.InlineTextInputTableViewCell = function InlineTextInputTableViewCell(reuseIdentifier) {
|
1871
|
+
|
1872
|
+
// Call the "super" constructor.
|
1873
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
1874
|
+
|
1875
|
+
var self = this;
|
1876
|
+
|
1877
|
+
// Attach an event handler to this cell to update its value when the input changes.
|
1878
|
+
this.$element.delegate('input', 'keyup change', function(evt) {
|
1879
|
+
var data = self.getData();
|
1880
|
+
var value = $(this).val();
|
1881
|
+
var dataSource = self.tableView.getDataSource();
|
1882
|
+
dataSource.setValueForKeyOnItem(data, 'value', value);
|
1883
|
+
|
1884
|
+
this._value = value;
|
1885
|
+
});
|
1886
|
+
|
1887
|
+
this.$element.bind(!!('ontouchstart' in window) ? 'touchend' : 'mouseup', function(evt) {
|
1888
|
+
evt.preventDefault();
|
1889
|
+
});
|
1890
|
+
};
|
1891
|
+
|
1892
|
+
Pushpop.InlineTextInputTableViewCell.prototype = new Pushpop.TableViewCell('pp-inline-text-input-table-view-cell');
|
1893
|
+
Pushpop.InlineTextInputTableViewCell.prototype.constructor = Pushpop.InlineTextInputTableViewCell;
|
1894
|
+
|
1895
|
+
Pushpop.InlineTextInputTableViewCell.prototype.getHtml = function() {
|
1896
|
+
var data = this.getData();
|
1897
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
1898
|
+
var name = $.trim((data && data.name) ? data.name : '');
|
1899
|
+
var value = $.trim((data && data.value) ? data.value : '');
|
1900
|
+
var autoCapitalize = (data) ? (data.autoCapitalize === false) ? 'off' : (data.autoCapitalize === true) ? 'on' : (data.autoCapitalize) ? data.autoCapitalize : 'on' : 'on';
|
1901
|
+
var autoCorrect = (data) ? (data.autoCorrect + '') : 'on';
|
1902
|
+
autoCorrect = !!(autoCorrect !== 'false' && autoCorrect !== 'off');
|
1903
|
+
var isPassword = (data) ? (data.password || 'false') : 'false';
|
1904
|
+
isPassword = isPassword !== 'false';
|
1905
|
+
return '<h1>' + title + '</h1><h2><input type="' + (isPassword ? 'password' : 'text') + '" name="' + name + '" value="' + value + '" autocapitalize="' + autoCapitalize + '" autocorrect="' + (autoCorrect ? 'on' : 'off') +'"/></h2>';
|
1906
|
+
};
|
1907
|
+
|
1908
|
+
Pushpop.InlineTextInputTableViewCell.prototype.didReceiveTap = function() {
|
1909
|
+
var $element = this.$element;
|
1910
|
+
$element.find('input').trigger('focus');
|
1911
|
+
window.setTimeout(function() { $element.removeClass('pp-table-view-selected-state'); }, 100);
|
1912
|
+
};
|
1913
|
+
|
1914
|
+
// Register the prototype for Pushpop.InlineTextInputTableViewCell as a reusable cell type.
|
1915
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.InlineTextInputTableViewCell.prototype);
|
1916
|
+
|
1917
|
+
/**
|
1918
|
+
Creates a new table view cell for a TableView with a small bold blue text label
|
1919
|
+
and a long black bold text value. When this type of cell is tapped, a new view
|
1920
|
+
is presented with a large text area for entering long strings of text.
|
1921
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
1922
|
+
to the group of cells that this cell should belong to.
|
1923
|
+
@constructor
|
1924
|
+
@extends Pushpop.TableViewCell
|
1925
|
+
*/
|
1926
|
+
Pushpop.TextAreaInputTableViewCell = function TextAreaInputTableViewCell(reuseIdentifier) {
|
1927
|
+
|
1928
|
+
// Call the "super" constructor.
|
1929
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
1930
|
+
};
|
1931
|
+
|
1932
|
+
Pushpop.TextAreaInputTableViewCell.prototype = new Pushpop.TableViewCell('pp-text-area-input-table-view-cell');
|
1933
|
+
Pushpop.TextAreaInputTableViewCell.prototype.constructor = Pushpop.TextAreaInputTableViewCell;
|
1934
|
+
|
1935
|
+
Pushpop.TextAreaInputTableViewCell.prototype.getHtml = function() {
|
1936
|
+
var data = this.getData();
|
1937
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
1938
|
+
var value = $.trim((data && data.value) ? data.value : ' ');
|
1939
|
+
return '<h1>' + title + '</h1><h2>' + value + '</h2>';
|
1940
|
+
};
|
1941
|
+
|
1942
|
+
Pushpop.TextAreaInputTableViewCell.prototype.getAccessoryType = function() { return this._accessoryType || Pushpop.TableViewCell.AccessoryType.DisclosureIndicator; };
|
1943
|
+
|
1944
|
+
Pushpop.TextAreaInputTableViewCell.prototype.didReceiveTap = function() {
|
1945
|
+
var tableView = this.tableView;
|
1946
|
+
var viewStack = tableView.getViewStack();
|
1947
|
+
if (!viewStack) return;
|
1948
|
+
|
1949
|
+
var data = this.getData();
|
1950
|
+
if (!data) return;
|
1951
|
+
|
1952
|
+
var title = data.title || '';
|
1953
|
+
var name = data.name || '';
|
1954
|
+
var value = data.value || '';
|
1955
|
+
|
1956
|
+
var self = this;
|
1957
|
+
|
1958
|
+
// Push a new view with a large text area input.
|
1959
|
+
viewStack.pushNewView(function(newView) {
|
1960
|
+
var $textarea = $('<textarea class="pp-text-area-input-table-view-cell-textarea" name="' + name + '">' + value + '</textarea>').appendTo(newView.$element);
|
1961
|
+
|
1962
|
+
newView.setTitle(title);
|
1963
|
+
newView.addBarButtonItem(new Pushpop.Button('Done', function(button) {
|
1964
|
+
self.setValue($textarea.val());
|
1965
|
+
tableView.reloadData();
|
1966
|
+
viewStack.pop();
|
1967
|
+
}, Pushpop.Button.ButtonAlignmentType.Right, Pushpop.Button.ButtonStyleType.Blue));
|
1968
|
+
});
|
1969
|
+
};
|
1970
|
+
|
1971
|
+
// Register the prototype for Pushpop.TextAreaInputTableViewCell as a reusable cell type.
|
1972
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.TextAreaInputTableViewCell.prototype);
|
1973
|
+
|
1974
|
+
/**
|
1975
|
+
Creates a new table view cell for a TableView with a small bold blue text label
|
1976
|
+
and a long black bold text value. When this type of cell is tapped, a table view
|
1977
|
+
is presented that contains the cell's "child" data source with a list of options
|
1978
|
+
to pick from.
|
1979
|
+
@description NOTE: The data for the "child" data source must be contained in a
|
1980
|
+
property in this cell's data called |childDataSource|.
|
1981
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
1982
|
+
to the group of cells that this cell should belong to.
|
1983
|
+
@constructor
|
1984
|
+
@extends Pushpop.TableViewCell
|
1985
|
+
*/
|
1986
|
+
Pushpop.SelectInputTableViewCell = function SelectInputTableViewCell(reuseIdentifier) {
|
1987
|
+
|
1988
|
+
// Call the "super" constructor.
|
1989
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
1990
|
+
};
|
1991
|
+
|
1992
|
+
Pushpop.SelectInputTableViewCell.prototype = new Pushpop.TableViewCell('pp-select-input-table-view-cell');
|
1993
|
+
Pushpop.SelectInputTableViewCell.prototype.constructor = Pushpop.SelectInputTableViewCell;
|
1994
|
+
|
1995
|
+
Pushpop.SelectInputTableViewCell.prototype.getHtml = function() {
|
1996
|
+
var data = this.getData();
|
1997
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
1998
|
+
var value = $.trim((data && data.value) ? ((data.value.title) ? data.value.title : data.value) : ' ');
|
1999
|
+
return '<h1>' + title + '</h1><h2>' + value + '</h2>';
|
2000
|
+
};
|
2001
|
+
|
2002
|
+
Pushpop.SelectInputTableViewCell.prototype.getAccessoryType = function() { return this._accessoryType || Pushpop.TableViewCell.AccessoryType.DisclosureIndicator; };
|
2003
|
+
|
2004
|
+
Pushpop.SelectInputTableViewCell.prototype.didReceiveTap = function() {
|
2005
|
+
var tableView = this.tableView;
|
2006
|
+
|
2007
|
+
var viewStack = tableView.getViewStack();
|
2008
|
+
if (!viewStack) return;
|
2009
|
+
|
2010
|
+
var view = tableView.getView();
|
2011
|
+
if (!view) return;
|
2012
|
+
|
2013
|
+
var data = this.getData();
|
2014
|
+
if (!data) return;
|
2015
|
+
|
2016
|
+
var childDataSource = new Pushpop.TableViewDataSource(data.childDataSource);
|
2017
|
+
|
2018
|
+
var self = this;
|
2019
|
+
|
2020
|
+
// Push a new view with a large text area input.
|
2021
|
+
viewStack.pushNewTableView(function(newTableView) {
|
2022
|
+
newTableView.setSearchBar(new Pushpop.TableViewSearchBar(newTableView));
|
2023
|
+
newTableView.setDataSource(childDataSource);
|
2024
|
+
|
2025
|
+
newTableView.$bind(Pushpop.TableView.EventType.DidSelectRowAtIndex, function(evt) {
|
2026
|
+
if (evt.hasChildDataSource) return;
|
2027
|
+
|
2028
|
+
var tableView = evt.tableView;
|
2029
|
+
var dataSource = tableView.getDataSource();
|
2030
|
+
var item = dataSource.getFilteredItemAtIndex(evt.index);
|
2031
|
+
|
2032
|
+
self.setValue(item);
|
2033
|
+
viewStack.pop(view);
|
2034
|
+
});
|
2035
|
+
});
|
2036
|
+
};
|
2037
|
+
|
2038
|
+
Pushpop.SelectInputTableViewCell.prototype.setValue = function(value) {
|
2039
|
+
var data = this.getData();
|
2040
|
+
var childDataSource;
|
2041
|
+
|
2042
|
+
if (data) {
|
2043
|
+
if (!(value instanceof Object) && (childDataSource = data.childDataSource)) {
|
2044
|
+
for (var i = 0, length = childDataSource.length; i < length; i++) {
|
2045
|
+
if (childDataSource[i].value === value) {
|
2046
|
+
value = childDataSource[i];
|
2047
|
+
break;
|
2048
|
+
}
|
2049
|
+
}
|
2050
|
+
}
|
2051
|
+
|
2052
|
+
var dataSource = this.tableView.getDataSource();
|
2053
|
+
dataSource.setValueForKeyOnItem(data, 'value', value);
|
2054
|
+
}
|
2055
|
+
|
2056
|
+
this._value = value;
|
2057
|
+
this.draw();
|
2058
|
+
};
|
2059
|
+
|
2060
|
+
// Register the prototype for Pushpop.SelectInputTableViewCell as a reusable cell type.
|
2061
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.SelectInputTableViewCell.prototype);
|
2062
|
+
|
2063
|
+
/**
|
2064
|
+
Creates a new table view cell for a TableView with a small bold blue text label
|
2065
|
+
and a black bold date value. When this type of cell is tapped, a table view is
|
2066
|
+
presented that allows the user to select a date.
|
2067
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
2068
|
+
to the group of cells that this cell should belong to.
|
2069
|
+
@constructor
|
2070
|
+
@extends Pushpop.TableViewCell
|
2071
|
+
*/
|
2072
|
+
Pushpop.DateInputTableViewCell = function DateInputTableViewCell(reuseIdentifier) {
|
2073
|
+
|
2074
|
+
// Call the "super" constructor.
|
2075
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
2076
|
+
};
|
2077
|
+
|
2078
|
+
Pushpop.DateInputTableViewCell.prototype = new Pushpop.TableViewCell('pp-date-input-table-view-cell');
|
2079
|
+
Pushpop.DateInputTableViewCell.prototype.constructor = Pushpop.DateInputTableViewCell;
|
2080
|
+
|
2081
|
+
Pushpop.DateInputTableViewCell.prototype.getHtml = function() {
|
2082
|
+
var data = this.getData();
|
2083
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
2084
|
+
var value = $.trim((data && data.value) ? data.value : ' ');
|
2085
|
+
return '<h1>' + title + '</h1><h2>' + value + '</h2>';
|
2086
|
+
};
|
2087
|
+
|
2088
|
+
Pushpop.DateInputTableViewCell.prototype.getAccessoryType = function() { return this._accessoryType || Pushpop.TableViewCell.AccessoryType.DisclosureIndicator; };
|
2089
|
+
|
2090
|
+
Pushpop.DateInputTableViewCell.prototype.didReceiveTap = function() {
|
2091
|
+
var tableView = this.tableView;
|
2092
|
+
|
2093
|
+
var viewStack = tableView.getViewStack();
|
2094
|
+
if (!viewStack) return;
|
2095
|
+
|
2096
|
+
var data = this.getData();
|
2097
|
+
if (!data) return;
|
2098
|
+
|
2099
|
+
var i, dayDataSource = [], yearDataSource = [];
|
2100
|
+
for (i = 1; i <= 31; i++) dayDataSource.push({ value: i, title: i + '' });
|
2101
|
+
for (i = 1970; i <= 2100; i++) yearDataSource.push({ value: i, title: i + '' });
|
2102
|
+
|
2103
|
+
var monthDataSource = [
|
2104
|
+
{ value: 1, title: 'January' }, { value: 2, title: 'February' },
|
2105
|
+
{ value: 3, title: 'March' }, { value: 4, title: 'April' },
|
2106
|
+
{ value: 5, title: 'May' }, { value: 6, title: 'June' },
|
2107
|
+
{ value: 7, title: 'July' }, { value: 8, title: 'August' },
|
2108
|
+
{ value: 9, title: 'September' }, { value: 10, title: 'October' },
|
2109
|
+
{ value: 11, title: 'November' }, { value: 12, title: 'December' }
|
2110
|
+
];
|
2111
|
+
|
2112
|
+
var dateParts = this.getValue(), currentDate = new Date();
|
2113
|
+
if (!dateParts || (typeof dateParts !== 'string')) dateParts = currentDate.getFullYear() + '-' + (currentDate.getMonth() + 1) + '-' + currentDate.getDate();
|
2114
|
+
dateParts = dateParts.split('-');
|
2115
|
+
|
2116
|
+
var year = window.parseInt(dateParts[0], 10);
|
2117
|
+
var month = window.parseInt(dateParts[1], 10);
|
2118
|
+
var day = window.parseInt(dateParts[2], 10);
|
2119
|
+
|
2120
|
+
year = { value: year, title: year + '' };
|
2121
|
+
day = { value: day, title: day + '' };
|
2122
|
+
|
2123
|
+
for (i = 0; i < 12; i++) if (monthDataSource[i].value === month) {
|
2124
|
+
month = monthDataSource[i];
|
2125
|
+
break;
|
2126
|
+
}
|
2127
|
+
|
2128
|
+
if (!month || !month.value) month = monthDataSource[0];
|
2129
|
+
|
2130
|
+
var dataSource = new Pushpop.TableViewDataSource([
|
2131
|
+
{
|
2132
|
+
reuseIdentifier: 'pp-select-input-table-view-cell',
|
2133
|
+
title: 'Month',
|
2134
|
+
name: 'month',
|
2135
|
+
value: month,
|
2136
|
+
childDataSource: monthDataSource
|
2137
|
+
},
|
2138
|
+
{
|
2139
|
+
reuseIdentifier: 'pp-select-input-table-view-cell',
|
2140
|
+
title: 'Day',
|
2141
|
+
name: 'day',
|
2142
|
+
value: day,
|
2143
|
+
childDataSource: dayDataSource
|
2144
|
+
},
|
2145
|
+
{
|
2146
|
+
reuseIdentifier: 'pp-select-input-table-view-cell',
|
2147
|
+
title: 'Year',
|
2148
|
+
name: 'year',
|
2149
|
+
value: year,
|
2150
|
+
childDataSource: yearDataSource
|
2151
|
+
}
|
2152
|
+
]);
|
2153
|
+
|
2154
|
+
var self = this;
|
2155
|
+
|
2156
|
+
// Push a new view with a large text area input.
|
2157
|
+
viewStack.pushNewTableView(function(newTableView) {
|
2158
|
+
newTableView.setDataSource(dataSource);
|
2159
|
+
|
2160
|
+
var newView = newTableView.getView();
|
2161
|
+
newView.setTitle($.trim((data && data.title) ? data.title : 'Date'));
|
2162
|
+
newView.addBarButtonItem(new Pushpop.Button('Done', function(button) {
|
2163
|
+
var value = dataSource.getValuesObject();
|
2164
|
+
var year = value.year.value;
|
2165
|
+
var month = value.month.value;
|
2166
|
+
var day = value.day.value;
|
2167
|
+
|
2168
|
+
self.setValue(year + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day);
|
2169
|
+
tableView.reloadData();
|
2170
|
+
viewStack.pop();
|
2171
|
+
}, Pushpop.Button.ButtonAlignmentType.Right, Pushpop.Button.ButtonStyleType.Blue));
|
2172
|
+
});
|
2173
|
+
};
|
2174
|
+
|
2175
|
+
// Register the prototype for Pushpop.DateInputTableViewCell as a reusable cell type.
|
2176
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.DateInputTableViewCell.prototype);
|
2177
|
+
|
2178
|
+
/**
|
2179
|
+
Creates a new table view cell for a TableView with a small bold blue text label
|
2180
|
+
and a black bold time value. When this type of cell is tapped, a table view is
|
2181
|
+
presented that allows the user to select a time.
|
2182
|
+
@param {String} reuseIdentifier A string containing an identifier that is unique
|
2183
|
+
to the group of cells that this cell should belong to.
|
2184
|
+
@constructor
|
2185
|
+
@extends Pushpop.TableViewCell
|
2186
|
+
*/
|
2187
|
+
Pushpop.TimeInputTableViewCell = function TimeInputTableViewCell(reuseIdentifier) {
|
2188
|
+
|
2189
|
+
// Call the "super" constructor.
|
2190
|
+
Pushpop.TableViewCell.prototype.constructor.apply(this, arguments);
|
2191
|
+
};
|
2192
|
+
|
2193
|
+
Pushpop.TimeInputTableViewCell.prototype = new Pushpop.TableViewCell('pp-time-input-table-view-cell');
|
2194
|
+
Pushpop.TimeInputTableViewCell.prototype.constructor = Pushpop.TimeInputTableViewCell;
|
2195
|
+
|
2196
|
+
Pushpop.TimeInputTableViewCell.prototype.getHtml = function() {
|
2197
|
+
var data = this.getData();
|
2198
|
+
var title = $.trim((data && data.title) ? data.title : ' ');
|
2199
|
+
var value = $.trim((data && data.value) ? data.value : ' ');
|
2200
|
+
return '<h1>' + title + '</h1><h2>' + value + '</h2>';
|
2201
|
+
};
|
2202
|
+
|
2203
|
+
Pushpop.TimeInputTableViewCell.prototype.getAccessoryType = function() { return this._accessoryType || Pushpop.TableViewCell.AccessoryType.DisclosureIndicator; };
|
2204
|
+
|
2205
|
+
Pushpop.TimeInputTableViewCell.prototype.didReceiveTap = function() {
|
2206
|
+
var tableView = this.tableView;
|
2207
|
+
|
2208
|
+
var viewStack = tableView.getViewStack();
|
2209
|
+
if (!viewStack) return;
|
2210
|
+
|
2211
|
+
var data = this.getData();
|
2212
|
+
if (!data) return;
|
2213
|
+
|
2214
|
+
var i, hourDataSource = [], minuteDataSource = [];
|
2215
|
+
for (i = 0; i <= 23; i++) hourDataSource.push({ value: (i < 10 ? '0' : '') + i, title: (i < 10 ? '0' : '') + i });
|
2216
|
+
for (i = 0; i <= 59; i++) minuteDataSource.push({ value: (i < 10 ? '0' : '') + i, title: (i < 10 ? '0' : '') + i });
|
2217
|
+
|
2218
|
+
var timeParts = this.getValue(), currentTime = new Date();
|
2219
|
+
if (!timeParts || (typeof timeParts !== 'string')) timeParts = currentTime.getHours() + ':' + currentTime.getMinutes();
|
2220
|
+
timeParts = timeParts.split(':');
|
2221
|
+
|
2222
|
+
var hour = window.parseInt(timeParts[0], 10);
|
2223
|
+
var minute = window.parseInt(timeParts[1], 10);
|
2224
|
+
|
2225
|
+
hour = { value: (hour < 10 ? '0' : '') + hour, title: (hour < 10 ? '0' : '') + hour };
|
2226
|
+
minute = { value: (minute < 10 ? '0' : '') + minute, title: (minute < 10 ? '0' : '') + minute };
|
2227
|
+
|
2228
|
+
var dataSource = new Pushpop.TableViewDataSource([
|
2229
|
+
{
|
2230
|
+
reuseIdentifier: 'pp-select-input-table-view-cell',
|
2231
|
+
title: 'Hour',
|
2232
|
+
name: 'hour',
|
2233
|
+
value: hour,
|
2234
|
+
childDataSource: hourDataSource
|
2235
|
+
},
|
2236
|
+
{
|
2237
|
+
reuseIdentifier: 'pp-select-input-table-view-cell',
|
2238
|
+
title: 'Minute',
|
2239
|
+
name: 'minute',
|
2240
|
+
value: minute,
|
2241
|
+
childDataSource: minuteDataSource
|
2242
|
+
}
|
2243
|
+
]);
|
2244
|
+
|
2245
|
+
var self = this;
|
2246
|
+
|
2247
|
+
// Push a new view with a large text area input.
|
2248
|
+
viewStack.pushNewTableView(function(newTableView) {
|
2249
|
+
newTableView.setDataSource(dataSource);
|
2250
|
+
|
2251
|
+
var newView = newTableView.getView();
|
2252
|
+
newView.setTitle($.trim((data && data.title) ? data.title : 'Time'));
|
2253
|
+
newView.addBarButtonItem(new Pushpop.Button('Done', function(button) {
|
2254
|
+
var value = dataSource.getValuesObject();
|
2255
|
+
var hour = value.hour.value;
|
2256
|
+
var minute = value.minute.value;
|
2257
|
+
|
2258
|
+
self.setValue(hour + ':' + minute);
|
2259
|
+
tableView.reloadData();
|
2260
|
+
viewStack.pop();
|
2261
|
+
}, Pushpop.Button.ButtonAlignmentType.Right, Pushpop.Button.ButtonStyleType.Blue));
|
2262
|
+
});
|
2263
|
+
};
|
2264
|
+
|
2265
|
+
// Register the prototype for Pushpop.TimeInputTableViewCell as a reusable cell type.
|
2266
|
+
Pushpop.TableView.registerReusableCellPrototype(Pushpop.TimeInputTableViewCell.prototype);
|
2267
|
+
|
2268
|
+
$(function() {
|
2269
|
+
var tableViews = Pushpop.tableViews = Pushpop.tableViews || {};
|
2270
|
+
|
2271
|
+
$('.pp-table-view').each(function(index, element) {
|
2272
|
+
var tableView = new Pushpop.TableView(element);
|
2273
|
+
if (element.id) tableViews[Pushpop.Util.convertDashedStringToCamelCase(element.id)] = tableView;
|
2274
|
+
});
|
2275
|
+
});
|