├── LICENSE
├── README.md
├── shell-caching
├── .gitignore
├── README.md
├── build.js
├── firebase.json
├── package.json
└── public
│ ├── cached.html
│ ├── ignored.html
│ ├── ignored2.html
│ ├── images
│ └── thumbsup.png
│ ├── index.html
│ └── scripts
│ └── app.js
└── teamoji
├── .bowerrc
├── .editorconfig
├── .firebaserc
├── .gitattributes
├── .gitignore
├── .travis.yml
├── app
├── data
│ └── emoji.json
├── elements
│ ├── elements.html
│ ├── firebase-storage-upload-button.html
│ ├── x-app.html
│ ├── x-create-team.html
│ ├── x-emoji-iconset.html
│ ├── x-emoji-picker.html
│ ├── x-emoji-update.html
│ ├── x-login.html
│ ├── x-shade.html
│ ├── x-team-page.html
│ └── x-update-detail.html
├── images
│ ├── avatars
│ │ ├── bunny.jpg
│ │ ├── dragon.jpg
│ │ ├── koala.jpg
│ │ ├── monkey.jpg
│ │ ├── octopus.jpg
│ │ ├── sheep.jpg
│ │ └── tiger.jpg
│ └── icons
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ ├── icon-384x384.png
│ │ ├── icon-512x512.png
│ │ ├── icon-72x72.png
│ │ └── icon-96x96.png
├── index.html
├── manifest.json
├── robots.txt
├── scripts
│ ├── app.js
│ └── service-worker-registration.js
└── styles
│ ├── app-theme.html
│ ├── main.css
│ └── shared-styles.html
├── bower.json
├── database.rules.json
├── firebase.json
├── gulpfile.js
├── package.json
├── scripts
├── fake-usage
└── parse-emoji
├── tasks
└── ensure-files.js
└── travis-runner.sh
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2016 Google Inc. All Rights Reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Progressive Web Apps on Firebase
2 |
3 | This repository contains sample code and demos related to my 2016
4 | Google I/O presentation "Progressive Web Apps on Firebase".
5 |
6 | ## In this repo
7 |
8 | * `shell-caching`: A minimal intro of using `sw-precache` to cache an app shell.
9 | * `teamoji`: A full-featured PWA built with Firebase and PolymerFire
10 |
11 | ## Resources
12 |
13 | * [PWAs on Firebase Space](https://spaces.google.com/space/403967086)
14 | * [Firebase Docs](https://firebase.google.com/docs)
15 | * [sw-precache](https://github.com/GoogleChrome/sw-precache)
16 | * [PolymerFire](https://github.com/firebase/polymerfire)
17 |
--------------------------------------------------------------------------------
/shell-caching/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | bower_components
4 | .tmp
5 | .publish/
6 | scripts/data/emoji_annotations.xml
7 |
--------------------------------------------------------------------------------
/shell-caching/README.md:
--------------------------------------------------------------------------------
1 | # Firebase App Shell Caching
2 |
3 | This is an example of how to use the [sw-precache](https://github.com/GoogleChrome/sw-precache)
4 | for a Firebase Hosting site to cache an app shell for a single-page style app.
5 |
6 | ## Running Locally
7 |
8 | npm install
9 | npm run build
10 | npm install -g firebase-tools
11 | firebase serve
12 |
13 | ## How it Works
14 |
15 | The script in `build.js` utilizes the [node-glob](https://github.com/isaacs/node-glob)
16 | library to build up a list of the files that will be deployed to Firebase Hosting.
17 | The `sw-precache` library is then used to generate a service worker which is
18 | placed in the `dist` directory.
19 |
20 | This implementation uses a `navigateFallback` option on `sw-precache` which causes
21 | any unrecognized navigation to serve up `index.html`.
22 |
--------------------------------------------------------------------------------
/shell-caching/build.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2016 Google, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | 'use strict';
18 |
19 | var glob = require('glob');
20 | var path = require('path');
21 | var swPrecache = require('sw-precache');
22 |
23 | var fbjson = require('./firebase.json');
24 | var rootDir = 'dist';
25 |
26 | var filesToCache = glob.sync('**', {
27 | ignore: fbjson.hosting.ignore,
28 | cwd: rootDir
29 | });
30 |
31 | swPrecache.write(path.join(rootDir, 'service-worker.js'), {
32 | staticFileGlobs: filesToCache.map(file => path.join(rootDir, file)),
33 | stripPrefix: rootDir,
34 | navigateFallback: '/index.html'
35 | });
36 |
--------------------------------------------------------------------------------
/shell-caching/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "dist",
4 | "ignore": [
5 | "ignored*"
6 | ],
7 | "rewrites": [
8 | {"source": "**", "destination": "/index.html"}
9 | ]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/shell-caching/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "firebase-shell-caching",
3 | "version": "0.0.1",
4 | "description": "An example of how to cache an app shell with Firebase",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "rm -rf dist; mkdir dist && cp -r public/* dist && node build.js"
8 | },
9 | "author": "Michael Bleigh",
10 | "license": "Apache-2.0",
11 | "devDependencies": {
12 | "glob": "^7.0.3",
13 | "sw-precache": "^3.1.1"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/shell-caching/public/cached.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 | This Page is Cached Offline
21 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/shell-caching/public/ignored.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 | This Page is Cached Offline
21 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/shell-caching/public/ignored2.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 | This Page is Cached Offline
21 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/shell-caching/public/images/thumbsup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/shell-caching/public/images/thumbsup.png
--------------------------------------------------------------------------------
/shell-caching/public/index.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 | App Shell Caching
21 |
48 |
49 |
50 |
51 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/shell-caching/public/scripts/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2016 Google, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | 'use strict';
18 |
19 | if ('serviceWorker' in navigator) {
20 | navigator.serviceWorker.register('/service-worker.js')
21 | .then(function(registration) {
22 | registration.onupdatefound = function() {
23 | var installingWorker = registration.installing;
24 | installingWorker.onstatechange = function() {
25 | switch (installingWorker.state) {
26 | case 'installed':
27 | if (navigator.serviceWorker.controller) {
28 | console.log('New or updated content is available.');
29 | } else {
30 | console.log('Content is now available offline!');
31 | }
32 | break;
33 |
34 | case 'redundant':
35 | console.error('The installing service worker became redundant.');
36 | break;
37 | }
38 | };
39 | };
40 | }).catch(function(error) {
41 | console.error('Error during service worker registration:', error);
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/teamoji/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "app/bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/teamoji/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/teamoji/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "teamoji-app"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/teamoji/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/teamoji/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | bower_components
4 | .tmp
5 | .publish/
6 | scripts/data/emoji_annotations.xml
7 | scripts/data/users.json
8 | scripts/data/service-account.json
9 |
--------------------------------------------------------------------------------
/teamoji/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | addons:
4 | firefox: latest
5 | apt:
6 | sources:
7 | - google-chrome
8 | - ubuntu-toolchain-r-test
9 | packages:
10 | - google-chrome-stable
11 | - g++-4.8
12 | node_js:
13 | - '4.2'
14 | - '5.1'
15 | before_script:
16 | - 'export DISPLAY=:99.0'
17 | - sh -e /etc/init.d/xvfb start
18 | - sleep 3
19 | - npm i -g bower@1.7.1 gulp@3.9.0 firebase-tools@2.2.0
20 | - bower i
21 | script:
22 | - ./travis-runner.sh
23 | env:
24 | global:
25 | - "CXX='g++-4.8'"
26 | - secure: SbcQ7plU7aRGQlaAG2ffMhSvEs84073YSljOQ62DZAjRxgizMhF4xM7H2mPrmac9YRM4IBrQRvBKMMZy3L6OhN8gwpm8o+w2zV+5Q1fwpY9V8bilznnhp1JUY6jrB2l7aLTOFxt/cG+5ABxiupwWz/n+I7BaByYhBiHWntIBgDc528eecRNDYI5R36KWjLO/yr+SdElvyxDlDOdJGaluPvgMItbinFGcE1hYb/Jqrkkw8zpE6CTDmvMOq1aRBWSo9afgh2zDeKc02lTYP/4N0xcn8CqzHF7k5zGWHjN9DR8Ep8Bp1ff/sM7zHGZBqgVhn5WGv305jBQY6eOxiTp5cDP0WVIOjgJeM5rBu9hBQxhZSaMKBPr2B1NYUjIwTVQkBsnR4sr095Ugjg8JCZAmEevf/Ysl4CzQyW3gT+WcEluqjxUuicQWDclH6L/kOVPBJ+Eqdo/LY3G1tpLcc6fsvj4FlVO6LPTrbMyCagwQvnjX3uIdFyuthqtWWrHKQMGx2Ow9suNUi8Hyvk7WboS1Z6jrLIcs1rvXSX8rQmlMR5vJBK3Ejg6fS1OHxn/lrtLhj4lDLB9r/Fcu2PEHT1lcvQqsTa3W+t4Fk1qaShUlBDiwMbZWZgmlf1SdG5OzK1yrPLjTTdRFdqJGgb6TANCdetgczRWynvjIhr5IDMxvfJg=
27 |
--------------------------------------------------------------------------------
/teamoji/app/elements/elements.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/teamoji/app/elements/firebase-storage-upload-button.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
29 |
30 |
31 | Upload File
32 |
33 |
73 |
74 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-app.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
77 |
78 |
83 |
84 |
85 |
88 |
89 |
95 |
96 |
97 |
102 |
103 |
109 |
110 |
111 |
114 |
115 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | Your Teams
128 |
129 |
130 |
131 |
132 |
133 | [[item.name]]
134 |
135 |
136 |
137 | Create Team
138 | Sign Out
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
306 |
307 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-create-team.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
95 |
96 |
97 | Feeling a little lonely on [[domain]]?
98 | Let's make a new team!
99 |
100 |
101 | Create Team
102 |
103 |
142 |
143 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-emoji-iconset.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-emoji-picker.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
59 |
60 |
65 |
66 |
67 |
68 |
69 | Select an Emoji
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
[[domain]] [[team]]
78 |

79 |
80 |
81 |
82 |
83 |
84 |
90 |
91 |
92 |
93 |
94 |
95 |
121 |
122 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-emoji-update.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
52 |
53 |
54 |
58 |
59 |
72 |
73 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-login.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
87 |
88 |
89 | Teamoji
90 |
Team Status 
91 |
92 |
93 | Sign in with Google
94 | Go online to sign in
95 |
96 |
97 | powered by Firebase
98 |
source on GitHub
99 |
100 |
131 |
132 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-shade.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
29 |
30 |
31 |
32 |
79 |
80 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-team-page.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
68 |
69 |
70 |
71 |
72 |
73 | [[team.name]]
74 | Offline
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
114 |
115 |
--------------------------------------------------------------------------------
/teamoji/app/elements/x-update-detail.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
25 |
26 |
27 |
32 |
33 |
--------------------------------------------------------------------------------
/teamoji/app/images/avatars/bunny.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/avatars/bunny.jpg
--------------------------------------------------------------------------------
/teamoji/app/images/avatars/dragon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/avatars/dragon.jpg
--------------------------------------------------------------------------------
/teamoji/app/images/avatars/koala.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/avatars/koala.jpg
--------------------------------------------------------------------------------
/teamoji/app/images/avatars/monkey.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/avatars/monkey.jpg
--------------------------------------------------------------------------------
/teamoji/app/images/avatars/octopus.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/avatars/octopus.jpg
--------------------------------------------------------------------------------
/teamoji/app/images/avatars/sheep.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/avatars/sheep.jpg
--------------------------------------------------------------------------------
/teamoji/app/images/avatars/tiger.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/avatars/tiger.jpg
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-384x384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-384x384.png
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-512x512.png
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-72x72.png
--------------------------------------------------------------------------------
/teamoji/app/images/icons/icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mbleigh/pwas-on-firebase/cda0de6f58d983290d4ec17015c3d1ee45f526da/teamoji/app/images/icons/icon-96x96.png
--------------------------------------------------------------------------------
/teamoji/app/index.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Teamoji
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/teamoji/app/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Teamoji Team Status",
3 | "short_name": "Teamoji",
4 | "theme_color": "#ffd54f",
5 | "background_color": "#2196f3",
6 | "display": "standalone",
7 | "orientation": "portrait",
8 | "Scope": "/",
9 | "start_url": "/",
10 | "icons": [
11 | {
12 | "src": "images/icons/icon-72x72.png",
13 | "sizes": "72x72",
14 | "type": "image/png"
15 | },
16 | {
17 | "src": "images/icons/icon-96x96.png",
18 | "sizes": "96x96",
19 | "type": "image/png"
20 | },
21 | {
22 | "src": "images/icons/icon-128x128.png",
23 | "sizes": "128x128",
24 | "type": "image/png"
25 | },
26 | {
27 | "src": "images/icons/icon-144x144.png",
28 | "sizes": "144x144",
29 | "type": "image/png"
30 | },
31 | {
32 | "src": "images/icons/icon-152x152.png",
33 | "sizes": "152x152",
34 | "type": "image/png"
35 | },
36 | {
37 | "src": "images/icons/icon-192x192.png",
38 | "sizes": "192x192",
39 | "type": "image/png"
40 | },
41 | {
42 | "src": "images/icons/icon-384x384.png",
43 | "sizes": "384x384",
44 | "type": "image/png"
45 | },
46 | {
47 | "src": "images/icons/icon-512x512.png",
48 | "sizes": "512x512",
49 | "type": "image/png"
50 | }
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/teamoji/app/robots.txt:
--------------------------------------------------------------------------------
1 | # www.robotstxt.org
2 |
3 | User-agent: *
4 | Disallow:
5 |
--------------------------------------------------------------------------------
/teamoji/app/scripts/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2016 Google, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | (function(document) {
17 | 'use strict';
18 |
19 | window.app = document.getElementById('app');
20 | })(document);
21 |
--------------------------------------------------------------------------------
/teamoji/app/scripts/service-worker-registration.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2016 Google, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /* eslint-env browser */
18 | 'use strict';
19 |
20 | if ('serviceWorker' in navigator) {
21 | // Your service-worker.js *must* be located at the top-level directory relative to your site.
22 | // It won't be able to control pages unless it's located at the same level or higher than them.
23 | // *Don't* register service worker file in, e.g., a scripts/ sub-directory!
24 | // See https://github.com/slightlyoff/ServiceWorker/issues/468
25 | navigator.serviceWorker.register('/service-worker.js').then(function(reg) {
26 | // updatefound is fired if service-worker.js changes.
27 | reg.onupdatefound = function() {
28 | // The updatefound event implies that reg.installing is set; see
29 | // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
30 | var installingWorker = reg.installing;
31 |
32 | installingWorker.onstatechange = function() {
33 | switch (installingWorker.state) {
34 | case 'installed':
35 | if (navigator.serviceWorker.controller) {
36 | app.toast('A new version of Teamoji is available. Refresh', 5000);
37 | } else {
38 | app.toast('Teamoji is now offline ready!');
39 | }
40 | break;
41 |
42 | case 'redundant':
43 | console.error('The installing service worker became redundant.');
44 | break;
45 | }
46 | };
47 | };
48 | }).catch(function(e) {
49 | console.error('Error during service worker registration:', e);
50 | });
51 | }
52 |
--------------------------------------------------------------------------------
/teamoji/app/styles/app-theme.html:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
234 |
--------------------------------------------------------------------------------
/teamoji/app/styles/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
3 | This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
4 | The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
5 | The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
6 | Code distributed by Google as part of the polymer project is also
7 | subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
8 | */
9 |
10 | body {
11 | /* --paper-amber-200 */
12 | background: #ffecb3;
13 | font-family: 'Varela Round', 'Helvetica Neue', Helvetica, Arial, sans-serif;
14 | color: #333;
15 | }
16 |
17 | paper-toast a {
18 | color: #ffecb3;
19 | font-weight: bold;
20 | }
21 |
--------------------------------------------------------------------------------
/teamoji/app/styles/shared-styles.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/teamoji/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "polymer-starter-kit",
3 | "private": true,
4 | "dependencies": {
5 | "iron-elements": "PolymerElements/iron-elements#^1.0.0",
6 | "neon-elements": "PolymerElements/neon-elements#^1.0.0",
7 | "page": "visionmedia/page.js#~1.6.4",
8 | "paper-elements": "PolymerElements/paper-elements#^1.0.1",
9 | "platinum-elements": "PolymerElements/platinum-elements#^1.1.0",
10 | "polymer": "Polymer/polymer#^1.4.0",
11 | "polymerfire": "firebase/polymerfire.git",
12 | "app-layout": "PolymerLabs/app-layout#^0.0.14",
13 | "neon-animation": "PolymerElements/neon-animation#^1.2.0",
14 | "iron-selector": "PolymerElements/iron-selector#master",
15 | "time-elements": "~0.4.0"
16 | },
17 | "devDependencies": {},
18 | "ignore": [],
19 | "resolutions": {
20 | "iron-selector": "master"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/teamoji/database.rules.json:
--------------------------------------------------------------------------------
1 | {
2 | "domains": {
3 | "$domain": {
4 | ".read": "auth.email.endsWith('@' + $domain.replace(',', '.'))",
5 | "updates": {
6 | "$team": {
7 | ".indexOn": ["updated"],
8 | "$uid": {
9 | ".write": "auth.uid === $uid && auth.email.endsWith('@' + $domain.replace(',', '.'))"
10 | }
11 | }
12 | },
13 | "teams": {
14 | "$team": {
15 | ".write": "auth.email.endsWith('@' + $domain.replace(',', '.'))",
16 | "id": {
17 | ".validate": "newData.val() === $team"
18 | }
19 | }
20 | },
21 | "history": {
22 | "$team": {
23 | "$uid": {
24 | "$updateId": {
25 | ".write": "auth.uid === $uid && auth.email.endsWith('@' + $domain.replace(',', '.'))"
26 | }
27 | }
28 | }
29 | }
30 | }
31 | },
32 | "prefs": {
33 | "$uid": {
34 | ".read": "auth.uid === $uid",
35 | ".write": "auth.uid === $uid"
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/teamoji/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "database": {
3 | "rules": "database.rules.json"
4 | },
5 | "hosting": {
6 | "public": "dist",
7 | "rewrites": [
8 | {
9 | "source": "!{/__,/bower_components,/elements,/images,/scripts,/styles}/**",
10 | "destination": "/index.html"
11 | }
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/teamoji/gulpfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2016 Google, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | 'use strict';
18 |
19 | // Include Gulp & tools we'll use
20 | var gulp = require('gulp');
21 | var $ = require('gulp-load-plugins')();
22 | var del = require('del');
23 | var runSequence = require('run-sequence');
24 | var browserSync = require('browser-sync');
25 | var reload = browserSync.reload;
26 | var merge = require('merge-stream');
27 | var path = require('path');
28 | var fs = require('fs');
29 | var glob = require('glob-all');
30 | var superstatic = require('superstatic');
31 | var fbConfig = require('./firebase.json');
32 | var packageJson = require('./package.json');
33 | var crypto = require('crypto');
34 | var ensureFiles = require('./tasks/ensure-files.js');
35 |
36 | // var ghPages = require('gulp-gh-pages');
37 |
38 | var AUTOPREFIXER_BROWSERS = [
39 | 'ie >= 10',
40 | 'ie_mob >= 10',
41 | 'ff >= 30',
42 | 'chrome >= 34',
43 | 'safari >= 7',
44 | 'opera >= 23',
45 | 'ios >= 7',
46 | 'android >= 4.4',
47 | 'bb >= 10'
48 | ];
49 |
50 | var DIST = 'dist';
51 |
52 | var dist = function(subpath) {
53 | return !subpath ? DIST : path.join(DIST, subpath);
54 | };
55 |
56 | var styleTask = function(stylesPath, srcs) {
57 | return gulp.src(srcs.map(function(src) {
58 | return path.join('app', stylesPath, src);
59 | }))
60 | .pipe($.changed(stylesPath, {extension: '.css'}))
61 | .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
62 | .pipe(gulp.dest('.tmp/' + stylesPath))
63 | .pipe($.minifyCss())
64 | .pipe(gulp.dest(dist(stylesPath)))
65 | .pipe($.size({title: stylesPath}));
66 | };
67 |
68 | var imageOptimizeTask = function(src, dest) {
69 | return gulp.src(src)
70 | .pipe($.imagemin({
71 | progressive: true,
72 | interlaced: true
73 | }))
74 | .pipe(gulp.dest(dest))
75 | .pipe($.size({title: 'images'}));
76 | };
77 |
78 | var optimizeHtmlTask = function(src, dest) {
79 | var assets = $.useref.assets({
80 | searchPath: ['.tmp', 'app']
81 | });
82 |
83 | return gulp.src(src)
84 | .pipe(assets)
85 | // Concatenate and minify JavaScript
86 | .pipe($.if('*.js', $.uglify({
87 | preserveComments: 'some'
88 | })))
89 | // Concatenate and minify styles
90 | // In case you are still using useref build blocks
91 | .pipe($.if('*.css', $.minifyCss()))
92 | .pipe(assets.restore())
93 | .pipe($.useref())
94 | // Minify any HTML
95 | .pipe($.if('*.html', $.minifyHtml({
96 | quotes: true,
97 | empty: true,
98 | spare: true
99 | })))
100 | // Output files
101 | .pipe(gulp.dest(dest))
102 | .pipe($.size({
103 | title: 'html'
104 | }));
105 | };
106 |
107 | // Compile and automatically prefix stylesheets
108 | gulp.task('styles', function() {
109 | return styleTask('styles', ['**/*.css']);
110 | });
111 |
112 | gulp.task('elements', function() {
113 | return styleTask('elements', ['**/*.css']);
114 | });
115 |
116 | // Ensure that we are not missing required files for the project
117 | // "dot" files are specifically tricky due to them being hidden on
118 | // some systems.
119 | gulp.task('ensureFiles', function(cb) {
120 | var requiredFiles = ['.bowerrc'];
121 |
122 | ensureFiles(requiredFiles.map(function(p) {
123 | return path.join(__dirname, p);
124 | }), cb);
125 | });
126 |
127 | // Optimize images
128 | gulp.task('images', function() {
129 | return imageOptimizeTask('app/images/**/*', dist('images'));
130 | });
131 |
132 | // Copy all files at the root level (app)
133 | gulp.task('copy', function() {
134 | var app = gulp.src([
135 | 'app/*',
136 | 'app/data/emoji.json',
137 | '!app/test',
138 | '!app/elements',
139 | '!app/bower_components',
140 | '!**/.DS_Store'
141 | ], {
142 | dot: true
143 | }).pipe(gulp.dest(dist()));
144 |
145 | var data = gulp.src('app/data/emoji.json').pipe(gulp.dest(dist('data')));
146 |
147 | // Copy over only the bower_components we need
148 | // These are things which cannot be vulcanized
149 | var bower = gulp.src([
150 | 'app/bower_components/{webcomponentsjs,promise-polyfill,app-storage}/**/*.js'
151 | ]).pipe(gulp.dest(dist('bower_components')));
152 |
153 | return merge(app, bower, data)
154 | .pipe($.size({
155 | title: 'copy'
156 | }));
157 | });
158 |
159 | // Copy web fonts to dist
160 | gulp.task('fonts', function() {
161 | return gulp.src(['app/fonts/**'])
162 | .pipe(gulp.dest(dist('fonts')))
163 | .pipe($.size({
164 | title: 'fonts'
165 | }));
166 | });
167 |
168 | // Scan your HTML for assets & optimize them
169 | gulp.task('html', function() {
170 | return optimizeHtmlTask(
171 | ['app/**/*.html', '!app/{elements,test,bower_components}/**/*.html'],
172 | dist());
173 | });
174 |
175 | // Vulcanize granular configuration
176 | gulp.task('vulcanize', function() {
177 | return gulp.src('app/elements/elements.html')
178 | .pipe($.vulcanize({
179 | stripComments: true,
180 | inlineCss: true,
181 | inlineScripts: true
182 | }))
183 | .pipe(gulp.dest(dist('elements')))
184 | .pipe($.size({title: 'vulcanize'}));
185 | });
186 |
187 | gulp.task('generate-dev-service-worker', function(callback) {
188 | var dir = 'app';
189 | var swPrecache = require('sw-precache');
190 |
191 | swPrecache.write(path.join('.tmp', 'service-worker.js'), {
192 | cacheId: packageJson.name,
193 | staticFileGlobs: [
194 | dir + '/**/*.{js,html,css,png,svg,jpg,gif}',
195 | dir + '/data/emoji.json'
196 | ],
197 | stripPrefix: dir,
198 | logger: $.util.log,
199 | runtimeCaching: [{
200 | // cache Google Web Fonts (both css and font files)
201 | urlPattern: /^https:\/\/fonts.(?:googleapis|gstatic).com\/.*/,
202 | handler: 'cacheFirst'
203 | },
204 | {
205 | // cache Google user profile pics
206 | urlPattern: /^https:\/\/lh3.googleusercontent.com\/.*/,
207 | handler: 'networkFirst'
208 | },
209 | {
210 | // cache Firebase Storage data
211 | urlPattern: /^https:\/\/storage.googleapis.com\/teamoji-app.appspot.com\/.*/,
212 | handler: 'networkFirst'
213 | }]
214 | }, callback);
215 | });
216 |
217 | gulp.task('generate-service-worker', function(callback) {
218 | var dir = dist();
219 | var swPrecache = require('sw-precache');
220 |
221 | swPrecache.write(path.join(dir, 'service-worker.js'), {
222 | cacheId: packageJson.name,
223 | staticFileGlobs: [
224 | dir + '/**/*.{js,html,css,png,svg,jpg,gif}',
225 | dir + '/data/emoji.json'
226 | ],
227 | stripPrefix: dir,
228 | logger: $.util.log,
229 | verbose: true,
230 | runtimeCaching: [{
231 | // cache Google Web Fonts (both css and font files)
232 | urlPattern: /^https:\/\/fonts.(?:googleapis|gstatic).com\/.*/,
233 | handler: 'cacheFirst'
234 | },
235 | {
236 | // cache Google user profile pics
237 | urlPattern: /^https:\/\/lh3.googleusercontent.com\/.*/,
238 | handler: 'networkFirst'
239 | },
240 | {
241 | // cache Firebase Storage data
242 | urlPattern: /^https:\/\/storage.googleapis.com\/teamoji-app.appspot.com\/.*/,
243 | handler: 'networkFirst'
244 | }]
245 | }, callback);
246 | });
247 |
248 | // Clean output directory
249 | gulp.task('clean', function() {
250 | return del(['.tmp', dist()]);
251 | });
252 |
253 | // Watch files for changes & reload
254 | gulp.task('serve', ['styles', 'elements', 'generate-dev-service-worker'], function() {
255 | browserSync({
256 | port: 5000,
257 | notify: false,
258 | logPrefix: 'PSK',
259 | snippetOptions: {
260 | rule: {
261 | match: '',
262 | fn: function(snippet) {
263 | return snippet;
264 | }
265 | }
266 | },
267 | // Run as an https by uncommenting 'https: true'
268 | // Note: this uses an unsigned certificate which on first access
269 | // will present a certificate warning in the browser.
270 | // https: true,
271 | server: {
272 | baseDir: ['app'],
273 | middleware: [superstatic({
274 | config: Object.assign({}, fbConfig.hosting, {public: ['.tmp', 'app']})
275 | })]
276 | }
277 | });
278 |
279 | gulp.watch(['app/**/*.html'], ['generate-dev-service-worker', reload]);
280 | gulp.watch(['app/styles/**/*.css'], ['styles', 'generate-dev-service-worker', reload]);
281 | gulp.watch(['app/elements/**/*.css'], ['elements', 'generate-dev-service-worker', reload]);
282 | gulp.watch(['app/images/**/*'], ['generate-dev-service-worker', reload]);
283 | });
284 |
285 | // Build and serve the output from the dist build
286 | gulp.task('serve:dist', ['default'], function() {
287 | browserSync({
288 | port: 5001,
289 | notify: false,
290 | logPrefix: 'PSK',
291 | snippetOptions: {
292 | rule: {
293 | match: '',
294 | fn: function(snippet) {
295 | return snippet;
296 | }
297 | }
298 | },
299 | // Run as an https by uncommenting 'https: true'
300 | // Note: this uses an unsigned certificate which on first access
301 | // will present a certificate warning in the browser.
302 | // https: true,
303 | server: dist(),
304 | middleware: [superstatic({config: Object.assign({}, fbConfig.hosting, {public: 'dist'})})]
305 | });
306 | });
307 |
308 | // Build production files, the default task
309 | gulp.task('default', ['clean'], function(cb) {
310 | runSequence(
311 | ['ensureFiles', 'copy', 'styles'],
312 | 'elements',
313 | ['images', 'fonts', 'html'],
314 | 'vulcanize',
315 | 'generate-service-worker',
316 | cb);
317 | });
318 |
319 | // Load custom tasks from the `tasks` directory
320 | try {
321 | require('require-dir')('tasks');
322 | } catch (err) {}
323 |
--------------------------------------------------------------------------------
/teamoji/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "teamoji",
3 | "private": true,
4 | "devDependencies": {
5 | "browser-sync": "^2.7.7",
6 | "connect-history-api-fallback": "^1.1.0",
7 | "del": "^2.0.2",
8 | "firebase": "^3.0",
9 | "glob-all": "^3.0.1",
10 | "gulp": "^3.8.5",
11 | "gulp-autoprefixer": "^3.1.0",
12 | "gulp-cache": "^0.4.0",
13 | "gulp-changed": "^1.0.0",
14 | "gulp-gh-pages": "^0.5.4",
15 | "gulp-html-extract": "^0.1.0",
16 | "gulp-if": "^2.0.0",
17 | "gulp-imagemin": "^2.2.1",
18 | "gulp-load-plugins": "^1.1.0",
19 | "gulp-minify-css": "^1.2.1",
20 | "gulp-minify-html": "^1.0.2",
21 | "gulp-rename": "^1.2.0",
22 | "gulp-replace": "^0.5.4",
23 | "gulp-size": "^2.0.0",
24 | "gulp-uglify": "^1.2.0",
25 | "gulp-useref": "^2.1.0",
26 | "gulp-util": "^3.0.7",
27 | "gulp-vulcanize": "^6.0.0",
28 | "merge-stream": "^1.0.0",
29 | "require-dir": "^0.3.0",
30 | "run-sequence": "^1.0.2",
31 | "superstatic": "^4.0.2",
32 | "vulcanize": ">= 1.4.2",
33 | "xml2js": "^0.4.16"
34 | },
35 | "scripts": {
36 | "test": "gulp test:local",
37 | "start": "gulp serve"
38 | },
39 | "engines": {
40 | "node": ">=0.10.0"
41 | },
42 | "dependencies": {
43 | "sw-precache": "^3.1.1"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/teamoji/scripts/fake-usage:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var firebase = require('firebase');
4 | var WHITELIST = '1f638 1f642 1f989 1f984 1f451 1f426 1f355 1f363 1f369 1f60e 1f44d 1f32e 1f6eb 1f4f4 1f3a5 1f6b4 1f6cc 1f6cd 1f42c 1f302 1f487 1f635 1f634 2603 270f 1f680 1f697 1f687 1f575 1f64c'.split(' ');
5 | var TEAMS = ['firebase'];
6 | var USERS = [
7 | {id: 'sheep', name: 'Baa Ramu', pic: '/images/avatars/sheep.jpg'},
8 | {id: 'dragon', name: 'Drogon Targaryan', pic: '/images/avatars/dragon.jpg'},
9 | {id: 'tiger', name: 'Rory Felis', pic: '/images/avatars/tiger.jpg'},
10 | {id: 'monkey', name: 'Gunther Farnsworth', pic: '/images/avatars/monkey.jpg'},
11 | {id: 'koala', name: 'Eu Calyptus', pic: '/images/avatars/koala.jpg'},
12 | {id: 'bunny', name: 'Bugs Hoppy', pic: '/images/avatars/bunny.jpg'},
13 | {id: 'octopus', name: 'Armand Yeats', pic: '/images/avatars/octopus.jpg'}
14 | ];
15 | var IMG_PREFIX = 'https://storage.googleapis.com/teamoji-app.appspot.com/emoji/svg/emoji_u';
16 |
17 | firebase.initializeApp({
18 | serviceAccount: __dirname + '/data/service-account.json',
19 | databaseURL: 'https://teamoji-app.firebaseio.com'
20 | });
21 |
22 | var db = firebase.database();
23 | var domainRef = db.ref('domains/google,com');
24 |
25 | function randomFrom(arr) {
26 | return arr[Math.floor(Math.random()*arr.length)];
27 | }
28 |
29 | function nextUpdate() {
30 | var time = Math.random() * 15000 + 5000;
31 | console.log('Updating next in', (time / 1000.0) + 's');
32 | return time;
33 | }
34 |
35 | function randomUpdate() {
36 | var user = randomFrom(USERS);
37 | var team = randomFrom(TEAMS);
38 | var emoji = randomFrom(WHITELIST);
39 | domainRef.child('updates')
40 | .child(team)
41 | .child(user.id)
42 | .set({
43 | name: user.name,
44 | pic: user.pic,
45 | updated: firebase.database.ServerValue.TIMESTAMP,
46 | emoji: IMG_PREFIX + emoji + '.svg'
47 | }).then(function() {
48 | console.log('Updating', user.name, 'to', emoji);
49 | return setTimeout(randomUpdate, nextUpdate());
50 | });
51 | }
52 |
53 | randomUpdate();
54 |
--------------------------------------------------------------------------------
/teamoji/scripts/parse-emoji:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /*
4 | Copyright 2016 Google, Inc.
5 |
6 | Licensed under the Apache License, Version 2.0 (the "License");
7 | you may not use this file except in compliance with the License.
8 | You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing, software
13 | distributed under the License is distributed on an "AS IS" BASIS,
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | See the License for the specific language governing permissions and
16 | limitations under the License.
17 | */
18 |
19 | var parseString = require('xml2js').parseString;
20 | var fs = require('fs');
21 |
22 | var codePointAt = function(position) {
23 | if (this == null) {
24 | throw TypeError();
25 | }
26 | var string = String(this);
27 | var size = string.length;
28 | // `ToInteger`
29 | var index = position ? Number(position) : 0;
30 | if (index != index) { // better `isNaN`
31 | index = 0;
32 | }
33 | // Account for out-of-bounds indices:
34 | if (index < 0 || index >= size) {
35 | return undefined;
36 | }
37 | // Get the first code unit
38 | var first = string.charCodeAt(index);
39 | var second;
40 | if ( // check if it’s the start of a surrogate pair
41 | first >= 0xD800 && first <= 0xDBFF && // high surrogate
42 | size > index + 1 // there is a next code unit
43 | ) {
44 | second = string.charCodeAt(index + 1);
45 | if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
46 | // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
47 | return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
48 | }
49 | }
50 | return first;
51 | };
52 | if (Object.defineProperty) {
53 | Object.defineProperty(String.prototype, 'codePointAt', {
54 | 'value': codePointAt,
55 | 'configurable': true,
56 | 'writable': true
57 | });
58 | } else {
59 | String.prototype.codePointAt = codePointAt;
60 | }
61 |
62 | parseString(fs.readFileSync(__dirname + '/data/emoji_annotations.xml', 'utf8'), function(err, data) {
63 | var data = data.ldml.annotations[0].annotation.map(function(annotation) {
64 | var code = annotation.$.cp.codePointAt(1).toString(16);
65 | try {
66 | fs.statSync(process.env.HOME + '/Downloads/noto-emoji/svg/emoji_u' + code + '.svg')
67 | return {
68 | desc: annotation.$.tts,
69 | tags: annotation._.split('; '),
70 | code: code,
71 | urls: {
72 | svg: 'https://storage.googleapis.com/teamoji-app.appspot.com/emoji/svg/emoji_u' + code + '.svg'
73 | }
74 | };
75 | } catch (e) {
76 | process.stderr.write('- missing "' + annotation.$.tts + '"\n');
77 | }
78 | }).filter(function(entry) {
79 | return !!entry;
80 | });
81 |
82 | console.log(JSON.stringify(data, null, 2));
83 | });
84 |
--------------------------------------------------------------------------------
/teamoji/tasks/ensure-files.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2016 Google, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | var fs = require('fs');
17 |
18 | /**
19 | * @param {Array} files
20 | * @param {Function} cb
21 | */
22 |
23 | function ensureFiles(files, cb) {
24 | var missingFiles = files.reduce(function(prev, filePath) {
25 | var fileFound = false;
26 |
27 | try {
28 | fileFound = fs.statSync(filePath).isFile();
29 | } catch (e) { }
30 |
31 | if (!fileFound) {
32 | prev.push(filePath + ' Not Found');
33 | }
34 |
35 | return prev;
36 | }, []);
37 |
38 | if (missingFiles.length) {
39 | var err = new Error('Missing Required Files\n' + missingFiles.join('\n'));
40 | }
41 |
42 | if (cb) {
43 | cb(err);
44 | } else if (err) {
45 | throw err;
46 | }
47 | }
48 |
49 | module.exports = ensureFiles;
50 |
--------------------------------------------------------------------------------
/teamoji/travis-runner.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | # Copyright 2016 Google, Inc.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | set -o pipefail
18 |
19 | if [ "$TRAVIS_BRANCH" = "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_NODE_VERSION" = "5.1" ]
20 | then
21 | git config --global user.email "samccone@gmail.com"
22 | git config --global user.name "auto deployer"
23 |
24 | # Stamp index.html with the date and time of PSK's deploying
25 | date_value=`date`
26 | sed -i.tmp1 "s/This is another card./This is another card. PSK Deployed on: $date_value/" app/index.html
27 |
28 | deploy_ghpages () {
29 | # Deploying to GitHub Pages! (http://polymerelements.github.io/polymer-starter-kit)
30 | echo Deploying to GitHub Pages
31 | sed -i.tmp "s/\/\/ app.baseUrl = '\/polymer-starter-kit/app.baseUrl = '\/polymer-starter-kit/" app/scripts/app.js
32 | sed -i.tmp2 "s/<\/head>/\ \