tre-prototypes
Version:
javascript-style prototype-chains for ssb messages
169 lines (156 loc) • 5.17 kB
JavaScript
const {client} = require('tre-client')
const Finder = require('tre-finder')
const Editor = require('tre-json-editor')
const h = require('mutant/html-element')
const Value = require('mutant/value')
const computed = require('mutant/computed')
const WatchHeads = require('tre-watch-heads')
const setStyle = require('module-styles')('tre-prototype-demo')
const {makePane, makeDivider, makeSplitPane} = require('tre-split-pane')
const oll = require('observable-linked-list')
const WatchMerged = require('.')
const deepEqaul = require('deep-equal')
require('brace/theme/solarized_dark')
setStyle(`
body, html, .tre-prototypes-demo {
height: 100%;
margin: 0;
padding: 0;
}
body {
--tre-selection-color: green;
--tre-secondary-selection-color: yellow;
font-family: sans-serif;
}
h1 {
font-size: 18px;
}
.pane {
background: #eee;
}
.tre-finder .summary select {
font-size: 9pt;
background: transparent;
border: none;
width: 50px;
}
.tre-finder summary {
white-space: nowrap;
}
.tre-finder summary:focus {
outline: 1px solid rgba(255,255,255,0.1);
}
`)
client( (err, ssb, config) => {
if (err) return console.error(err)
const watchHeads = WatchHeads(ssb)
const watchMerged = WatchMerged(ssb)
const primarySelection = Value()
const editorBase = Value()
const realtime_kv = computed(primarySelection, kv => {
const content = kv && kv.value && kv.value.content
if (!content) return
return watchHeads(kv.value.content.revisionRoot || kv.key)
})
const chain_kv = oll(realtime_kv, proto, watchHeads)
const merged_kv = computed(primarySelection, kv => {
const c = content(kv)
if (!c) return
return watchMerged(c.revisionRoot || kv.key)
})
const renderFinder = Finder(ssb, {
primarySelection,
skipFirstLevel: true,
details: (kv, ctx) => {
return kv && kv.meta && kv.meta["prototype-chain"] ? h('i', '(has proto)') : []
},
factory: {
menu: ()=> [{label: 'Object', type: 'object'}],
make: type => type == 'object' && {
type: 'object',
text: "Hi, I'm Elfo!"
}
}
})
const renderEditor = Editor(null, {
ace: {
theme: 'ace/theme/solarized_dark',
tabSize: 2,
useSoftTabs: true
}
})
document.body.appendChild(
h('.tre-prototypes-demo', [
makeSplitPane({horiz: false}, [
makeSplitPane({horiz: true}, [
makePane('25%', [
h('h1', 'Finder'),
renderFinder(config.tre.branches.root)
]),
makeDivider(),
makePane('70%', [
h('h1', 'Editor'),
h('span', computed(editorBase, kv => `based on ${kv && kv.key}`)),
h('span', computed([editorBase, realtime_kv], (base, real) => base && real && base.key !== real.key ? '(outdated)' : '(no conflict)' )),
computed(primarySelection, kv => {
editorBase.set(kv)
if (!kv) return []
// the Finder selection will give as the merged content,
// but in the editor, we want raw content
const content = (kv.meta && kv.meta['prototype-chain']) ? kv.meta['prototype-chain'][0].value.content : kv.value.content
console.warn('ps', kv, content)
const contentObs = Value(content)
return [
// contentObs will be updated by the editor whenever the edited text is valid json
renderEditor({
key: kv.key,
value: {content}
}, {contentObs}),
h('button', {
disabled: computed([contentObs, editorBase], (c, base) => deepEqaul(c, base.value.content)),
'ev-click': e => {
const content = contentObs()
content.revisionBranch = kv.key
content.revisionRoot = kv.value.content.revisionRoot || kv.key
console.log('new content', content)
ssb.publish(content, (err, msg) => {
if (err) return console.error(err)
kv = msg
editorBase.set(msg)
contentObs.set(msg.value.content)
})
}
}, 'Save')
]
})
])
]),
makeDivider(),
makeSplitPane({horiz: true}, [
makePane('30%', [
h('h1', 'Realtime Value'),
h('pre.realtime', computed(realtime_kv, kv => JSON.stringify(kv, null, 2)))
]),
makeDivider(),
makePane('30%', [
h('h1', 'Prototype Chain'),
h('pre.chain', computed(chain_kv, kv => JSON.stringify(kv, null, 2)))
]),
makeDivider(),
makePane('30%', [
h('h1', 'Merged'),
h('pre.merged', computed(merged_kv, kv => JSON.stringify(kv, null, 2)))
])
])
])
])
)
})
// -- utils
function content(kv) {
return kv && kv.value && kv.value.content
}
function proto(kv) {
const c = content(kv)
return c && c.prototype
}