├── LICENSE ├── README.md ├── idb.js ├── index.html └── worker.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Sandro Paganotti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Service Worker Wiki 2 | =================== 3 | 4 | Service Workers are basically like Shared Web Workers with some interesting 5 | extra abilities, one of them is that they can intercept all the http request 6 | leaving from all the documents of the same domain of the Service Worker itself. 7 | 8 | This basically transform this technology in an awesome way to have a proxy between 9 | our document and the server, the main pourpose is, of course, to allow developers 10 | to design how the application should behave when there is no connectivity. 11 | 12 | But there are other, maybe less conventional, ways to take advantage of this technology, 13 | one of them is shown here: a Wiki engine that leverage on the power of a Service Worker 14 | to allow the user to create their own pages. 15 | 16 | This, is only a Proof-of-concept but it might be useful to better understand the dynamics, and the possibilities, of this technology. 17 | 18 | Kudos to +jakearchibald for IndexedDB support. 19 | 20 | Working Demo 21 | ============ 22 | 23 | You can experiment this POC here: [https://sandropaganotti.github.io/service-worker-wiki/](https://sandropaganotti.github.io/service-worker-wiki/) -------------------------------------------------------------------------------- /idb.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | function promisifyRequest(obj) { 3 | return new Promise(function(resolve, reject) { 4 | function onsuccess(event) { 5 | resolve(obj.result); 6 | unlisten(); 7 | } 8 | function onerror(event) { 9 | reject(obj.error); 10 | unlisten(); 11 | } 12 | function unlisten() { 13 | obj.removeEventListener('complete', onsuccess); 14 | obj.removeEventListener('success', onsuccess); 15 | obj.removeEventListener('error', onerror); 16 | obj.removeEventListener('abort', onerror); 17 | } 18 | obj.addEventListener('complete', onsuccess); 19 | obj.addEventListener('success', onsuccess); 20 | obj.addEventListener('error', onerror); 21 | obj.addEventListener('abort', onerror); 22 | }); 23 | } 24 | 25 | function IDBHelper(name, version, upgradeCallback) { 26 | var request = indexedDB.open(name, version); 27 | this.ready = promisifyRequest(request); 28 | request.onupgradeneeded = function(event) { 29 | upgradeCallback(request.result, event.oldVersion); 30 | }; 31 | } 32 | 33 | IDBHelper.supported = 'indexedDB' in self; 34 | 35 | var IDBHelperProto = IDBHelper.prototype; 36 | 37 | IDBHelperProto.transaction = function(stores, callback, opts) { 38 | opts = opts || {}; 39 | 40 | return this.ready.then(function(db) { 41 | var mode = opts.mode || 'readonly'; 42 | 43 | var tx = db.transaction(stores, mode); 44 | var val = callback(tx, db); 45 | var promise = promisifyRequest(tx); 46 | var readPromise; 47 | 48 | if (!val) { 49 | return promise; 50 | } 51 | 52 | if (val[0] && 'result' in val[0]) { 53 | readPromise = Promise.all(val.map(promisifyRequest)); 54 | } 55 | else { 56 | readPromise = promisifyRequest(val); 57 | } 58 | 59 | return promise.then(function() { 60 | return readPromise; 61 | }); 62 | }); 63 | }; 64 | 65 | IDBHelperProto.get = function(store, key) { 66 | return this.transaction(store, function(tx) { 67 | return tx.objectStore(store).get(key); 68 | }); 69 | }; 70 | 71 | IDBHelperProto.put = function(store, key, value) { 72 | return this.transaction(store, function(tx) { 73 | tx.objectStore(store).put(value, key); 74 | }, { 75 | mode: 'readwrite' 76 | }); 77 | }; 78 | 79 | IDBHelperProto.each = function(storeName, callback, opts) { 80 | opts = opts || {}; 81 | 82 | return new Promise(function(resolve, reject) { 83 | this.transaction(storeName, function(tx) { 84 | var store = tx.objectStore(storeName); 85 | var cursorRequest; 86 | 87 | if (opts.indexName) { 88 | cursorRequest = store.index(opts.indexName).openCursor(); 89 | } 90 | else { 91 | cursorRequest = store.openCursor(); 92 | } 93 | 94 | cursorRequest.onsuccess = function() { 95 | var cursor = cursorRequest.result; 96 | 97 | if (!cursor) { 98 | resolve(); 99 | return; 100 | } 101 | 102 | callback(cursor.value, cursor.key, cursor); 103 | cursor.continue(); 104 | }; 105 | 106 | cursorRequest.onerror = function() { 107 | reject(cursorRequest.error); 108 | }; 109 | }); 110 | }.bind(this)); 111 | }; 112 | 113 | self.IDBHelper = IDBHelper; 114 | }()); 115 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
9 | This is a simple Proof-Of-Concept wiki built using
10 | the service workers api, to test it you can use the latest Chrome Canary (v38)
11 | enabling the flag 'Experimental Platform Features"
12 | (chrome://flags/#enable-experimental-web-platform-features).
13 |
15 | The pages created are stored in the browser using IndexedDB
(chrome://indexeddb-internals/) and persisted
16 | between sessions
(kudos to Jake Archibald).
17 |
19 | Service Worker Support: 20 |
21 | 22 | 23 | 24 | 30 | 31 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /worker.js: -------------------------------------------------------------------------------- 1 | importScripts('idb.js'); 2 | 3 | function getDB() { 4 | return new IDBHelper('sw-wiki', 1, function(db, oldVersion) { 5 | if (oldVersion < 1) { 6 | db.createObjectStore('pages'); 7 | } 8 | }); 9 | } 10 | 11 | this.addEventListener('install', function(event) { 12 | event.waitUntil(getDB().ready); 13 | }); 14 | 15 | this.addEventListener('fetch', function(e) { 16 | var idb = getDB(); 17 | 18 | e.respondWith( 19 | new Promise(function(resolve) { 20 | if(/\/savepage\?/.test(e.request.url)){ 21 | var params = e.request.url.match(/\?(.+)$/)[1].split("&"); 22 | var req_url = decodeURIComponent(params[0].split("=")[1]); 23 | var req_body = decodeURI(params[1].split("=")[1]).replace(/\+/g," "); 24 | resolve( 25 | idb.put('pages', req_url, req_body).then(function() { 26 | return "