96 lines
2.3 KiB
JavaScript
96 lines
2.3 KiB
JavaScript
|
import {ElemJS} from "./basic.js"
|
||
|
import {Subscribable} from "./store/Subscribable.js"
|
||
|
|
||
|
class Event extends ElemJS {
|
||
|
constructor(data) {
|
||
|
super("div")
|
||
|
this.class("c-message")
|
||
|
this.data = null
|
||
|
this.update(data)
|
||
|
}
|
||
|
|
||
|
update(data) {
|
||
|
this.data = data
|
||
|
this.render()
|
||
|
}
|
||
|
|
||
|
render() {
|
||
|
this.child(this.data.content.body)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Timeline extends Subscribable {
|
||
|
constructor() {
|
||
|
super()
|
||
|
Object.assign(this.events, {
|
||
|
addItem: [],
|
||
|
removeItem: []
|
||
|
})
|
||
|
Object.assign(this.eventDeps, {
|
||
|
addItem: [],
|
||
|
removeItem: []
|
||
|
})
|
||
|
this.list = []
|
||
|
this.map = new Map()
|
||
|
this.elementsMap = new Map()
|
||
|
this.elementsList = []
|
||
|
}
|
||
|
|
||
|
_binarySearch(event, min = 0, max = -1) {
|
||
|
if (this.list.length === 0) return {success: false, i: 0}
|
||
|
|
||
|
if (max === -1) max = this.list.length - 1
|
||
|
let mid = Math.floor((max + min) / 2)
|
||
|
// success condition
|
||
|
if (this.list[mid] && this.list[mid].event_id === event.event_id) return {success: true, i: mid}
|
||
|
// failed condition
|
||
|
if (min >= max) {
|
||
|
while (mid !== -1 && (!this.list[mid] || this.list[mid].origin_server_ts > event.origin_server_ts)) mid--
|
||
|
return {
|
||
|
success: false,
|
||
|
i: mid + 1
|
||
|
}
|
||
|
}
|
||
|
// recurse (below)
|
||
|
if (this.list[mid].origin_server_ts > event.origin_server_ts) return this._binarySearch(event, min, mid-1)
|
||
|
// recurse (above)
|
||
|
else return this._binarySearch(event, mid+1, max)
|
||
|
}
|
||
|
|
||
|
updateEvents(events) {
|
||
|
for (const event of events) {
|
||
|
if (this.map.has(event.event_id)) {
|
||
|
this.map.set(event.event_id, event)
|
||
|
this.elementsMap.get(event.event_id).update(this.map.get(event.event_id))
|
||
|
} else {
|
||
|
const index = this._binarySearch(event).i
|
||
|
this.list.splice(index, 0, event)
|
||
|
this.map.set(event.event_id, event)
|
||
|
const e = new Event(event)
|
||
|
this.elementsList.splice(index, 0, e)
|
||
|
this.elementsMap.set(event.event_id, e)
|
||
|
this.broadcast("addItem", {index, element: e})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
getGroupedEvents() {
|
||
|
let currentSender = Symbol("N/A")
|
||
|
let groups = []
|
||
|
let currentGroup = []
|
||
|
for (const event of this.list) {
|
||
|
if (event.sender === currentSender) {
|
||
|
currentGroup.push(event)
|
||
|
} else {
|
||
|
if (currentGroup.length) groups.push(currentGroup)
|
||
|
currentGroup = [event]
|
||
|
currentSender = event.sender
|
||
|
}
|
||
|
}
|
||
|
if (currentGroup.length) groups.push(currentGroup)
|
||
|
return groups
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export {Timeline}
|