-
Notifications
You must be signed in to change notification settings - Fork 76
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
IE Support #33
Comments
Which versions of IE aren't supported? Every available version? |
Hi jonjamz, I added that to the ticket (probably after you saw it). I tested the sample app with IE 7-9. All give the same error, expected as IE doesn't support [add/remove]EventListener. Working with some polyfills, there are other errors that show up. Here is a link to the open ticket with the underlying page.js project: I have not tried applying the attached code fix as I don't think the project maintainer plans on accepting that pull request and I would rather not work off of a custom fork. |
Thanks for the heads up. Was just starting to work with this today. You mentioned a Backbone version of this router -- do you mean simply using the Backbone smart package, or is it an older version of Meteor Router? |
Meteor Router tag v0.1.1 seems to be the last version of this smart package which uses Backbone underneath. After that, Tom switched from Backbone to page.js. I'm looking into what it would take to swap back in the latest version. Will post my findings. |
Yeah, 0.2 was the switch to page.js. I hadn't realised it didn't work at all in IE. Strangely enough I get a different error in IE9 (about What would be the ideal behaviour here? Getting a hash-based pushState polyfill working? Or just falling back to not using AJAX? |
(Updated the issue description with results of running the unit tests in IE7-9. Btw, you may want to consider moving the actual package down into a 'router' folder so that renaming the cloned folder is not required in order to run the tests. I used that trick in my roles package and it works well: https://github.com/alanning/meteor-roles) Hash-based pushState would be ideal but falling back to no-AJAX would certainly be easier if my tests earlier today were any indication. I also looked into swapping out page.js for backbone with the current api. Looks like a no-go as backbone seems to require all routes be defined prior to calling Backbone.history.start; which doesn't fit the current api model. I'll see what I can do regarding the no-AJAX fall-back. |
Hmm, as you mention on the package site, the lack of Spark on the server is a major limitation for no-AJAX fall-back. I saw someone mention on one of the Google groups that they had successfully gotten Spark to render on the server so hopefully that functionality is not too far off. |
OK, History.js + monkey-patching gets client-side tests to pass in IE9! if (History &&
(!window.history || !window.history.replaceState)) {
// Monkey-patch page.js with HTML4 history polyfill
console && console.log('Router: using History.js polyfill')
page.Context.prototype.pushState = function () {
History.pushState(this.state, this.title, this.canonicalPath);
};
page.Context.prototype.save = function () {
History.replaceState(this.state, this.title, this.canonicalPath);
};
} I added that near the top of router_client.js but it could actually be included anywhere if you didn't want to add it into the meteor-router package itself. Could just include instructions on how to hook it in if needed. If anybody wants to take on adding IE7 & 8 support, please feel free. :-) To test from package root, you'll need to update package.js a bit: There was one failing server-side test, "Router.server various response types" but I think it is unrelated as it was already failing for me 100% in IE9 and intermittently in Chrome. If you'd like to include this in the router smart package, let me know where it should go and I can submit a pull request. History.js - https://github.com/balupton/history.js |
Wow, great stuff! Would it just be a matter of patching |
Yeah, I'm really glad the page.js guy exposed that Context class. I'm not that familiar with older ie's event accessors. I've always heard there were weird edge cases that caused trouble so I generally used a library to avoid dealing with them directly. Actually, if we're using jquery for History anyways we could use that and be fairly confident of avoiding weirdness. |
Along with that implementation, would it be possible to let us get more detailed control over how the router affects the address bar and history, such as with Backbone's navigate? Or maybe reveal access to History.js through an abstraction layer in the router. I'm currently using jquery-history to push address bar changes along with Meteor-Router. If Meteor-Router implements History.js, I don't want to have 2x the code on the client side. |
I just ran into this bug too. Perhaps we could get @alanning 's patch in place so at least IE9+ has support? Although @jonjamz makes a good point that jquery-history is already a sanctioned package in the meteor core...so if that could be used instead of History for the fix? I obviously haven't tried any of that yet :) |
Meteor's jquery-history smart package is actually using History.js. So that's an even easier option. The monkey-patch code remains the same, but rather than manually including these files... api.use('jquery', 'client'); ...jquery-history does it for you so you just need to add the following packages: jquery & jquery-history Thanks for the pointer! |
It should go in the client folder. I have it in a separate file named Order doesn't seem to matter. I would have figured that it would but I Adrian Sent from my iPhone On Jan 12, 2013, at 5:36 AM, Jonathan James notifications@github.com alanning, I can use the code you provided anywhere in the client side of my — |
I think ideally people wouldn't have to use jquery (it's a pretty large dependency if it's not needed). I would guess that's the reason why jquery-history now redirects you to History.js. I changed from backbone -> page.js for the same reason (didn't want to have a large dependency that I mostly wasn't using). Also, I wouldn't read too much into the fact that jquery-history is sanctioned by core. @alanning so with that in mind, is it just a matter of a minor patch to page.js, and an inclusion of history.js to get support for IE7+8 working? |
@jonjamz Have you tried playing with the page.js |
Thanks, and thanks for responding to me on the other post I made. No, I'm still kind of a noob when it comes to page.js, as I transitioned to Meteor from backbone/ajax. I'll look more into it. |
I did some more work on getting IE7&8 working and ended up having to I'll post up what I've got later today and maybe we can come up with a Sent from my iPhone On Jan 13, 2013, at 9:25 PM, Tom Coleman notifications@github.com wrote: I think ideally people wouldn't have to use jquery (it's a pretty large Also, I wouldn't read too much into the fact that jquery-history is @alanning https://github.com/alanning so with that in mind, is it just a — |
Tests are passing in IE7 and IE8 with the patch code included below. The key part is using addEvent and removeEvent in page.start and page.stop, respectively. The rest is copied straight from the page.js source in order to give access to the function closures dependencies. I'm still a little concerned about using this patch in production because of those three vars (closures) at the top of the patch...may interfere with page.js inner-workings in other use cases. If somebody else can run it through some more tests, that would be helpful. Also, it would be hard to upgrade to the latest page.js after using this patch as a lot of core code is duplicated. Still, working is better than broken. Steps to get it to work with the router tests:
api.use('jquery-history', ['client', 'server']);
// patch for IE7 and IE8
if (page) {
var running,
dispatch = true,
base = '';
function onpopstate(e) {
if (e.state) {
var path = e.state.path;
page.replace(path, e.state);
}
}
function addEvent( obj, type, fn ) {
if ( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
obj.attachEvent( 'on'+type, obj[type+fn] );
} else
obj.addEventListener( type, fn, false );
}
function removeEvent( obj, type, fn ) {
if ( obj.detachEvent ) {
obj.detachEvent( 'on'+type, obj[type+fn] );
obj[type+fn] = null;
} else
obj.removeEventListener( type, fn, false );
}
function onclick(e) {
if (1 != which(e)) return;
if (e.defaultPrevented) return;
var el = e.target;
while (el && 'A' != el.nodeName) el = el.parentNode;
if (!el || 'A' != el.nodeName) return;
var href = el.href;
var path = el.pathname + el.search;
if (el.hash || '#' == el.getAttribute('href')) return;
if (!sameOrigin(href)) return;
var orig = path;
path = path.replace(base, '');
if (base && orig == path) return;
e.preventDefault();
page.show(orig);
}
function which(e) {
e = e || window.event;
return null == e.which
? e.button
: e.which;
}
function sameOrigin(href) {
var origin = location.protocol + '//' + location.hostname;
if (location.port) origin += ':' + location.port;
return 0 == href.indexOf(origin);
}
page.start = function(options){
options = options || {};
if (running) return;
running = true;
if (false === options.dispatch) dispatch = false;
if (false !== options.popstate) addEvent(window, 'popstate', onpopstate);
if (false !== options.click) addEvent(window, 'click', onclick);
if (!dispatch) return;
page.replace(location.pathname + location.search, null, true, dispatch);
};
page.stop = function(){
running = false;
removeEvent('click', onclick, false);
removeEvent('popstate', onpopstate, false);
};
} |
Awesome @alanning ! So the router works (albeit with Rather than monkey patching page.js, let's submit a PR to them directly ("support polyfilled IE" or something), and run off a forked version until they accept it. I can take a look at this on monday (still returning from holidays) if you'd like. |
@alanning et al. -- I've created a branch that uses https://github.com/devote/HTML5-History-API (which is a true polyfill -- i.e. doesn't require any changes to page.js for page.js to use it). Using that package + unmodified page.js, the tests are now passing on IE9. However it's not really working (and I'd be surprised if your code was either) in practice, as there are some assumptions made in page.js's You can see how it fails if you run the example app; compare the console output in a modern browser when you click the first link. Anyway, some progress is being made, but what still needs to happen is:
Probably not too hard but I'm out of energy for today. God I hate IE. I'd really appreciate any comments / thoughts / critiques etc. |
@tmeasday nice job tracking down that polyfill. There are two outstanding tickets for page.js regarding supporting non-HTML5 browsers. The oldest is 9 months old... There have been patches submitted as well. At this point I would suggest we fork page.js, rewrite it to support non-HTML5 browsers, and then base Router off of that. We can submit the fork as a pull request back to the main project and when they officially support non-HTML5, Router can switch back. I don't think it would be too hard (page.js isn't that big after all) and I'm willing to do the work if you'll repoint Router to the fork. What do you think? (Ditto regarding my feelings towards IE) |
@alanning - I've made some progress here; or at least I've set things up to move forward. The It's a bit complicated, but basically it means that if you run that branch of the router, you'll end up with the polyfill and this commit, and thus support for IE9. I'll probably have time to integrate your other changes and get support for IE8 by the end of the week. Then we can send off a PR upstream to page.js. If you'd like to have a go yourself feel free; you'll probably want to develop with |
For the record, the bug in meteorite is squashed. |
@tmeasday - Thanks for getting that dependency chain worked out. I'll track your page.js fork and see how I can help contribute. If you're planning on doing that soon (before end of week) I'm pretty sure you'll be done before I have a chance to work on it, though. :-) @TimHeckel - You're welcome! Credit to Tom for the great smart package. IE9 is important for my project too. Right now we're doing the ol' detect and suggest message... "Oh, you're using an old, busted browser? Sorry, we don't support that. Might we suggest --> Google Chrome Frame?" |
@tmeasday - btw, I'd like to add a failing test for the IE9 patch since it doesn't really work in practice. If I'm understanding correctly, history is working when using the Meteor.Router.to() method but not with clicked a-href's. So the failing use case is: from a url other than root, click a link, then hit the back button, right? And the test can reproduce this by simulating the click somehow (probably reusing page.js code) and checking the url state after 'back' is triggered? |
@alanning - I was thinking about that. A test could just be something like: window.globalSet = true;
clickLink();
assert(window.globalSet); Although actually I have no idea how exactly to implement it, and exactly how it will break if it fails. A simpler way to tell is to look at the URL -- if I go to |
@alanning - Ok, I have a working version. Can you test it out? It should work in IE8 + 9. I simplified your I'd like to figure out how to do that test too; that's next on my list. |
Alright! I've submitted the patch upstream: visionmedia/page.js#48 I've released a new, temporary atmosphere package: https://atmosphere.meteor.com/package/page-js-ie-support, which other packages can use to get a patched page.js until the patch is accepted upstream, as well as a HTML5-History-API package wrapper. See the notes here on usage: https://github.com/tmeasday/meteor-page-js-ie-support. I'll add a note to the README of router with an explanation. I'm going to wait for a little longer to see if any bugs surface (or the PR gets accepted quickly) before releasing a new, supporting version of the router, that way I can be more comfortable removing the temporary page.js package later on. |
@tmeasday - Congratulations!! Thank you for all of your hard work to get IE supported! |
@tmeasday always glad to help, write and ask, I'm always connected. |
@tmeasday I have a question about the IE-support. I get the Meteor Router to work in IE if I go to my root domain and then use But if I want to go to directly to mysite.com/wherever in IE, is the Router supposed to automatically change the URL to mysite.com/#/wherever, or not? If not: how am I supposed to handle URL's? mysite.com/#/wherever will work in IE, but not in other browsers, and vice versa? Thank you! |
I guess all browsers could be moved to the hash version, to solve both problems. Just for interest, what would be any problem(s) with this? |
@krstffr I guess this a limitation of the polyfilled approach or a bug in the polyfill. You can't expect page.js to start looking at the hash part of the URL and trying to guess what scheme the polyfill is using to represent URLs via the hash. On the other hand, I don't know if the polyfill should be messing with things in browsers where it doesn't need to polyfill. @devote -- what are your thoughts here? Should we open a bug against HTML5-History-API? |
@tmeasday I don't know what the exact technical problems would be with going with the hash-version for all browsers, I did see a talk on SXSW about this subject last year though. It was about how Twitters hashed URL's caused problems, I don't remember exactly what the problem was though. Maybe it was just that it's not the correct way to use URL's. http://en.wikipedia.org/wiki/Fragment_identifier The fact that Twitter and Facebook can handle both versions depending on what browser the client is using does mean that it's possible to add/remove the hash based on the clients browser. But of course they probably have one or two or a thousand more people working on these kinds of issues :) To me, it's better to go with ONE way that works across browsers (the hashed I guess?), cause the URL to me is supposed to represent a specific piece of content on a website, and if I share a URL to someone I want to be 99.99% sure they get the exact same content that I intended from that URL. In a perfect world the hash would be added/removed depending on browser though :) Thanks for your support! |
I've read a few things about this topic, and here's my summary: The biggest problems for hash-based URLs are:
But I also found this (not negating the above problems):
My conclusion:
From my limited testing, this solves the problem: changing page.js's index.js to https://gist.github.com/tom-adsfund/5013093 (4 lines changed). Now works on Android 2.* and 3, IE8 and 9, Chrome-latest, FF19, Safari, iOS6.1. |
History.js supports sharing links between browsers because it takes a much more intrusive approach, unlike the polyfill which just tries to simulate @krstffr I don't think there are many that would choose hashed-URLs everywhere anymore. Not only are there a bunch of problems with them, but also (especially meteor-) developers just plain don't care as much about old IE's anymore[1]. Obviously some people have to cater for such browsers, but unless I've read the community wrong, there's no way that I'm going to compromise this package when most people aren't too concerned. I hope the last paragraph didn't sound aggressive - I completely appreciate this conversation, I just wanted to make my feelings on the matter clear. [1] Some evidence: page.js doesn't even work, at all in IE8-. |
@tmeasday Yeah I understand. But I think that if we have an IE-branch, I would like it to work in IE. If URL's are not shareable between IE and other browsers, to me it doesn't work in IE, so I would rather have ugly links that work everywhere than links that only work in IE (or only work in other browsers). To not care for IE today is something that at least my clients would never accept unfortunately. At least like 7 % of users coming to my sites use IE 8. But maybe I'm just too optimistic about actually using meteor in real (smaller!) projects today? |
@krstffr if you want to use it with IE and sharable links, my 4 line change will work, you can try it yourself. Use it on the current master. |
@tmeasday I'll try that, thank you! |
@krstffr the plan isn't to have an IE support branch, rather I am going to merge this into master and release a new version very soon. I'm just trying to figure out what's happening on android, and then I'm going to release. Having broken links between IE + other browsers is IMHO a better solution than a) not working at all in IE (the current situation) or b) killing single-page-app-ness in IE (which is what @tom-adsfund's solution does). |
Ok, after discussing with @devote, I've made a change to the HTML5-History-API package to enable link sharing. Please run |
@tmeasday seems to work perfectly for me in IE 8-9. Great work! |
Trying to get this to work in an embedded browser control in a c# windows application. It fails saying object doesn't support replaceState. Control is reporting that it's IE 10.0. Tried the HTML5 shim and that did not help. Does work on IE10 browser on the same system. Any ideas? Not really sure how to debut a webbrowser control since there are not a lot of tools that I can see initially. |
If it's IE10, then it shouldn't need the shim. Apart from that I really have no idea. |
A few days ago I released a new version of the library. Numerous errors have been corrected, for the most part to the mobile version of browsers and the browsers in MAC OS. And still some bugs in other browsers. Enjoy your work! |
Release a new version of meteor-HTML5-History-API. @scott6666 maybe try mrt update? |
No change. Tried it. Update shows Github master does not seem to show any updates on the code list page. Not sure that I picked up the updates. I also tried (before this change) messing with various registry settings that claim they might affect which browser version the control uses. No help there either. If it helps, it first says it can't fiind redirect in line 4 of http://192.168.1.2:3000/packages/HTML5-History-API/settings.js, the fails on finding 'replaceState' in http://192.168.1.2:3000/packages/page-js-ie-support/page-js/index.js? (line 233). If the History shim is removed it can't find replaceState in http://192.168.1.2:3000/packages/page-js-ie-support/page-js/index (line 233) I setup a button that reports me the browser version which is 10.0 and Assembly 4.0.30319.18036. I don't really have a machine that I can easily back down to IE9. All this will work on the IE of the same machine. Did some googling and there are cases when the browser controls seems to act differently than the base IE browser but nothing popped out as a solution. I can use backbone as a router and borrow the renderPage function. That works well although it seems to do about 3 page grabs for every URL change. This may be meteor standard live paging. It's not hard to replicate if you have Visual Studio 2012. Put a webcontrol on a page, set the url to the local server, run it, see errors. In case anyone has a VM with Win 7 and VS2012 and wants to refute or deny. I'm doing this to drive a printer application (labeling) without dialog boxes appearing so meteor does the work and the C# project just grabs info from the page and does the printing. Otherwise, I have to write a full fledged C# app to do this. Seems I could be nimbler if the core of the app was in meteor. |
@scott6666 -- just to be sure: you have the HTML5-History-API package listed before router in your |
Yes. Just tried again. Same result. webBrowser control does seem to be pretty picky. Crapped out on one of my scripts because I had a comma ending an object list before the closing }. Other browser ran it fine. I'll try to see if there's a way to javascript debug the thing. On May 28, 2013, at 6:11 PM, Tom Coleman notifications@github.com wrote:
|
First off, thanks for the great package.
I wanted to point out that, unfortunately, IE is not supported.
(Edit: Updated with versions and errors)
Running the package tests in IE results in:
IE7 & 8 - blank page with console error: "SCRIPT5007: The value of the property 'addEventListener' is null or undefined, not a Function object " from line page-js/index.js:95
IE9 - Regular test runner view all client tests failing, 1 server test failing and console error: "SCRIPT438: Object doesn't support property or method 'replaceState' " from line page-js/index.js:227
Tracing this error shows that it is actually a limitation of page.js. There is an open issue regarding IE support but it is quite old and I am not sure if the maintainer is planning on adding support. I've tried using pushState polyfills but the errors get progressively more esoteric and I've given up on that solution.
I'd like to suggest noting in the documentation that IE is not supported and perhaps pointing users to the older backbone version of this router package (v0.1.1) until this is resolved.
The text was updated successfully, but these errors were encountered: