Custom page preserve scrolling


(bunjee) #1

Continuing the discussion from Custom home page to discourse:

Dear Discoursers,

I felt adventurous and coded a custom mixin to preserve page scrolling.

I took inspiration from this and discourse code:

Discourse.ScrollKeep = Ember.Mixin.create(
{
    didInsertElement: function()
    {
        this._super();

        var self = this;

        var router = Discourse.__container__.lookup("router:main").router;

        var onScroll = function()
        {
            if (router.activeTransition) { return; }

            return Em.run.scheduleOnce("afterRender", self, "scrolled");
        };

        onScroll = Discourse.debounce(onScroll, 100);

        $(document).bind("touchmove.discourse-default", onScroll);

        $(window).bind("scroll.discourse-default", onScroll);

        $(window).scrollTop(this.getWithDefault("controller.pos", 0));
    },

    willDestroyElement: function()
    {
        this._super();

        $(document).unbind("touchmove.discourse-default");

        $(window).unbind("scroll.discourse-default");
    },

    scrolled: function()
    {
        this.set("controller.pos", $(window).scrollTop());
    }
});

It restores scroll every time the view loads.

I would like it to fire only on browser back or forward events.

Anyone knows how ?

Thanks :heart:.


(Kane York) #2

Tip: you can use .on('didInsertElement') instead of calling this._super().


(bunjee) #3

Here comes my dirty hack.

discourse.js:

window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
  rootElement: '#main',
  
  // Dirty hack
  w_route: false,

  ...

lib/url.js:

routeTo: function(path) {
    
  if (Em.isEmpty(path)) { return; }
    
  // Dirty hack
  Discourse.w_route = true;

...

My mixin:

Discourse.ScrollKeep = Ember.Mixin.create(
{
    w_pos: 0,

    w_hash: undefined,

    didInsertElement: function()
    {
        this._super();

        var self = this;

        var onScroll = function()
        {
            var router = Discourse.__container__.lookup('router:main').router;

            if (router.activeTransition) { return; }

            Em.run.scheduleOnce("afterRender", self, "scrolled");
        };

        onScroll = Discourse.debounce(onScroll, 100);

        if (Discourse.w_route)
        {
            Discourse.w_route = false;

            this.w_pos = 0;

            this.w_hash = window.location.hash;
        }
        else
        {
            this.w_pos = this.getWithDefault("controller.w_pos", 0);

            this.w_hash = undefined;
        }

        $(document).bind("touchmove.discourse-default", onScroll);

        $(window).bind("scroll.discourse-default", onScroll);

        Em.run.scheduleOnce("afterRender", function()
        {
            if (self.w_hash)
            {
                Discourse.URL.scrollToId(self.w_hash);
            }
            else $(window).scrollTop(self.w_pos);
        });
    },

    willDestroyElement: function()
    {
        this._super();

        $(document).unbind("touchmove.discourse-default");

        $(window).unbind("scroll.discourse-default");

        this.set("controller.w_pos", this.w_pos);
    },

    scrolled: function()
    {
        this.w_pos = $(window).scrollTop();
    }
});

P34C3.


(Kane York) #4

You can move those top two into <script> tags.

Discourse.reopen({
  // Dirty hack
  w_route: false
});

Discourse.URL.reopen({
  routeTo: function(path) {
    if (Em.isEmpty(path)) { return; }
    
    // Dirty hack
    Discourse.w_route = true;

    return this._super();
  }
});

(bunjee) #5

Thanks @riking that’s a cleaner way to do my dirty hack :smiley: .