story-content: Added edit/delete chapters
This commit is contained in:
@@ -1,7 +1,17 @@
|
|||||||
const moment = require("moment")
|
const moment = require("moment")
|
||||||
|
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate({kind, weak, value, updated}) {
|
onCreate() {
|
||||||
|
this.state = {text: null, color: "color-menu", href: null, tooltip: null}
|
||||||
|
}
|
||||||
|
|
||||||
|
onInput(input) {
|
||||||
|
if (this.state != null) {
|
||||||
|
this.updateState(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState({kind, weak, value, updated}) {
|
||||||
this.state = {text: null, color: "color-menu", href: null, tooltip: null}
|
this.state = {text: null, color: "color-menu", href: null, tooltip: null}
|
||||||
|
|
||||||
if (value == null || value == "") {
|
if (value == null || value == "") {
|
||||||
|
|||||||
@@ -1,5 +1,25 @@
|
|||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate(input) {
|
onCreate(input) {
|
||||||
this.state = Object.assign({}, input.chapter)
|
this.state = {
|
||||||
|
modal: null,
|
||||||
|
removed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateChapter(data) {
|
||||||
|
this.emit("edit", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChapter() {
|
||||||
|
this.state.removed = true
|
||||||
|
this.emit("remove")
|
||||||
|
}
|
||||||
|
|
||||||
|
open(modal) {
|
||||||
|
this.state.modal = modal
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.state.modal = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
const moment = require("moment")
|
||||||
|
|
||||||
|
const {chapterApi} = require("../../../../../../../rpdata/api/Chapter")
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
onCreate(input) {
|
||||||
|
this.state = {
|
||||||
|
error: null,
|
||||||
|
loading: false,
|
||||||
|
values: {
|
||||||
|
title: "",
|
||||||
|
source: "",
|
||||||
|
fictionalDate: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
this.first = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onInput(input) {
|
||||||
|
if (input.chapter && !this.first) {
|
||||||
|
let {fictionalDate, title, source} = input.chapter
|
||||||
|
|
||||||
|
if (fictionalDate != null) {
|
||||||
|
fictionalDate = moment.utc(fictionalDate).format("MMM D, YYYY")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.values = {fictionalDate, title, source}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
change(key, ev) {
|
||||||
|
this.state.values[key] = ev.target.value
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.first = false
|
||||||
|
this.emit("close")
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
const values = this.state.values
|
||||||
|
|
||||||
|
let fictionalDate = new Date(values.fictionalDate + " UTC")
|
||||||
|
if (values.fictionalDate != "") {
|
||||||
|
if (Number.isNaN(fictionalDate)) {
|
||||||
|
this.state.error = `Could not parse ${values.fictionalDate} as date`
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fictionalDate = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const input = {id: this.input.chapter.id, title: values.title, source: values.source}
|
||||||
|
|
||||||
|
if (fictionalDate != null) {
|
||||||
|
input.fictionalDate = fictionalDate
|
||||||
|
} else {
|
||||||
|
input.clearFictionalDate = true
|
||||||
|
}
|
||||||
|
|
||||||
|
chapterApi.editChapter(input).then(data => {
|
||||||
|
this.emit("edit", data)
|
||||||
|
this.emit("close")
|
||||||
|
}).catch(errs => {
|
||||||
|
console.warn("Failed to edit:", errs)
|
||||||
|
|
||||||
|
this.state.error = "Failed to edit: " + errs[0].message
|
||||||
|
}).then(() => {
|
||||||
|
this.state.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<modal class="modal color-text nolabel" key="modal" enabled=(input.enabled) closable on-close("close") on-open("open") >
|
||||||
|
<h1>Edit Chapter</h1>
|
||||||
|
|
||||||
|
<p key="error" class="color-error">${state.error}</p>
|
||||||
|
|
||||||
|
<input key="title" placeholder="Title" class="big" on-change("change", "title") value=state.values.title />
|
||||||
|
<input key="icdate" placeholder="IC Date" on-change("change", "fictionalDate") value=state.values.fictionalDate />
|
||||||
|
<textarea key="source" placeholder="Content" class="tall" on-change("change", "source") value=state.values.source />
|
||||||
|
|
||||||
|
<button disabled=state.loading on-click("save")>Save</button>
|
||||||
|
</modal>
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
const moment = require("moment")
|
||||||
|
|
||||||
|
const {chapterApi} = require("../../../../../../../rpdata/api/Chapter")
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
onCreate(input) {
|
||||||
|
this.state = {
|
||||||
|
error: null,
|
||||||
|
loading: false,
|
||||||
|
values: {
|
||||||
|
title: "",
|
||||||
|
source: "",
|
||||||
|
fictionalDate: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onInput(input) {
|
||||||
|
if (input.chapter && !this.first) {
|
||||||
|
let {fictionalDate, title, source} = input.chapter
|
||||||
|
|
||||||
|
if (fictionalDate != null) {
|
||||||
|
fictionalDate = moment.utc(fictionalDate).format("MMM D, YYYY")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.values = {fictionalDate, title, source}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
change(key, ev) {
|
||||||
|
this.state.values[key] = ev.target.value
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.emit("close")
|
||||||
|
}
|
||||||
|
|
||||||
|
doIt() {
|
||||||
|
chapterApi.removeChapter({id: this.input.chapter.id}).then(() => {
|
||||||
|
this.emit("remove")
|
||||||
|
this.emit("close")
|
||||||
|
}).catch(errs => {
|
||||||
|
console.warn("Failed to delete:", errs)
|
||||||
|
|
||||||
|
this.state.error = "Failed to delete: " + errs.message || errs[0].message
|
||||||
|
}).then(() => {
|
||||||
|
this.state.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<modal class="modal color-text nolabel" key="modal" enabled=(input.enabled) notification closable on-close("close") on-open("open") >
|
||||||
|
<h1>Delete Chapter</h1>
|
||||||
|
|
||||||
|
<p class="color-error">${state.error}</p>
|
||||||
|
|
||||||
|
<p class="color-danger">This is irreversible!</p>
|
||||||
|
|
||||||
|
<button disabled=state.loading on-click("doIt")>Yes, do it!</button>
|
||||||
|
</modal>
|
||||||
@@ -1,10 +1,19 @@
|
|||||||
<div class="story-chapter">
|
import moment from "moment"
|
||||||
<a class="anchor" id=state.id />
|
|
||||||
|
<div class="story-chapter" if(!state.removed)>
|
||||||
|
<a class="anchor" id=input.chapter.id />
|
||||||
<div class="metadata">
|
<div class="metadata">
|
||||||
<chapter-meta kind="title" value=state.title />
|
<div class="options color-menu">
|
||||||
<chapter-meta kind="date" value=state.fictionalDate />
|
<a on-click("open", "edit") >Edit</a>
|
||||||
<chapter-meta weak kind="date" value=state.createdDate />
|
<a on-click("open", "remove") >Remove</a>
|
||||||
<chapter-meta weak kind="author" value=state.author />
|
</div>
|
||||||
|
<chapter-meta kind="title" value=input.chapter.title />
|
||||||
|
<chapter-meta kind="date" value=input.chapter.fictionalDate />
|
||||||
|
<chapter-meta weak kind="date" value=input.chapter.createdDate />
|
||||||
|
<chapter-meta weak kind="author" value=input.chapter.author />
|
||||||
</div>
|
</div>
|
||||||
<markdown class="chapter-content" source=state.source />
|
<markdown class="chapter-content" source=input.chapter.source />
|
||||||
|
|
||||||
|
<edit-chapter-modal enabled=(state.modal === "edit") chapter=input.chapter on-close("close") on-edit("updateChapter") />
|
||||||
|
<remove-chapter-modal enabled=(state.modal === "remove") chapter=input.chapter on-close("close") on-remove("removeChapter") />
|
||||||
</div>
|
</div>
|
||||||
@@ -11,4 +11,24 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
top: -8em;
|
top: -8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
position: absolute;
|
||||||
|
text-align: right;
|
||||||
|
width: calc(100% - 35.5ch);
|
||||||
|
max-width: 75ch;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 0.5ch;
|
||||||
|
|
||||||
|
opacity: 0.5;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
module.exports = class {
|
||||||
|
onCreate(input) {
|
||||||
|
this.state = {
|
||||||
|
story: input.story
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateChapter(id, data) {
|
||||||
|
const index = this.state.story.chapters.findIndex(ch => ch.id === id)
|
||||||
|
if (index === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!data.hasOwnProperty(key)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.story.chapters[index][key] = data[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeChapter(id) {
|
||||||
|
const index = this.state.story.chapters.findIndex(ch => ch.id === id)
|
||||||
|
if (index === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.story.chapters.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<story-content-menu story=input.story selected=(input.selected || {}) user=input.user />
|
<story-content-menu key="menu" story=state.story selected=(input.selected || {}) user=input.user />
|
||||||
<main>
|
<main>
|
||||||
<div class="story-content">
|
<div class="story-content">
|
||||||
<h1 class="color-primary">${input.story.name}</h1>
|
<h1 class="color-primary">${state.story.name}</h1>
|
||||||
<story-tags tags=input.story.tags />
|
<story-tags tags=state.story.tags />
|
||||||
<chapter for(chapter in input.story.chapters) key=chapter.id chapter=chapter />
|
<chapter for(chapter in state.story.chapters) key=chapter.id chapter=chapter on-edit("updateChapter", chapter.id) on-remove("removeChapter", chapter.id)/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -3,35 +3,32 @@ const moment = require("moment")
|
|||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate(input) {
|
onCreate(input) {
|
||||||
this.state = {
|
this.state = {
|
||||||
chapterTitles: {},
|
selectedChapter: "",
|
||||||
fdateLink: "",
|
bullshit: 0,
|
||||||
fdate: "",
|
|
||||||
selectedChapter: ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount() {
|
onMount() {
|
||||||
this.state.selectedChapter = (window.location.hash||"#").slice(1)
|
this.state.selectedChapter = (window.location.hash||"#").slice(1)
|
||||||
|
|
||||||
|
// Marko is being silly and needs a state change to re-render
|
||||||
|
setInterval(() => {
|
||||||
|
this.state.bullshit++
|
||||||
|
if (this.state.bullshit > 10000) {
|
||||||
|
this.state.bullshit = 0
|
||||||
|
}
|
||||||
|
}, 250)
|
||||||
}
|
}
|
||||||
|
|
||||||
onInput(input) {
|
chapterTitle(chapter) {
|
||||||
if (input.story.fictionalDate && input.story.fictionalDate.getUTCFullYear() > 10) {
|
let title = "Chapter " + this.input.story.chapters.indexOf(chapter) + 1
|
||||||
const fdate = input.story.fictionalDate
|
if (chapter.title) {
|
||||||
|
title = chapter.title
|
||||||
this.state.fdateLink = `/story/by-month/${moment(fdate).format("YYYY-MM")}`
|
} else if (chapter.fictionalDate && chapter.fictionalDate.getUTCFullYear() > 1) {
|
||||||
this.state.fdate = moment(fdate).format("MMM D, YYYY")
|
title = moment(chapter.fictionalDate).format("MMM D, YYYY")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const chapter of input.story.chapters) {
|
return title
|
||||||
let title = "Chapter " + input.story.chapters.indexOf(chapter) + 1
|
|
||||||
if (chapter.title) {
|
|
||||||
title = chapter.title
|
|
||||||
} else if (chapter.fictionalDate && chapter.fictionalDate.getUTCFullYear() > 1) {
|
|
||||||
title = moment(chapter.fictionalDate).format("MMM D, YYYY")
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.chapterTitles[chapter.id] = title
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectChapter(id) {
|
selectChapter(id) {
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
<menu user=input.user>
|
<menu user=input.user>
|
||||||
<if(input.story.chapters.length > 1)>
|
<menu-header>${input.story.name}</menu-header>
|
||||||
<menu-header>${input.story.name}</menu-header>
|
<for(chapter in input.story.chapters | status-var=loop)>
|
||||||
<for(chapter in input.story.chapters | status-var=loop)>
|
<menu-link key=chapter.id on-click("selectChapter", chapter.id) href=("#" + chapter.id) selected=(state.selectedChapter === chapter.id) icon=(loop.getIndex()+1)>${component.chapterTitle(chapter)}</menu-link>
|
||||||
<menu-link on-click("selectChapter", chapter.id) href=("#" + chapter.id) selected=(state.selectedChapter === chapter.id) icon=(loop.getIndex()+1)>${state.chapterTitles[chapter.id]}</menu-link>
|
</for>
|
||||||
</for>
|
|
||||||
<menu-gap />
|
|
||||||
</if>
|
|
||||||
</menu>
|
</menu>
|
||||||
Reference in New Issue
Block a user