capybara-ember-inspector 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ }