├── 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 | 33 | 73 | 74 | -------------------------------------------------------------------------------- /teamoji/app/elements/x-app.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 157 | 306 | 307 | -------------------------------------------------------------------------------- /teamoji/app/elements/x-create-team.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 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 | 95 | 121 | 122 | -------------------------------------------------------------------------------- /teamoji/app/elements/x-emoji-update.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 59 | 72 | 73 | -------------------------------------------------------------------------------- /teamoji/app/elements/x-login.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 100 | 131 | 132 | -------------------------------------------------------------------------------- /teamoji/app/elements/x-shade.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 32 | 79 | 80 | -------------------------------------------------------------------------------- /teamoji/app/elements/x-team-page.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 86 | 114 | 115 | -------------------------------------------------------------------------------- /teamoji/app/elements/x-update-detail.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 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 | 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>/\ \