diff --git a/api/cont.js b/api/cont.js index 2c18611c..e7100b53 100644 --- a/api/cont.js +++ b/api/cont.js @@ -226,6 +226,11 @@ return Async(this, function(cont, async) { if (args.length == 1) data = cont.all(); dust.render(template, data, function(err, out) { + // Apply scroll fix to iOS 8.0 + if (out && Mobify.isIOS8_0()) { + out = Mobify.ios8_0ScrollFix(out); + } + if (err) { async.finish(out); debug.die(err); diff --git a/api/util.js b/api/util.js index d6ecb8a1..31295717 100644 --- a/api/util.js +++ b/api/util.js @@ -81,6 +81,68 @@ return i18nlookup; }; + Mobify.isIOS8_0 = function() { + var IOS8_REGEX = /ip(hone|od|ad).*OS 8_0/i; + + return IOS8_REGEX.test(window.navigator.userAgent); + }; + + /** + * iOS 8.0 has a bug where dynamically switching the viewport (by swapping the + * viewport meta tag) causes the viewport to automatically scroll. When + * capturing, the initial document never has an active meta viewport tag. + * Then, the rendered document injects one causing the aforementioned scroll. + * + * This patches HTML to hide the body until the first paint (and hopefully after + * the initial viewport is calculated). By the time we show the body the new + * viewport should have already taken effect. + * + * JIRA: https://mobify.atlassian.net/browse/GOLD-883 + * Open Radar: http://www.openradar.me/radar?id=5516452639539200 + * WebKit Bugzilla: https://bugs.webkit.org/show_bug.cgi?id=136904 + */ + Mobify.ios8_0ScrollFix = function(htmlString) { + var BODY_REGEX = /
'"]*|'[^']*?'|"[^"]*?")*>/i; + + var openingBodyTag = BODY_REGEX.exec(htmlString); + // Do nothing if we can't find an opening `body` tag. + if (!openingBodyTag) { + return htmlString; + } + openingBodyTag = openingBodyTag[0]; + + // Use DOM methods to manipulate the attributes on the `body` tag. This + // lets us rely on the browser to set body's style to `display: none`. + // We create a containing element to be able to set an inner HTML string. + var divEl = document.createElement('div'); + + // The `div`'s inner string can't be a `body` tag, so we temporarily change + // it to a `div`.. + var openingBodyTagAsDiv = openingBodyTag.replace(/^$/, ''); + openingBodyTag = openingBodyTagAsDiv.replace(/^