Skip to content

Commit

Permalink
v1.0.1 supporting lib
Browse files Browse the repository at this point in the history
  • Loading branch information
samthor committed Jul 14, 2016
1 parent a48a03a commit d4b17fb
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 101 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.DS_Store
node_modules
62 changes: 32 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,56 @@
pwacompat is a drop-in JS companion library to help your modern website be more progressive.
This takes a `manifest.json` file and, where possible, provides support to non-standard browsers such as Safari on iOS.
pwacompat is a library to help your modern website be more progressive.
This takes a [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest), and, where possible, provides support to non-standard browsers such as Safari on iOS.

# Usage

## Drop-In

Drop-in the `pwacompat.min.js` script into your page directly to get its benefits.
Add this script tag anywhere after your manifest file is included, e.g., at the bottom of your page-

```html
<link rel="manifest" href="manifest.json" />
<script src="https://cdn.rawgit.com/GoogleChrome/pwacompat/v1.0.0/pwacompat.min.js"></script>
```

**Warning!** Don't use the `pwacompat.js` file directly, as it's written in ES6, which can't be run natively in most browsers.

### Browsers

This is supported in most modern browsers (UC Browser, Safari, Firefox, Chrome, IE9+).

## Library

You can also use pwacompat as a library, where it will convert a manifest to HTML that can be inserted into your document's header.
Install with NPM-

```bash
$ npm install --save pwacompat
```

And then include as part of your build process to generate templates-

```js
const pwacompat = require('pwacompat');
const html = compat(require('./path/to/manifest.json'));
console.info(html); // prints '<meta name="...">\n' and so on
```

# Details

pwacompat performs a few main tasks-

* Creates fallback meta tags for older devices (e.g., iOS, older WebKit/Chromium forks etc)
* Creates meta icon tags for all icons in the manifest
* For webapps added to an [iOS homescreen](https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html#//apple_ref/doc/uid/TP40002051-CH3-SW2)-
* Ensures your webapp always starts at your `start_url`
* Fixes internal navigation so users stay within the webapp

# Requirements
The drop-in version also provides JS that enhances webapps added to an [iOS homescreen](https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html#//apple_ref/doc/uid/TP40002051-CH3-SW2)-

If your site has a [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest), you're good to go.
Your `<head>` tag should contain-

```html
<link rel="manifest" href="manifest.json" />
```
* Ensures your webapp always starts at your `start_url`
* Fixes internal navigation so users stay within the webapp

And the `manifest.json` file itself should look a bit like-
# Web App Manifest

Your Web App Manifest is normally named `manifest.json`, live at `/manifest.json`, and should look a bit like this-

```js
{
Expand All @@ -49,20 +68,3 @@ And the `manifest.json` file itself should look a bit like-

For more information on Web App Manifest, and how e.g., modern browsers will prompt engaged users to install your site to their home screen, check out [Google Developers](https://developers.google.com/web/updates/2014/11/Support-for-installable-web-apps-with-webapp-manifest-in-chrome-38-for-Android).
To learn about how to be more progressive with your features, supporting all your users, check out [Always Be Progressive](https://samthor.github.io/AlwaysBeProgressive/).

## Browsers

This is supported in most modern browsers (UC Browser, Safari, Firefox, Chrome, IE9+).

# Release

Compile code with [Closure Compiler](https://closure-compiler.appspot.com/home).

```
// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name pwacompat.min.js
// ==/ClosureCompiler==
// code here
```
32 changes: 32 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2016 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

'use strict';

const parse = require('./lib');
const escapeHTML = require('escape-html');

module.exports = function(manifest) {
const tags = parse(manifest);
const text = tags.map(tag => {
const attrs = Object.keys(tag.attr).map(name => {
const v = tag.attr[name];
return `${name}="${escapeHTML(v)}"`
});
return `<${tag.name} ${attrs.join(' ')}/>`
});
return text.join('\n');
};
95 changes: 95 additions & 0 deletions lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2016 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

'use strict';

/**
* @param {!Object} manifest Parsed JSON manifest.
* @return {!Array<{name: string, attr: !Object}>}
*/
function parse(manifest) {
const out = [];

function createMeta(name, value) {
if (!value) { return; }
out.push({
name: 'meta',
attr: {
'name': name,
'content': value === true ? 'yes' : value,
},
});
}

const capable = ['standalone', 'fullscreen'].indexOf(manifest['display']) !== -1;
createMeta('apple-mobile-web-app-capable', capable);
createMeta('mobile-web-app-capable', capable);
createMeta('apple-mobile-web-app-title', manifest['short_name'] || manifest['name']);
createMeta('msapplication-starturl', manifest['start_url'] || '/');
createMeta('msapplication-TileColor', manifest['theme_color']);

// nb. pwacompat does _not_ create the meta 'theme-color', as browsers that support the manifest
// file don't use its 'theme_color' when the webpage is just loaded in a normal browser (as of
// July 2016). So be sure to set it yourself.

// TODO(samthor): Set 'apple-mobile-web-app-status-bar-style' to 'black' for dark theme-color,
// and use 'default' for light theme-color.

let itunes;
(manifest['related_applications'] || [])
.filter(app => app['platform'] == 'itunes')
.forEach(app => {
if (app['id']) {
itunes = app['id'];
} else {
const match = app['url'].match(/id(\d+)/);
if (match) {
itunes = match[1];
}
}
});
if (itunes) {
createMeta('apple-itunes-app', `app-id=${itunes}`)
}

// Parse the icons.
const icons = manifest['icons'] || [];
icons.sort((a, b) => {
return parseInt(b.sizes, 10) - parseInt(a.sizes, 10); // sort larger first
});
icons.forEach(icon => {
out.push({
name: 'icon',
attr: {
'rel': 'icon',
'href': icon.src,
'sizes': icon.sizes,
},
});
out.push({
name: 'icon',
attr: {
'rel': 'apple-touch-icon',
'href': icon.src,
'sizes': icon.sizes,
},
});
});

return out;
}

module.exports = parse;
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "pwacompat",
"version": "1.0.0",
"version": "1.0.1",
"description": "library to bring Web App Manifest files to older browsers",
"main": "pwacompat.min.js",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/GoogleChrome/pwacompat.git"
Expand All @@ -19,5 +19,8 @@
"bugs": {
"url": "https://github.com/GoogleChrome/pwacompat/issues"
},
"homepage": "https://github.com/GoogleChrome/pwacompat"
"homepage": "https://github.com/GoogleChrome/pwacompat",
"dependencies": {
"escape-html": "^1.0.3"
}
}
70 changes: 7 additions & 63 deletions pwacompat.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,69 +57,13 @@
}

function processManifest(manifest) {
/**
* @param {string} name
* @param {string|boolean|null} value
*/
function createMeta(name, value) {
if (!value) { return; }
if (document.querySelector(`meta[name="${name}"]`)) { return; }
const tag = document.createElement('meta');
tag.setAttribute('name', name);
tag.setAttribute('content', value === true ? 'yes' : value);
document.head.appendChild(tag);
}

const capable = ['standalone', 'fullscreen'].indexOf(manifest['display']) !== -1;
createMeta('apple-mobile-web-app-capable', capable);
createMeta('mobile-web-app-capable', capable);
createMeta('apple-mobile-web-app-title', manifest['short_name'] || manifest['name']);
createMeta('msapplication-starturl', manifest['start_url'] || '/');
createMeta('msapplication-TileColor', manifest['theme_color']);

/*
* nb. pwacompat does _not_ create the meta 'theme-color', as browsers that support the manifest
* file don't use its 'theme_color' when the webpage is just loaded in a normal browser (as of
* July 2016). So be sure to set it yourself.
*/

let itunes;
(manifest['related_applications'] || [])
.filter(app => app['platform'] == 'itunes')
.forEach(app => {
if (app['id']) {
itunes = app['id'];
} else {
const match = app['url'].match(/id(\d+)/);
if (match) {
itunes = match[1];
}
}
});
if (itunes) {
createMeta('apple-itunes-app', `app-id=${itunes}`)
}

// nb. this doesn't set 'apple-mobile-web-app-status-bar-style', as using 'black-translucent'
// moves the page up behind the status bar.
// TODO(samthor): Use white for a bright theme-color, black for a dark one.

// Parse the icons.
const icons = manifest['icons'] || [];
icons.sort((a, b) => {
// sort larger first
return parseInt(b.sizes, 10) - parseInt(a.sizes, 10);
});
icons.forEach(icon => {
const iconEl = document.createElement('link');
iconEl.setAttribute('rel', 'icon');
iconEl.setAttribute('href', icon.src);
iconEl.setAttribute('sizes', icon.sizes);
document.head.appendChild(iconEl);

const appleIconEl = iconEl.cloneNode(true);
appleIconEl.setAttribute('rel', 'apple-touch-icon');
document.head.appendChild(appleIconEl);
const parse = require('./lib');
parse(manifest).forEach(tag => {
const node = document.createElement(tag.name);
for (const k in tag.attr) {
node.setAttribute(k, tag.attr[k]);
}
document.head.appendChild(node);
});

// If this is a standalone iOS ATHS app, perform setup actions.
Expand Down
11 changes: 6 additions & 5 deletions pwacompat.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d4b17fb

Please sign in to comment.