Skip to content

Instantly share code, notes, and snippets.

@stefanpenner
Created June 29, 2012 21:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefanpenner/3020853 to your computer and use it in GitHub Desktop.
Save stefanpenner/3020853 to your computer and use it in GitHub Desktop.
A web page created at CodePen.io
$ ->
window.App = Ember.Application.create()
$(document).bind('resize orientationChanged scroll', => $(window).trigger('viewportDidChange') )
App.BufferedView = Ember.View.extend
collection: []
offset: 0
limit: 4
bufferStateBinding: 'manager.currentState.name'
init: ->
@set('manager', App.BufferedView.Manager.create({delegate: @}))
window.manager = @get('manager')
@_super()
getNextSegment: -> @get('manager').send('getNextSegment')
doesHaveMore: ->
Ember.run.next( -> $(document).trigger('scroll') )
isInFlight: ->
didInsertElement: ->
viewportDidChange = =>
element = @.$()
height = element.height()
elementYOffset = element.offset().top + height
pageYOffset = $(window).height() + window.pageYOffset
doesHaveMore = @getPath('manager.currentState.name') is 'hasMore'
if (pageYOffset + 10) > elementYOffset and doesHaveMore
@getNextSegment()
$(window).bind('viewportDidChange', viewportDidChange).trigger('viewportDidChange')
shouldConsumeMore: ->
source = @getPath('source')
collectionLength = @getPath('collection.length')
state = @getPath('manager.currentState.name')
manager = @get('manager')
source.consumerIsWaitingForMore(manager, collectionLength)
doesNotHaveMore: -> @shouldConsumeMore()
isIdle: -> @shouldConsumeMore()
appendNextSegment: ->
collection = @get('collection')
source = @get('source')
limit = @get('limit')
offset = @get('offset')
manager = @get('manager')
nextSegment = source.slice(offset, offset + limit)
collection.pushObjects(nextSegment)
@set('offset', collection.get('length'))
manager.send('didGetNextSegment')
App.BufferedView = Ember.View.extend
collection: []
offset: 0
limit: 4
bufferStateBinding: 'manager.currentState.name'
init: ->
@set('manager', App.BufferedView.Manager.create({delegate: @}))
window.manager = @get('manager')
@_super()
getNextSegment: -> @get('manager').send('getNextSegment')
doesHaveMore: ->
Ember.run.next( -> $(document).trigger('scroll') )
isInFlight: ->
didInsertElement: ->
viewportDidChange = =>
element = @.$()
height = element.height()
elementYOffset = element.offset().top + height
pageYOffset = $(window).height() + window.pageYOffset
doesHaveMore = @getPath('manager.currentState.name') is 'hasMore'
if (pageYOffset + 10) > elementYOffset and doesHaveMore
@getNextSegment()
$(window).bind('viewportDidChange', viewportDidChange).trigger('viewportDidChange')
shouldConsumeMore: ->
source = @getPath('source')
collectionLength = @getPath('collection.length')
state = @getPath('manager.currentState.name')
manager = @get('manager')
source.consumerIsWaitingForMore(manager, collectionLength)
doesNotHaveMore: -> @shouldConsumeMore()
isIdle: -> @shouldConsumeMore()
appendNextSegment: ->
collection = @get('collection')
source = @get('source')
limit = @get('limit')
offset = @get('offset')
manager = @get('manager')
nextSegment = source.slice(offset, offset + limit)
collection.pushObjects(nextSegment)
@set('offset', collection.get('length'))
manager.send('didGetNextSegment')
App.BufferedView.Manager = Ember.StateManager.extend
initialState: 'idle'
apple: 'stefan'
hasMore: Ember.State.create
enter: (manager) ->
Ember.run.next => manager.delegate.doesHaveMore()
getNextSegment: (manager) -> manager.goToState('inFlight')
inFlight: Ember.State.create
enter: (manager) ->
Ember.run.next => manager.delegate.isInFlight()
didGetNextSegment: (manager) -> manager.goToState('idle')
idle: Ember.State.create
enter: (manager) ->
Ember.run.next => manager.delegate.isIdle()
doesHaveMore: (manager) -> manager.goToState('hasMore')
doesNotHaveMore: (manager) -> manager.goToState('hasNoMore')
hasNoMore: Ember.State.create
enter: ->
Ember.run.next => manager.delegate.doesNotHaveMore()
# re-awaken
doesHaveMore: (manager) -> manager.goToState('hasMore')
doesNotHaveMore: (manager) -> manager.goToState('hasNoMore')
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CodePen &middot; A Pen by stefanpenner</title>
<style>
#codepen-footer, #codepen-footer * {
-webkit-box-sizing: border-box !important;
-moz-box-sizing: border-box !important;
box-sizing: border-box !important;
}
#codepen-footer {
display: block !important;
position: fixed !important;
bottom: 0 !important;
left: 0 !important;
width: 100% !important;
padding: 0 10px !important;
margin: 0 !important;
height: 30px !important;
line-height: 30px !important;
font-size: 12px !important;
color: #eeeeee !important;
background-color: #505050 !important;
text-align: left !important;
background: -webkit-linear-gradient(top, #505050, #383838) !important;
background: -moz-linear-gradient(top, #505050, #383838) !important;
background: -ms-linear-gradient(top, #505050, #383838) !important;
background: -o-linear-gradient(top, #505050, #383838) !important;
border-top: 1px solid black !important;
border-bottom: 1px solid black !important;
border-radius: 0 !important;
border-image: none !important;
box-shadow: inset 0 1px 0 #6e6e6e, 0 2px 2px rgba(0, 0, 0, 0.4) !important;
z-index: 300 !important;
font-family: "Lucida Grande", "Lucida Sans Unicode", Tahoma, sans-serif !important;
letter-spacing: 0 !important;
word-spacing: 0 !important;
}
#codepen-footer a {
color: #a7a7a7 !important;
text-decoration: none !important;
}
#codepen-footer a:hover {
color: white !important;
}
</style>
<script>
// Kill alerts, confirmations and prompts
window.alert = function(){};
window.confirm = function(){};
window.prompt = function(){};
window.open = function(){};
window.print = function(){};
</script>
<script src="http://codepen.io/javascripts/libs/prefixfree.min.js"></script>
</head>
<body>
<script src="https://raw.github.com/qlabs/when/master/app/assets/javascripts/ember/lib/ember.js?login=stefanpenner&token=dd36bd239833661c6c6e3e1f8702b07a"></script>
<script type="text/x-handlebars">
<h1>Buffered View Example:</h1>
{{#view App.BufferedView sourceBinding="App.sourceController"}}
<div style="position: fixed; top: 0; right: 0">
Limit: {{limit}} Offset: {{offset}} BufferState: {{bufferState}}
<br/>
Visible Collection Length: {{collection.length}}
<br/>
Total Collection Length: {{source.length}}
(<a href="#" {{action "appendMore" target="App.sourceController"}}>Append More</a>)
<br/>
</div>
{{#each collection}}
{{this}}
<br/>
{{/each}}
{{/view}}
</script>​
<script src="http://codepen.io/javascripts/libs/modernizr.js"></script>
<!-- invalid external javascript file: https://raw.github.com/qlabs/when/master/app/assets/javascripts/ember/lib/ember.js?login=stefanpenner&token=dd36bd239833661c6c6e3e1f8702b07a -->
<script>
(function() {
(function() {
$(function() {
var _this = this;
window.App = Ember.Application.create();
$(document).bind('resize orientationChanged scroll', function() {
return $(window).trigger('viewportDidChange');
});
return App.BufferedView = Ember.View.extend({
collection: [],
offset: 0,
limit: 4,
bufferStateBinding: 'manager.currentState.name',
init: function() {
this.set('manager', App.BufferedView.Manager.create({
delegate: this
}));
window.manager = this.get('manager');
return this._super();
},
getNextSegment: function() {
return this.get('manager').send('getNextSegment');
},
doesHaveMore: function() {
return Ember.run.next(function() {
return $(document).trigger('scroll');
});
},
isInFlight: function() {},
didInsertElement: function() {
var viewportDidChange,
_this = this;
viewportDidChange = function() {
var doesHaveMore, element, elementYOffset, height, pageYOffset;
element = _this.$();
height = element.height();
elementYOffset = element.offset().top + height;
pageYOffset = $(window).height() + window.pageYOffset;
doesHaveMore = _this.getPath('manager.currentState.name') === 'hasMore';
if ((pageYOffset + 10) > elementYOffset && doesHaveMore) {
return _this.getNextSegment();
}
};
return $(window).bind('viewportDidChange', viewportDidChange).trigger('viewportDidChange');
},
shouldConsumeMore: function() {
var collectionLength, manager, source, state;
source = this.getPath('source');
collectionLength = this.getPath('collection.length');
state = this.getPath('manager.currentState.name');
manager = this.get('manager');
return source.consumerIsWaitingForMore(manager, collectionLength);
},
doesNotHaveMore: function() {
return this.shouldConsumeMore();
},
isIdle: function() {
return this.shouldConsumeMore();
},
appendNextSegment: function() {
var collection, limit, manager, nextSegment, offset, source;
collection = this.get('collection');
source = this.get('source');
limit = this.get('limit');
offset = this.get('offset');
manager = this.get('manager');
nextSegment = source.slice(offset, offset + limit);
collection.pushObjects(nextSegment);
this.set('offset', collection.get('length'));
return manager.send('didGetNextSegment');
}
});
});
App.BufferedView = Ember.View.extend({
collection: [],
offset: 0,
limit: 4,
bufferStateBinding: 'manager.currentState.name',
init: function() {
this.set('manager', App.BufferedView.Manager.create({
delegate: this
}));
window.manager = this.get('manager');
return this._super();
},
getNextSegment: function() {
return this.get('manager').send('getNextSegment');
},
doesHaveMore: function() {
return Ember.run.next(function() {
return $(document).trigger('scroll');
});
},
isInFlight: function() {},
didInsertElement: function() {
var viewportDidChange,
_this = this;
viewportDidChange = function() {
var doesHaveMore, element, elementYOffset, height, pageYOffset;
element = _this.$();
height = element.height();
elementYOffset = element.offset().top + height;
pageYOffset = $(window).height() + window.pageYOffset;
doesHaveMore = _this.getPath('manager.currentState.name') === 'hasMore';
if ((pageYOffset + 10) > elementYOffset && doesHaveMore) {
return _this.getNextSegment();
}
};
return $(window).bind('viewportDidChange', viewportDidChange).trigger('viewportDidChange');
},
shouldConsumeMore: function() {
var collectionLength, manager, source, state;
source = this.getPath('source');
collectionLength = this.getPath('collection.length');
state = this.getPath('manager.currentState.name');
manager = this.get('manager');
return source.consumerIsWaitingForMore(manager, collectionLength);
},
doesNotHaveMore: function() {
return this.shouldConsumeMore();
},
isIdle: function() {
return this.shouldConsumeMore();
},
appendNextSegment: function() {
var collection, limit, manager, nextSegment, offset, source;
collection = this.get('collection');
source = this.get('source');
limit = this.get('limit');
offset = this.get('offset');
manager = this.get('manager');
nextSegment = source.slice(offset, offset + limit);
collection.pushObjects(nextSegment);
this.set('offset', collection.get('length'));
return manager.send('didGetNextSegment');
}
});
App.BufferedView.Manager = Ember.StateManager.extend({
initialState: 'idle',
apple: 'stefan',
hasMore: Ember.State.create({
enter: function(manager) {
var _this = this;
return Ember.run.next(function() {
return manager.delegate.doesHaveMore();
});
}
}),
getNextSegment: function(manager) {
return manager.goToState('inFlight');
}
});
({
inFlight: Ember.State.create({
enter: function(manager) {
var _this = this;
return Ember.run.next(function() {
return manager.delegate.isInFlight();
});
},
didGetNextSegment: function(manager) {
return manager.goToState('idle');
}
}),
idle: Ember.State.create({
enter: function(manager) {
var _this = this;
return Ember.run.next(function() {
return manager.delegate.isIdle();
});
},
doesHaveMore: function(manager) {
return manager.goToState('hasMore');
},
doesNotHaveMore: function(manager) {
return manager.goToState('hasNoMore');
}
}),
hasNoMore: Ember.State.create({
enter: function() {
var _this = this;
return Ember.run.next(function() {
return manager.delegate.doesNotHaveMore();
});
},
doesHaveMore: function(manager) {
return manager.goToState('hasMore');
},
doesNotHaveMore: function(manager) {
return manager.goToState('hasNoMore');
}
})
});
}).call(this);
})();
</script>
<div id="codepen-footer">
<a style="color: #f73535 !important;" href="https://codepen.wufoo.com/forms/m7x3r3/def/field14=" onclick="window.open(this.href, null, 'height=517, width=680, toolbar=0, location=0, status=1, scrollbars=1, resizable=1'); return false">Report Abuse</a>
&nbsp;
<a href="/stefanpenner/pen/1/5">Edit this Pen</a>
</div>
</body>
</html>
<script src="https://raw.github.com/qlabs/when/master/app/assets/javascripts/ember/lib/ember.js?login=stefanpenner&token=dd36bd239833661c6c6e3e1f8702b07a"></script>
<script type="text/x-handlebars">
<h1>Buffered View Example:</h1>
{{#view App.BufferedView sourceBinding="App.sourceController"}}
<div style="position: fixed; top: 0; right: 0">
Limit: {{limit}} Offset: {{offset}} BufferState: {{bufferState}}
<br/>
Visible Collection Length: {{collection.length}}
<br/>
Total Collection Length: {{source.length}}
(<a href="#" {{action "appendMore" target="App.sourceController"}}>Append More</a>)
<br/>
</div>
{{#each collection}}
{{this}}
<br/>
{{/each}}
{{/view}}
</script>​
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment