Skip to content

Commit

Permalink
commit beginnings of this humble add-on
Browse files Browse the repository at this point in the history
  • Loading branch information
bttf committed Apr 1, 2016
1 parent 3f81fd4 commit af99ee3
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 5 deletions.
71 changes: 69 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,69 @@
# Ember-scroll-operator
# ember-scroll-operator

This README outlines the details of collaborating on this Ember addon.
This ember-cli addon provides two route mixins that will handle scroll preservation and resetting. Read more for details.

## Theme music

<iframe width="420" height="315" src="https://www.youtube.com/embed/cA9gUspn6gc" frameborder="0" allowfullscreen></iframe>

Please mentally replace the word 'smooth' with 'scroll'.

## ScrollOperatorMixin

This will save the scrolling position of a route. When the route is re-entered, it will automatically scroll to the previously saved position *only if accessed by the browser's forward and back buttons*. Accessing the route via link-to or address bar will not trigger this behavior. This is by design in order to more closely emulate the HTML experience.

```
import ScrollOperatorMixin from 'ember-scroll-operator/mixins/scroll-operator';
export default Ember.Route.extend(ScrollOperatorMixin, {
// If any of the following methods are implemented in your route, be sure to
// include a call to the parent to make sure the mixin is included.
activate() {
this._super(...arguments);
// existing code
},
deactivate() {
this._super(...arguments);
// existing code
},
beforeModel() {
this._super(...arguments);
// existing code
},
setupController() {
this._super(...arguments);
// existing code
},
});
```

## ResetScrollMixin

A simple mixin to ensure that a route is always scrolled to the top when accessed.

```
import ResetScrollMixin from 'ember-scroll-operator/mixins/reset-scroll';
export default Ember.Route.extend(ResetScrollMixin, {
// If the following methods are implemented in your route, be sure to include
// a call to the parent to make sure the mixin is included.
activate() {
this._super(...arguments);
// existing code
},
});
```

# Development Setup

## Installation

Expand All @@ -24,3 +87,7 @@ This README outlines the details of collaborating on this Ember addon.
* `ember build`

For more information on using ember-cli, visit [http://www.ember-cli.com/](http://www.ember-cli.com/).

# Credits

Thanks to @gdub22 for their insight on determining when transitions are triggered by the browser's back/forward buttons ([related](https://github.com/emberjs/ember.js/issues/3087#issuecomment-22064811)).
10 changes: 10 additions & 0 deletions addon/mixins/reset-scroll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Ember from 'ember';

export default Ember.Mixin.create({
/**
* Scroll to top when route is entered.
*/
activate() {
Ember.$(window).scrollTop(0);
},
});
60 changes: 60 additions & 0 deletions addon/mixins/scroll-operator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Ember from 'ember';

export default Ember.Mixin.create({
scrollingTimeout: 100,

/**
* Attach on-scroll handler to window/document. Handler will call _scrollTop
* on scroll.
*/
activate() {
const onScroll = () => {
Ember.run.debounce(this, this._setScrollTop, this.scrollingTimeout);
};
Ember.$(document).on('touchmove.scrollable', onScroll);
Ember.$(window).on('scroll.scrollable', onScroll);
},

/**
* Detach on-scroll handlers on route exit.
*/
deactivate() {
Ember.$(document).off('.scrollable');
Ember.$(window).off('.scrollable');
},

/**
* On entering route, decide whether we want to resume previous scrolling
* position or not based on transition.
*/
beforeModel(transition) {
if (!this._didTransitionViaBackOrForward(transition) && this.controller) {
this.controller.set('currentPosition', 0);
}
},

/**
* Scroll to currentPosition value. Uses run-loop's next helper to ensure it
* happens after model hooks have been fully executed.
*/
setupController(controller) {
Ember.run.next(null, () => {
Ember.$(window).scrollTop(controller.getWithDefault('currentPosition', 0));
});
},

/**
* Set currentPosition to $(window).scrollTop value.
*/
_setScrollTop() {
this.set('controller.currentPosition', Ember.$(window).scrollTop());
},

/**
* Determine if transition is triggered by browser forward/back buttons.
* Credit: https://github.com/emberjs/ember.js/issues/3087
*/
_didTransitionViaBackOrForward(transition) {
return transition && transition.sequence > 1 && transition.hasOwnProperty('urlMethod');
},
});
4 changes: 4 additions & 0 deletions app/mixins/reset-scroll.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Ember from 'ember';
import ResetScrollMixin from 'ember-scroll-operator/mixins/reset-scroll';

export default ResetScrollMixin;
4 changes: 4 additions & 0 deletions app/mixins/scroll-operator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Ember from 'ember';
import ScrollOperatorMixin from 'ember-scroll-operator/mixins/scroll-operator';

export default ScrollOperatorMixin;
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ember-scroll-operator",
"version": "0.0.0",
"description": "The default blueprint for ember-cli addons.",
"version": "0.0.1",
"description": "Handle the preservation of scrolling positions when traversing routes via the browser's back and forward buttons.",
"directories": {
"doc": "doc",
"test": "tests"
Expand Down Expand Up @@ -40,7 +40,10 @@
"loader.js": "^4.0.0"
},
"keywords": [
"ember-addon"
"ember-addon",
"scrolling",
"scroll position",
"browser history"
],
"dependencies": {
"ember-cli-babel": "^5.1.5"
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/mixins/reset-scroll-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Ember from 'ember';
import ResetScrollMixin from 'ember-scroll-operator/mixins/reset-scroll';
import { module, test } from 'qunit';

module('Unit | Mixin | reset scroll');

// Replace this with your real tests.
test('it works', function(assert) {
let ResetScrollObject = Ember.Object.extend(ResetScrollMixin);
let subject = ResetScrollObject.create();
assert.ok(subject);
});
12 changes: 12 additions & 0 deletions tests/unit/mixins/scroll-operator-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Ember from 'ember';
import ScrollOperatorMixin from 'ember-scroll-operator/mixins/scroll-operator';
import { module, test } from 'qunit';

module('Unit | Mixin | scroll operator');

// Replace this with your real tests.
test('it works', function(assert) {
let ScrollOperatorObject = Ember.Object.extend(ScrollOperatorMixin);
let subject = ScrollOperatorObject.create();
assert.ok(subject);
});

0 comments on commit af99ee3

Please sign in to comment.