Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tabs deeplink history to work with back button within page #9674

Merged
merged 4 commits into from
Jan 23, 2017

Conversation

kball
Copy link
Contributor

@kball kball commented Jan 18, 2017

I noticed while working on a lesson on tabs deep linking that the history feature was a little flaky - while it added the history to the URL, clicking back did not appropriately open the previous tab. This fixes this bug by moving the deep link logic into a function and calling it on popstate.

@kball
Copy link
Contributor Author

kball commented Jan 18, 2017

@ahebrank and @xhezairi you have both worked in this code recently, can you review this PR? Thanks

dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
dom-serializer@0, dom-serializer@~0.0.0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update yarn time to time, but not in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, incidental, will fix.

@@ -365,6 +371,7 @@ class Tabs {
}
}

$(window).off('popstate', this._checkDeepLink);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No check for this.options.deepLink ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can, but shouldn't matter. If the handler isn't there it's a noop

Copy link
Contributor

@ncoden ncoden Jan 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should explicitly show that a piece of code is only required by an option.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One year later: that was a stupid idea.

Options can changes, listeners can be created in complex tests, remplaced, created dynamically. Here we only want to clear everything. No need for that check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. So do we need further changes here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, don't worry. I seen that while working on #11077

@@ -114,9 +93,32 @@ class Tabs {
}
}

this._checkDeepLink = this._checkDeepLink.bind(this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that we can

  1. Count on this within the function being a reference to the plugin
  2. have a single representation of the function (rather than doing bind at the time we add the handler), letting us remove it using off

@ahebrank
Copy link
Contributor

Thanks, haven't been eating my dogfood and didn't see this glitch.

Two minor armchair things:

  1. I find the bound function's name reuse confusing, so I'd probably try anonymizing it.
  2. move the options check to the top of the new function so you can call it with impunity and get rid of a couple of ifs elsewhere.

So, at L96:

this._checkDeepLink = () => {
    if (!this.options.deepLink) { 
      return; 
    }
    var anchor = window.location.hash;
    //need a hash and a relevant anchor in this tabset
    if(anchor.length) {
      var $link = this.$element.find('[href="'+anchor+'"]');
      if ($link.length) {
        this.selectTab($(anchor));

        //roll up a little to show the titles
        if (this.options.deepLinkSmudge) {
          var offset = this.$element.offset();
          $('html, body').animate({ scrollTop: offset.top }, this.options.deepLinkSmudgeDelay);
        }

        /**
          * Fires when the zplugin has deeplinked at pageload
          * @event Tabs#deeplink
          */
         this.$element.trigger('deeplink.zf.tabs', [$link, $(anchor)]);
       }
     }
};

The only other thing I'm wondering is if the popstate event should check options.updateHistory. I'm thinking the answer is no, because if this is false the back button shouldn't be doing anything relevant to the tabs anyway. But just in case, L137 would become:

    if(this.options.updateHistory) {
      $(window).on('popstate', this._checkDeepLink);
    }

@kball
Copy link
Contributor Author

kball commented Jan 19, 2017

@ahebrank can you clarify a little what you meant by anonymizing it? The reason I set it up this way was to be able to remove explicitly this handler on destroy, so as not to have to mess with other handlers...

That said, maybe we should implement a global popstate handler similar to how we handle resize/scroll. Thoughts @coreysyms?

@ahebrank
Copy link
Contributor

@kball, here's a diff that should clarify: fix-tabs-history...ahebrank:fix-tabs-history

@kball
Copy link
Contributor Author

kball commented Jan 19, 2017

Righto, makes sense. Will push up an update later today. Thanks @ahebrank

@designerno1
Copy link
Contributor

the updateHistory got a little problem in _handleTabChange if it get's handled by the deeplink check it shouldn't pushState again.
otherwise we got the panel hash two times in history after changing the tab on popstate or init
maybe adding a parameter to the _handleTabChange could do the job if it's set by the checkdeeplink do not pushstate

@kball
Copy link
Contributor Author

kball commented Jan 20, 2017

@designerno1 @ahebrank @ncoden Updated to address all of the concerns raised, please take another look thanks

@designerno1
Copy link
Contributor

looks good to me

@@ -297,7 +304,7 @@ class Tabs {
* @param {jQuery | String} elem - jQuery object or string of the id of the pane to display.
* @function
Copy link
Contributor

@ahebrank ahebrank Jan 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need a @param definition, like:

  • @param {boolean} - browser has already handled a history update

@@ -206,7 +213,7 @@ class Tabs {
* @fires Tabs#change
Copy link
Contributor

@ahebrank ahebrank Jan 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • @param {boolean} - browser has already handled a history update

@ahebrank
Copy link
Contributor

Needs a comment for the new function parameter, but otherwise thumbs up.

@kball kball merged commit fd6cdc7 into develop Jan 23, 2017
kball added a commit that referenced this pull request Jan 23, 2017
Fix tabs deeplink history to work with back button within page
@kball kball deleted the fix-tabs-history branch April 20, 2017 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants