Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99aec4d2cb | ||
|
|
3f944ff029 | ||
|
|
3cbe42e1ba | ||
|
|
01b501f9e5 | ||
|
|
9b7d182955 |
@@ -0,0 +1,93 @@
|
|||||||
|
const {logHeaderApi} = require("../../../../../rpdata/api/LogHeader")
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
onCreate(input) {
|
||||||
|
this.state = {
|
||||||
|
id: input.log.id,
|
||||||
|
channelName: input.log.channelName,
|
||||||
|
eventName: input.log.eventName,
|
||||||
|
nexts: [],
|
||||||
|
prevs: [],
|
||||||
|
loaded: false,
|
||||||
|
error: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount() {
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
logHeaderApi.list().then(logs => {
|
||||||
|
const index = logs.findIndex(l => l.id === this.state.id);
|
||||||
|
if (index === -1) {
|
||||||
|
return Promise.reject("This log not found in list.")
|
||||||
|
}
|
||||||
|
const log = logs[index]
|
||||||
|
const characterIds = log.characters.map(c => c.id);
|
||||||
|
const nexts = []
|
||||||
|
const prevs = []
|
||||||
|
const foundGroups = {}
|
||||||
|
let foundChannel = false
|
||||||
|
|
||||||
|
for (let i = index - 1; i >= 0; --i) {
|
||||||
|
const log2 = logs[i]
|
||||||
|
const hasEvent = (log.eventName ? log.eventName === log2.eventName : false)
|
||||||
|
const hasChannel = (log.channelName === log2.channelName)
|
||||||
|
|
||||||
|
const characters = log2.findCharacters(...characterIds)
|
||||||
|
const characterIdsKey = characters.map(c => c.id).sort().join(",")
|
||||||
|
|
||||||
|
const suggestion = {log: log2, characters, hasEvent, hasChannel}
|
||||||
|
|
||||||
|
if (hasChannel && !foundChannel) {
|
||||||
|
foundChannel = true
|
||||||
|
foundGroups[characterIdsKey] = true
|
||||||
|
|
||||||
|
nexts.push(suggestion)
|
||||||
|
} else if (hasEvent) {
|
||||||
|
foundGroups[characterIdsKey] = true
|
||||||
|
|
||||||
|
nexts.push(suggestion)
|
||||||
|
} else if (nexts.length < 8 && !hasEvent && characters.length > 1 && !foundGroups[characterIdsKey]) {
|
||||||
|
foundGroups[characterIdsKey] = true
|
||||||
|
nexts.push(suggestion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = index + 1; i < logs.length; ++i) {
|
||||||
|
const log2 = logs[i]
|
||||||
|
const hasEvent = (log.eventName ? log.eventName === log2.eventName : false)
|
||||||
|
const hasChannel = (log.channelName === log2.channelName)
|
||||||
|
|
||||||
|
const characters = log2.findCharacters(...characterIds)
|
||||||
|
const characterIdsKey = characters.map(c => c.id).sort().join(",")
|
||||||
|
|
||||||
|
const suggestion = {log: log2, characters, hasEvent, hasChannel}
|
||||||
|
|
||||||
|
if (hasChannel && !foundChannel) {
|
||||||
|
foundChannel = true
|
||||||
|
foundGroups[characterIdsKey] = true
|
||||||
|
|
||||||
|
prevs.push(suggestion)
|
||||||
|
} else if (hasEvent) {
|
||||||
|
foundGroups[characterIdsKey] = true
|
||||||
|
|
||||||
|
prevs.push(suggestion)
|
||||||
|
} else if (prevs.length < 8 && !hasEvent && characters.length > 1 && !foundGroups[characterIdsKey]) {
|
||||||
|
foundGroups[characterIdsKey] = true
|
||||||
|
prevs.push(suggestion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.nexts = nexts;
|
||||||
|
this.state.prevs = prevs;
|
||||||
|
this.state.loaded = true;
|
||||||
|
}).catch(err => {
|
||||||
|
console.warn("Suggestions load error:", err)
|
||||||
|
this.suggestionsError = "Failed to load suggestions: " + err.toString()
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmount() {
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import moment from "moment"
|
||||||
|
|
||||||
|
<div class="log-suggestions">
|
||||||
|
<if (state.loaded && state.error == null)>
|
||||||
|
<if (state.nexts.length > 0 || state.prevs.length > 0)>
|
||||||
|
<if (state.nexts.length > 0)>
|
||||||
|
<h2 class="color-primary">Next Logs</h2>
|
||||||
|
<div for(s in state.nexts) class="suggestion color-primary">
|
||||||
|
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.name || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
|
||||||
|
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
|
||||||
|
<div class="suggestion-tags">
|
||||||
|
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${s.log.eventName}</div>
|
||||||
|
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
|
||||||
|
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</if>
|
||||||
|
<if (state.prevs.length > 0)>
|
||||||
|
<h2 class="color-primary">Previous Logs</h2>
|
||||||
|
<div for(s in state.prevs) class="suggestion color-primary">
|
||||||
|
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.name || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
|
||||||
|
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
|
||||||
|
<div class="suggestion-tags">
|
||||||
|
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${s.log.eventName}</div>
|
||||||
|
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
|
||||||
|
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</if>
|
||||||
|
</if>
|
||||||
|
<else>
|
||||||
|
<div class="empty color-menu">(No suggestions)</div>
|
||||||
|
</else>
|
||||||
|
</if>
|
||||||
|
<else-if(state.error != null)>
|
||||||
|
<div class="error color-danger">{state.error}</div>
|
||||||
|
</else-if>
|
||||||
|
<else>
|
||||||
|
<div class="loading color-menu">Loading suggestions...</div>
|
||||||
|
</else>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
div.log-suggestions {
|
||||||
|
padding: 0 0.5ch;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.empty, div.loading {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.suggestion {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
padding: 0.5em;
|
||||||
|
|
||||||
|
div.suggestion-header {
|
||||||
|
margin: 0.125em 0.5ch;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.suggestion-description {
|
||||||
|
margin: 0.125em 0.5ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.suggestion-tags {
|
||||||
|
margin-top: 0.25em;
|
||||||
|
|
||||||
|
div.suggestion-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 0.5ch;
|
||||||
|
margin: 0.125em 0.5ch;
|
||||||
|
border: 0.25px solid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
<div class="logs-content">
|
<div class="logs-content">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1 class="color-primary">${component.title}</h1>
|
<h1 class="color-primary">${component.title}</h1>
|
||||||
|
<p for(paragraph in state.log.description.split("\n").filter(p => p)) class="color-text">${paragraph}</p>
|
||||||
<if-permitted user=input.user permission="log.edit">
|
<if-permitted user=input.user permission="log.edit">
|
||||||
<a on-click("open", "log.edit") class="color-menu">Edit</a>
|
<a on-click("open", "log.edit") class="color-menu">Edit</a>
|
||||||
</if-permitted>
|
</if-permitted>
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
highlights=state.highlights
|
highlights=state.highlights
|
||||||
last=(post.position === state.log.posts.length)
|
last=(post.position === state.log.posts.length)
|
||||||
/>
|
/>
|
||||||
|
<log-suggestions log=state.log />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<add-post-modal enabled=(state.modal === "post.add") logId=state.log.id on-close("close") on-added("postAdded") />
|
<add-post-modal enabled=(state.modal === "post.add") logId=state.log.id on-close("close") on-added("postAdded") />
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ div.logs-content {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0.25em 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ module.exports = class {
|
|||||||
if (filter.search) {
|
if (filter.search) {
|
||||||
queries.push("search=" + encodeURIComponent(filter.search))
|
queries.push("search=" + encodeURIComponent(filter.search))
|
||||||
}
|
}
|
||||||
if (filter.limit) {
|
if (filter.limit != null) {
|
||||||
queries.push("limit=" + encodeURIComponent(filter.limit.toString()))
|
queries.push("limit=" + encodeURIComponent(filter.limit.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ const moment = require("moment")
|
|||||||
|
|
||||||
const {storyApi} = require("../../../../../rpdata/api/Story")
|
const {storyApi} = require("../../../../../rpdata/api/Story")
|
||||||
|
|
||||||
|
const ORDINAL_REGEX = /[0-9]{1,2}(st|nd|rd|th)/g
|
||||||
|
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
onCreate() {
|
onCreate() {
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -45,11 +47,13 @@ module.exports = class {
|
|||||||
const values = this.state.values
|
const values = this.state.values
|
||||||
|
|
||||||
let fictionalDate = new Date(values.fictionalDate + " UTC")
|
let fictionalDate = new Date(values.fictionalDate + " UTC")
|
||||||
if (values.fictionalDate != "") {
|
if (values.fictionalDate) {
|
||||||
if (Number.isNaN(fictionalDate.getTime())) {
|
if (Number.isNaN(fictionalDate.getTime())) {
|
||||||
this.state.error = `Could not parse ${values.fictionalDate} as date.`
|
this.state.error = `Could not parse ${values.fictionalDate} as date.`
|
||||||
if (values.fictionalDate.includes("th")) {
|
|
||||||
this.state.error += " Try to remove the 'th'."
|
const ordinal = values.fictionalDate.match(ORDINAL_REGEX)[0]
|
||||||
|
if (ordinal != null) {
|
||||||
|
this.state.error += " Try to remove the '"+ordinal.slice(-2)+"'."
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -27,6 +27,15 @@ class LogHeader {
|
|||||||
this.open = open
|
this.open = open
|
||||||
this.characters = characters.map(ch => new LogHeaderCharacter(ch.id, ch.name, ch.shortName, ch.author))
|
this.characters = characters.map(ch => new LogHeaderCharacter(ch.id, ch.name, ch.shortName, ch.author))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all characters in that log.
|
||||||
|
*
|
||||||
|
* @param {...string} ids Character IDs
|
||||||
|
*/
|
||||||
|
findCharacters(...ids) {
|
||||||
|
return this.characters.filter(c => ids.includes(c.id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LogHeaderCharacter {
|
class LogHeaderCharacter {
|
||||||
@@ -89,6 +98,11 @@ const logHeaderApi = {
|
|||||||
* @returns {Promise<LogHeader[]>}
|
* @returns {Promise<LogHeader[]>}
|
||||||
*/
|
*/
|
||||||
list(filter = {}) {
|
list(filter = {}) {
|
||||||
|
filter = Object.assign({}, filter)
|
||||||
|
if (filter.limit != null && filter.limit <= 0) {
|
||||||
|
delete filter.limit
|
||||||
|
}
|
||||||
|
|
||||||
return query(`
|
return query(`
|
||||||
query LogHeaders($filter: LogsFilter) {
|
query LogHeaders($filter: LogsFilter) {
|
||||||
headers: logs(filter:$filter) {
|
headers: logs(filter:$filter) {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ app.use("/story/by-author/", require("./routes/story/by-author"))
|
|||||||
app.use("/story/tag-list/", require("./routes/story/tag-list"))
|
app.use("/story/tag-list/", require("./routes/story/tag-list"))
|
||||||
app.use("/story/:id(S[0-9a-z]{15})/", require("./routes/story-content"))
|
app.use("/story/:id(S[0-9a-z]{15})/", require("./routes/story-content"))
|
||||||
app.use("/logs/", require("./routes/logs"))
|
app.use("/logs/", require("./routes/logs"))
|
||||||
app.use("/logs/:id([0-9]{4}-[0-1][0-9]-[0-3][0-9]_[0-9]{9}_[A-Za-z0-9\,\']{2,})/", require("./routes/logs-content"))
|
app.use("/logs/:id([0-9]{4}-[0-1][0-9]-[0-3][0-9]_[0-9]{9}_[A-Za-z0-9\,\'\-]{2,})/", require("./routes/logs-content"))
|
||||||
app.use("/logs/:id(L[0-9]{0,7})/", require("./routes/logs-content"))
|
app.use("/logs/:id(L[0-9]{0,7})/", require("./routes/logs-content"))
|
||||||
app.use("/data/", require("./routes/data"))
|
app.use("/data/", require("./routes/data"))
|
||||||
app.use("/data/characters/", require("./routes/data/characters"))
|
app.use("/data/characters/", require("./routes/data/characters"))
|
||||||
|
|||||||
Reference in New Issue
Block a user