capybara-ember-inspector 1.6.2

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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +37 -0
  6. data/Rakefile +2 -0
  7. data/capybara-ember-inspector.gemspec +26 -0
  8. data/lib/capybara/ember/inspector.rb +12 -0
  9. data/lib/capybara/ember/inspector/extension/.gitignore +0 -0
  10. data/lib/capybara/ember/inspector/extension/background-script.js +74 -0
  11. data/lib/capybara/ember/inspector/extension/content-script.js +58 -0
  12. data/lib/capybara/ember/inspector/extension/devtools.html +24 -0
  13. data/lib/capybara/ember/inspector/extension/devtools.js +5 -0
  14. data/lib/capybara/ember/inspector/extension/ember_debug/ember_debug.js +3173 -0
  15. data/lib/capybara/ember/inspector/extension/images/arrow_down.svg +52 -0
  16. data/lib/capybara/ember/inspector/extension/images/calculate.svg +15 -0
  17. data/lib/capybara/ember/inspector/extension/images/ember-icon-final.png +0 -0
  18. data/lib/capybara/ember/inspector/extension/images/fishy_tomster.png +0 -0
  19. data/lib/capybara/ember/inspector/extension/images/hamster.png +0 -0
  20. data/lib/capybara/ember/inspector/extension/images/icon128.png +0 -0
  21. data/lib/capybara/ember/inspector/extension/images/icon16.png +0 -0
  22. data/lib/capybara/ember/inspector/extension/images/icon19.png +0 -0
  23. data/lib/capybara/ember/inspector/extension/images/icon38.png +0 -0
  24. data/lib/capybara/ember/inspector/extension/images/icon48.png +0 -0
  25. data/lib/capybara/ember/inspector/extension/images/send.png +0 -0
  26. data/lib/capybara/ember/inspector/extension/images/send_arrow.png +0 -0
  27. data/lib/capybara/ember/inspector/extension/images/tomster.png +0 -0
  28. data/lib/capybara/ember/inspector/extension/in-page-script.js +14 -0
  29. data/lib/capybara/ember/inspector/extension/manifest.json +39 -0
  30. data/lib/capybara/ember/inspector/extension/options.html +62 -0
  31. data/lib/capybara/ember/inspector/extension/options.js +26 -0
  32. data/lib/capybara/ember/inspector/extension/panes/ember_extension.css +1411 -0
  33. data/lib/capybara/ember/inspector/extension/panes/ember_extension.js +4687 -0
  34. data/lib/capybara/ember/inspector/extension/panes/index.html +17 -0
  35. data/lib/capybara/ember/inspector/extension/panes/start.js +3 -0
  36. data/lib/capybara/ember/inspector/extension/vendor/chrome-bootstrap.css +636 -0
  37. data/lib/capybara/ember/inspector/extension/vendor/ember.js +46943 -0
  38. data/lib/capybara/ember/inspector/extension/vendor/ember.prod.js +46498 -0
  39. data/lib/capybara/ember/inspector/extension/vendor/handlebars.js +2278 -0
  40. data/lib/capybara/ember/inspector/extension/vendor/jquery.js +9555 -0
  41. data/lib/capybara/ember/inspector/extension/vendor/list-view.prod.js +1437 -0
  42. data/lib/capybara/ember/inspector/extension/vendor/loader.js +41 -0
  43. data/lib/capybara/ember/inspector/extension/vendor/resolver.js +188 -0
  44. data/lib/capybara/ember/inspector/version.rb +7 -0
  45. metadata +158 -0
@@ -0,0 +1,1437 @@
1
+ // Last commit: adcb1c8 (2014-02-20 11:33:26 -0500)
2
+
3
+
4
+ // ==========================================================================
5
+ // Project: Ember ListView
6
+ // Copyright: ©2012-2013 Erik Bryn, Yapp Inc., and contributors.
7
+ // License: Licensed under MIT license
8
+ // ==========================================================================
9
+
10
+
11
+ (function() {
12
+ var get = Ember.get, set = Ember.set;
13
+
14
+ function samePosition(a, b) {
15
+ return a && b && a.x === b.x && a.y === b.y;
16
+ }
17
+
18
+ function positionElement() {
19
+ var element, position, _position;
20
+
21
+ Ember.instrument('view.updateContext.positionElement', this, function() {
22
+ element = get(this, 'element');
23
+ position = this.position;
24
+ _position = this._position;
25
+
26
+ if (!position || !element) { return; }
27
+
28
+ // TODO: avoid needing this by avoiding unnecessary
29
+ // calls to this method in the first place
30
+ if (samePosition(position, _position)) { return; }
31
+ Ember.run.schedule('render', this, this._parentView.applyTransform, element, position.x, position.y);
32
+ this._position = position;
33
+ }, this);
34
+ }
35
+
36
+ Ember.ListItemViewMixin = Ember.Mixin.create({
37
+ init: function(){
38
+ this._super();
39
+ this.one('didInsertElement', positionElement);
40
+ },
41
+ classNames: ['ember-list-item-view'],
42
+ _position: null,
43
+ updatePosition: function(position) {
44
+ this.position = position;
45
+ this._positionElement();
46
+ },
47
+ _positionElement: positionElement
48
+ });
49
+
50
+ })();
51
+
52
+
53
+
54
+ (function() {
55
+ var get = Ember.get, set = Ember.set;
56
+
57
+ var backportedInnerString = function(buffer) {
58
+ var content = [], childBuffers = buffer.childBuffers;
59
+
60
+ Ember.ArrayPolyfills.forEach.call(childBuffers, function(buffer) {
61
+ var stringy = typeof buffer === 'string';
62
+ if (stringy) {
63
+ content.push(buffer);
64
+ } else {
65
+ buffer.array(content);
66
+ }
67
+ });
68
+
69
+ return content.join('');
70
+ };
71
+
72
+ function willInsertElementIfNeeded(view) {
73
+ if (view.willInsertElement) {
74
+ view.willInsertElement();
75
+ }
76
+ }
77
+
78
+ function didInsertElementIfNeeded(view) {
79
+ if (view.didInsertElement) {
80
+ view.didInsertElement();
81
+ }
82
+ }
83
+
84
+ function rerender() {
85
+ var element, buffer, context, hasChildViews;
86
+ element = get(this, 'element');
87
+
88
+ if (!element) { return; }
89
+
90
+ context = get(this, 'context');
91
+
92
+ // releases action helpers in contents
93
+ // this means though that the ListViewItem itself can't use classBindings or attributeBindings
94
+ // need support for rerender contents in ember
95
+ this.triggerRecursively('willClearRender');
96
+
97
+ if (this.lengthAfterRender > this.lengthBeforeRender) {
98
+ this.clearRenderedChildren();
99
+ this._childViews.length = this.lengthBeforeRender; // triage bug in ember
100
+ }
101
+
102
+ if (context) {
103
+ buffer = Ember.RenderBuffer();
104
+ buffer = this.renderToBuffer(buffer);
105
+
106
+ // check again for childViews, since rendering may have added some
107
+ hasChildViews = this._childViews.length > 0;
108
+
109
+ if (hasChildViews) {
110
+ this.invokeRecursively(willInsertElementIfNeeded, false);
111
+ }
112
+
113
+ element.innerHTML = buffer.innerString ? buffer.innerString() : backportedInnerString(buffer);
114
+
115
+ set(this, 'element', element);
116
+
117
+ this.transitionTo('inDOM');
118
+
119
+ if (hasChildViews) {
120
+ this.invokeRecursively(didInsertElementIfNeeded, false);
121
+ }
122
+ } else {
123
+ element.innerHTML = ''; // when there is no context, this view should be completely empty
124
+ }
125
+ }
126
+
127
+ /**
128
+ The `Ember.ListViewItem` view class renders a
129
+ [div](https://developer.mozilla.org/en/HTML/Element/div) HTML element
130
+ with `ember-list-item-view` class. It allows you to specify a custom item
131
+ handlebars template for `Ember.ListView`.
132
+
133
+ Example:
134
+
135
+ ```handlebars
136
+ <script type="text/x-handlebars" data-template-name="row_item">
137
+ {{name}}
138
+ </script>
139
+ ```
140
+
141
+ ```javascript
142
+ App.ListView = Ember.ListView.extend({
143
+ height: 500,
144
+ rowHeight: 20,
145
+ itemViewClass: Ember.ListItemView.extend({templateName: "row_item"})
146
+ });
147
+ ```
148
+
149
+ @extends Ember.View
150
+ @class ListItemView
151
+ @namespace Ember
152
+ */
153
+ Ember.ListItemView = Ember.View.extend(Ember.ListItemViewMixin, {
154
+ updateContext: function(newContext){
155
+ var context = get(this, 'context');
156
+ Ember.instrument('view.updateContext.render', this, function() {
157
+ if (context !== newContext) {
158
+ set(this, 'context', newContext);
159
+ if (newContext && newContext.isController) {
160
+ set(this, 'controller', newContext);
161
+ }
162
+ }
163
+ }, this);
164
+ },
165
+ rerender: function () { Ember.run.scheduleOnce('render', this, rerender); },
166
+ _contextDidChange: Ember.observer(rerender, 'context', 'controller')
167
+ });
168
+
169
+ })();
170
+
171
+
172
+
173
+ (function() {
174
+ var get = Ember.get, set = Ember.set;
175
+
176
+ Ember.ReusableListItemView = Ember.View.extend(Ember.ListItemViewMixin, {
177
+ init: function(){
178
+ this._super();
179
+ var context = Ember.ObjectProxy.create();
180
+ this.set('context', context);
181
+ this._proxyContext = context;
182
+ },
183
+ isVisible: Ember.computed('context.content', function(){
184
+ return !!this.get('context.content');
185
+ }),
186
+ updateContext: function(newContext){
187
+ var context = get(this._proxyContext, 'content');
188
+ if (context !== newContext) {
189
+ if (this.state === 'inDOM') {
190
+ this.prepareForReuse(newContext);
191
+ }
192
+
193
+ set(this._proxyContext, 'content', newContext);
194
+
195
+ if (newContext && newContext.isController) {
196
+ set(this, 'controller', newContext);
197
+ }
198
+ }
199
+ },
200
+ prepareForReuse: Ember.K
201
+ });
202
+
203
+ })();
204
+
205
+
206
+
207
+ (function() {
208
+ var el = document.createElement('div'), style = el.style;
209
+
210
+ var propPrefixes = ['Webkit', 'Moz', 'O', 'ms'];
211
+
212
+ function testProp(prop) {
213
+ if (prop in style) return prop;
214
+ var uppercaseProp = prop.charAt(0).toUpperCase() + prop.slice(1);
215
+ for (var i=0; i<propPrefixes.length; i++) {
216
+ var prefixedProp = propPrefixes[i] + uppercaseProp;
217
+ if (prefixedProp in style) {
218
+ return prefixedProp;
219
+ }
220
+ }
221
+ return null;
222
+ }
223
+
224
+ var transformProp = testProp('transform');
225
+ var perspectiveProp = testProp('perspective');
226
+
227
+ var supports2D = transformProp !== null;
228
+ var supports3D = perspectiveProp !== null;
229
+
230
+ Ember.ListViewHelper = {
231
+ transformProp: transformProp,
232
+ applyTransform: (function(){
233
+ if (supports2D) {
234
+ return function(element, x, y){
235
+ element.style[transformProp] = 'translate(' + x + 'px, ' + y + 'px)';
236
+ };
237
+ } else {
238
+ return function(element, x, y){
239
+ element.style.top = y + 'px';
240
+ element.style.left = x + 'px';
241
+ };
242
+ }
243
+ })(),
244
+ apply3DTransform: (function(){
245
+ if (supports3D) {
246
+ return function(element, x, y){
247
+ element.style[transformProp] = 'translate3d(' + x + 'px, ' + y + 'px, 0)';
248
+ };
249
+ } else if (supports2D) {
250
+ return function(element, x, y){
251
+ element.style[transformProp] = 'translate(' + x + 'px, ' + y + 'px)';
252
+ };
253
+ } else {
254
+ return function(element, x, y){
255
+ element.style.top = y + 'px';
256
+ element.style.left = x + 'px';
257
+ };
258
+ }
259
+ })()
260
+ };
261
+
262
+ })();
263
+
264
+
265
+
266
+ (function() {
267
+ var get = Ember.get, set = Ember.set,
268
+ min = Math.min, max = Math.max, floor = Math.floor,
269
+ ceil = Math.ceil,
270
+ forEach = Ember.ArrayPolyfills.forEach;
271
+
272
+ function addContentArrayObserver() {
273
+ var content = get(this, 'content');
274
+ if (content) {
275
+ content.addArrayObserver(this);
276
+ }
277
+ }
278
+
279
+ function removeAndDestroy(object){
280
+ this.removeObject(object);
281
+ object.destroy();
282
+ }
283
+
284
+ function syncChildViews(){
285
+ Ember.run.once(this, '_syncChildViews');
286
+ }
287
+
288
+ function sortByContentIndex (viewOne, viewTwo){
289
+ return get(viewOne, 'contentIndex') - get(viewTwo, 'contentIndex');
290
+ }
291
+
292
+ function notifyMutationListeners() {
293
+ if (Ember.View.notifyMutationListeners) {
294
+ Ember.run.once(Ember.View, 'notifyMutationListeners');
295
+ }
296
+ }
297
+
298
+ var domManager = Ember.create(Ember.ContainerView.proto().domManager);
299
+
300
+ domManager.prepend = function(view, html) {
301
+ view.$('.ember-list-container').prepend(html);
302
+ notifyMutationListeners();
303
+ };
304
+
305
+ function syncListContainerWidth(){
306
+ var elementWidth, columnCount, containerWidth, element;
307
+
308
+ elementWidth = get(this, 'elementWidth');
309
+ columnCount = get(this, 'columnCount');
310
+ containerWidth = elementWidth * columnCount;
311
+ element = this.$('.ember-list-container');
312
+
313
+ if (containerWidth && element) {
314
+ element.css('width', containerWidth);
315
+ }
316
+ }
317
+
318
+ function enableProfilingOutput() {
319
+ function before(name, time, payload) {
320
+ console.time(name);
321
+ }
322
+
323
+ function after (name, time, payload) {
324
+ console.timeEnd(name);
325
+ }
326
+
327
+ if (Ember.ENABLE_PROFILING) {
328
+ Ember.subscribe('view._scrollContentTo', {
329
+ before: before,
330
+ after: after
331
+ });
332
+ Ember.subscribe('view.updateContext', {
333
+ before: before,
334
+ after: after
335
+ });
336
+ }
337
+ }
338
+
339
+ /**
340
+ @class Ember.ListViewMixin
341
+ @namespace Ember
342
+ */
343
+ Ember.ListViewMixin = Ember.Mixin.create({
344
+ itemViewClass: Ember.ReusableListItemView,
345
+ emptyViewClass: Ember.View,
346
+ classNames: ['ember-list-view'],
347
+ attributeBindings: ['style'],
348
+ domManager: domManager,
349
+ scrollTop: 0,
350
+ bottomPadding: 0,
351
+ _lastEndingIndex: 0,
352
+ paddingCount: 1,
353
+
354
+ /**
355
+ @private
356
+
357
+ Setup a mixin.
358
+ - adding observer to content array
359
+ - creating child views based on height and length of the content array
360
+
361
+ @method init
362
+ */
363
+ init: function() {
364
+ this._super();
365
+ this.on('didInsertElement', syncListContainerWidth);
366
+ this.columnCountDidChange();
367
+ this._syncChildViews();
368
+ this._addContentArrayObserver();
369
+ },
370
+
371
+ _addContentArrayObserver: Ember.beforeObserver(function() {
372
+ addContentArrayObserver.call(this);
373
+ }, 'content'),
374
+
375
+ /**
376
+ Called on your view when it should push strings of HTML into a
377
+ `Ember.RenderBuffer`.
378
+
379
+ Adds a [div](https://developer.mozilla.org/en-US/docs/HTML/Element/div)
380
+ with a required `ember-list-container` class.
381
+
382
+ @method render
383
+ @param {Ember.RenderBuffer} buffer The render buffer
384
+ */
385
+ render: function(buffer) {
386
+ buffer.push('<div class="ember-list-container">');
387
+ this._super(buffer);
388
+ buffer.push('</div>');
389
+ },
390
+
391
+ willInsertElement: function() {
392
+ if (!this.get("height") || !this.get("rowHeight")) {
393
+ throw new Error("A ListView must be created with a height and a rowHeight.");
394
+ }
395
+ this._super();
396
+ },
397
+
398
+ /**
399
+ @private
400
+
401
+ Sets inline styles of the view:
402
+ - height
403
+ - width
404
+ - position
405
+ - overflow
406
+ - -webkit-overflow
407
+ - overflow-scrolling
408
+
409
+ Called while attributes binding.
410
+
411
+ @property {Ember.ComputedProperty} style
412
+ */
413
+ style: Ember.computed('height', 'width', function() {
414
+ var height, width, style, css;
415
+
416
+ height = get(this, 'height');
417
+ width = get(this, 'width');
418
+ css = get(this, 'css');
419
+
420
+ style = '';
421
+
422
+ if (height) { style += 'height:' + height + 'px;'; }
423
+ if (width) { style += 'width:' + width + 'px;'; }
424
+
425
+ for ( var rule in css ){
426
+ if (css.hasOwnProperty(rule)) {
427
+ style += rule + ':' + css[rule] + ';';
428
+ }
429
+ }
430
+
431
+ return style;
432
+ }),
433
+
434
+ /**
435
+ @private
436
+
437
+ Performs visual scrolling. Is overridden in Ember.ListView.
438
+
439
+ @method scrollTo
440
+ */
441
+ scrollTo: function(y) {
442
+ throw new Error('must override to perform the visual scroll and effectively delegate to _scrollContentTo');
443
+ },
444
+
445
+ /**
446
+ @private
447
+
448
+ Internal method used to force scroll position
449
+
450
+ @method scrollTo
451
+ */
452
+ _scrollTo: Ember.K,
453
+
454
+ /**
455
+ @private
456
+ @method _scrollContentTo
457
+ */
458
+ _scrollContentTo: function(y) {
459
+ var startingIndex, endingIndex,
460
+ contentIndex, visibleEndingIndex, maxContentIndex,
461
+ contentIndexEnd, contentLength, scrollTop, content;
462
+
463
+ scrollTop = max(0, y);
464
+
465
+ if (this.scrollTop === scrollTop) {
466
+ return;
467
+ }
468
+
469
+ // allow a visual overscroll, but don't scroll the content. As we are doing needless
470
+ // recycyling, and adding unexpected nodes to the DOM.
471
+ var maxScrollTop = max(0, get(this, 'totalHeight') - get(this, 'height'));
472
+ scrollTop = min(scrollTop, maxScrollTop);
473
+
474
+ content = get(this, 'content');
475
+ contentLength = get(content, 'length');
476
+ startingIndex = this._startingIndex(contentLength);
477
+
478
+ Ember.instrument('view._scrollContentTo', {
479
+ scrollTop: scrollTop,
480
+ content: content,
481
+ startingIndex: startingIndex,
482
+ endingIndex: min(max(contentLength - 1, 0), startingIndex + this._numChildViewsForViewport())
483
+ }, function () {
484
+ this.scrollTop = scrollTop;
485
+
486
+ maxContentIndex = max(contentLength - 1, 0);
487
+
488
+ startingIndex = this._startingIndex();
489
+ visibleEndingIndex = startingIndex + this._numChildViewsForViewport();
490
+
491
+ endingIndex = min(maxContentIndex, visibleEndingIndex);
492
+
493
+ if (startingIndex === this._lastStartingIndex &&
494
+ endingIndex === this._lastEndingIndex) {
495
+
496
+ this.trigger('scrollYChanged', y);
497
+ return;
498
+ } else {
499
+
500
+ Ember.run(this, function(){
501
+ this._reuseChildren();
502
+
503
+ this._lastStartingIndex = startingIndex;
504
+ this._lastEndingIndex = endingIndex;
505
+ this.trigger('scrollYChanged', y);
506
+ });
507
+ }
508
+ }, this);
509
+
510
+ },
511
+
512
+ /**
513
+ @private
514
+
515
+ Computes the height for a `Ember.ListView` scrollable container div.
516
+ You must specify `rowHeight` parameter for the height to be computed properly.
517
+
518
+ @property {Ember.ComputedProperty} totalHeight
519
+ */
520
+ totalHeight: Ember.computed('content.length', 'rowHeight', 'columnCount', 'bottomPadding', function() {
521
+ var contentLength, rowHeight, columnCount, bottomPadding;
522
+
523
+ contentLength = get(this, 'content.length');
524
+ rowHeight = get(this, 'rowHeight');
525
+ columnCount = get(this, 'columnCount');
526
+ bottomPadding = get(this, 'bottomPadding');
527
+
528
+ return ((ceil(contentLength / columnCount)) * rowHeight) + bottomPadding;
529
+ }),
530
+
531
+ /**
532
+ @private
533
+ @method _prepareChildForReuse
534
+ */
535
+ _prepareChildForReuse: function(childView) {
536
+ childView.prepareForReuse();
537
+ },
538
+
539
+ /**
540
+ @private
541
+ @method _reuseChildForContentIndex
542
+ */
543
+ _reuseChildForContentIndex: function(childView, contentIndex) {
544
+ var content, context, newContext, childsCurrentContentIndex, position, enableProfiling;
545
+
546
+ content = get(this, 'content');
547
+ enableProfiling = get(this, 'enableProfiling');
548
+ position = this.positionForIndex(contentIndex);
549
+ childView.updatePosition(position);
550
+
551
+ set(childView, 'contentIndex', contentIndex);
552
+
553
+ if (enableProfiling) {
554
+ Ember.instrument('view._reuseChildForContentIndex', position, function(){}, this);
555
+ }
556
+
557
+ newContext = content.objectAt(contentIndex);
558
+ childView.updateContext(newContext);
559
+ },
560
+
561
+ /**
562
+ @private
563
+ @method positionForIndex
564
+ */
565
+ positionForIndex: function(index){
566
+ var elementWidth, width, columnCount, rowHeight, y, x;
567
+
568
+ elementWidth = get(this, 'elementWidth') || 1;
569
+ width = get(this, 'width') || 1;
570
+ columnCount = get(this, 'columnCount');
571
+ rowHeight = get(this, 'rowHeight');
572
+
573
+ y = (rowHeight * floor(index/columnCount));
574
+ x = (index % columnCount) * elementWidth;
575
+
576
+ return {
577
+ y: y,
578
+ x: x
579
+ };
580
+ },
581
+
582
+ /**
583
+ @private
584
+ @method _childViewCount
585
+ */
586
+ _childViewCount: function() {
587
+ var contentLength, childViewCountForHeight;
588
+
589
+ contentLength = get(this, 'content.length');
590
+ childViewCountForHeight = this._numChildViewsForViewport();
591
+
592
+ return min(contentLength, childViewCountForHeight);
593
+ },
594
+
595
+ /**
596
+ @private
597
+
598
+ Returns a number of columns in the Ember.ListView (for grid layout).
599
+
600
+ If you want to have a multi column layout, you need to specify both
601
+ `width` and `elementWidth`.
602
+
603
+ If no `elementWidth` is specified, it returns `1`. Otherwise, it will
604
+ try to fit as many columns as possible for a given `width`.
605
+
606
+ @property {Ember.ComputedProperty} columnCount
607
+ */
608
+ columnCount: Ember.computed('width', 'elementWidth', function() {
609
+ var elementWidth, width, count;
610
+
611
+ elementWidth = get(this, 'elementWidth');
612
+ width = get(this, 'width');
613
+
614
+ if (elementWidth) {
615
+ count = floor(width / elementWidth);
616
+ } else {
617
+ count = 1;
618
+ }
619
+
620
+ return count;
621
+ }),
622
+
623
+ /**
624
+ @private
625
+
626
+ Fires every time column count is changed.
627
+
628
+ @event columnCountDidChange
629
+ */
630
+ columnCountDidChange: Ember.observer(function(){
631
+ var ratio, currentScrollTop, proposedScrollTop, maxScrollTop,
632
+ scrollTop, lastColumnCount, newColumnCount, element;
633
+
634
+ lastColumnCount = this._lastColumnCount;
635
+
636
+ currentScrollTop = this.scrollTop;
637
+ newColumnCount = get(this, 'columnCount');
638
+ maxScrollTop = get(this, 'maxScrollTop');
639
+ element = get(this, 'element');
640
+
641
+ this._lastColumnCount = newColumnCount;
642
+
643
+ if (lastColumnCount) {
644
+ ratio = (lastColumnCount / newColumnCount);
645
+ proposedScrollTop = currentScrollTop * ratio;
646
+ scrollTop = min(maxScrollTop, proposedScrollTop);
647
+
648
+ this._scrollTo(scrollTop);
649
+ this.scrollTop = scrollTop;
650
+ }
651
+
652
+ if (arguments.length > 0) {
653
+ // invoked by observer
654
+ Ember.run.schedule('afterRender', this, syncListContainerWidth);
655
+ }
656
+ }, 'columnCount'),
657
+
658
+ /**
659
+ @private
660
+
661
+ Computes max possible scrollTop value given the visible viewport
662
+ and scrollable container div height.
663
+
664
+ @property {Ember.ComputedProperty} maxScrollTop
665
+ */
666
+ maxScrollTop: Ember.computed('height', 'totalHeight', function(){
667
+ var totalHeight, viewportHeight;
668
+
669
+ totalHeight = get(this, 'totalHeight');
670
+ viewportHeight = get(this, 'height');
671
+
672
+ return max(0, totalHeight - viewportHeight);
673
+ }),
674
+
675
+ /**
676
+ @private
677
+
678
+ Computes the number of views that would fit in the viewport area.
679
+ You must specify `height` and `rowHeight` parameters for the number of
680
+ views to be computed properly.
681
+
682
+ @method _numChildViewsForViewport
683
+ */
684
+ _numChildViewsForViewport: function() {
685
+ var height, rowHeight, paddingCount, columnCount;
686
+
687
+ height = get(this, 'height');
688
+ rowHeight = get(this, 'rowHeight');
689
+ paddingCount = get(this, 'paddingCount');
690
+ columnCount = get(this, 'columnCount');
691
+
692
+ return (ceil(height / rowHeight) * columnCount) + (paddingCount * columnCount);
693
+ },
694
+
695
+ /**
696
+ @private
697
+
698
+ Computes the starting index of the item views array.
699
+ Takes `scrollTop` property of the element into account.
700
+
701
+ Is used in `_syncChildViews`.
702
+
703
+ @method _startingIndex
704
+ */
705
+ _startingIndex: function(_contentLength) {
706
+ var scrollTop, rowHeight, columnCount, calculatedStartingIndex,
707
+ contentLength, largestStartingIndex;
708
+
709
+ if (_contentLength === undefined) {
710
+ contentLength = get(this, 'content.length');
711
+ } else {
712
+ contentLength = _contentLength;
713
+ }
714
+
715
+ scrollTop = this.scrollTop;
716
+ rowHeight = get(this, 'rowHeight');
717
+ columnCount = get(this, 'columnCount');
718
+
719
+ calculatedStartingIndex = floor(scrollTop / rowHeight) * columnCount;
720
+
721
+ largestStartingIndex = max(contentLength - 1, 0);
722
+
723
+ return min(calculatedStartingIndex, largestStartingIndex);
724
+ },
725
+
726
+ /**
727
+ @private
728
+ @event contentWillChange
729
+ */
730
+ contentWillChange: Ember.beforeObserver(function() {
731
+ var content;
732
+
733
+ content = get(this, 'content');
734
+
735
+ if (content) {
736
+ content.removeArrayObserver(this);
737
+ }
738
+ }, 'content'),
739
+
740
+ /**),
741
+ @private
742
+ @event contentDidChange
743
+ */
744
+ contentDidChange: Ember.observer(function() {
745
+ addContentArrayObserver.call(this);
746
+ syncChildViews.call(this);
747
+ }, 'content'),
748
+
749
+ /**
750
+ @private
751
+ @property {Function} needsSyncChildViews
752
+ */
753
+ needsSyncChildViews: Ember.observer(syncChildViews, 'height', 'width', 'columnCount'),
754
+
755
+ /**
756
+ @private
757
+
758
+ Returns a new item view. Takes `contentIndex` to set the context
759
+ of the returned view properly.
760
+
761
+ @param {Number} contentIndex item index in the content array
762
+ @method _addItemView
763
+ */
764
+ _addItemView: function(contentIndex){
765
+ var itemViewClass, childView;
766
+
767
+ itemViewClass = get(this, 'itemViewClass');
768
+ childView = this.createChildView(itemViewClass);
769
+
770
+ this.pushObject(childView);
771
+ },
772
+
773
+ /**
774
+ @private
775
+
776
+ Intelligently manages the number of childviews.
777
+
778
+ @method _syncChildViews
779
+ **/
780
+ _syncChildViews: function(){
781
+ var itemViewClass, startingIndex, childViewCount,
782
+ endingIndex, numberOfChildViews, numberOfChildViewsNeeded,
783
+ childViews, count, delta, index, childViewsLength, contentIndex;
784
+
785
+ if (get(this, 'isDestroyed') || get(this, 'isDestroying')) {
786
+ return;
787
+ }
788
+
789
+ childViewCount = this._childViewCount();
790
+ childViews = this.positionOrderedChildViews();
791
+
792
+ startingIndex = this._startingIndex();
793
+ endingIndex = startingIndex + childViewCount;
794
+
795
+ numberOfChildViewsNeeded = childViewCount;
796
+ numberOfChildViews = childViews.length;
797
+
798
+ delta = numberOfChildViewsNeeded - numberOfChildViews;
799
+
800
+ if (delta === 0) {
801
+ // no change
802
+ } else if (delta > 0) {
803
+ // more views are needed
804
+ contentIndex = this._lastEndingIndex;
805
+
806
+ for (count = 0; count < delta; count++, contentIndex++) {
807
+ this._addItemView(contentIndex);
808
+ }
809
+
810
+ } else {
811
+ // less views are needed
812
+ forEach.call(
813
+ childViews.splice(numberOfChildViewsNeeded, numberOfChildViews),
814
+ removeAndDestroy,
815
+ this
816
+ );
817
+ }
818
+
819
+ this._reuseChildren();
820
+
821
+ this._lastStartingIndex = startingIndex;
822
+ this._lastEndingIndex = this._lastEndingIndex + delta;
823
+ },
824
+
825
+ /**
826
+ @private
827
+ @method _reuseChildren
828
+ */
829
+ _reuseChildren: function(){
830
+ var contentLength, childViews, childViewsLength,
831
+ startingIndex, endingIndex, childView, attrs,
832
+ contentIndex, visibleEndingIndex, maxContentIndex,
833
+ contentIndexEnd, scrollTop;
834
+
835
+ scrollTop = this.scrollTop;
836
+ contentLength = get(this, 'content.length');
837
+ maxContentIndex = max(contentLength - 1, 0);
838
+ childViews = this.getReusableChildViews();
839
+ childViewsLength = childViews.length;
840
+
841
+ startingIndex = this._startingIndex();
842
+ visibleEndingIndex = startingIndex + this._numChildViewsForViewport();
843
+
844
+ endingIndex = min(maxContentIndex, visibleEndingIndex);
845
+
846
+ contentIndexEnd = min(visibleEndingIndex, startingIndex + childViewsLength);
847
+
848
+ for (contentIndex = startingIndex; contentIndex < contentIndexEnd; contentIndex++) {
849
+ childView = childViews[contentIndex % childViewsLength];
850
+ this._reuseChildForContentIndex(childView, contentIndex);
851
+ }
852
+ },
853
+
854
+ /**
855
+ @private
856
+ @method getReusableChildViews
857
+ */
858
+ getReusableChildViews: function() {
859
+ return this._childViews;
860
+ },
861
+
862
+ /**
863
+ @private
864
+ @method positionOrderedChildViews
865
+ */
866
+ positionOrderedChildViews: function() {
867
+ return this.getReusableChildViews().sort(sortByContentIndex);
868
+ },
869
+
870
+ arrayWillChange: Ember.K,
871
+
872
+ /**
873
+ @private
874
+ @event arrayDidChange
875
+ */
876
+ // TODO: refactor
877
+ arrayDidChange: function(content, start, removedCount, addedCount) {
878
+ var index, contentIndex;
879
+
880
+ if (this.state === 'inDOM') {
881
+ // ignore if all changes are out of the visible change
882
+ if( start >= this._lastStartingIndex || start < this._lastEndingIndex) {
883
+ index = 0;
884
+ // ignore all changes not in the visible range
885
+ // this can re-position many, rather then causing a cascade of re-renders
886
+ forEach.call(
887
+ this.positionOrderedChildViews(),
888
+ function(childView) {
889
+ contentIndex = this._lastStartingIndex + index;
890
+ this._reuseChildForContentIndex(childView, contentIndex);
891
+ index++;
892
+ },
893
+ this
894
+ );
895
+ }
896
+
897
+ syncChildViews.call(this);
898
+ }
899
+ }
900
+ });
901
+
902
+ })();
903
+
904
+
905
+
906
+ (function() {
907
+ var get = Ember.get, set = Ember.set;
908
+
909
+ /**
910
+ The `Ember.ListView` view class renders a
911
+ [div](https://developer.mozilla.org/en/HTML/Element/div) HTML element,
912
+ with `ember-list-view` class.
913
+
914
+ The context of each item element within the `Ember.ListView` are populated
915
+ from the objects in the `Element.ListView`'s `content` property.
916
+
917
+ ### `content` as an Array of Objects
918
+
919
+ The simplest version of an `Ember.ListView` takes an array of object as its
920
+ `content` property. The object will be used as the `context` each item element
921
+ inside the rendered `div`.
922
+
923
+ Example:
924
+
925
+ ```javascript
926
+ App.ContributorsRoute = Ember.Route.extend({
927
+ model: function() {
928
+ return [{ name: 'Stefan Penner' }, { name: 'Alex Navasardyan' }, { name: 'Ray Cohen'}];
929
+ }
930
+ });
931
+ ```
932
+
933
+ ```handlebars
934
+ {{#ember-list items=contributors height=500 rowHeight=50}}
935
+ {{name}}
936
+ {{/ember-list}}
937
+ ```
938
+
939
+ Would result in the following HTML:
940
+
941
+ ```html
942
+ <div id="ember181" class="ember-view ember-list-view" style="height:500px;width:500px;position:relative;overflow:scroll;-webkit-overflow-scrolling:touch;overflow-scrolling:touch;">
943
+ <div class="ember-list-container">
944
+ <div id="ember186" class="ember-view ember-list-item-view" style="-webkit-transform: translate3d(0px, 0px, 0);">
945
+ <script id="metamorph-0-start" type="text/x-placeholder"></script>Stefan Penner<script id="metamorph-0-end" type="text/x-placeholder"></script>
946
+ </div>
947
+ <div id="ember187" class="ember-view ember-list-item-view" style="-webkit-transform: translate3d(0px, 50px, 0);">
948
+ <script id="metamorph-1-start" type="text/x-placeholder"></script>Alex Navasardyan<script id="metamorph-1-end" type="text/x-placeholder"></script>
949
+ </div>
950
+ <div id="ember188" class="ember-view ember-list-item-view" style="-webkit-transform: translate3d(0px, 100px, 0);">
951
+ <script id="metamorph-2-start" type="text/x-placeholder"></script>Rey Cohen<script id="metamorph-2-end" type="text/x-placeholder"></script>
952
+ </div>
953
+ <div id="ember189" class="ember-view ember-list-scrolling-view" style="height: 150px"></div>
954
+ </div>
955
+ </div>
956
+ ```
957
+
958
+ By default `Ember.ListView` provides support for `height`,
959
+ `rowHeight`, `width`, `elementWidth`, `scrollTop` parameters.
960
+
961
+ Note, that `height` and `rowHeight` are required parameters.
962
+
963
+ ```handlebars
964
+ {{#ember-list items=this height=500 rowHeight=50}}
965
+ {{name}}
966
+ {{/ember-list}}
967
+ ```
968
+
969
+ If you would like to have multiple columns in your view layout, you can
970
+ set `width` and `elementWidth` parameters respectively.
971
+
972
+ ```handlebars
973
+ {{#ember-list items=this height=500 rowHeight=50 width=500 elementWidth=80}}
974
+ {{name}}
975
+ {{/ember-list}}
976
+ ```
977
+
978
+ ### extending `Ember.ListView`
979
+
980
+ Example:
981
+
982
+ ```handlebars
983
+ {{view App.ListView contentBinding="content"}}
984
+
985
+ <script type="text/x-handlebars" data-template-name="row_item">
986
+ {{name}}
987
+ </script>
988
+ ```
989
+
990
+ ```javascript
991
+ App.ListView = Ember.ListView.extend({
992
+ height: 500,
993
+ width: 500,
994
+ elementWidth: 80,
995
+ rowHeight: 20,
996
+ itemViewClass: Ember.ListItemView.extend({templateName: "row_item"})
997
+ });
998
+ ```
999
+
1000
+ @extends Ember.ContainerView
1001
+ @class ListView
1002
+ @namespace Ember
1003
+ */
1004
+ Ember.ListView = Ember.ContainerView.extend(Ember.ListViewMixin, {
1005
+ css: {
1006
+ position: 'relative',
1007
+ overflow: 'scroll',
1008
+ '-webkit-overflow-scrolling': 'touch',
1009
+ 'overflow-scrolling': 'touch'
1010
+ },
1011
+
1012
+ applyTransform: Ember.ListViewHelper.applyTransform,
1013
+
1014
+ _scrollTo: function(scrollTop) {
1015
+ var element = get(this, 'element');
1016
+
1017
+ if (element) { element.scrollTop = scrollTop; }
1018
+ },
1019
+
1020
+ didInsertElement: function() {
1021
+ var that = this,
1022
+ element = get(this, 'element');
1023
+
1024
+ this._updateScrollableHeight();
1025
+
1026
+ this._scroll = function(e) { that.scroll(e); };
1027
+
1028
+ Ember.$(element).on('scroll', this._scroll);
1029
+ },
1030
+
1031
+ willDestroyElement: function() {
1032
+ var element;
1033
+
1034
+ element = get(this, 'element');
1035
+
1036
+ Ember.$(element).off('scroll', this._scroll);
1037
+ },
1038
+
1039
+ scroll: function(e) {
1040
+ this.scrollTo(e.target.scrollTop);
1041
+ },
1042
+
1043
+ scrollTo: function(y){
1044
+ var element = get(this, 'element');
1045
+ this._scrollTo(y);
1046
+ this._scrollContentTo(y);
1047
+ },
1048
+
1049
+ totalHeightDidChange: Ember.observer(function () {
1050
+ Ember.run.scheduleOnce('afterRender', this, this._updateScrollableHeight);
1051
+ }, 'totalHeight'),
1052
+
1053
+ _updateScrollableHeight: function () {
1054
+ if (this.state === 'inDOM') {
1055
+ this.$('.ember-list-container').css({
1056
+ height: get(this, 'totalHeight')
1057
+ });
1058
+ }
1059
+ }
1060
+ });
1061
+
1062
+ })();
1063
+
1064
+
1065
+
1066
+ (function() {
1067
+ var fieldRegex = /input|textarea|select/i,
1068
+ hasTouch = ('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch,
1069
+ handleStart, handleMove, handleEnd, handleCancel,
1070
+ startEvent, moveEvent, endEvent, cancelEvent;
1071
+ if (hasTouch) {
1072
+ startEvent = 'touchstart';
1073
+ handleStart = function (e) {
1074
+ var touch = e.touches[0],
1075
+ target = touch && touch.target;
1076
+ // avoid e.preventDefault() on fields
1077
+ if (target && fieldRegex.test(target.tagName)) {
1078
+ return;
1079
+ }
1080
+ bindWindow(this.scrollerEventHandlers);
1081
+ this.willBeginScroll(e.touches, e.timeStamp);
1082
+ e.preventDefault();
1083
+ };
1084
+ moveEvent = 'touchmove';
1085
+ handleMove = function (e) {
1086
+ this.continueScroll(e.touches, e.timeStamp);
1087
+ };
1088
+ endEvent = 'touchend';
1089
+ handleEnd = function (e) {
1090
+ // if we didn't end up scrolling we need to
1091
+ // synthesize click since we did e.preventDefault()
1092
+ // on touchstart
1093
+ if (!this._isScrolling) {
1094
+ synthesizeClick(e);
1095
+ }
1096
+ unbindWindow(this.scrollerEventHandlers);
1097
+ this.endScroll(e.timeStamp);
1098
+ };
1099
+ cancelEvent = 'touchcancel';
1100
+ handleCancel = function (e) {
1101
+ unbindWindow(this.scrollerEventHandlers);
1102
+ this.endScroll(e.timeStamp);
1103
+ };
1104
+ } else {
1105
+ startEvent = 'mousedown';
1106
+ handleStart = function (e) {
1107
+ if (e.which !== 1) return;
1108
+ var target = e.target;
1109
+ // avoid e.preventDefault() on fields
1110
+ if (target && fieldRegex.test(target.tagName)) {
1111
+ return;
1112
+ }
1113
+ bindWindow(this.scrollerEventHandlers);
1114
+ this.willBeginScroll([e], e.timeStamp);
1115
+ e.preventDefault();
1116
+ };
1117
+ moveEvent = 'mousemove';
1118
+ handleMove = function (e) {
1119
+ this.continueScroll([e], e.timeStamp);
1120
+ };
1121
+ endEvent = 'mouseup';
1122
+ handleEnd = function (e) {
1123
+ unbindWindow(this.scrollerEventHandlers);
1124
+ this.endScroll(e.timeStamp);
1125
+ };
1126
+ cancelEvent = 'mouseout';
1127
+ handleCancel = function (e) {
1128
+ if (e.relatedTarget) return;
1129
+ unbindWindow(this.scrollerEventHandlers);
1130
+ this.endScroll(e.timeStamp);
1131
+ };
1132
+ }
1133
+
1134
+ function handleWheel(e) {
1135
+ this.mouseWheel(e);
1136
+ e.preventDefault();
1137
+ }
1138
+
1139
+ function bindElement(el, handlers) {
1140
+ el.addEventListener(startEvent, handlers.start, false);
1141
+ el.addEventListener('mousewheel', handlers.wheel, false);
1142
+ }
1143
+
1144
+ function unbindElement(el, handlers) {
1145
+ el.removeEventListener(startEvent, handlers.start, false);
1146
+ el.removeEventListener('mousewheel', handlers.wheel, false);
1147
+ }
1148
+
1149
+ function bindWindow(handlers) {
1150
+ window.addEventListener(moveEvent, handlers.move, true);
1151
+ window.addEventListener(endEvent, handlers.end, true);
1152
+ window.addEventListener(cancelEvent, handlers.cancel, true);
1153
+ }
1154
+
1155
+ function unbindWindow(handlers) {
1156
+ window.removeEventListener(moveEvent, handlers.move, true);
1157
+ window.removeEventListener(endEvent, handlers.end, true);
1158
+ window.removeEventListener(cancelEvent, handlers.cancel, true);
1159
+ }
1160
+
1161
+ Ember.VirtualListScrollerEvents = Ember.Mixin.create({
1162
+ init: function() {
1163
+ this.on('didInsertElement', this, 'bindScrollerEvents');
1164
+ this.on('willDestroyElement', this, 'unbindScrollerEvents');
1165
+ this.scrollerEventHandlers = {
1166
+ start: bind(this, handleStart),
1167
+ move: bind(this, handleMove),
1168
+ end: bind(this, handleEnd),
1169
+ cancel: bind(this, handleCancel),
1170
+ wheel: bind(this, handleWheel)
1171
+ };
1172
+ return this._super();
1173
+ },
1174
+ bindScrollerEvents: function() {
1175
+ var el = this.get('element'),
1176
+ handlers = this.scrollerEventHandlers;
1177
+ bindElement(el, handlers);
1178
+ },
1179
+ unbindScrollerEvents: function() {
1180
+ var el = this.get('element'),
1181
+ handlers = this.scrollerEventHandlers;
1182
+ unbindElement(el, handlers);
1183
+ unbindWindow(handlers);
1184
+ }
1185
+ });
1186
+
1187
+ function bind(view, handler) {
1188
+ return function (evt) {
1189
+ handler.call(view, evt);
1190
+ };
1191
+ }
1192
+
1193
+ function synthesizeClick(e) {
1194
+ var point = e.changedTouches[0],
1195
+ target = point.target,
1196
+ ev;
1197
+ if (target && fieldRegex.test(target.tagName)) {
1198
+ ev = document.createEvent('MouseEvents');
1199
+ ev.initMouseEvent('click', true, true, e.view, 1, point.screenX, point.screenY, point.clientX, point.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, 0, null);
1200
+ return target.dispatchEvent(ev);
1201
+ }
1202
+ }
1203
+
1204
+ })();
1205
+
1206
+
1207
+
1208
+ (function() {
1209
+ /*global Scroller*/
1210
+ var max = Math.max, get = Ember.get, set = Ember.set;
1211
+
1212
+ function updateScrollerDimensions(target) {
1213
+ var width, height, totalHeight;
1214
+
1215
+ target = target || this;
1216
+
1217
+ width = get(target, 'width');
1218
+ height = get(target, 'height');
1219
+ totalHeight = get(target, 'totalHeight');
1220
+
1221
+ target.scroller.setDimensions(width, height, width, totalHeight);
1222
+ target.trigger('scrollerDimensionsDidChange');
1223
+ }
1224
+
1225
+ /**
1226
+ VirtualListView
1227
+
1228
+ @class VirtualListView
1229
+ @namespace Ember
1230
+ */
1231
+ Ember.VirtualListView = Ember.ContainerView.extend(Ember.ListViewMixin, Ember.VirtualListScrollerEvents, {
1232
+ _isScrolling: false,
1233
+ _mouseWheel: null,
1234
+ css: {
1235
+ position: 'relative',
1236
+ overflow: 'hidden'
1237
+ },
1238
+
1239
+ init: function(){
1240
+ this._super();
1241
+ this.setupScroller();
1242
+ this.setupPullToRefresh();
1243
+ },
1244
+ _scrollerTop: 0,
1245
+ applyTransform: Ember.ListViewHelper.apply3DTransform,
1246
+
1247
+ setupScroller: function(){
1248
+ var view, y;
1249
+
1250
+ view = this;
1251
+
1252
+ view.scroller = new Scroller(function(left, top, zoom) {
1253
+ if (view.state !== 'inDOM') { return; }
1254
+
1255
+ if (view.listContainerElement) {
1256
+ view._scrollerTop = top;
1257
+ view._scrollContentTo(top);
1258
+ view.applyTransform(view.listContainerElement, 0, -top);
1259
+ }
1260
+ }, {
1261
+ scrollingX: false,
1262
+ scrollingComplete: function(){
1263
+ view.trigger('scrollingDidComplete');
1264
+ }
1265
+ });
1266
+
1267
+ view.trigger('didInitializeScroller');
1268
+ updateScrollerDimensions(view);
1269
+ },
1270
+ setupPullToRefresh: function() {
1271
+ if (!this.pullToRefreshViewClass) { return; }
1272
+ this._insertPullToRefreshView();
1273
+ this._activateScrollerPullToRefresh();
1274
+ },
1275
+ _insertPullToRefreshView: function(){
1276
+ this.pullToRefreshView = this.createChildView(this.pullToRefreshViewClass);
1277
+ this.insertAt(0, this.pullToRefreshView);
1278
+ var view = this;
1279
+ this.pullToRefreshView.on('didInsertElement', function(){
1280
+ Ember.run.schedule('afterRender', this, function(){
1281
+ view.applyTransform(this.get('element'), 0, -1 * view.pullToRefreshViewHeight);
1282
+ });
1283
+ });
1284
+ },
1285
+ _activateScrollerPullToRefresh: function(){
1286
+ var view = this;
1287
+ function activatePullToRefresh(){
1288
+ view.pullToRefreshView.set('active', true);
1289
+ view.trigger('activatePullToRefresh');
1290
+ }
1291
+ function deactivatePullToRefresh() {
1292
+ view.pullToRefreshView.set('active', false);
1293
+ view.trigger('deactivatePullToRefresh');
1294
+ }
1295
+ function startPullToRefresh() {
1296
+ Ember.run(function(){
1297
+ view.pullToRefreshView.set('refreshing', true);
1298
+
1299
+ function finishRefresh(){
1300
+ if (view && !view.get('isDestroyed') && !view.get('isDestroying')) {
1301
+ view.scroller.finishPullToRefresh();
1302
+ view.pullToRefreshView.set('refreshing', false);
1303
+ }
1304
+ }
1305
+ view.startRefresh(finishRefresh);
1306
+ });
1307
+ }
1308
+ this.scroller.activatePullToRefresh(
1309
+ this.pullToRefreshViewHeight,
1310
+ activatePullToRefresh,
1311
+ deactivatePullToRefresh,
1312
+ startPullToRefresh
1313
+ );
1314
+ },
1315
+
1316
+ getReusableChildViews: function(){
1317
+ var firstView = this._childViews[0];
1318
+ if (firstView && firstView === this.pullToRefreshView) {
1319
+ return this._childViews.slice(1);
1320
+ } else {
1321
+ return this._childViews;
1322
+ }
1323
+ },
1324
+
1325
+ scrollerDimensionsNeedToChange: Ember.observer(function() {
1326
+ Ember.run.once(this, updateScrollerDimensions);
1327
+ }, 'width', 'height', 'totalHeight'),
1328
+
1329
+ didInsertElement: function() {
1330
+ this.listContainerElement = this.$('> .ember-list-container')[0];
1331
+ },
1332
+
1333
+ willBeginScroll: function(touches, timeStamp) {
1334
+ this._isScrolling = false;
1335
+ this.trigger('scrollingDidStart');
1336
+
1337
+ this.scroller.doTouchStart(touches, timeStamp);
1338
+ },
1339
+
1340
+ continueScroll: function(touches, timeStamp) {
1341
+ var startingScrollTop, endingScrollTop, event;
1342
+
1343
+ if (this._isScrolling) {
1344
+ this.scroller.doTouchMove(touches, timeStamp);
1345
+ } else {
1346
+ startingScrollTop = this._scrollerTop;
1347
+
1348
+ this.scroller.doTouchMove(touches, timeStamp);
1349
+
1350
+ endingScrollTop = this._scrollerTop;
1351
+
1352
+ if (startingScrollTop !== endingScrollTop) {
1353
+ event = Ember.$.Event("scrollerstart");
1354
+ Ember.$(touches[0].target).trigger(event);
1355
+
1356
+ this._isScrolling = true;
1357
+ }
1358
+ }
1359
+ },
1360
+
1361
+ endScroll: function(timeStamp) {
1362
+ this.scroller.doTouchEnd(timeStamp);
1363
+ },
1364
+
1365
+ // api
1366
+ scrollTo: function(y, animate) {
1367
+ if (animate === undefined) {
1368
+ animate = true;
1369
+ }
1370
+
1371
+ this.scroller.scrollTo(0, y, animate, 1);
1372
+ },
1373
+
1374
+ // events
1375
+ mouseWheel: function(e){
1376
+ var inverted, delta, candidatePosition;
1377
+
1378
+ inverted = e.webkitDirectionInvertedFromDevice;
1379
+ delta = e.wheelDeltaY * (inverted ? 0.8 : -0.8);
1380
+ candidatePosition = this.scroller.__scrollTop + delta;
1381
+
1382
+ if ((candidatePosition >= 0) && (candidatePosition <= this.scroller.__maxScrollTop)) {
1383
+ this.scroller.scrollBy(0, delta, true);
1384
+ }
1385
+
1386
+ return false;
1387
+ }
1388
+ });
1389
+
1390
+ })();
1391
+
1392
+
1393
+
1394
+ (function() {
1395
+ Ember.Handlebars.registerHelper('ember-list', function emberList(options) {
1396
+ var hash = options.hash;
1397
+ var types = options.hashTypes;
1398
+
1399
+ hash.content = hash.items;
1400
+ delete hash.items;
1401
+
1402
+ types.content = types.items;
1403
+ delete types.items;
1404
+
1405
+ if (!hash.content) {
1406
+ hash.content = "this";
1407
+ types.content = "ID";
1408
+ }
1409
+
1410
+ for (var prop in hash) {
1411
+ if (/-/.test(prop)) {
1412
+ var camelized = Ember.String.camelize(prop);
1413
+ hash[camelized] = hash[prop];
1414
+ types[camelized] = types[prop];
1415
+ delete hash[prop];
1416
+ delete types[prop];
1417
+ }
1418
+ }
1419
+
1420
+ return Ember.Handlebars.helpers.collection.call(this, 'Ember.ListView', options);
1421
+ });
1422
+
1423
+
1424
+ })();
1425
+
1426
+
1427
+
1428
+ (function() {
1429
+
1430
+ })();
1431
+
1432
+
1433
+
1434
+ if (typeof location !== 'undefined' && (location.hostname === 'localhost' || location.hostname === '127.0.0.1')) {
1435
+ Ember.Logger.warn("You are running a production build of Ember on localhost and won't receive detailed error messages. "+
1436
+ "If you want full error messages please use the non-minified build provided on the Ember website.");
1437
+ }