UNPKG

gun

Version:

A realtime, decentralized, offline-first, graph data synchronization engine.

179 lines (170 loc) 6.46 kB
<html> <head> <title>Gun plugin for Vue</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- This example works only with vue 1 --> <script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script> <script src="https://unpkg.com/vue@1.0.0/dist/vue.min.js"></script> </head> <body> <div id="app"> This is example of simple Vue plugin. It works exatcly same as the Vue instance data property, but the name is gunData.<br> The cool part is that every property in the gunData is realtime synced via gunDB to every other page viewer!<br> <table> <tr> <td> Vue instance data: <pre v-html="prettyJSON($data)"></pre> </td> <td valign="top" style="text-align:right;"> test<br> arr[1]<br> obj.a<br> deepObj.level1.prop<br> deepObj.level1.arr[1]<br> </td> <td valign="top"> <input v-model="test"><br> <input v-model="arr[1]"><br> <input v-model="obj.a"><br> <input v-model="deepObj.level1.prop"><br> <input v-model="deepObj.level1.arr[1]"><br> <input v-if="obj.newProp_1" v-model="obj.newProp_1"><br> <br> <button @click="addProp()">Add new prop to obj</button> </td> </tr> </table> </div> <script> Vue.config.productionTip = false; localStorage.clear(); var GunData = { install: function (Vue, options) { Vue.$gunData = { gun: Gun(options), arrToGunObj: function (a) { var o = { _isArr: true }, l = a.length; for (var i = 0; i < l; i++) if (a[i] !== undefined) o[i] = a[i]; return o; }, addGunWatcher: function (keyPath, val, vm) { // console.log('addGunWatcher',keyPath); this.gun.get(vm.$options.$gunRootKey).path(keyPath) .not(function () { this.put(typeof val == 'object' && val.constructor === Array ? this.arrToGunObj(val) : val) }) .on(function (gunVal, gunKey) { if (typeof gunVal == 'object') return; /* only do stuff on non objects */ var vmPath = vm; for (var i = 0, a = keyPath.split('.'), l = a.length; i < l - 1; i++) vmPath = vmPath[a[i]]; if (typeof vmPath[gunKey] == 'undefined') console.log('EIPÄ OO', gunkey); if (vmPath[gunKey] !== gunVal) vm.$set(vmPath, vmPath.constructor === Array ? gunKey * 1 : gunKey, gunVal); }, { change: true }); }, timeout: {}, vueWatcher: {}, addVueWatcher: function (keyPath, vm) { // console.log('VUE WATCHER',keyPath,vm.$options.$gunRootKey); this.vueWatcher[keyPath] = vm.$watch(keyPath, function (newVal) { clearTimeout(Vue.$gunData.timeout[vm.$options.$gunRootKey + keyPath]); Vue.$gunData.timeout[vm.$options.$gunRootKey + keyPath] = setTimeout(function () { Vue.$gunData.gun.get(vm.$options.$gunRootKey).path(keyPath).put(newVal) }, 500); }); }, addWatchers: function (obj, keyPath, vm) { if (keyPath) keyPath += '.'; var o = {}, a = obj, ok = Object.keys(a), l = ok.length, k = '', v = ''; for (var i = 0; i < l, k = ok[i], v = a[k]; i++) { if (typeof v == 'object') { this.addWatchers(v, keyPath + k, vm); } else { // console.log('add watcher',k,v,keyPath+k); if (!this.vueWatcher[keyPath + k]) { Vue.$gunData.addVueWatcher(keyPath + k, vm); Vue.$gunData.addGunWatcher(keyPath + k, v, vm); } } } } } Vue.mixin({ data: function () { var o = {}, a = this.$options.gunData; this.$options.$gunRootKey = (a._rootKey || window.location.hostname).replace(/\./g, '-'); delete a._rootKey; for (var k = '', v = '', i = 0, ok = Object.keys(a), l = ok.length; i < l, k = ok[i], v = a[k]; i++) o[k] = v; return o; }, created: function () { Vue.$gunData.addWatchers(this.$options.gunData, '', this) } }); } } /********************** SIMPLE NODE GUN SERVER EXAMPLE FOR BACKEND **********************/ // var http = require('http'), Gun = require('gun'); // Gun({ web: http.createServer().listen(8765) }); /********************** MODIFY WITH OUR OWN SERVER ADDRESS **********************/ // Vue.use(GunData, 'http://REPLACE.WITH.YOUR.GUN.SERVER:SERVERPORT/gun'); var inst = new Vue({ el: '#app', methods: { addProp() { Vue.set(this.obj, 'newProp_' + Object.keys(this.obj).length, 'qwerty') }, // the prettyJSON code is from icebob https://jsfiddle.net/icebob/0mg1v81e/ prettyJSON: function (json) { if (json) { json = JSON.stringify(json, undefined, 4); json = json.replace(/&/g, '&').replace(/</g, '<').replace( />/g, '>'); return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { var cls = 'number'; if (/^"/.test(match)) { if (/:$/.test(match)) { cls = 'key'; } else { cls = 'string'; } } else if (/true|false/.test(match)) { cls = 'boolean'; } else if (/null/.test(match)) { cls = 'null'; } return '<span class="' + cls + '">' + match + '</span>'; }); } } }, gunData: { // _rootKey: 'put-your-gunDB-root-key-here', // DEFAULTS TO HOSTNAME test: 'abc', arr: [1, 2], obj: { a: 1 }, deepObj: { level1: { arr: [1, 2], prop: 2 } } } }); </script> <style> pre { overflow: auto; } pre .string { color: #885800; } pre .number { color: blue; } pre .boolean { color: magenta; } pre .null { color: red; } pre .key { color: green; } </style> </body> </html>