Browse Source

simple, buggy live sync

master
JonathanS 2 years ago
parent
commit
db5bb26eba
  1. 72
      model.js
  2. 48
      needs.js
  3. 4
      package.json
  4. 6
      server.js

72
model.js

@ -3,37 +3,75 @@ var PouchDB = require('pouchdb');
PouchDB.plugin(require('pouchdb-upsert'))
var m = require('mithril')
var Stream = require('mithril/stream')
// TODO: Broken global state, needs model API for live updates
var db = null
var model = null
// TODO: Name is inappropriate now for a multiple call "promise"
function getModel(db_url) {
db_url = "http://exodus.strfry.org:82/hq_needs/"
db = new PouchDB(db_url)
//var db = require('pouchdb')(db_url)
return new Promise((resolve, reject) => {
db.allDocs({include_docs: true}
db.allDocs({
include_docs: true,
update_seq: true}
).then(docs => {
var stores = docs.rows.map(doc => Object({store: doc.id, items: doc.doc.items}))
resolve(stores)
}).catch(reject)
})
}
// TODO: validate docs against a schema?
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
var items = docs.rows.map(row => row.doc).filter(doc => doc.type == "item")
model = groupBy(items, 'store')
resolve(model)
console.log(docs)
console.log(model)
var items = [
'Apfel',
'Birne',
'Schokoladenkuchen'
]
db.changes({
include_docs: true,
since: docs.update_seq,
live: true
}).on('change', change => {
console.log("change detected: ", change)
// TODO: More effective data structure
for (var key in model[change.doc.store]) {
if (model[change.doc.store][key]._id == change.doc._id) {
model[change.doc.store][key] = change.doc;
m.redraw() // TODO: move this out of model
return;
}
}
model[change.doc.store].push(change.doc)
m.redraw() // TODO: move this out of model
}).catch(error => console.log(error))
}).catch(reject)
})
}
module.exports.getModel = getModel;
module.exports.setItemState = (store, item, confirmed_state) => {
db.upsert(store, doc => {
doc.items = doc.items.map(x => { if (x.name == item) x.confirmed = confirmed_state; return x; })
return doc
}
)
module.exports.setItemState = (item) => {
db.put(item)
}

48
needs.js

@ -7,11 +7,9 @@ var m = require('mithril')
var stream = require('mithril-stream')
//import stream from 'mithril-stream'
var {Card, Checkbox, Icon, IconButton, SVG, ListTile, List} = require('polythene-mithril')
var {Card, Checkbox, Icon, IconButton, SVG, ListTile, List, TextField} = require('polythene-mithril')
//import {Card, Checkbox, ListTile, List} from 'polythene-mithril'
//var {CheckboxCss} = require('polythene-css');
//CheckboxCSS.addStyle("")
var model = require('./model')
@ -23,7 +21,8 @@ const Item = {
},
*/
view: vnode => {
console.log('Item.view', vnode)
console.log("trigger redraw", vnode.attrs)
vnode.state.checked = vnode.attrs.confirmed
return m(ListTile, {
title: vnode.attrs.name,
front:
@ -33,7 +32,11 @@ const Item = {
// value: model.confirmed,
defaultChecked: vnode.attrs.confirmed,
onChange: state => model.setItemState('Baumarkt', vnode.attrs.name, state.checked),
onChange: state => {
var doc = vnode.attrs
doc.confirmed = state.checked
model.setItemState(doc)
},
checked: vnode.state.checked,
}),
})
@ -43,23 +46,40 @@ const Item = {
const addIconSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
const AddIcon = m(Icon, {svg: m.trust(addIconSVG), size: 'large' })
const ItemEntryBox = {
view: vnode =>
m(ListTile,
m(TextField, {
require: true,
autofocus: true,
disabled: true
})
)
}
const StoreCard = {
view: vnode =>
m(Card, {
content: [
//shadowDepth: 5,
content: [
{
header: {
actions: {
content: [
// TODO: Find a more materialistic way to render store name as Card title
vnode.attrs.store,
m('.flex', { key: "space"}),
m(IconButton, {icon: AddIcon} )
]
]
}
},
]},
]
},
m(List, {
tiles: vnode.attrs.items.map(item => m(Item, item) )
header: {
title: vnode.attrs.store,
},
tiles: [
vnode.attrs.items.map(item => m(Item, item)),
m(ItemEntryBox, vnode.attrs)
]
} )
)
}
@ -86,7 +106,9 @@ const StoreCard = {
//export
const NeedsApp = {
view: (vnode) => {
return m('div', {id: 'mountpoint'}, [vnode.attrs.stores.map(store => m(StoreCard, store)),
var stores = vnode.attrs.stores
var keys = Object.keys(stores)
return m('div', {id: 'mountpoint'}, [keys.map(store => m(StoreCard, { store: store, items: stores[store]} )),
])
},
// oninit: vnode => { console.log('oninit') },

4
package.json

@ -13,6 +13,10 @@
},
"type": "module",
"devDependencies": {
"browser-sync": "^2.26.5",
"browserify": "^16.2.3"
},
"scripts": {
"live": "nodemon server.js"
}
}

6
server.js

@ -42,10 +42,16 @@ const ServerLayout = {
function render_index(req, res) {
getModel().then(model => {
console.log("the items i found: ", model)
var template = m(ServerLayout, m(NeedsApp, { stores: model}))
render(template).then(function (html) {
res.writeHead(200, {'Content-Type': 'text/html'})
res.end(html)
}).catch(error => {
res.writeHead(500)
console.log("ERR: ", error)
res.end(error.stack)
})
})
}

Loading…
Cancel
Save