/* eslint-env browser */ import { createYdbClient } from '../../YdbClient/index.js' import Y from '../../src/Y.dist.js' import * as ydb from '../../YdbClient/YdbClient.js' import DomBinding from '../../bindings/DomBinding/DomBinding.js' 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() } }) })