summaryrefslogtreecommitdiff
path: root/src/web/app/common
diff options
context:
space:
mode:
authorこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-13 15:17:59 +0900
committerこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-13 15:17:59 +0900
commitcffda0bcd213b74da3e6463f50896b32aeba5211 (patch)
treee7b22aa4c98b36e6023e51193c1204dd4d5912ff /src/web/app/common
parentwip (diff)
downloadsharkey-cffda0bcd213b74da3e6463f50896b32aeba5211.tar.gz
sharkey-cffda0bcd213b74da3e6463f50896b32aeba5211.tar.bz2
sharkey-cffda0bcd213b74da3e6463f50896b32aeba5211.zip
wip
Diffstat (limited to 'src/web/app/common')
-rw-r--r--src/web/app/common/-tags/messaging/room.tag319
-rw-r--r--src/web/app/common/views/components/messaging-room.vue314
2 files changed, 314 insertions, 319 deletions
diff --git a/src/web/app/common/-tags/messaging/room.tag b/src/web/app/common/-tags/messaging/room.tag
deleted file mode 100644
index 990f20a8e3..0000000000
--- a/src/web/app/common/-tags/messaging/room.tag
+++ /dev/null
@@ -1,319 +0,0 @@
-<mk-messaging-room>
- <div class="stream">
- <p class="init" v-if="init">%fa:spinner .spin%%i18n:common.loading%</p>
- <p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:common.tags.mk-messaging-room.empty%</p>
- <p class="no-history" v-if="!init && messages.length > 0 && !moreMessagesIsInStock">%fa:flag%%i18n:common.tags.mk-messaging-room.no-history%</p>
- <button class="more { fetching: fetchingMoreMessages }" v-if="moreMessagesIsInStock" @click="fetchMoreMessages" disabled={ fetchingMoreMessages }>
- <template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:common.tags.mk-messaging-room.more%' }
- </button>
- <template each={ message, i in messages }>
- <mk-messaging-message message={ message }/>
- <p class="date" v-if="i != messages.length - 1 && message._date != messages[i + 1]._date"><span>{ messages[i + 1]._datetext }</span></p>
- </template>
- </div>
- <footer>
- <div ref="notifications"></div>
- <div class="grippie" title="%i18n:common.tags.mk-messaging-room.resize-form%"></div>
- <mk-messaging-form user={ user }/>
- </footer>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > .stream
- max-width 600px
- margin 0 auto
-
- > .init
- width 100%
- margin 0
- padding 16px 8px 8px 8px
- text-align center
- font-size 0.8em
- color rgba(0, 0, 0, 0.4)
-
- [data-fa]
- margin-right 4px
-
- > .empty
- width 100%
- margin 0
- padding 16px 8px 8px 8px
- text-align center
- font-size 0.8em
- color rgba(0, 0, 0, 0.4)
-
- [data-fa]
- margin-right 4px
-
- > .no-history
- display block
- margin 0
- padding 16px
- text-align center
- font-size 0.8em
- color rgba(0, 0, 0, 0.4)
-
- [data-fa]
- margin-right 4px
-
- > .more
- display block
- margin 16px auto
- padding 0 12px
- line-height 24px
- color #fff
- background rgba(0, 0, 0, 0.3)
- border-radius 12px
-
- &:hover
- background rgba(0, 0, 0, 0.4)
-
- &:active
- background rgba(0, 0, 0, 0.5)
-
- &.fetching
- cursor wait
-
- > [data-fa]
- margin-right 4px
-
- > .message
- // something
-
- > .date
- display block
- margin 8px 0
- text-align center
-
- &:before
- content ''
- display block
- position absolute
- height 1px
- width 90%
- top 16px
- left 0
- right 0
- margin 0 auto
- background rgba(0, 0, 0, 0.1)
-
- > span
- display inline-block
- margin 0
- padding 0 16px
- //font-weight bold
- line-height 32px
- color rgba(0, 0, 0, 0.3)
- background #fff
-
- > footer
- position -webkit-sticky
- position sticky
- z-index 2
- bottom 0
- width 100%
- max-width 600px
- margin 0 auto
- padding 0
- background rgba(255, 255, 255, 0.95)
- background-clip content-box
-
- > [ref='notifications']
- position absolute
- top -48px
- width 100%
- padding 8px 0
- text-align center
-
- &:empty
- display none
-
- > p
- display inline-block
- margin 0
- padding 0 12px 0 28px
- cursor pointer
- line-height 32px
- font-size 12px
- color $theme-color-foreground
- background $theme-color
- border-radius 16px
- transition opacity 1s ease
-
- > [data-fa]
- position absolute
- top 0
- left 10px
- line-height 32px
- font-size 16px
-
- > .grippie
- height 10px
- margin-top -10px
- background transparent
- cursor ns-resize
-
- &:hover
- //background rgba(0, 0, 0, 0.1)
-
- &:active
- //background rgba(0, 0, 0, 0.2)
-
- </style>
- <script lang="typescript">
- import MessagingStreamConnection from '../../scripts/streaming/messaging-stream';
-
- this.mixin('i');
- this.mixin('api');
-
- this.user = this.opts.user;
- this.init = true;
- this.sending = false;
- this.messages = [];
- this.isNaked = this.opts.isNaked;
-
- this.connection = new MessagingStreamConnection(this.I, this.user.id);
-
- this.on('mount', () => {
- this.connection.on('message', this.onMessage);
- this.connection.on('read', this.onRead);
-
- document.addEventListener('visibilitychange', this.onVisibilitychange);
-
- this.fetchMessages().then(() => {
- this.init = false;
- this.update();
- this.scrollToBottom();
- });
- });
-
- this.on('unmount', () => {
- this.connection.off('message', this.onMessage);
- this.connection.off('read', this.onRead);
- this.connection.close();
-
- document.removeEventListener('visibilitychange', this.onVisibilitychange);
- });
-
- this.on('update', () => {
- this.messages.forEach(message => {
- const date = (new Date(message.created_at)).getDate();
- const month = (new Date(message.created_at)).getMonth() + 1;
- message._date = date;
- message._datetext = month + '月 ' + date + '日';
- });
- });
-
- this.onMessage = (message) => {
- const isBottom = this.isBottom();
-
- this.messages.push(message);
- if (message.user_id != this.I.id && !document.hidden) {
- this.connection.send({
- type: 'read',
- id: message.id
- });
- }
- this.update();
-
- if (isBottom) {
- // Scroll to bottom
- this.scrollToBottom();
- } else if (message.user_id != this.I.id) {
- // Notify
- this.notify('%i18n:common.tags.mk-messaging-room.new-message%');
- }
- };
-
- this.onRead = ids => {
- if (!Array.isArray(ids)) ids = [ids];
- ids.forEach(id => {
- if (this.messages.some(x => x.id == id)) {
- const exist = this.messages.map(x => x.id).indexOf(id);
- this.messages[exist].is_read = true;
- this.update();
- }
- });
- };
-
- this.fetchMoreMessages = () => {
- this.update({
- fetchingMoreMessages: true
- });
- this.fetchMessages().then(() => {
- this.update({
- fetchingMoreMessages: false
- });
- });
- };
-
- this.fetchMessages = () => new Promise((resolve, reject) => {
- const max = this.moreMessagesIsInStock ? 20 : 10;
-
- this.api('messaging/messages', {
- user_id: this.user.id,
- limit: max + 1,
- until_id: this.moreMessagesIsInStock ? this.messages[0].id : undefined
- }).then(messages => {
- if (messages.length == max + 1) {
- this.moreMessagesIsInStock = true;
- messages.pop();
- } else {
- this.moreMessagesIsInStock = false;
- }
-
- this.messages.unshift.apply(this.messages, messages.reverse());
- this.update();
-
- resolve();
- });
- });
-
- this.isBottom = () => {
- const asobi = 32;
- const current = this.isNaked
- ? window.scrollY + window.innerHeight
- : this.root.scrollTop + this.root.offsetHeight;
- const max = this.isNaked
- ? document.body.offsetHeight
- : this.root.scrollHeight;
- return current > (max - asobi);
- };
-
- this.scrollToBottom = () => {
- if (this.isNaked) {
- window.scroll(0, document.body.offsetHeight);
- } else {
- this.root.scrollTop = this.root.scrollHeight;
- }
- };
-
- this.notify = message => {
- const n = document.createElement('p');
- n.innerHTML = '%fa:arrow-circle-down%' + message;
- n.onclick = () => {
- this.scrollToBottom();
- n.parentNode.removeChild(n);
- };
- this.$refs.notifications.appendChild(n);
-
- setTimeout(() => {
- n.style.opacity = 0;
- setTimeout(() => n.parentNode.removeChild(n), 1000);
- }, 4000);
- };
-
- this.onVisibilitychange = () => {
- if (document.hidden) return;
- this.messages.forEach(message => {
- if (message.user_id !== this.I.id && !message.is_read) {
- this.connection.send({
- type: 'read',
- id: message.id
- });
- }
- });
- };
- </script>
-</mk-messaging-room>
diff --git a/src/web/app/common/views/components/messaging-room.vue b/src/web/app/common/views/components/messaging-room.vue
new file mode 100644
index 0000000000..2fb6671b8c
--- /dev/null
+++ b/src/web/app/common/views/components/messaging-room.vue
@@ -0,0 +1,314 @@
+<template>
+<div class="mk-messaging-room">
+ <div class="stream">
+ <p class="init" v-if="init">%fa:spinner .spin%%i18n:common.loading%</p>
+ <p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:common.tags.mk-messaging-room.empty%</p>
+ <p class="no-history" v-if="!init && messages.length > 0 && !moreMessagesIsInStock">%fa:flag%%i18n:common.tags.mk-messaging-room.no-history%</p>
+ <button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="moreMessagesIsInStock" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
+ <template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:common.tags.mk-messaging-room.more%' }}
+ </button>
+ <template v-for="(message, i) in messages">
+ <mk-messaging-message :message="message" :key="message.id"/>
+ <p class="date" :key="message.id + '-time'" v-if="i != messages.length - 1 && _message._date != _messages[i + 1]._date"><span>{{ _messages[i + 1]._datetext }}</span></p>
+ </template>
+ </div>
+ <footer>
+ <div ref="notifications"></div>
+ <div class="grippie" title="%i18n:common.tags.mk-messaging-room.resize-form%"></div>
+ <mk-messaging-form :user="user"/>
+ </footer>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import MessagingStreamConnection from '../../scripts/streaming/messaging-stream';
+
+export default Vue.extend({
+ props: ['user', 'isNaked'],
+ data() {
+ return {
+ init: true,
+ fetchingMoreMessages: false,
+ messages: [],
+ existMoreMessages: false,
+ connection: null
+ };
+ },
+ computed: {
+ _messages(): any[] {
+ return (this.messages as any).map(message => {
+ const date = new Date(message.created_at).getDate();
+ const month = new Date(message.created_at).getMonth() + 1;
+ message._date = date;
+ message._datetext = `${month}月 ${date}日`;
+ return message;
+ });
+ }
+ },
+
+ mounted() {
+ this.connection = new MessagingStreamConnection(this.$root.$data.os.i, this.user.id);
+
+ this.connection.on('message', this.onMessage);
+ this.connection.on('read', this.onRead);
+
+ document.addEventListener('visibilitychange', this.onVisibilitychange);
+
+ this.fetchMessages().then(() => {
+ this.init = false;
+ this.scrollToBottom();
+ });
+ },
+ beforeDestroy() {
+ this.connection.off('message', this.onMessage);
+ this.connection.off('read', this.onRead);
+ this.connection.close();
+
+ document.removeEventListener('visibilitychange', this.onVisibilitychange);
+ },
+ methods: {
+ fetchMessages() {
+ return new Promise((resolve, reject) => {
+ const max = this.existMoreMessages ? 20 : 10;
+
+ this.$root.$data.os.api('messaging/messages', {
+ user_id: this.user.id,
+ limit: max + 1,
+ until_id: this.existMoreMessages ? this.messages[0].id : undefined
+ }).then(messages => {
+ if (messages.length == max + 1) {
+ this.existMoreMessages = true;
+ messages.pop();
+ } else {
+ this.existMoreMessages = false;
+ }
+
+ this.messages.unshift.apply(this.messages, messages.reverse());
+ resolve();
+ });
+ });
+ },
+ fetchMoreMessages() {
+ this.fetchingMoreMessages = true;
+ this.fetchMessages().then(() => {
+ this.fetchingMoreMessages = false;
+ });
+ },
+ onMessage(message) {
+ const isBottom = this.isBottom();
+
+ this.messages.push(message);
+ if (message.user_id != this.$root.$data.os.i.id && !document.hidden) {
+ this.connection.send({
+ type: 'read',
+ id: message.id
+ });
+ }
+
+ if (isBottom) {
+ // Scroll to bottom
+ this.scrollToBottom();
+ } else if (message.user_id != this.$root.$data.os.i.id) {
+ // Notify
+ this.notify('%i18n:common.tags.mk-messaging-room.new-message%');
+ }
+ },
+ onRead(ids) {
+ if (!Array.isArray(ids)) ids = [ids];
+ ids.forEach(id => {
+ if (this.messages.some(x => x.id == id)) {
+ const exist = this.messages.map(x => x.id).indexOf(id);
+ this.messages[exist].is_read = true;
+ }
+ });
+ },
+ isBottom() {
+ const asobi = 32;
+ const current = this.isNaked
+ ? window.scrollY + window.innerHeight
+ : this.$el.scrollTop + this.$el.offsetHeight;
+ const max = this.isNaked
+ ? document.body.offsetHeight
+ : this.$el.scrollHeight;
+ return current > (max - asobi);
+ },
+ scrollToBottom() {
+ if (this.isNaked) {
+ window.scroll(0, document.body.offsetHeight);
+ } else {
+ this.$el.scrollTop = this.$el.scrollHeight;
+ }
+ },
+ notify(message) {
+ const n = document.createElement('p') as any;
+ n.innerHTML = '%fa:arrow-circle-down%' + message;
+ n.onclick = () => {
+ this.scrollToBottom();
+ n.parentNode.removeChild(n);
+ };
+ (this.$refs.notifications as any).appendChild(n);
+
+ setTimeout(() => {
+ n.style.opacity = 0;
+ setTimeout(() => n.parentNode.removeChild(n), 1000);
+ }, 4000);
+ },
+ onVisibilitychange() {
+ if (document.hidden) return;
+ this.messages.forEach(message => {
+ if (message.user_id !== this.$root.$data.os.i.id && !message.is_read) {
+ this.connection.send({
+ type: 'read',
+ id: message.id
+ });
+ }
+ });
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-messaging-room
+ > .stream
+ max-width 600px
+ margin 0 auto
+
+ > .init
+ width 100%
+ margin 0
+ padding 16px 8px 8px 8px
+ text-align center
+ font-size 0.8em
+ color rgba(0, 0, 0, 0.4)
+
+ [data-fa]
+ margin-right 4px
+
+ > .empty
+ width 100%
+ margin 0
+ padding 16px 8px 8px 8px
+ text-align center
+ font-size 0.8em
+ color rgba(0, 0, 0, 0.4)
+
+ [data-fa]
+ margin-right 4px
+
+ > .no-history
+ display block
+ margin 0
+ padding 16px
+ text-align center
+ font-size 0.8em
+ color rgba(0, 0, 0, 0.4)
+
+ [data-fa]
+ margin-right 4px
+
+ > .more
+ display block
+ margin 16px auto
+ padding 0 12px
+ line-height 24px
+ color #fff
+ background rgba(0, 0, 0, 0.3)
+ border-radius 12px
+
+ &:hover
+ background rgba(0, 0, 0, 0.4)
+
+ &:active
+ background rgba(0, 0, 0, 0.5)
+
+ &.fetching
+ cursor wait
+
+ > [data-fa]
+ margin-right 4px
+
+ > .message
+ // something
+
+ > .date
+ display block
+ margin 8px 0
+ text-align center
+
+ &:before
+ content ''
+ display block
+ position absolute
+ height 1px
+ width 90%
+ top 16px
+ left 0
+ right 0
+ margin 0 auto
+ background rgba(0, 0, 0, 0.1)
+
+ > span
+ display inline-block
+ margin 0
+ padding 0 16px
+ //font-weight bold
+ line-height 32px
+ color rgba(0, 0, 0, 0.3)
+ background #fff
+
+ > footer
+ position -webkit-sticky
+ position sticky
+ z-index 2
+ bottom 0
+ width 100%
+ max-width 600px
+ margin 0 auto
+ padding 0
+ background rgba(255, 255, 255, 0.95)
+ background-clip content-box
+
+ > [ref='notifications']
+ position absolute
+ top -48px
+ width 100%
+ padding 8px 0
+ text-align center
+
+ &:empty
+ display none
+
+ > p
+ display inline-block
+ margin 0
+ padding 0 12px 0 28px
+ cursor pointer
+ line-height 32px
+ font-size 12px
+ color $theme-color-foreground
+ background $theme-color
+ border-radius 16px
+ transition opacity 1s ease
+
+ > [data-fa]
+ position absolute
+ top 0
+ left 10px
+ line-height 32px
+ font-size 16px
+
+ > .grippie
+ height 10px
+ margin-top -10px
+ background transparent
+ cursor ns-resize
+
+ &:hover
+ //background rgba(0, 0, 0, 0.1)
+
+ &:active
+ //background rgba(0, 0, 0, 0.2)
+
+</style>