Files
frontend/marko/page/logs-content/components/page/component.js
T

181 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const moment = require("moment")
const {postApi} = require("../../../../../rpdata/api/Post")
const {logsApi} = require("../../../../../rpdata/api/Log")
module.exports = class {
onCreate(input) {
this.state = {
log: input.log,
modal: null,
removed: false,
highlights: [],
}
}
onMount() {
this.sub = logsApi.subscribeChanges(this.state.log.id)
this.sub.on("data", data => {
this.handleChange(data.changes)
})
this.sub.connect()
}
onUnmount() {
if (this.sub != null) {
this.sub.disconnect()
}
}
open(modal) {
this.state.modal = modal
}
close() {
this.state.modal = null
}
/**
* Patch the posts
*
* @param {{id:string, [x:string]: any}[]} patches
*/
patch(patches) {
const posts = this.state.log.posts.slice()
for (const patch of patches) {
const index = posts.findIndex(p => p.id === patch.id)
if (index == -1) {
continue
}
posts[index] = Object.assign(Object.assign({}, posts[index]), patch)
}
// Sort posts and look for continuity issues (duplicate or skipped positions)
posts.sort((a, b) => a.position - b.position)
for (let i = 1; i < posts.length; ++i) {
if (posts[i].position !== posts[i - 1].position + 1) {
console.warn("Discontinuity detected:", i, posts)
}
}
this.state.log.posts = posts
this.state.log = Object.assign({}, this.state.log)
}
movePost(post, toPosition, relative) {
if (relative) {
toPosition = post.position + toPosition
}
postApi.move({id: post.id, toPosition}).then(patches => {
this.patch(patches)
}).catch(err => {
console.warn(err)
})
}
removePost(post) {
postApi.remove({id: post.id}).then(() => {
this.postRemoved(post)
}).catch(errs => {
console.warn("Failed to delete:", errs)
this.state.error = "Failed to delete: " + (errs.message || errs[0].message)
})
}
postEdited(patch) {
this.patch([patch])
}
logEdited(patch) {
this.state.log = Object.assign(Object.assign({}, this.state.log), patch)
}
postRemoved(post) {
if (this.state.log.posts.find(p => p.id === post.id) == null) {
return
}
const posts = this.state.log.posts.filter(p => p.id !== post.id).map(p => {
if (p.position > post.position) {
return Object.assign({}, p, {position: p.position - 1})
}
return p
})
this.state.log = Object.assign({}, this.state.log, {posts: posts})
}
postAdded(post) {
// Stop duplicates in case of race condition.
if (this.state.log.posts.find(p => p.id === post.id)) {
return
}
this.state.log.posts = this.state.log.posts.concat([post])
this.state.log = Object.assign({}, this.state.log)
}
handleChange(change) {
switch (`${change.model}.${change.op}`) {
case "Post.add": {
for (const post of change.objects.filter(o => o.type === "Post")) {
this.postAdded(post)
}
break
}
case "Post.move":
case "Post.edit": {
this.patch(change.objects.filter(o => o.type === "Post"))
break
}
case "Post.remove": {
for (const post of change.objects.filter(o => o.type === "Post")) {
this.postRemoved(post)
}
}
case "Log.edit": {
const patch = change.objects.find(o => o.type === "Log")
if (patch == null) {
break
}
this.logEdited(patch)
break
}
case "Log.remove": {
this.logRemoved()
break
}
}
}
logRemoved() {
this.state.removed = true
}
highlightsChanged(highlights) {
this.state.highlights = highlights.slice();
}
get title() {
if (this.state.log.title) {
return this.state.log.title
}
return `${this.state.log.channel.name} – ${moment(this.state.log.date).format("MMMM D, YYYY")}`
}
}