New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

mobile-viewport-control

Package Overview
Dependencies
Maintainers
0
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mobile-viewport-control - npm Package Compare versions

Comparing version 0.3.0 to 0.3.1

74

index.js
//
// Mobile Viewport Control v0.3.0
// Mobile Viewport Control v0.3.1
//

@@ -7,3 +7,3 @@ // Copyright (c) 2016 Shaun Williams

//
// GitHub: https://github.com/shaunstripe/mobile-viewport-control
// GitHub: https://github.com/stripe/mobile-viewport-control
//

@@ -39,3 +39,10 @@

function setScroll(scroll) {
window.scrollTo(scroll.left, scroll.top);
if (window.scrollTo) {
window.scrollTo(scroll.left, scroll.top);
} else {
document.documentElement.scrollTop = scroll.top;
document.documentElement.scrollLeft = scroll.left;
document.body.scrollTop = scroll.top;
document.body.scrollLeft = scroll.left;
}
}

@@ -313,4 +320,3 @@

function thawIOS(hook, initial, onDone) {
function thawWebkit(hook, initial, onDone) {
// Restore the user's manual zoom.

@@ -342,6 +348,41 @@ hook.setAttribute('content', [

function thawAndroid(hook, initial, onDone) {
function thawGecko(hook, initial, onDone) {
// Restore the user's manual zoom.
hook.setAttribute('content', [
'initial-scale='+originalScale,
'minimum-scale='+originalScale,
'maximum-scale='+originalScale
].join(','));
// Updating the scroll here is too early,
// but it's used to force a refresh of the viewport
// with our current desired scale.
setScroll(originalScroll);
setTimeout(function(){
// Restore the page's zoom bounds.
hook.setAttribute('content', [
'user-scalable='+initial['user-scalable'],
'minimum-scale='+initial['minimum-scale'],
'maximum-scale='+initial['maximum-scale'],
(initial.width ? 'width='+initial.width : null)
].filter(Boolean).join(','));
// Restore the scroll again now that the scale is correct.
setScroll(originalScroll);
// Remove our meta viewport hook.
document.head.removeChild(hook);
if (onDone)
onDone();
}, refreshDelay);
}
function thawBlink(hook, initial, onDone) {
hook.setAttribute('content', [
'user-scalable='+initial['user-scalable'],
'initial-scale='+originalScale,
// WebView does not support this:
//'initial-scale='+originalScale
'initial-scale='+initial['initial-scale'],
'minimum-scale='+initial['minimum-scale'],

@@ -378,13 +419,10 @@ 'maximum-scale='+initial['maximum-scale'],

// thaw function defaults to webkit
var thawFunc = thawWebkit;
var os = getMobileOS();
if (os === 'iOS') {
thawIOS(hook, initial, onDone);
}
else if (os === 'Android') {
thawAndroid(hook, initial, onDone);
}
else {
// For other browsers, we just try Android's method.
thawAndroid(hook, initial, onDone);
}
if (os === 'Android') { thawFunc = isFirefox() ? thawGecko : thawBlink; }
else if (os === 'iOS') { thawFunc = thawWebkit; }
// call appropriate thaw function
thawFunc(hook, initial, onDone);
}

@@ -404,3 +442,3 @@

// stable
version: '0.3.0',
version: '0.3.1',
freeze: freeze,

@@ -407,0 +445,0 @@ thaw: thaw

{
"name": "mobile-viewport-control",
"version": "0.3.0",
"version": "0.3.1",
"description": "Dynamically control the mobile viewport",

@@ -8,6 +8,9 @@ "main": "index.js",

"type": "git",
"url": "git+https://github.com/shaunstripe/mobile-viewport-control.git"
"url": "git+https://github.com/stripe/mobile-viewport-control.git"
},
"files": [
"index.js"
],
"author": "Shaun Williams",
"license": "ISC"
}

@@ -0,23 +1,96 @@

> This library is under active development. Please [email us](mailto:shaun@stripe.com) if you’re ready to use it in a production environment.
# Mobile Viewport Control
On mobile browsers, Apple set a non-standardized precedent of controlling the
viewport with one or more meta tags:
This JavaScript library attempts to solve the hard problem of creating a
__[full-window modal]__ experience for mobile browsers. The goal is to allow
it to be dropped into any page regardless of its viewport settings. It does
this by attempting to control the mobile viewport and by hiding all elements
except the one you are trying to modalize.
```html
<meta name="viewport" content="name=value,name=value,...">
```
[full-window modal]:http://uxmovement.com/mobile/why-you-should-avoid-using-modal-windows-on-mobile/
> See Quirksmode for more context: [1], [2]
--
<table>
<tr>
<td>[![scroll][scroll-gif]][scroll-gfy]</td>
<td>[![zoom][zoom-gif]][zoom-gfy]</td>
</tr>
<tr>
<td>__Figure 1.__ Scrolling</td>
<td>__Figure 2.__ Zooming + Scrolling</td>
</tr>
</table>
--
__Background.__ The _viewport_ is the visible part of the webpage on your
screen (see quirksmode [[1]] [[2]]). It is controlled by two things: _scroll_
and _zoom_. The user can swipe to scroll and pinch to zoom. A JavaScript
developer can control the scroll programmatically, but there is no officially
supported method for controlling the _zoom_ programmatically. However, we do
have a de facto standard for limiting and initializing the zoom:
[1]:http://www.quirksmode.org/mobile/viewports2.html
[2]:http://www.quirksmode.org/mobile/metaviewport/
The goal of this project is to see if we can use these tags to dynamically
modify the viewport at runtime. Specifically, we want to freeze the viewport at
some zoom level, then restore the viewport later.
```html
<head>
<meta name="viewport" content="initial-scale=1">
<meta name="viewport" content="minimum-scale=0">
<meta name="viewport" content="maximum-scale=10">
</head>
```
Generally, a user should be able to pinch-zoom a page. But for things like
popup modals, the user experience is better if the viewport is preset like a
native app.
__Workaround.__ There is an undocumented feature that allows us to modify the
viewport state at runtime by adding and modifying viewport tags. There are
caveats depending on the browser. The goal of this library is to identify and
workaround these caveats until there is a standard for programmatically
controlling zoom. We have researched and tested on multiple platforms, though
we are currently focusing support for Mobile Safari and WebViews on iOS 7, 8, and 9.
(See __[Compatibility Testing](test/)__)
__Modals are the Use-Case.__ Viewport settings vary widely across different
webpages, making it hard to create drop-in modal experiences that work
everywhere (see [Stripe Checkout] and [Auth0 Lock]). For browsers that cannot
create pop-up tabs and for pages where redirection is not an option, this
library can help fill in the gaps.
> UPDATE: See the upcoming _[Payment Request API]_ for native mobile checkout modals for the web.
[Stripe Checkout]:https://stripe.com/checkout
[Auth0 Lock]:https://auth0.com/lock
[Payment Request API]:https://developers.google.com/web/updates/2016/07/payment-request
--
<table>
<tr>
<td>[![freeze][freeze-gif]][freeze-gfy]</td>
<td>[![isolate][isolate-gif]][isolate-gfy]</td>
</tr>
<tr>
<td>__Figure 3.__ Freezing and Thawing</td>
<td>__Figure 4.__ Isolating the Modal</td>
</tr>
</table>
--
__The Abstraction.__ This library provides a limited abstraction for
controlling zoom: _freezing_ and _thawing_. (See Figure 3). Freezing will lock
the zoom to a given scale. Thawing will restore the viewport to what it was
before freezing, while also restoring the appropriate zoom limits (i.e. min and
max). Thawing in this way is useful in the context of a modal.
__Isolating the Modal.__ The freeze/thaw functions are designed to be used in
conjunction with a third operation: _isolation_. (See Figure 4). This is done
by passing an optional element ID to the freeze function, which you would
presumably wish to be the full-window modal. This temporarily applies CSS
rules to ensure with high confidence that all elements except the given element
are collapsed (via `display:none`). You can then style your element to fill
the window as a modal. Thawing will restore the page back to what it was
before.
## Usage

@@ -50,106 +123,22 @@

## Compatibility Testing
## Testing
> __NOTE__: We do not test with Simulators, as iOS Simulator has been shown to
> produce different results than the real environment.
Please see __[Compatibility Testing](test/)__.
Compatibility is measured with a combination of automatic/manual testing:
## License
1. __[Measure Test]__ - verify that we can measure the current viewport scale.
1. __[Freeze Test]__ - verify that we can set and freeze the viewport scale.
1. Manual step - pinch-zoom before starting the test
1. Manual step - verify that you cannot pinch-zoom after the test
1. __[Thaw Test]__ - verify that we can restore the viewport scale and bounds.
1. Manual step - pinch-zoom before starting the test
1. Manual step - verify that you can still pinch-zoom after the test
1. __[Injection Method]__ - verify it works for any webpage by running a bookmarklet test to inject JS into the page
[ISC License](LICENSE)
| Mobile Browser | [Measure Test]\* | [Freeze Test] | [Thaw Test] | [Injection Method] |
|----------------------------|------------------|---------------|--------------------|--------------------------|
| iOS Safari | Y | Y | Y | devtools |
| iOS UIWebView | Y | Fails\*\* | Y if freeze works. | xcode+devtools |
| iOS WKWebView | Y | Y | Y | xcode+devtools |
| iOS SFSafariViewController | Y | Y | Y | |
| iOS Chrome | Y | Y | Y | bookmarklet |
| iOS Firefox | Y | Y | Y | |
| iOS Opera Mini | Y | Fails\*\* | Y if freeze works. | |
| Android Browser (Stock) | ? | ? | ? | |
| Android Chrome | Y | Y | Y | devtools or bookmarklet |
| Android WebView | Y | Y | Y | devtools |
| Android Chrome Custom Tabs | Y | Y | Y | devtools |
| Android Firefox | Y | Fails | Fails | devtools or bookmarklet |
| Android Opera Mini | Fails | Fails | Fails | |
--
_\* This test fails in the iOS Simulator because `initial-scale` is ignored
there for wide pages for some reason._
_Source code for the animated figures above: [mobile-viewport-control-viz](https://github.com/shaun-stripe/mobile-viewport-control-viz)_
_\*\* Fails if user pinch-zooms before freezing. Pinch-zooming causes the
page's scale to change from its specified `initial-scale`. This custom zoom
level is maintained across refreshes. When opening in a new tab, the
`initial-scale` is resumed._
[Measure Test]:http://shaunstripe.github.io/mobile-viewport-control/test/01-measure.html
[Freeze Test]:http://shaunstripe.github.io/mobile-viewport-control/test/02-freeze.html
[Thaw Test]:http://shaunstripe.github.io/mobile-viewport-control/test/03-thaw.html
[Injection Method]:#injecting-into-existing-pages
### Injecting into Existing Pages
To allow us to quickly gauge compatibility for externally owned webpages
across several browsers, we must be able to inject our library code into
their running pages.
##### With Bookmarklet
Bookmarklets are URLs of the form `javascript:(function(){ ... }())` which some
browsers allow for evaluating JS in the context of the current page. The
mobile browsers compatible are listed in the above table under the Injection
Method column.
The following bookmarklet will freeze the viewport scale, show a custom
isolated element, and allow you to press a button to restore the view.
```js
javascript:(function(){document.body.appendChild(document.createElement('script')).src='https://rawgit.com/shaunstripe/mobile-viewport-control/master/bookmarklet/index.js?'+Math.random();}())
```
##### With DevTools
Some mobile browsers allow you to connect to a Desktop DevTools environment
with a JS console for evaluating JS in the context of its page. iOS Safari
supports connecting to Desktop Safari DevTools in this way. Android
Chrome/webview can connect to Desktop Chrome DevTools. Inside DevTools, we can
simply paste the body of the bookmarklet inside the JS console:
```js
document.body.appendChild(document.createElement('script')).src='https://rawgit.com/shaunstripe/mobile-viewport-control/master/bookmarklet/index.js?'+Math.random();
```
iOS webviews require an extra step: you must run an webview app from a live
XCode project on your mac. Only then will Desktop Safari DevTools to connect
to its webview.
### Variables
We currently do not test all variables, but the test outcomes depend on the following:
- browser/platform
- page width (modify in `test.css`)
- screen orientation (portrait or landscape)
- refresh delay (for viewport changes to take effect)
- initial zoom, influenced by either of:
- default zoom specified in initial-scale
- manual zoom remembered before page refresh
- manual zoom after page load and before test run
- initial zoom bounds (controlled by page's original viewport meta tags)
### Quirks when Dynamically Modifying Viewport
- iOS UIWebView does not allow scale adjustments after the user has manually adjusted it.
- Android does not register a new viewport meta tag if it is immediately removed after creation.
- Android will modify the scroll some time after a new viewport tag is registered.
- Android (at least in Chrome) will not freeze scale at 1.0, but will at 1.0±ε for some ε>0.
## License
[ISC License](LICENSE)
[scroll-gif]:https://zippy.gfycat.com/EnchantedPowerfulIndri.gif
[scroll-gfy]:https://gfycat.com/EnchantedPowerfulIndri
[zoom-gif]:https://zippy.gfycat.com/InconsequentialImperturbableBuckeyebutterfly.gif
[zoom-gfy]:https://gfycat.com/InconsequentialImperturbableBuckeyebutterfly
[freeze-gif]:https://fat.gfycat.com/YearlyBitesizedBangeltiger.gif
[freeze-gfy]:https://gfycat.com/YearlyBitesizedBangeltiger
[isolate-gif]:https://fat.gfycat.com/MetallicFrighteningApisdorsatalaboriosa.gif
[isolate-gfy]:https://gfycat.com/MetallicFrighteningApisdorsatalaboriosa

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc