Skip to content

Instantly share code, notes, and snippets.

@komagata
Created November 23, 2018 08:20
Show Gist options
  • Save komagata/eea2fdb6000eb63b2c449712019fffb2 to your computer and use it in GitHub Desktop.
Save komagata/eea2fdb6000eb63b2c449712019fffb2 to your computer and use it in GitHub Desktop.
comments component
<template lang="pug">
.review-comments
.narrow-container
h2.review-comments__title コメント
transition-group(name="fade" tag="div" class="review-comments__items")
comment(v-for="(comment, index) in comments"
v-bind:key="comment.id"
v-bind:comment="comment"
v-bind:userId="reviewUserId"
v-on:delete="deleteComment")
.review-comments-item.is-editor(v-if="signedIn" :class="{ 'is-author': author }")
form#new_comment(:class="{ 'is-loading': loading, 'is-error': error }")
.review-comments-item__avatar
img.review-comments-item__avatar-image(:src="currentUser.avatar_url")
.review-comments-item__main.a-card
header.review-comments-item-header
.review-comments-item-header__inner
h3.review-comments-item__label コメント投稿
.review-comments-item-tabs
ul.review-comments-item-tabs__items
li.review-comments-item-tabs__item
.review-comments-item-tabs__item-inner.is-active(v-show="!reviewing") 入力
.review-comments-item-tabs__item-inner(v-show="reviewing" @click="edit") 入力
li.review-comments-item-tabs__item
.review-comments-item-tabs__item-inner.is-active(@click="review" v-show="reviewing") プレビュー
.review-comments-item-tabs__item-inner(@click="review" v-show="!reviewing") プレビュー
.review-comments-item__body.a-card__body.is-form
div(v-show="reviewing")
.review-comments-item__comment.js-mojik(v-html="HTML")
div(v-show="!reviewing")
.review-comments-item__error(v-if="error" v-text="errorMessage")
.review-comments-item__comment.test-new-comment
markdown-textarea(v-model="body" id="js-new-comment" class="comment-edit comment-edit__text-input js-autosize a-text-input")
.comment-edit__actions
ul.comment-edit__actions-items
li.comment-edit__actions-item
#test-post-comment.is-button-flat-sm-primary.comment-edit__item-action(@click="createComment") コメントする
.review-comments-auth-links(v-else)
h3.review-comments-auth-links__title コメントするにはアカウント登録が必要です。
ul.review-comments-auth-links__items
li.review-comments-auth-links__item
a.is-button-flat-md-warning.is-block.review-comments-auth-links__item-link(href="/users/sign_up") アカウント登録
.review-comments-auth-links-child.is-hidden-sm-down
a.review-comments-auth-links-child__text-link(href="/pages/about?has_back_link=true") このサイトについて
li.review-comments-auth-links__item
a.is-button-flat-md-primary.is-block.review-comments-auth-links__item-link(href="/users/sign_in") サインイン
</template>
<script>
import axios from "axios"
import marked from "marked"
import Comment from "./comment.vue"
import MarkdownTextarea from "./markdown-textarea.vue"
axios.defaults.headers["X-Requested-With"] = "XMLHttpRequest";
export default {
props: ["reviewId", "reviewUserId"],
components: {
"comment": Comment,
"markdown-textarea": MarkdownTextarea
},
data: () => {
return {
comments: [],
body: "",
signedIn: false,
currentUser: {},
reviewing: false,
loading: false,
author: false,
error: false,
errorMessage: "コメントを入力してください。"
}
},
created: function() {
let meta = document.querySelector("meta[name=\"csrf-token\"]");
if (meta) { axios.defaults.headers["X-CSRF-TOKEN"] = meta.content; }
this.currentUser = window.currentUser;
this.signedIn = window.signedIn;
if (this.reviewUserId == window.currentUserID) { this.author = true; }
axios.get(
`/api/reviews/${this.reviewId}/comments`
).then(response => {
this.comments = response["data"];
}).catch(error => {
console.log(error);
});
},
mounted: function() {
$("textarea.js-autosize").textareaAutoSize();
},
methods: {
review: function(event) { this.reviewing = true; },
edit: function(event) { this.reviewing = false; },
createComment: function(event) {
// Validation
if (this.body.length <= 1) {
this.error = true;
return null;
} else {
this.error = false;
}
this.loading = true;
const params = new URLSearchParams();
params.append("body", this.body);
axios.post(
`/api/reviews/${this.reviewId}/comments`,
params
).then(response => {
const comment = response["data"];
this.comments.push(comment);
this.body = "";
this.loading = false;
}).catch(error => {
console.log(error);
this.loading = false;
});
},
deleteComment: function(id) {
axios.delete(
`/api/reviews/${this.reviewId}/comments/${id}`
).then(response => {
this.comments.forEach((comment, i) => {
if (comment.id == id) { this.comments.splice(i, 1); }
});
}).catch(error => {
console.log(error);
});
},
},
computed: {
HTML: function() {
return marked(this.body, { breaks: true });
}
}
}
</script>
<style scoped>
.is-loading {
pointer-events: none;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to {
opacity: 0
}
</style>
import Vue from "vue"
import Comments from "../comments.vue"
document.addEventListener("DOMContentLoaded", () => {
const comments = document.getElementById("js-comments");
if (comments) {
const reviewId = comments.getAttribute("data-review-id");
const reviewUserId = comments.getAttribute("data-review-user-id");
new Vue({
render: h => h(Comments, { props: { reviewId: reviewId, reviewUserId: reviewUserId } })
}).$mount("#js-comments");
}
});
<template lang="pug">
.review-comments
.narrow-container
h2.review-comments__title コメント
transition-group(name="fade" tag="div" class="review-comments__items")
comment(v-for="(comment, index) in comments"
v-bind:key="comment.id"
v-bind:comment="comment"
v-bind:userId="reviewUserId"
v-on:delete="deleteComment")
.review-comments-item.is-editor(v-if="signedIn" :class="{ 'is-author': author }")
form#new_comment(:class="{ 'is-loading': loading, 'is-error': error }")
.review-comments-item__avatar
img.review-comments-item__avatar-image(:src="currentUser.avatar_url")
.review-comments-item__main.a-card
header.review-comments-item-header
.review-comments-item-header__inner
h3.review-comments-item__label コメント投稿
.review-comments-item-tabs
ul.review-comments-item-tabs__items
li.review-comments-item-tabs__item
.review-comments-item-tabs__item-inner.is-active(v-show="!reviewing") 入力
.review-comments-item-tabs__item-inner(v-show="reviewing" @click="edit") 入力
li.review-comments-item-tabs__item
.review-comments-item-tabs__item-inner.is-active(@click="review" v-show="reviewing") プレビュー
.review-comments-item-tabs__item-inner(@click="review" v-show="!reviewing") プレビュー
.review-comments-item__body.a-card__body.is-form
div(v-show="reviewing")
.review-comments-item__comment.js-mojik(v-html="HTML")
div(v-show="!reviewing")
.review-comments-item__error(v-if="error" v-text="errorMessage")
.review-comments-item__comment.test-new-comment
markdown-textarea(v-model="body" id="js-new-comment" class="comment-edit comment-edit__text-input js-autosize a-text-input")
.comment-edit__actions
ul.comment-edit__actions-items
li.comment-edit__actions-item
#test-post-comment.is-button-flat-sm-primary.comment-edit__item-action(@click="createComment") コメントする
.review-comments-auth-links(v-else)
h3.review-comments-auth-links__title コメントするにはアカウント登録が必要です。
ul.review-comments-auth-links__items
li.review-comments-auth-links__item
a.is-button-flat-md-warning.is-block.review-comments-auth-links__item-link(href="/users/sign_up") アカウント登録
.review-comments-auth-links-child.is-hidden-sm-down
a.review-comments-auth-links-child__text-link(href="/pages/about?has_back_link=true") このサイトについて
li.review-comments-auth-links__item
a.is-button-flat-md-primary.is-block.review-comments-auth-links__item-link(href="/users/sign_in") サインイン
</template>
<script>
import axios from "axios"
import marked from "marked"
import Comment from "./comment.vue"
import MarkdownTextarea from "./markdown-textarea.vue"
axios.defaults.headers["X-Requested-With"] = "XMLHttpRequest";
export default {
props: ["reviewId", "reviewUserId"],
components: {
"comment": Comment,
"markdown-textarea": MarkdownTextarea
},
data: () => {
return {
comments: [],
body: "",
signedIn: false,
currentUser: {},
reviewing: false,
loading: false,
author: false,
error: false,
errorMessage: "コメントを入力してください。"
}
},
created: function() {
let meta = document.querySelector("meta[name=\"csrf-token\"]");
if (meta) { axios.defaults.headers["X-CSRF-TOKEN"] = meta.content; }
this.currentUser = window.currentUser;
this.signedIn = window.signedIn;
if (this.reviewUserId == window.currentUserID) { this.author = true; }
axios.get(
`/api/reviews/${this.reviewId}/comments`
).then(response => {
this.comments = response["data"];
}).catch(error => {
console.log(error);
});
},
mounted: function() {
$("textarea.js-autosize").textareaAutoSize();
},
methods: {
review: function(event) { this.reviewing = true; },
edit: function(event) { this.reviewing = false; },
createComment: function(event) {
// Validation
if (this.body.length <= 1) {
this.error = true;
return null;
} else {
this.error = false;
}
this.loading = true;
const params = new URLSearchParams();
params.append("body", this.body);
axios.post(
`/api/reviews/${this.reviewId}/comments`,
params
).then(response => {
const comment = response["data"];
this.comments.push(comment);
this.body = "";
this.loading = false;
}).catch(error => {
console.log(error);
this.loading = false;
});
},
deleteComment: function(id) {
axios.delete(
`/api/reviews/${this.reviewId}/comments/${id}`
).then(response => {
this.comments.forEach((comment, i) => {
if (comment.id == id) { this.comments.splice(i, 1); }
});
}).catch(error => {
console.log(error);
});
},
},
computed: {
HTML: function() {
return marked(this.body, { breaks: true });
}
}
}
</script>
<style scoped>
.is-loading {
pointer-events: none;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to {
opacity: 0
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment