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

History native calls #3006

Merged
merged 20 commits into from
Feb 27, 2014
Merged

History native calls #3006

merged 20 commits into from
Feb 27, 2014

Conversation

akre54
Copy link
Collaborator

@akre54 akre54 commented Feb 19, 2014

Split from #3003, this removes Backbone.$ from Backbone.History and leaves View untouched.

@akre54
Copy link
Collaborator Author

akre54 commented Feb 19, 2014

@jdalton can you verify this works in all versions of IE? My VM isn't booting on me.

removeEventListener('popstate', this.checkUrl);
} else if (this._wantsHashChange && 'onhashchange' in window && !this._oldIE) {
removeEventListener('hashchange', this.checkUrl);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Need to pass false for useCapture here as well, no?

* No need for `_oldIE` when we can just use `this.iframe`.
* Added `this._hasHashchange`.
@braddunbar
Copy link
Collaborator

👍 This is good stuff. There's a quick tweak or two in akre54#2, tested in IE7-9.

@jashkenas
Copy link
Owner

@braddunbar — You like this change in general? Or only in conjunction with other patches that make it easier to untangle jQuery?

@braddunbar
Copy link
Collaborator

I like this one in general, regardless of what we decide about View. Removing the dependency from History is nice and has the bonus of reducing Backbone.$ API usage.

);
this.iframe = body.appendChild(frame).contentWindow;
}
} catch(e){}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we remove the try/catch if we check 'documentMode' in document instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The try-catch is also for the createElement call. Although that likely shouldnt matter if your check is there.

I also seem to recall that Safari doesnt expose document.body until the page has finished downloading (i.e. scripts in the head tag that use it are broken)

Copy link
Collaborator

Choose a reason for hiding this comment

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

We were using document.body already so I'm not too worried about that. I'm not certain about documentMode though.

@braddunbar
Copy link
Collaborator

Removed isExplorer RegEx in akre54#3.

Remove `isExplorer` RegEx.
@braddunbar
Copy link
Collaborator

One more in akre54#4. 😃

@jdalton
Copy link
Contributor

jdalton commented Feb 19, 2014

@jdalton can you verify this works in all versions of IE? My VM isn't booting on me.

I'll run it through the VMs again this evening. To see if anything changed after the cleanup.

@acstll
Copy link

acstll commented Feb 19, 2014

Glad to see that after all the discussion on #2959 (trolling included) we might end up having native Router and a View you can cleanly patch regardless of Backbone.$

👍

@jdalton
Copy link
Contributor

jdalton commented Feb 20, 2014

@akre54 Tested latest from history-native-hooks in IE6-11, and IE9 in IE7 compat mode, all unit tests pass.

@@ -1448,7 +1455,16 @@
// Disable Backbone.history, perhaps temporarily. Not useful in a real app,
// but possibly useful for unit testing Routers.
stop: function() {
Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
// Add a cross-platform `removeEventListener` shim for older browsers.
var removeEventListener = window.removeEventListener || function (eventName, listener) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@braddunbar Just wondering, but do we have to get rid of the iframe here? It looks like it just hangs around in the DOM with no listeners after stop is called, and creates a new one on each start. Potential memory leak?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep yep, we should remove it. Good catch!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We only store a reference to the iframe's contentWindow. Any idea how to turn this into a reference we can remove from the DOM?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm...let's punt on it for this issue and address it separately. It's not a regression in any case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

okey #3015

@braddunbar
Copy link
Collaborator

documentMode is only present in IE>=8 so everything else hits the createElement. I updated with comments just before you asked above.

@jashkenas
Copy link
Owner

That seems quite a bit nastier than simply sniffing the UA. We shouldn't be attempting to create an iframe in environments where we know that none is needed in the first place.

@jdalton
Copy link
Contributor

jdalton commented Feb 21, 2014

That seems quite a bit nastier than simply sniffing the UA.

Relying on a unique and relevant behavior to the target browsers is better than an arbitrary UA sniff. It also reduces the code needed to create the iframe, the try-catch is barely there.

We shouldn't be attempting to create an iframe in environments where we know that none is needed in the first place.

True, it could be done under a if (this._wantsHashChange) check.

@jashkenas
Copy link
Owner

Relying on a unique and relevant behavior to the target browsers is better than an arbitrary UA sniff.

In this particular case, hogwash. It's not at all out of the realm of plausibility that a new browser introduced in future years would allow HTML to be passed to document.createElement.

@jdalton
Copy link
Contributor

jdalton commented Feb 21, 2014

In this particular case, hogwash.

It's not hogwash, and it simplifies creating the iframe element at the expense of ~15 chars for the try-catch.

It's not at all out of the realm of plausibility that a new browser introduced in future years would allow HTML to be passed to document.createElement.

Specs try to avoid breaking the web, doing research into api usage, and this area is well paved with IE opting to actually align with spec and drop the behavior in later releases. If your hangup is on the specific feature test that can be adjusted.

@wyuenho
Copy link
Contributor

wyuenho commented Feb 21, 2014

Can we feature detect oldIE with this?

var oldIE = document.compatMode || (document.documentMode || 0) < 8;

@jdalton
Copy link
Contributor

jdalton commented Feb 21, 2014

Can we feature detect oldIE with this

Others have document.compatMode, at least Chrome.

@wyuenho
Copy link
Contributor

wyuenho commented Feb 21, 2014

Ergh

@wyuenho
Copy link
Contributor

wyuenho commented Feb 21, 2014

http://www.nczonline.net/blog/2009/12/29/feature-detection-is-not-browser-detection/

https://github.com/jquery/jquery-migrate/blob/master/src/core.js#L50

As much as I'd like to feature detect unique old IE features, I just don't think it's reliable. IE 6 was widespread enough that everyone else started copying over stuff. @jashkenas is right. The try catch createElement block is a little too clever and I think it will trip people up during maintenance.

@wyuenho
Copy link
Contributor

wyuenho commented Feb 21, 2014

I have a stupid question:

Why can't we do something like this?

if (!this._hasHashChange && this._wantsHashChange &&
   (!this._wantsPushState || !this._hasPushState)) {
  // make iframe
}

Why go thru the trouble detecting old browser features and/or UA sniff at all?

@braddunbar
Copy link
Collaborator

That's a great question. :)

@jdalton
Copy link
Contributor

jdalton commented Feb 21, 2014

As much as I'd like to feature detect unique old IE features, I just don't think it's reliable.

Backbone is already employing feature inferences. If the createElement inference makes core queezy the check could be modeled after the existing noXhrPatch combo'ed with a docMode check of 0 || > 7 which would combined be an inference for more modern browsers to avoid creating the iframe.

@braddunbar
Copy link
Collaborator

I like @wyuenho's approach in akre54#10. If neither hashChange or pushState are supported, History will be broken anyway so there's no obvious downside.

@jdalton
Copy link
Contributor

jdalton commented Feb 22, 2014

I like @wyuenho's approach in akre54#10. If neither hashChange or pushState are supported, History will be broken anyway so there's no obvious downside.

Can dig.

wyuenho and others added 2 commits February 22, 2014 22:48
Create iframe conditional on options and hashchange and pushstate support
@braddunbar
Copy link
Collaborator

Looking good, just ran the tests in IE7-9 successfully. 👍

@braddunbar
Copy link
Collaborator

...and also a test page to ensure routing worked correctly.

@jashkenas
Copy link
Owner

So this looks ready to go ... but it seems like a patch that only really makes sense in conjunction with one of the native-view patches. By itself, it simply uses jQuery a little bit less.

Should the current state of this changed be merged into the open native-view patches ... instead of being merged directly?

@wyuenho
Copy link
Contributor

wyuenho commented Feb 27, 2014

I think this can be merged as step 1, this PR and #3003 don't have a direct dependency like in #2959. This PR is also blocking #3015. The sooner this gets merge the sooner #3015 can be fixed.

@jashkenas
Copy link
Owner

I think this can be merged as step 1, this PR and #3003 don't have a direct dependency like in #2959. This PR is also blocking #3015. The sooner this gets merge the sooner #3015 can be fixed.

Not so fast. #3015 is not a real problem. Fixing it is fine, but it doesn't matter.

I understand that this PR doesn't have a direct dependency — but that's not the question. This change, looked at in isolation, is a step backwards. If we merge it, and then never merge the two-steps-forward, then that's no good.

Instead, let's try adding it in to the proposed patches that would rely on it (or make use of it).

@akre54
Copy link
Collaborator Author

akre54 commented Feb 27, 2014

To be fair #3015 isnt a showstopper -- by a long shot. Should be no harm in merging this now and working out the kinks in View in the next few days

@akre54
Copy link
Collaborator Author

akre54 commented Feb 27, 2014

This change, looked at in isolation, is a step backwards.

How so? One could avoid jquery entirely if they only wanted routing and not views. We're almost there with #3003.

@braddunbar
Copy link
Collaborator

This change, looked at in isolation, is a step backwards.

I disagree. Removing the jQuery dependency allows use of Backbone.History without extra steps in cases that don't use Backbone.View. Otherwise, it requires jQuery or a shim. I'd call that a step forward on it's own.

Further, it removes the browser sniffing and fixes a long standing issue regarding starting history before the page loads. All wins in my book.

@jashkenas
Copy link
Owner

Alright then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants