diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/pwa/https.py b/pwa/https.py new file mode 100644 index 0000000..267aa0d --- /dev/null +++ b/pwa/https.py @@ -0,0 +1,14 @@ +# taken from http://www.piware.de/2011/01/creating-an-https-server-in-python/ +# generate server.xml with the following command: +# openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes +# run as follows: +# python simple-https-server.py +# then in your browser, visit: +# https://localhost:4443 + +import BaseHTTPServer, SimpleHTTPServer +import ssl + +httpd = BaseHTTPServer.HTTPServer(('localhost', 4443), SimpleHTTPServer.SimpleHTTPRequestHandler) +httpd.socket = ssl.wrap_socket (httpd.socket, certfile='./server.pem', server_side=True) +httpd.serve_forever() diff --git a/pwa/index.html b/pwa/index.html new file mode 100644 index 0000000..40bd7c8 --- /dev/null +++ b/pwa/index.html @@ -0,0 +1,67 @@ + + + + + + + Vue.js • TodoMVC + + + + + + +
+
+

todos

+ +
+
+ + +
+ +
+ + + + + + + + + + + diff --git a/pwa/js/app.js b/pwa/js/app.js new file mode 100644 index 0000000..eb06021 --- /dev/null +++ b/pwa/js/app.js @@ -0,0 +1,143 @@ +/*global Vue, todoStorage */ + +(function (exports) { + + 'use strict'; + + var filters = { + all: function (todos) { + return todos; + }, + active: function (todos) { + return todos.filter(function (todo) { + return !todo.completed; + }); + }, + completed: function (todos) { + return todos.filter(function (todo) { + return todo.completed; + }); + } + }; + + exports.app = new Vue({ + + // the root element that will be compiled + el: '.todoapp', + + // app initial state + data: { + todos: todoStorage.fetch(), + newTodo: '', + editedTodo: null, + visibility: 'all' + }, + // watch todos change for localStorage persistence + watch: { + todos: { + deep: true, + handler: todoStorage.save + } + }, + + // computed properties + // http://vuejs.org/guide/computed.html + computed: { + filteredTodos: function () { + return filters[this.visibility](this.todos); + }, + remaining: function () { + return filters.active(this.todos).length; + }, + allDone: { + get: function () { + return this.remaining === 0; + }, + set: function (value) { + this.todos.forEach(function (todo) { + todo.completed = value; + }); + } + } + }, + mounted: function() { + this.sync(); + }, + // methods that implement data logic. + // note there's no DOM manipulation here at all. + methods: { + + pluralize: function (word, count) { + return word + (count === 1 ? '' : 's'); + }, + + addTodo: function () { + var value = this.newTodo && this.newTodo.trim(); + if (!value) { + return; + } + this.todos.push({ title: value, completed: false, pendingOnlineCreation: true }); + this.newTodo = ''; + }, + + removeTodo: function (todo) { + var index = this.todos.indexOf(todo); + this.todos.splice(index, 1); + }, + + editTodo: function (todo) { + this.beforeEditCache = todo.title; + this.editedTodo = todo; + }, + + doneEdit: function (todo) { + if (!this.editedTodo) { + return; + } + this.editedTodo = null; + todo.title = todo.title.trim(); + if (!todo.title) { + this.removeTodo(todo); + } + }, + + cancelEdit: function (todo) { + this.editedTodo = null; + todo.title = this.beforeEditCache; + }, + + removeCompleted: function () { + this.todos = filters.active(this.todos); + }, + + sync: function () { + Promise.all( + todoStorage + .fetch() + .filter((todo) => todo.pendingOnlineCreation) + .map(({ title, completed }) => { + return axios.post( + 'https://4b6aadd7.ngrok.io/todos', { title, completed } + ); + }) + ).then(() => { + axios.get('https://4b6aadd7.ngrok.io/todos').then(({ data }) => { + this.todos = data + }); + }); + } + }, + + // a custom directive to wait for the DOM to be updated + // before focusing on the input field. + // http://vuejs.org/guide/custom-directive.html + directives: { + 'todo-focus': function (el, binding) { + if (binding.value) { + el.focus(); + } + } + } + }); + +})(window); diff --git a/pwa/js/routes.js b/pwa/js/routes.js new file mode 100644 index 0000000..b555605 --- /dev/null +++ b/pwa/js/routes.js @@ -0,0 +1,24 @@ +/*global app, Router */ + +(function (app, Router) { + + 'use strict'; + + var router = new Router(); + + ['all', 'active', 'completed'].forEach(function (visibility) { + router.on(visibility, function () { + app.visibility = visibility; + }); + }); + + router.configure({ + notfound: function () { + window.location.hash = ''; + app.visibility = 'all'; + } + }); + + router.init(); + +})(app, Router); diff --git a/pwa/js/store.js b/pwa/js/store.js new file mode 100644 index 0000000..4a4b12b --- /dev/null +++ b/pwa/js/store.js @@ -0,0 +1,18 @@ +/*jshint unused:false */ + +(function (exports) { + + 'use strict'; + + var STORAGE_KEY = 'todos-vuejs'; + + exports.todoStorage = { + fetch: function () { + return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]'); + }, + save: function (todos) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)); + } + }; + +})(window); diff --git a/pwa/learn.json b/pwa/learn.json new file mode 100644 index 0000000..e69de29 diff --git a/pwa/manifest.webmanifest b/pwa/manifest.webmanifest new file mode 100644 index 0000000..a9a7b41 --- /dev/null +++ b/pwa/manifest.webmanifest @@ -0,0 +1,38 @@ +{ + "name": "Whatsapp clone", + "short_name": "Whatsapp clone", + "start_url": "/", + "display": "standalone", + "background_color": "#fff", + "description": "Another todo list", + "theme_color": "#000000", + "icons": [{ + "src": "https://image.freepik.com/free-icon/whatsapp-logo_318-49685.jpg", + "sizes": "48x48", + "type": "image/png" + }, { + "src": "https://image.freepik.com/free-icon/whatsapp-logo_318-49685.jpg", + "sizes": "72x72", + "type": "image/png" + }, { + "src": "https://image.freepik.com/free-icon/whatsapp-logo_318-49685.jpg", + "sizes": "96x96", + "type": "image/png" + }, { + "src": "https://image.freepik.com/free-icon/whatsapp-logo_318-49685.jpg", + "sizes": "144x144", + "type": "image/png" + }, { + "src": "https://image.freepik.com/free-icon/whatsapp-logo_318-49685.jpg", + "sizes": "168x168", + "type": "image/png" + }, { + "src": "https://image.freepik.com/free-icon/whatsapp-logo_318-49685.jpg", + "sizes": "192x192", + "type": "image/png" + }, { + "src": "https://image.freepik.com/free-icon/whatsapp-logo_318-49685.jpg", + "sizes": "512x512", + "type": "image/png" + }] +} diff --git a/pwa/package-lock.json b/pwa/package-lock.json new file mode 100644 index 0000000..fdaf407 --- /dev/null +++ b/pwa/package-lock.json @@ -0,0 +1,61 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "axios": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", + "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", + "requires": { + "follow-redirects": "1.2.6", + "is-buffer": "1.1.6" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "director": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/director/-/director-1.2.8.tgz", + "integrity": "sha1-xtm03YkOmv9TZRg/6cyOc5lM8tU=" + }, + "follow-redirects": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.6.tgz", + "integrity": "sha512-FrMqZ/FONtHnbqO651UPpfRUVukIEwJhXMfdr/JWAmrDbeYBu773b1J6gdWDyRIj4hvvzQEHoEOTrdR8o6KLYA==", + "requires": { + "debug": "3.1.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "todomvc-app-css": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/todomvc-app-css/-/todomvc-app-css-2.1.0.tgz", + "integrity": "sha1-tvJxbTOa+i5feZNH0qSLBTliQqU=" + }, + "todomvc-common": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/todomvc-common/-/todomvc-common-1.0.4.tgz", + "integrity": "sha512-AA0Z4exovEqubhbZCrzzn9roVT4zvOncS319p2zIc4CsNe5B9TLL7Sei1NIV6d+WrgR5rOi+y0I9Y6GE7xgNOw==" + }, + "vue": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.8.tgz", + "integrity": "sha512-aY26SGDHJTCKM+mndzuiQ0dozPpNeWO5Mtq760OrHO0AOiqVHMhzvU5h0LdCkVF9A+vE+DMTm74xSi+sxnMEDg==" + } + } +} diff --git a/pwa/package.json b/pwa/package.json new file mode 100644 index 0000000..8aafc00 --- /dev/null +++ b/pwa/package.json @@ -0,0 +1,10 @@ +{ + "private": true, + "dependencies": { + "axios": "^0.17.1", + "director": "^1.2.0", + "todomvc-app-css": "^2.0.0", + "todomvc-common": "^1.0.1", + "vue": "^2.1.8" + } +} diff --git a/pwa/readme.md b/pwa/readme.md new file mode 100644 index 0000000..de50031 --- /dev/null +++ b/pwa/readme.md @@ -0,0 +1,29 @@ +# Vue.js TodoMVC Example + +> Vue.js is a library for building interactive web interfaces. +It provides data-driven, nestable view components with a simple and flexible API. + +> _[Vue.js - vuejs.org](http://vuejs.org)_ + +## Learning Vue.js + +The [Vue.js website](http://vuejs.org/) is a great resource to get started. + +Here are some links you may find helpful: + +* [Official Guide](http://vuejs.org/guide/) +* [API Reference](http://vuejs.org/api/) +* [Examples](http://vuejs.org/examples/) +* [Building Larger Apps with Vue.js](http://v1.vuejs.org/guide/application.html) + +Get help from other Vue.js users: + +* [Vue.js on Twitter](https://twitter.com/vuejs) +* [Vue.js on Gitter](https://gitter.im/vuejs/vue) +* [Vue.js Forum](http://forum.vuejs.org) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + +## Credit + +This TodoMVC application was created by [Evan You](http://evanyou.me). diff --git a/pwa/server.pem b/pwa/server.pem new file mode 100644 index 0000000..9235471 --- /dev/null +++ b/pwa/server.pem @@ -0,0 +1,49 @@ +-----BEGIN PRIVATE KEY----- +MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC9I5+qzbL+J0Sr +bc/DL1blFt1zB5b2voqydY1qtV8pJL/Ss3P9cIq1sndalJHc3Al7sqoPqwEZpsJQ +W5pumpboHAI0ta9s90c4eMb42mJxCF0OWH7mEJDTGZ5fWrzxL2sV1FKtKEo7jV36 +nndYbWINKo/mdMznCdDVHHBHIFSCvenJ/Z524C7NE+HoLPTB9b2p1YCRWoFnjQ7Z +KKY4cFu7r41mFFB1WDONQU41uZsqQe64sh3EIwfh3NKdNewbWXK0aol8M08D/NpW +49ow+5Kn73uVfaiH1btrxR479ri8osJmlqi6FBga8vCA8TSLB934SoSnA4X0d4rM +KliR0hgFAgMBAAECggEBAIL/fGPhilprOi19pgtq60VKO+Ci3hVRzWBi+KpyqlEl +ydIWRny/iOLlk7Lh+dC9ebf5+71UVDO/AxCDEYgPe/uRApodSD4xWlurkyvinZHq +GAGKm4Ge8Z+0O7ORdhGaJRH+d7DEmf17IR8myEQvply2IOqd9RkD/GbOBpnMs5vE +2l7IAm6XVZu9Ps80xbnaPD/Hdm0tXQbi9Ru6IcQ6VlB3ih3Z3RP69VTOu3WWBA3i +dtsess1hOIxST4F9LZDd/NyvIQ86hsV0/IRVXB4YwPOWb4w1Ec4bPh74h5DQwLm/ +SiOjrAtm7xSY029tTpICU9iTonj25mhkUT/25CsF1ZUCgYEA5gLh6xUHjT3VxynS +UDK2bgT0w1Je/Rw3LuwMhNtFve4TJMWNJpZSCG4nFp3Hs4XRb85tTdQziVEn76PM +uFymrnIPt8VjIaMSXzz3Jn36lAI3kql1YdoTPNWt9DX4NId5RmKbK8T8r1xvVyKW +Zy/oZCBoVBaZvinKyQyQMA+BgDcCgYEA0oKCFgJWCdcxAWxv5mEOjzMoKV1ZS64B +XG8f8hxnMP0D2LZAwAAKLqonRaEhL5/vlh1C8iX6DXuGI3qPeV0HgHVW4NxfG93o +jsyxVvFwKYaEMPwdId8y3i5ejQBek9mR+xl3PA8OvlrKRyeQjlEyhFtI1dfbbuwh +1lOo3caBs6MCgYEAhMM9K7fjt/7tGhxlrKzY6AAsV2GAOpDCuW6+eyElzE9S9XKh +2pgBmaQbI87GqjSfgu2f4cCOTsBtUME3NWMlQqPLtsNUSOIbhKVn8uvcavosoZb2 +jhiV6hNcaQ2NyqQ3uAzKjCUTxRSRn7XzInRgqwqZrY+uBjmRNyLtRxBsK1kCgYEA +n1NLpeDKwdPvMUajQth+rn9njDcs2IywVwd8RECfEYLOIH2AcFEXY85AvwB/H46L +RTCMdL2tjfrJwZyHbrGsddtZkAL6sRq5YyslpcpCvAsljfWjDvnhhCvQQCPhcUGg +rU3O4tP6srQAmO4nCLAH7gkxDTi8yi1KRu82xfPyQsUCgYEAnmVMp7e40GrfWr31 +aViMG4Ql1tddBUFrDRedld4TsHlytu5WfH40TTOk0ofLePxtOGRPWXavhjm2PaNt +z0BuVsYIceIgkTXJx1DZkc94s96Ehp7I9HTuPvUNJpZ9+zTGuvGmidWAHWbhu9Dk +BDxk302STIbza6VkhR2p4C9ZpG4= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAPVAdy+Zo+SjMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTcxMTI1MTcyNDQyWhcNMTgxMTI1MTcyNDQyWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvSOfqs2y/idEq23Pwy9W5RbdcweW9r6KsnWNarVfKSS/0rNz/XCKtbJ3 +WpSR3NwJe7KqD6sBGabCUFuabpqW6BwCNLWvbPdHOHjG+NpicQhdDlh+5hCQ0xme +X1q88S9rFdRSrShKO41d+p53WG1iDSqP5nTM5wnQ1RxwRyBUgr3pyf2eduAuzRPh +6Cz0wfW9qdWAkVqBZ40O2SimOHBbu6+NZhRQdVgzjUFONbmbKkHuuLIdxCMH4dzS +nTXsG1lytGqJfDNPA/zaVuPaMPuSp+97lX2oh9W7a8UeO/a4vKLCZpaouhQYGvLw +gPE0iwfd+EqEpwOF9HeKzCpYkdIYBQIDAQABo1AwTjAdBgNVHQ4EFgQUWnX5qJkR +FazWToDo5ThZdnt0fBwwHwYDVR0jBBgwFoAUWnX5qJkRFazWToDo5ThZdnt0fBww +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAFxYgBtu5YtMUxyk6Z8AE +uoyP0XJ7Q7NJRSaUgS8bs9fBp7DwCb0itDwDQTFVzP4IQ8FkU2Ru8ovLNdQU0lqk +ekp4Htfs5iJ1acml9J0YrVyjHXln2FWsPOFlgdk8g5n43VYHKDVjKrDs8ZyAi0Xe +S0pH+GYeo9FhDnFt+zmLbtd1TucQFoalgad+BQBLThtR4dwWGEWqTaw0aYO0Sd/6 +m+sjQsQltz28Ks6GY/ACm2i5ah2wKv/+ve/QYJDogfGO31gYaAzrgVmvSvpoVLBq +Bre0gwfmZlNOajK6dyThZNi9Eu569junmHT4KDCWtthrWnzplugHEY/96HH3upQh +Qw== +-----END CERTIFICATE----- diff --git a/pwa/sw.js b/pwa/sw.js new file mode 100644 index 0000000..bad94a5 --- /dev/null +++ b/pwa/sw.js @@ -0,0 +1,34 @@ + +self.addEventListener('install', function (e) { + console.log(caches); + e.waitUntil( + caches.open('todos').then(function (cache) { + return cache.addAll([ + '/', + '/index.html', + '/node_modules/todomvc-common/base.css', + '/node_modules/todomvc-app-css/index.css', + '/node_modules/todomvc-common/base.js', + '/node_modules/director/build/director.js', + '/node_modules/vue/dist/vue.js', + '/node_modules/axios/dist/axios.min.js', + '/js/store.js', + '/js/app.js', + '/js/routes.js', + '/learn.json' + ]).then((x) => { + console.log('O cache acabou!!!!') + return x + }); + }) + ); +}); + +self.addEventListener('fetch', function (event) { + console.log(event.request.url); + event.respondWith( + caches.match(event.request).then(function (response) { + return response || fetch(event.request); + }) + ); +});