@@ -10,6 +10,10 @@ module.exports = class {
|
||||
this.emit("edit", data)
|
||||
}
|
||||
|
||||
moveChapter(data) {
|
||||
this.emit("move", data)
|
||||
}
|
||||
|
||||
removeChapter() {
|
||||
this.state.removed = true
|
||||
this.emit("remove")
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import moment from "moment"
|
||||
|
||||
<div class="story-chapter">
|
||||
<a class="anchor" id=input.chapter.id />
|
||||
<div class="metadata">
|
||||
@@ -7,6 +5,9 @@ import moment from "moment"
|
||||
<if-permitted user=input.user author=input.chapter.author permission="chapter.edit">
|
||||
<a on-click("open", "edit") >Edit</a>
|
||||
</if-permitted>
|
||||
<if-permitted user=input.user author=input.chapter.author permission="chapter.move">
|
||||
<a on-click("open", "move") >Move</a>
|
||||
</if-permitted>
|
||||
<if-permitted user=input.user author=input.chapter.author permission="chapter.remove">
|
||||
<a on-click("open", "remove") >Remove</a>
|
||||
</if-permitted>
|
||||
@@ -19,5 +20,6 @@ import moment from "moment"
|
||||
<markdown class="chapter-content color-text" source=input.chapter.source />
|
||||
|
||||
<edit-chapter-modal enabled=(state.modal === "edit") chapter=input.chapter on-close("close") on-edit("updateChapter") />
|
||||
<move-chapter-modal enabled=(state.modal === "move") chapter=input.chapter user=input.user on-close("close") on-move("moveChapter") />
|
||||
<remove-chapter-modal enabled=(state.modal === "remove") chapter=input.chapter on-close("close") on-remove("removeChapter") />
|
||||
</div>
|
||||
@@ -0,0 +1,89 @@
|
||||
const {storyApi} = require("../../../../../rpdata/api/Story")
|
||||
const {chapterApi} = require("../../../../../rpdata/api/Chapter")
|
||||
|
||||
module.exports = class {
|
||||
onCreate(input) {
|
||||
this.state = {
|
||||
error: null,
|
||||
loading: false,
|
||||
loadingStories: true,
|
||||
stories: [],
|
||||
selected: null,
|
||||
}
|
||||
|
||||
this.first = false
|
||||
}
|
||||
|
||||
change(key, ev) {
|
||||
const value = ev.target.value
|
||||
|
||||
switch (key) {
|
||||
case "selected": {
|
||||
this.state.selected = Object.assign({}, this.state.stories.find(s => s.id === value))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
const promises = []
|
||||
if ((this.input.user.permissions || []).includes("chapter.move")) {
|
||||
promises.push(storyApi.list())
|
||||
} else {
|
||||
promises.push(storyApi.list({author: this.input.user.name}))
|
||||
promises.push(storyApi.list({open: true}))
|
||||
}
|
||||
|
||||
this.state.loadingStories = true
|
||||
|
||||
Promise.all(promises).then(lists => {
|
||||
this.state.stories = unique(Array.prototype.concat.call(...lists))
|
||||
this.state.selected = this.state.stories[0]
|
||||
}).catch(err => {
|
||||
console.warn(err)
|
||||
}).then(() => {
|
||||
this.state.loadingStories = false
|
||||
})
|
||||
}
|
||||
|
||||
close() {
|
||||
this.first = false
|
||||
this.emit("close")
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.state.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
const input = {id: this.input.chapter.id, storyId: this.state.selected.id}
|
||||
|
||||
this.state.loading = true
|
||||
chapterApi.moveChapter(input).then(data => {
|
||||
this.emit("move", input)
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function unique(stories) {
|
||||
const ids = {}
|
||||
const results = []
|
||||
|
||||
for (const story of stories) {
|
||||
if (ids[story.id]) {
|
||||
continue
|
||||
}
|
||||
|
||||
ids[story.id] = true
|
||||
results.push(story)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
$ const selected = (state.selected||{id:null});
|
||||
|
||||
<modal class="modal color-text nolabel" key="modal" enabled=(input.enabled) closable on-close("close") on-open("open") >
|
||||
<h1>Move Chapter</h1>
|
||||
|
||||
<p key="error" class="color-error">${state.error}</p>
|
||||
|
||||
<label>Target story</label>
|
||||
<select key="story" on-change("change", "selected") value=selected.id>
|
||||
<option for(story in state.stories) value=story.id selected=(selected.id === story.id)>${story.name}</option>
|
||||
</select>
|
||||
|
||||
<if-permitted not permission="story.move">
|
||||
<p>Only stories you are allowed to move the chapter to appear in the above list.</p>
|
||||
</if-permitted>
|
||||
|
||||
<button disabled=state.loading on-click("save")>Move</button>
|
||||
</modal>
|
||||
@@ -24,6 +24,12 @@ module.exports = class {
|
||||
this.refreshStory()
|
||||
}
|
||||
|
||||
moveChapter(chapter, data) {
|
||||
if (data.storyId !== this.state.story.id) {
|
||||
this.state.story = Object.assign({}, this.state.story, {chapters: this.state.story.chapters.filter(ch => ch.id !== chapter.id)})
|
||||
}
|
||||
}
|
||||
|
||||
updateChapter(id, data) {
|
||||
const index = this.state.story.chapters.findIndex(ch => ch.id === id)
|
||||
if (index === -1) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
so you can still read it (or back it up) before leaving the page.
|
||||
</p>
|
||||
</annotation>
|
||||
<chapter for(chapter in state.story.chapters) key=chapter.id chapter=chapter user=(!state.removed ? input.user : null) on-edit("updateChapter", chapter.id) on-remove("removeChapter", chapter.id)/>
|
||||
<chapter for(chapter in state.story.chapters) key=chapter.id chapter=chapter user=(!state.removed ? input.user : null) on-edit("updateChapter", chapter.id) on-remove("removeChapter", chapter.id) on-move("moveChapter", chapter) />
|
||||
</div>
|
||||
|
||||
<create-chapter-modal storyId=state.story.id enabled=(state.modal === "chapter.add") chapter=input.chapter on-close("close") on-add("addChapter") />
|
||||
|
||||
+23
-5
@@ -21,7 +21,7 @@ class Chapter {
|
||||
}
|
||||
}
|
||||
|
||||
const chapterApi = {
|
||||
class ChapterAPI {
|
||||
/**
|
||||
* Call `addChapter(input)` mutation, returns the entire object.
|
||||
*
|
||||
@@ -46,7 +46,7 @@ const chapterApi = {
|
||||
|
||||
return new Chapter(ac.id, ac.title, ac.author, ac.source, ac.createdDate, ac.fictionalDate, ac.editedDate)
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `editChapter(input)` mutation, returns editable fields
|
||||
@@ -70,7 +70,25 @@ const chapterApi = {
|
||||
|
||||
return editChapter
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `moveChapter(input)` mutation, returns the ID.
|
||||
*
|
||||
* @param {{id:string, storyId:string}} input
|
||||
* @returns {Promise<{id:string}>}
|
||||
*/
|
||||
moveChapter(input) {
|
||||
return query(`
|
||||
mutation MoveChapter($input: ChapterMoveInput!) {
|
||||
moveChapter(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`, {input}, {permissions: ["member", "story.move"]}).then(({moveChapter}) => {
|
||||
return moveChapter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `removeChapter(input)` mutation, returns only the id
|
||||
@@ -88,7 +106,7 @@ const chapterApi = {
|
||||
`, {input}, {permissions: ["member", "story.edit"]}).then(({removeChapter}) => {
|
||||
return removeChapter
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {Chapter, chapterApi}
|
||||
module.exports = {Chapter, chapterApi: new ChapterAPI}
|
||||
Reference in New Issue
Block a user