133 lines
4.3 KiB
JavaScript
133 lines
4.3 KiB
JavaScript
/* eslint-env browser */
|
|
|
|
import { createYdbClient } from '../../YdbClient/index.mjs'
|
|
import Y from '../../src/Y.dist.mjs'
|
|
import * as ydb from '../../YdbClient/YdbClient.mjs'
|
|
import DomBinding from '../../bindings/DomBinding/DomBinding.mjs'
|
|
|
|
const uuidv4 = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
|
const r = Math.random() * 16 | 0
|
|
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
|
|
})
|
|
|
|
createYdbClient('ws://localhost:8899/ws').then(ydbclient => {
|
|
const y = ydbclient.getY('notelist')
|
|
let ynotelist = y.define('notelist', Y.Array)
|
|
window.ynotelist = ynotelist
|
|
const domNoteList = document.querySelector('.notelist')
|
|
|
|
// utils
|
|
const addEventListener = (element, eventname, f) => element.addEventListener(eventname, f)
|
|
|
|
// create note button
|
|
const createNoteButton = event => {
|
|
ynotelist.insert(0, [{
|
|
guid: uuidv4(),
|
|
title: 'Note #' + ynotelist.length
|
|
}])
|
|
}
|
|
addEventListener(document.querySelector('#createNoteButton'), 'click', createNoteButton)
|
|
window.createNote = createNoteButton
|
|
window.createNotes = n => {
|
|
y.transact(() => {
|
|
for (let i = 0; i < n; i++) {
|
|
createNoteButton()
|
|
}
|
|
})
|
|
}
|
|
|
|
// clear note list function
|
|
window.clearNotes = () => ynotelist.delete(0, ynotelist.length)
|
|
|
|
// update editor and editor title
|
|
let domBinding = null
|
|
const updateEditor = () => {
|
|
domNoteList.querySelectorAll('a').forEach(a => a.classList.remove('selected'))
|
|
const domNote = document.querySelector('.notelist').querySelector(`[href="${location.hash}"]`)
|
|
if (domNote !== null) {
|
|
domNote.classList.add('selected')
|
|
const note = ynotelist.toArray().find(note => note.guid === location.hash.slice(1))
|
|
if (note !== undefined) {
|
|
const ydoc = ydbclient.getY(note.guid)
|
|
const ycontent = ydoc.define('content', Y.XmlFragment)
|
|
if (domBinding !== null) {
|
|
domBinding.destroy()
|
|
}
|
|
domBinding = new DomBinding(ycontent, document.querySelector('#editor'))
|
|
document.querySelector('#headline').innerText = note.title
|
|
document.querySelector('#editor').focus()
|
|
}
|
|
}
|
|
}
|
|
|
|
// listen to url-hash changes
|
|
addEventListener(window, 'hashchange', updateEditor)
|
|
updateEditor()
|
|
|
|
const styleSyncedState = (div, noteSyncedState) => {
|
|
let classes = []
|
|
if (noteSyncedState.persisted) {
|
|
classes.push('persisted')
|
|
} else {
|
|
if (noteSyncedState.upsynced) {
|
|
classes.push('upsynced')
|
|
} else {
|
|
classes.push('noupsynced')
|
|
}
|
|
if (noteSyncedState.downsynced) {
|
|
classes.push('downsynced')
|
|
} else {
|
|
classes.push('nodownsynced')
|
|
}
|
|
}
|
|
div.setAttribute('class', classes.join(' '))
|
|
}
|
|
|
|
ydbclient.on('syncstate', event => event.updated.forEach((state, room) => {
|
|
const a = document.querySelector(`[href="#${room}"]`)
|
|
if (a !== null) {
|
|
styleSyncedState(a.firstChild, state)
|
|
}
|
|
}))
|
|
|
|
// render note list
|
|
const renderNoteList = (elementList, insertRef = domNoteList.firstChild) => {
|
|
const fragment = document.createDocumentFragment()
|
|
const addNow = elementList.splice(0, 100)
|
|
addNow.forEach(note => {
|
|
const a = document.createElement('a')
|
|
const div = document.createElement('div')
|
|
a.insertBefore(div, null)
|
|
a.setAttribute('href', '#' + note.guid)
|
|
div.innerText = note.title
|
|
styleSyncedState(div, ydbclient.getRoomState(note.guid))
|
|
fragment.insertBefore(a, null)
|
|
})
|
|
if (domBinding == null) {
|
|
updateEditor()
|
|
}
|
|
domNoteList.insertBefore(fragment, insertRef)
|
|
if (elementList.length > 0) {
|
|
setTimeout(() => renderNoteList(elementList, insertRef), 100)
|
|
}
|
|
}
|
|
{
|
|
const notelist = ynotelist.toArray()
|
|
if (notelist.length > 0) {
|
|
renderNoteList(notelist)
|
|
ydb.subscribeRooms(ydbclient, notelist.map(note => note.guid))
|
|
}
|
|
}
|
|
ynotelist.observe(event => {
|
|
const addedNotes = []
|
|
event.addedElements.forEach(itemJson => itemJson._content.forEach(json => addedNotes.push(json)))
|
|
renderNoteList(addedNotes.slice().reverse()) // renderNoteList modifies addedNotes, so first make a copy of it
|
|
setTimeout(() => {
|
|
ydb.subscribeRooms(ydbclient, addedNotes.map(note => note.guid))
|
|
}, 200)
|
|
if (domBinding === null) {
|
|
updateEditor()
|
|
}
|
|
})
|
|
})
|