diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a584ddb0..95d21ac05f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ChangeLog ========= 主に notable な changes を書いていきます +unreleased +---------- +* 投稿ページに次の投稿/前の投稿リンクを作成 (#734) + 2380 ---- アプリケーションが作れない問題を修正 diff --git a/locales/en.yml b/locales/en.yml index 55a588f99f..9bf6446641 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -231,6 +231,10 @@ desktop: attaches: "{} media attached" uploading-media: "Uploading {} media" + mk-post-page: + prev: "Previous post" + next: "Next post" + mk-timeline-post: reposted-by: "Reposted by {}" reply: "Reply" diff --git a/locales/ja.yml b/locales/ja.yml index e5b2beaed1..d2b282bff6 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -231,6 +231,10 @@ desktop: attaches: "添付: {}メディア" uploading-media: "{}個のメディアをアップロード中" + mk-post-page: + prev: "前の投稿" + next: "次の投稿" + mk-timeline-post: reposted-by: "{}がRepost" reply: "返信" diff --git a/src/api/serializers/post.ts b/src/api/serializers/post.ts index 3c96884dd1..13773bda9e 100644 --- a/src/api/serializers/post.ts +++ b/src/api/serializers/post.ts @@ -73,44 +73,79 @@ const self = ( )); } - if (_post.reply_to_id && opts.detail) { - // Populate reply to post - _post.reply_to = await self(_post.reply_to_id, me, { - detail: false + // When requested a detailed post data + if (opts.detail) { + // Get previous post info + const prev = await Post.findOne({ + user_id: _post.user_id, + _id: { + $lt: id + } + }, { + fields: { + _id: true + }, + sort: { + _id: -1 + } }); - } + _post.prev = prev ? prev._id : null; - if (_post.repost_id && opts.detail) { - // Populate repost - _post.repost = await self(_post.repost_id, me, { - detail: _post.text == null + // Get next post info + const next = await Post.findOne({ + user_id: _post.user_id, + _id: { + $gt: id + } + }, { + fields: { + _id: true + }, + sort: { + _id: 1 + } }); - } + _post.next = next ? next._id : null; - // Poll - if (me && _post.poll && opts.detail) { - const vote = await Vote - .findOne({ - user_id: me._id, - post_id: id + if (_post.reply_to_id) { + // Populate reply to post + _post.reply_to = await self(_post.reply_to_id, me, { + detail: false }); - - if (vote != null) { - _post.poll.choices.filter(c => c.id == vote.choice)[0].is_voted = true; } - } - // Fetch my reaction - if (me && opts.detail) { - const reaction = await Reaction - .findOne({ - user_id: me._id, - post_id: id, - deleted_at: { $exists: false } + if (_post.repost_id) { + // Populate repost + _post.repost = await self(_post.repost_id, me, { + detail: _post.text == null }); + } - if (reaction) { - _post.my_reaction = reaction.reaction; + // Poll + if (me && _post.poll) { + const vote = await Vote + .findOne({ + user_id: me._id, + post_id: id + }); + + if (vote != null) { + _post.poll.choices.filter(c => c.id == vote.choice)[0].is_voted = true; + } + } + + // Fetch my reaction + if (me) { + const reaction = await Reaction + .findOne({ + user_id: me._id, + post_id: id, + deleted_at: { $exists: false } + }); + + if (reaction) { + _post.my_reaction = reaction.reaction; + } } } diff --git a/src/web/app/desktop/tags/pages/post.tag b/src/web/app/desktop/tags/pages/post.tag index c91e98bbd4..f270b43ac2 100644 --- a/src/web/app/desktop/tags/pages/post.tag +++ b/src/web/app/desktop/tags/pages/post.tag @@ -1,7 +1,9 @@ <mk-post-page> <mk-ui ref="ui"> - <main> + <main if={ !parent.fetching }> + <a if={ parent.post.next } href={ parent.post.next }><i class="fa fa-angle-up"></i>%i18n:desktop.tags.mk-post-page.next%</a> <mk-post-detail ref="detail" post={ parent.post }/> + <a if={ parent.post.prev } href={ parent.post.prev }><i class="fa fa-angle-down"></i>%i18n:desktop.tags.mk-post-page.prev%</a> </main> </mk-ui> <style> @@ -10,6 +12,19 @@ main padding 16px + text-align center + + > a + display inline-block + + &:first-child + margin-bottom 4px + + &:last-child + margin-top 4px + + > i + margin-right 4px > mk-post-detail margin 0 auto @@ -18,16 +33,23 @@ <script> import Progress from '../../../common/scripts/loading'; - this.post = this.opts.post; + this.mixin('api'); + + this.fetching = true; + this.post = null; this.on('mount', () => { Progress.start(); - this.refs.ui.refs.detail.on('post-fetched', () => { - Progress.set(0.5); - }); + this.api('posts/show', { + post_id: this.opts.post + }).then(post => { + + this.update({ + fetching: false, + post: post + }); - this.refs.ui.refs.detail.on('loaded', () => { Progress.done(); }); }); diff --git a/src/web/app/desktop/tags/post-detail.tag b/src/web/app/desktop/tags/post-detail.tag index b162a4084a..2a962816e1 100644 --- a/src/web/app/desktop/tags/post-detail.tag +++ b/src/web/app/desktop/tags/post-detail.tag @@ -1,8 +1,5 @@ <mk-post-detail title={ title }> - <div class="fetching" if={ fetching }> - <mk-ellipsis-icon/> - </div> - <div class="main" if={ !fetching }> + <div class="main"> <button class="read-more" if={ p.reply_to && p.reply_to.reply_to_id && context == null } title="会話をもっと読み込む" onclick={ loadContext } disabled={ contextFetching }> <i class="fa fa-ellipsis-v" if={ !contextFetching }></i> <i class="fa fa-spinner fa-pulse" if={ contextFetching }></i> @@ -71,13 +68,11 @@ padding 0 width 640px overflow hidden + text-align left background #fff border solid 1px rgba(0, 0, 0, 0.1) border-radius 8px - > .fetching - padding 64px 0 - > .main > .read-more @@ -262,56 +257,41 @@ this.mixin('api'); this.mixin('user-preview'); - this.fetching = true; this.contextFetching = false; this.context = null; - this.post = null; + this.post = this.opts.post; + this.isRepost = this.post.repost != null; + this.p = this.isRepost ? this.post.repost : this.post; + this.p.reactions_count = this.p.reaction_counts ? Object.keys(this.p.reaction_counts).map(key => this.p.reaction_counts[key]).reduce((a, b) => a + b) : 0; + this.title = dateStringify(this.p.created_at); this.on('mount', () => { - this.api('posts/show', { - post_id: this.opts.post - }).then(post => { - const isRepost = post.repost != null; - const p = isRepost ? post.repost : post; - p.reactions_count = p.reaction_counts ? Object.keys(p.reaction_counts).map(key => p.reaction_counts[key]).reduce((a, b) => a + b) : 0; + if (this.p.text) { + const tokens = this.p.ast; - this.update({ - fetching: false, - post: post, - isRepost: isRepost, - p: p, - title: dateStringify(p.created_at) + this.refs.text.innerHTML = compile(tokens); + + this.refs.text.children.forEach(e => { + if (e.tagName == 'MK-URL') riot.mount(e); }); - this.trigger('loaded'); - - if (this.p.text) { - const tokens = this.p.ast; - - this.refs.text.innerHTML = compile(tokens); - - this.refs.text.children.forEach(e => { - if (e.tagName == 'MK-URL') riot.mount(e); + // URLをプレビュー + tokens + .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) + .map(t => { + riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), { + url: t.url }); + }); + } - // URLをプレビュー - tokens - .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) - .map(t => { - riot.mount(this.refs.text.appendChild(document.createElement('mk-url-preview')), { - url: t.url - }); - }); - } - - // Get replies - this.api('posts/replies', { - post_id: this.p.id, - limit: 8 - }).then(replies => { - this.update({ - replies: replies - }); + // Get replies + this.api('posts/replies', { + post_id: this.p.id, + limit: 8 + }).then(replies => { + this.update({ + replies: replies }); }); });