diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2018-02-18 12:35:18 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2018-02-18 12:35:18 +0900 |
| commit | 99b34993640eb91a591faa4bccf7d7b6f176ad97 (patch) | |
| tree | f45bd1e385dc9a78f5322e233767cbb44e3fa2cf /src/web | |
| parent | wip (diff) | |
| download | sharkey-99b34993640eb91a591faa4bccf7d7b6f176ad97.tar.gz sharkey-99b34993640eb91a591faa4bccf7d7b6f176ad97.tar.bz2 sharkey-99b34993640eb91a591faa4bccf7d7b6f176ad97.zip | |
wip
Diffstat (limited to 'src/web')
103 files changed, 878 insertions, 790 deletions
diff --git a/src/web/app/common/views/components/messaging-form.vue b/src/web/app/common/views/components/messaging-form.vue index bf4dd17baa..18d45790e4 100644 --- a/src/web/app/common/views/components/messaging-form.vue +++ b/src/web/app/common/views/components/messaging-form.vue @@ -62,7 +62,7 @@ export default Vue.extend({ send() { this.sending = true; - this.$root.$data.os.api('messaging/messages/create', { + (this as any).api('messaging/messages/create', { user_id: this.user.id, text: this.text }).then(message => { diff --git a/src/web/app/common/views/components/messaging-message.vue b/src/web/app/common/views/components/messaging-message.vue index b1afe7a690..6f44332aff 100644 --- a/src/web/app/common/views/components/messaging-message.vue +++ b/src/web/app/common/views/components/messaging-message.vue @@ -8,7 +8,7 @@ <p class="read" v-if="message.is_me && message.is_read">%i18n:common.tags.mk-messaging-message.is-read%</p> <button class="delete-button" v-if="message.is_me" title="%i18n:common.delete%"><img src="/assets/desktop/messaging/delete.png" alt="Delete"/></button> <div class="content" v-if="!message.is_deleted"> - <mk-post-html v-if="message.ast" :ast="message.ast" :i="$root.$data.os.i"/> + <mk-post-html v-if="message.ast" :ast="message.ast" :i="os.i"/> <mk-url-preview v-for="url in urls" :url="url" :key="url"/> <div class="image" v-if="message.file"><img src={ message.file.url } alt="image" title={ message.file.name }/></div> </div> @@ -30,7 +30,7 @@ export default Vue.extend({ props: ['message'], computed: { isMe(): boolean { - return this.message.user_id == this.$root.$data.os.i.id; + return this.message.user_id == (this as any).os.i.id; }, urls(): string[] { if (this.message.ast) { diff --git a/src/web/app/common/views/components/messaging-room.vue b/src/web/app/common/views/components/messaging-room.vue index 838e1e2653..978610d7ff 100644 --- a/src/web/app/common/views/components/messaging-room.vue +++ b/src/web/app/common/views/components/messaging-room.vue @@ -48,7 +48,7 @@ export default Vue.extend({ }, mounted() { - this.connection = new MessagingStreamConnection(this.$root.$data.os.i, this.user.id); + this.connection = new MessagingStreamConnection((this as any).os.i, this.user.id); this.connection.on('message', this.onMessage); this.connection.on('read', this.onRead); @@ -72,7 +72,7 @@ export default Vue.extend({ return new Promise((resolve, reject) => { const max = this.existMoreMessages ? 20 : 10; - this.$root.$data.os.api('messaging/messages', { + (this as any).api('messaging/messages', { user_id: this.user.id, limit: max + 1, until_id: this.existMoreMessages ? this.messages[0].id : undefined @@ -99,7 +99,7 @@ export default Vue.extend({ const isBottom = this.isBottom(); this.messages.push(message); - if (message.user_id != this.$root.$data.os.i.id && !document.hidden) { + if (message.user_id != (this as any).os.i.id && !document.hidden) { this.connection.send({ type: 'read', id: message.id @@ -109,7 +109,7 @@ export default Vue.extend({ if (isBottom) { // Scroll to bottom this.scrollToBottom(); - } else if (message.user_id != this.$root.$data.os.i.id) { + } else if (message.user_id != (this as any).os.i.id) { // Notify this.notify('%i18n:common.tags.mk-messaging-room.new-message%'); } @@ -157,7 +157,7 @@ export default Vue.extend({ onVisibilitychange() { if (document.hidden) return; this.messages.forEach(message => { - if (message.user_id !== this.$root.$data.os.i.id && !message.is_read) { + if (message.user_id !== (this as any).os.i.id && !message.is_read) { this.connection.send({ type: 'read', id: message.id diff --git a/src/web/app/common/views/components/messaging.vue b/src/web/app/common/views/components/messaging.vue index f45f99b535..1b56382b08 100644 --- a/src/web/app/common/views/components/messaging.vue +++ b/src/web/app/common/views/components/messaging.vue @@ -71,13 +71,13 @@ export default Vue.extend({ }; }, mounted() { - this.connection = this.$root.$data.os.streams.messagingIndexStream.getConnection(); - this.connectionId = this.$root.$data.os.streams.messagingIndexStream.use(); + this.connection = (this as any).os.streams.messagingIndexStream.getConnection(); + this.connectionId = (this as any).os.streams.messagingIndexStream.use(); this.connection.on('message', this.onMessage); this.connection.on('read', this.onRead); - this.$root.$data.os.api('messaging/history').then(messages => { + (this as any).api('messaging/history').then(messages => { this.fetching = false; this.messages = messages; }); @@ -85,11 +85,11 @@ export default Vue.extend({ beforeDestroy() { this.connection.off('message', this.onMessage); this.connection.off('read', this.onRead); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { isMe(message) { - return message.user_id == this.$root.$data.os.i.id; + return message.user_id == (this as any).os.i.id; }, onMessage(message) { this.messages = this.messages.filter(m => !( @@ -109,7 +109,7 @@ export default Vue.extend({ this.result = []; return; } - this.$root.$data.os.api('users/search', { + (this as any).api('users/search', { query: this.q, max: 5 }).then(users => { diff --git a/src/web/app/common/views/components/poll.vue b/src/web/app/common/views/components/poll.vue index 19ce557e73..d06c019dba 100644 --- a/src/web/app/common/views/components/poll.vue +++ b/src/web/app/common/views/components/poll.vue @@ -47,7 +47,7 @@ }, vote(id) { if (this.poll.choices.some(c => c.is_voted)) return; - this.$root.$data.os.api('posts/polls/vote', { + (this as any).api('posts/polls/vote', { post_id: this.post.id, choice: id }).then(() => { diff --git a/src/web/app/common/views/components/post-menu.vue b/src/web/app/common/views/components/post-menu.vue index 7a33360f60..e14d67fc8d 100644 --- a/src/web/app/common/views/components/post-menu.vue +++ b/src/web/app/common/views/components/post-menu.vue @@ -48,7 +48,7 @@ export default Vue.extend({ }, methods: { pin() { - this.$root.$data.os.api('i/pin', { + (this as any).api('i/pin', { post_id: this.post.id }).then(() => { this.$destroy(); diff --git a/src/web/app/common/views/components/reaction-picker.vue b/src/web/app/common/views/components/reaction-picker.vue index 0446d7b18e..f3731cd632 100644 --- a/src/web/app/common/views/components/reaction-picker.vue +++ b/src/web/app/common/views/components/reaction-picker.vue @@ -68,7 +68,7 @@ export default Vue.extend({ }, methods: { react(reaction) { - this.$root.$data.os.api('posts/reactions/create', { + (this as any).api('posts/reactions/create', { post_id: this.post.id, reaction: reaction }).then(() => { diff --git a/src/web/app/common/views/components/signin.vue b/src/web/app/common/views/components/signin.vue index 989c017054..31243e99a1 100644 --- a/src/web/app/common/views/components/signin.vue +++ b/src/web/app/common/views/components/signin.vue @@ -28,7 +28,7 @@ export default Vue.extend({ }, methods: { onUsernameChange() { - this.$root.$data.os.api('users/show', { + (this as any).api('users/show', { username: this.username }).then(user => { this.user = user; @@ -37,7 +37,7 @@ export default Vue.extend({ onSubmit() { this.signing = true; - this.$root.$data.os.api('signin', { + (this as any).api('signin', { username: this.username, password: this.password, token: this.user && this.user.two_factor_enabled ? this.token : undefined diff --git a/src/web/app/common/views/components/signup.vue b/src/web/app/common/views/components/signup.vue index 34d17ef0ea..1fdc49a181 100644 --- a/src/web/app/common/views/components/signup.vue +++ b/src/web/app/common/views/components/signup.vue @@ -88,7 +88,7 @@ export default Vue.extend({ this.usernameState = 'wait'; - this.$root.$data.os.api('username/available', { + (this as any).api('username/available', { username: this.username }).then(result => { this.usernameState = result.available ? 'ok' : 'unavailable'; @@ -115,12 +115,12 @@ export default Vue.extend({ this.passwordRetypeState = this.password == this.retypedPassword ? 'match' : 'not-match'; }, onSubmit() { - this.$root.$data.os.api('signup', { + (this as any).api('signup', { username: this.username, password: this.password, 'g-recaptcha-response': (window as any).grecaptcha.getResponse() }).then(() => { - this.$root.$data.os.api('signin', { + (this as any).api('signin', { username: this.username, password: this.password }).then(() => { diff --git a/src/web/app/common/views/components/stream-indicator.vue b/src/web/app/common/views/components/stream-indicator.vue index 00bd58c1f9..c1c0672e48 100644 --- a/src/web/app/common/views/components/stream-indicator.vue +++ b/src/web/app/common/views/components/stream-indicator.vue @@ -26,10 +26,10 @@ export default Vue.extend({ }; }, created() { - this.stream = this.$root.$data.os.stream.borrow(); + this.stream = (this as any).os.stream.borrow(); - this.$root.$data.os.stream.on('connected', this.onConnected); - this.$root.$data.os.stream.on('disconnected', this.onDisconnected); + (this as any).os.stream.on('connected', this.onConnected); + (this as any).os.stream.on('disconnected', this.onDisconnected); this.$nextTick(() => { if (this.stream.state == 'connected') { @@ -38,12 +38,12 @@ export default Vue.extend({ }); }, beforeDestroy() { - this.$root.$data.os.stream.off('connected', this.onConnected); - this.$root.$data.os.stream.off('disconnected', this.onDisconnected); + (this as any).os.stream.off('connected', this.onConnected); + (this as any).os.stream.off('disconnected', this.onDisconnected); }, methods: { onConnected() { - this.stream = this.$root.$data.os.stream.borrow(); + this.stream = (this as any).os.stream.borrow(); setTimeout(() => { anime({ diff --git a/src/web/app/common/views/components/uploader.vue b/src/web/app/common/views/components/uploader.vue index 21f92caabf..6367b69973 100644 --- a/src/web/app/common/views/components/uploader.vue +++ b/src/web/app/common/views/components/uploader.vue @@ -50,7 +50,7 @@ export default Vue.extend({ reader.readAsDataURL(file); const data = new FormData(); - data.append('i', this.$root.$data.os.i.token); + data.append('i', (this as any).os.i.token); data.append('file', file); if (folder) data.append('folder_id', folder); diff --git a/src/web/app/common/views/components/widgets/photo-stream.vue b/src/web/app/common/views/components/widgets/photo-stream.vue index afbdc2162c..4d6b660696 100644 --- a/src/web/app/common/views/components/widgets/photo-stream.vue +++ b/src/web/app/common/views/components/widgets/photo-stream.vue @@ -26,12 +26,12 @@ export default define({ }; }, mounted() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('drive_file_created', this.onDriveFileCreated); - this.$root.$data.os.api('drive/stream', { + (this as any).api('drive/stream', { type: 'image/*', limit: 9 }).then(images => { @@ -41,7 +41,7 @@ export default define({ }, beforeDestroy() { this.connection.off('drive_file_created', this.onDriveFileCreated); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { onDriveFileCreated(file) { diff --git a/src/web/app/common/views/components/widgets/slideshow.vue b/src/web/app/common/views/components/widgets/slideshow.vue index c24e3003c4..a200aa061d 100644 --- a/src/web/app/common/views/components/widgets/slideshow.vue +++ b/src/web/app/common/views/components/widgets/slideshow.vue @@ -89,7 +89,7 @@ export default define({ fetch() { this.fetching = true; - this.$root.$data.os.api('drive/files', { + (this as any).api('drive/files', { folder_id: this.props.folder, type: 'image/*', limit: 100 @@ -102,7 +102,7 @@ export default define({ }); }, choose() { - this.$root.$data.api.chooseDriveFolder().then(folder => { + (this as any).apis.chooseDriveFolder().then(folder => { this.props.folder = folder ? folder.id : null; this.fetch(); }); diff --git a/src/web/app/desktop/-tags/drive/browser-window.tag b/src/web/app/desktop/-tags/drive/browser-window.tag deleted file mode 100644 index c9c7652521..0000000000 --- a/src/web/app/desktop/-tags/drive/browser-window.tag +++ /dev/null @@ -1,60 +0,0 @@ -<mk-drive-browser-window> - <mk-window ref="window" is-modal={ false } width={ '800px' } height={ '500px' } popout={ popout }> - <yield to="header"> - <p class="info" v-if="parent.usage"><b>{ parent.usage.toFixed(1) }%</b> %i18n:desktop.tags.mk-drive-browser-window.used%</p> - %fa:cloud%%i18n:desktop.tags.mk-drive-browser-window.drive% - </yield> - <yield to="content"> - <mk-drive-browser multiple={ true } folder={ parent.folder } ref="browser"/> - </yield> - </mk-window> - <style lang="stylus" scoped> - :scope - > mk-window - [data-yield='header'] - > .info - position absolute - top 0 - left 16px - margin 0 - font-size 80% - - > [data-fa] - margin-right 4px - - [data-yield='content'] - > mk-drive-browser - height 100% - - </style> - <script lang="typescript"> - this.mixin('api'); - - this.folder = this.opts.folder ? this.opts.folder : null; - - this.popout = () => { - const folder = this.$refs.window.refs.browser.folder; - if (folder) { - return `${_URL_}/i/drive/folder/${folder.id}`; - } else { - return `${_URL_}/i/drive`; - } - }; - - this.on('mount', () => { - this.$refs.window.on('closed', () => { - this.$destroy(); - }); - - this.$root.$data.os.api('drive').then(info => { - this.update({ - usage: info.usage / info.capacity * 100 - }); - }); - }); - - this.close = () => { - this.$refs.window.close(); - }; - </script> -</mk-drive-browser-window> diff --git a/src/web/app/desktop/-tags/drive/file-contextmenu.tag b/src/web/app/desktop/-tags/drive/file-contextmenu.tag deleted file mode 100644 index 8776fcc029..0000000000 --- a/src/web/app/desktop/-tags/drive/file-contextmenu.tag +++ /dev/null @@ -1,99 +0,0 @@ -<mk-drive-browser-file-contextmenu> - <mk-contextmenu ref="ctx"> - <ul> - <li @click="parent.rename"> - <p>%fa:i-cursor%%i18n:desktop.tags.mk-drive-browser-file-contextmenu.rename%</p> - </li> - <li @click="parent.copyUrl"> - <p>%fa:link%%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copy-url%</p> - </li> - <li><a href={ parent.file.url + '?download' } download={ parent.file.name } @click="parent.download">%fa:download%%i18n:desktop.tags.mk-drive-browser-file-contextmenu.download%</a></li> - <li class="separator"></li> - <li @click="parent.delete"> - <p>%fa:R trash-alt%%i18n:common.delete%</p> - </li> - <li class="separator"></li> - <li class="has-child"> - <p>%i18n:desktop.tags.mk-drive-browser-file-contextmenu.else-files%%fa:caret-right%</p> - <ul> - <li @click="parent.setAvatar"> - <p>%i18n:desktop.tags.mk-drive-browser-file-contextmenu.set-as-avatar%</p> - </li> - <li @click="parent.setBanner"> - <p>%i18n:desktop.tags.mk-drive-browser-file-contextmenu.set-as-banner%</p> - </li> - </ul> - </li> - <li class="has-child"> - <p>%i18n:desktop.tags.mk-drive-browser-file-contextmenu.open-in-app%...%fa:caret-right%</p> - <ul> - <li @click="parent.addApp"> - <p>%i18n:desktop.tags.mk-drive-browser-file-contextmenu.add-app%...</p> - </li> - </ul> - </li> - </ul> - </mk-contextmenu> - <script lang="typescript"> - import copyToClipboard from '../../../common/scripts/copy-to-clipboard'; - import dialog from '../../scripts/dialog'; - import inputDialog from '../../scripts/input-dialog'; - import updateAvatar from '../../scripts/update-avatar'; - import NotImplementedException from '../../scripts/not-implemented-exception'; - - this.mixin('i'); - this.mixin('api'); - - this.browser = this.opts.browser; - this.file = this.opts.file; - - this.on('mount', () => { - this.$refs.ctx.on('closed', () => { - this.$emit('closed'); - this.$destroy(); - }); - }); - - this.open = pos => { - this.$refs.ctx.open(pos); - }; - - this.rename = () => { - this.$refs.ctx.close(); - - inputDialog('%i18n:desktop.tags.mk-drive-browser-file-contextmenu.rename-file%', '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.input-new-file-name%', this.file.name, name => { - this.$root.$data.os.api('drive/files/update', { - file_id: this.file.id, - name: name - }) - }); - }; - - this.copyUrl = () => { - copyToClipboard(this.file.url); - this.$refs.ctx.close(); - dialog('%fa:check%%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copied%', - '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copied-url-to-clipboard%', [{ - text: '%i18n:common.ok%' - }]); - }; - - this.download = () => { - this.$refs.ctx.close(); - }; - - this.setAvatar = () => { - this.$refs.ctx.close(); - updateAvatar(this.I, null, this.file); - }; - - this.setBanner = () => { - this.$refs.ctx.close(); - updateBanner(this.I, null, this.file); - }; - - this.addApp = () => { - NotImplementedException(); - }; - </script> -</mk-drive-browser-file-contextmenu> diff --git a/src/web/app/desktop/-tags/drive/folder-contextmenu.tag b/src/web/app/desktop/-tags/drive/folder-contextmenu.tag deleted file mode 100644 index a0146410f6..0000000000 --- a/src/web/app/desktop/-tags/drive/folder-contextmenu.tag +++ /dev/null @@ -1,63 +0,0 @@ -<mk-drive-browser-folder-contextmenu> - <mk-contextmenu ref="ctx"> - <ul> - <li @click="parent.move"> - <p>%fa:arrow-right%%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.move-to-this-folder%</p> - </li> - <li @click="parent.newWindow"> - <p>%fa:R window-restore%%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.show-in-new-window%</p> - </li> - <li class="separator"></li> - <li @click="parent.rename"> - <p>%fa:i-cursor%%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.rename%</p> - </li> - <li class="separator"></li> - <li @click="parent.delete"> - <p>%fa:R trash-alt%%i18n:common.delete%</p> - </li> - </ul> - </mk-contextmenu> - <script lang="typescript"> - import inputDialog from '../../scripts/input-dialog'; - - this.mixin('api'); - - this.browser = this.opts.browser; - this.folder = this.opts.folder; - - this.open = pos => { - this.$refs.ctx.open(pos); - - this.$refs.ctx.on('closed', () => { - this.$emit('closed'); - this.$destroy(); - }); - }; - - this.move = () => { - this.browser.move(this.folder.id); - this.$refs.ctx.close(); - }; - - this.newWindow = () => { - this.browser.newWindow(this.folder.id); - this.$refs.ctx.close(); - }; - - this.createFolder = () => { - this.browser.createFolder(); - this.$refs.ctx.close(); - }; - - this.rename = () => { - this.$refs.ctx.close(); - - inputDialog('%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.rename-folder%', '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.input-new-folder-name%', this.folder.name, name => { - this.$root.$data.os.api('drive/folders/update', { - folder_id: this.folder.id, - name: name - }); - }); - }; - </script> -</mk-drive-browser-folder-contextmenu> diff --git a/src/web/app/desktop/api/choose-drive-file.ts b/src/web/app/desktop/api/choose-drive-file.ts new file mode 100644 index 0000000000..e048441713 --- /dev/null +++ b/src/web/app/desktop/api/choose-drive-file.ts @@ -0,0 +1,18 @@ +import MkChooseFileFromDriveWindow from '../views/components/choose-file-from-drive-window.vue'; + +export default function(opts) { + return new Promise((res, rej) => { + const o = opts || {}; + const w = new MkChooseFileFromDriveWindow({ + propsData: { + title: o.title, + multiple: o.multiple, + initFolder: o.currentFolder + } + }).$mount(); + w.$once('selected', file => { + res(file); + }); + document.body.appendChild(w.$el); + }); +} diff --git a/src/web/app/desktop/api/choose-drive-folder.ts b/src/web/app/desktop/api/choose-drive-folder.ts index a5116f7bcd..9b33a20d9a 100644 --- a/src/web/app/desktop/api/choose-drive-folder.ts +++ b/src/web/app/desktop/api/choose-drive-folder.ts @@ -1,12 +1,12 @@ -import MkChooseFolderFromDriveWindow from '../../../common/views/components/choose-folder-from-drive-window.vue'; +import MkChooseFolderFromDriveWindow from '../views/components/choose-folder-from-drive-window.vue'; -export default function(this: any, opts) { +export default function(opts) { return new Promise((res, rej) => { const o = opts || {}; const w = new MkChooseFolderFromDriveWindow({ - parent: this, propsData: { - title: o.title + title: o.title, + initFolder: o.currentFolder } }).$mount(); w.$once('selected', folder => { diff --git a/src/web/app/desktop/api/contextmenu.ts b/src/web/app/desktop/api/contextmenu.ts new file mode 100644 index 0000000000..b70d7122d3 --- /dev/null +++ b/src/web/app/desktop/api/contextmenu.ts @@ -0,0 +1,16 @@ +import Ctx from '../views/components/context-menu.vue'; + +export default function(e, menu, opts?) { + const o = opts || {}; + const vm = new Ctx({ + propsData: { + menu, + x: e.pageX - window.pageXOffset, + y: e.pageY - window.pageYOffset, + } + }).$mount(); + vm.$once('closed', () => { + if (o.closed) o.closed(); + }); + document.body.appendChild(vm.$el); +} diff --git a/src/web/app/desktop/api/dialog.ts b/src/web/app/desktop/api/dialog.ts new file mode 100644 index 0000000000..07935485b0 --- /dev/null +++ b/src/web/app/desktop/api/dialog.ts @@ -0,0 +1,19 @@ +import Dialog from '../views/components/dialog.vue'; + +export default function(opts) { + return new Promise<string>((res, rej) => { + const o = opts || {}; + const d = new Dialog({ + propsData: { + title: o.title, + text: o.text, + modal: o.modal, + buttons: o.actions + } + }).$mount(); + d.$once('clicked', id => { + res(id); + }); + document.body.appendChild(d.$el); + }); +} diff --git a/src/web/app/desktop/api/input.ts b/src/web/app/desktop/api/input.ts new file mode 100644 index 0000000000..a5ab07138a --- /dev/null +++ b/src/web/app/desktop/api/input.ts @@ -0,0 +1,19 @@ +import InputDialog from '../views/components/input-dialog.vue'; + +export default function(opts) { + return new Promise<string>((res, rej) => { + const o = opts || {}; + const d = new InputDialog({ + propsData: { + title: o.title, + placeholder: o.placeholder, + default: o.default, + type: o.type || 'text' + } + }).$mount(); + d.$once('done', text => { + res(text); + }); + document.body.appendChild(d.$el); + }); +} diff --git a/src/web/app/desktop/script.ts b/src/web/app/desktop/script.ts index cd894170e2..cb7a53fb2b 100644 --- a/src/web/app/desktop/script.ts +++ b/src/web/app/desktop/script.ts @@ -11,6 +11,9 @@ import HomeStreamManager from '../common/scripts/streaming/home-stream-manager'; import composeNotification from '../common/scripts/compose-notification'; import chooseDriveFolder from './api/choose-drive-folder'; +import chooseDriveFile from './api/choose-drive-file'; +import dialog from './api/dialog'; +import input from './api/input'; import MkIndex from './views/pages/index.vue'; @@ -30,7 +33,10 @@ init(async (launch) => { require('./views/components'); const app = launch({ - chooseDriveFolder + chooseDriveFolder, + chooseDriveFile, + dialog, + input }); /** diff --git a/src/web/app/desktop/views/components/2fa-setting.vue b/src/web/app/desktop/views/components/2fa-setting.vue index 146d707e1c..8271cbbf36 100644 --- a/src/web/app/desktop/views/components/2fa-setting.vue +++ b/src/web/app/desktop/views/components/2fa-setting.vue @@ -36,7 +36,7 @@ export default Vue.extend({ methods: { register() { passwordDialog('%i18n:desktop.tags.mk-2fa-setting.enter-password%', password => { - this.$root.$data.os.api('i/2fa/register', { + (this as any).api('i/2fa/register', { password: password }).then(data => { this.data = data; @@ -46,21 +46,21 @@ export default Vue.extend({ unregister() { passwordDialog('%i18n:desktop.tags.mk-2fa-setting.enter-password%', password => { - this.$root.$data.os.api('i/2fa/unregister', { + (this as any).api('i/2fa/unregister', { password: password }).then(() => { notify('%i18n:desktop.tags.mk-2fa-setting.unregistered%'); - this.$root.$data.os.i.two_factor_enabled = false; + (this as any).os.i.two_factor_enabled = false; }); }); }, submit() { - this.$root.$data.os.api('i/2fa/done', { + (this as any).api('i/2fa/done', { token: this.token }).then(() => { notify('%i18n:desktop.tags.mk-2fa-setting.success%'); - this.$root.$data.os.i.two_factor_enabled = true; + (this as any).os.i.two_factor_enabled = true; }).catch(() => { notify('%i18n:desktop.tags.mk-2fa-setting.failed%'); }); diff --git a/src/web/app/desktop/views/components/api-setting.vue b/src/web/app/desktop/views/components/api-setting.vue index 78429064b9..08c5a0c512 100644 --- a/src/web/app/desktop/views/components/api-setting.vue +++ b/src/web/app/desktop/views/components/api-setting.vue @@ -1,6 +1,6 @@ <template> <div class="mk-api-setting"> - <p>Token: <code>{{ $root.$data.os.i.token }}</code></p> + <p>Token: <code>{{ os.i.token }}</code></p> <p>%i18n:desktop.tags.mk-api-info.intro%</p> <div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:desktop.tags.mk-api-info.caution%</p></div> <p>%i18n:desktop.tags.mk-api-info.regeneration-of-token%</p> @@ -16,7 +16,7 @@ export default Vue.extend({ methods: { regenerateToken() { passwordDialog('%i18n:desktop.tags.mk-api-info.enter-password%', password => { - this.$root.$data.os.api('i/regenerate_token', { + (this as any).api('i/regenerate_token', { password: password }); }); diff --git a/src/web/app/desktop/views/components/context-menu-menu.vue b/src/web/app/desktop/views/components/context-menu-menu.vue new file mode 100644 index 0000000000..423ea0a1f0 --- /dev/null +++ b/src/web/app/desktop/views/components/context-menu-menu.vue @@ -0,0 +1,113 @@ +<template> +<ul class="me-nu"> + <li v-for="(item, i) in menu" :key="i" :class="item.type"> + <template v-if="item.type == 'item'"> + <p @click="click(item)"><span class="icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</p> + </template> + <template v-else-if="item.type == 'nest'"> + <p><span class="icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}...<span class="caret">%fa:caret-right%</span></p> + <me-nu :menu="item.menu" @x="click"/> + </template> + </li> +</ul> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ + name: 'me-nu', + props: ['menu'], + methods: { + click(item) { + this.$emit('x', item); + } + } +}); +</script> + +<style lang="stylus" scoped> +.me-nu + $width = 240px + $item-height = 38px + $padding = 10px + + ul + display block + margin 0 + padding $padding 0 + list-style none + + li + display block + + &:empty + margin-top $padding + padding-top $padding + border-top solid 1px #eee + + &.nest + > p + cursor default + + > .caret + > * + position absolute + top 0 + right 8px + line-height $item-height + + &:hover > ul + visibility visible + + &:active + > p, a + background $theme-color + + > p, a + display block + z-index 1 + margin 0 + padding 0 32px 0 38px + line-height $item-height + color #868C8C + text-decoration none + cursor pointer + + &:hover + text-decoration none + + * + pointer-events none + + > .icon + > * + width 28px + margin-left -28px + text-align center + + &:hover + > p, a + text-decoration none + background $theme-color + color $theme-color-foreground + + &:active + > p, a + text-decoration none + background darken($theme-color, 10%) + color $theme-color-foreground + + li > ul + visibility hidden + position absolute + top 0 + left $width + margin-top -($padding) + width $width + background #fff + border-radius 0 4px 4px 4px + box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2) + transition visibility 0s linear 0.2s + +</style> + diff --git a/src/web/app/desktop/views/components/context-menu.vue b/src/web/app/desktop/views/components/context-menu.vue new file mode 100644 index 0000000000..9f5787e476 --- /dev/null +++ b/src/web/app/desktop/views/components/context-menu.vue @@ -0,0 +1,74 @@ +<template> +<div class="context-menu" :style="{ x: `${x}px`, y: `${y}px` }" @contextmenu.prevent="() => {}"> + <me-nu :menu="menu" @x="click"/> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import * as anime from 'animejs'; +import contains from '../../../common/scripts/contains'; +import meNu from './context-menu-menu.vue'; + +export default Vue.extend({ + components: { + 'me-nu': meNu + }, + props: ['x', 'y', 'menu'], + mounted() { + this.$nextTick(() => { + Array.from(document.querySelectorAll('body *')).forEach(el => { + el.addEventListener('mousedown', this.onMousedown); + }); + + this.$el.style.display = 'block'; + + anime({ + targets: this.$el, + opacity: [0, 1], + duration: 100, + easing: 'linear' + }); + }); + }, + methods: { + onMousedown(e) { + e.preventDefault(); + if (!contains(this.$el, e.target) && (this.$el != e.target)) this.close(); + return false; + }, + click(item) { + if (item.onClick) item.onClick(); + this.close(); + }, + close() { + Array.from(document.querySelectorAll('body *')).forEach(el => { + el.removeEventListener('mousedown', this.onMousedown); + }); + + this.$emit('closed'); + this.$destroy(); + } + } +}); +</script> + +<style lang="stylus" scoped> +.context-menu + $width = 240px + $item-height = 38px + $padding = 10px + + display none + position fixed + top 0 + left 0 + z-index 4096 + width $width + font-size 0.8em + background #fff + border-radius 0 4px 4px 4px + box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2) + opacity 0 + +</style> diff --git a/src/web/app/desktop/views/components/contextmenu.vue b/src/web/app/desktop/views/components/contextmenu.vue deleted file mode 100644 index c6fccc22c0..0000000000 --- a/src/web/app/desktop/views/components/contextmenu.vue +++ /dev/null @@ -1,142 +0,0 @@ -<template> -<div class="mk-contextmenu" @contextmenu.prevent="() => {}"> - <slot></slot> -</div> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import * as anime from 'animejs'; -import contains from '../../../common/scripts/contains'; - -export default Vue.extend({ - props: ['x', 'y'], - mounted() { - document.querySelectorAll('body *').forEach(el => { - el.addEventListener('mousedown', this.onMousedown); - }); - - this.$el.style.display = 'block'; - this.$el.style.left = this.x + 'px'; - this.$el.style.top = this.y + 'px'; - - anime({ - targets: this.$el, - opacity: [0, 1], - duration: 100, - easing: 'linear' - }); - }, - methods: { - onMousedown(e) { - e.preventDefault(); - if (!contains(this.$el, e.target) && (this.$el != e.target)) this.close(); - return false; - }, - close() { - Array.from(document.querySelectorAll('body *')).forEach(el => { - el.removeEventListener('mousedown', this.onMousedown); - }); - - this.$emit('closed'); - this.$destroy(); - } - } -}); -</script> - -<style lang="stylus" scoped> -.mk-contextmenu - $width = 240px - $item-height = 38px - $padding = 10px - - display none - position fixed - top 0 - left 0 - z-index 4096 - width $width - font-size 0.8em - background #fff - border-radius 0 4px 4px 4px - box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2) - opacity 0 - - ul - display block - margin 0 - padding $padding 0 - list-style none - - li - display block - - &.separator - margin-top $padding - padding-top $padding - border-top solid 1px #eee - - &.has-child - > p - cursor default - - > [data-fa]:last-child - position absolute - top 0 - right 8px - line-height $item-height - - &:hover > ul - visibility visible - - &:active - > p, a - background $theme-color - - > p, a - display block - z-index 1 - margin 0 - padding 0 32px 0 38px - line-height $item-height - color #868C8C - text-decoration none - cursor pointer - - &:hover - text-decoration none - - * - pointer-events none - - > i - width 28px - margin-left -28px - text-align center - - &:hover - > p, a - text-decoration none - background $theme-color - color $theme-color-foreground - - &:active - > p, a - text-decoration none - background darken($theme-color, 10%) - color $theme-color-foreground - - li > ul - visibility hidden - position absolute - top 0 - left $width - margin-top -($padding) - width $width - background #fff - border-radius 0 4px 4px 4px - box-shadow 2px 2px 8px rgba(0, 0, 0, 0.2) - transition visibility 0s linear 0.2s - -</style> diff --git a/src/web/app/desktop/views/components/dialog.vue b/src/web/app/desktop/views/components/dialog.vue index 9bb7fca1bf..f2be5e4433 100644 --- a/src/web/app/desktop/views/components/dialog.vue +++ b/src/web/app/desktop/views/components/dialog.vue @@ -5,7 +5,7 @@ <header v-html="title"></header> <div class="body" v-html="text"></div> <div class="buttons"> - <button v-for="(button, i) in buttons" @click="click(button)" :key="i">{{ button.text }}</button> + <button v-for="button in buttons" @click="click(button)" :key="button.id">{{ button.text }}</button> </div> </div> </div> @@ -26,13 +26,9 @@ export default Vue.extend({ buttons: { type: Array }, - canThrough: { + modal: { type: Boolean, - default: true - }, - onThrough: { - type: Function, - required: false + default: false } }, mounted() { @@ -54,7 +50,7 @@ export default Vue.extend({ }, methods: { click(button) { - if (button.onClick) button.onClick(); + this.$emit('clicked', button.id); this.close(); }, close() { @@ -77,8 +73,7 @@ export default Vue.extend({ }); }, onBgClick() { - if (this.canThrough) { - if (this.onThrough) this.onThrough(); + if (!this.modal) { this.close(); } } diff --git a/src/web/app/desktop/views/components/drive-contextmenu.vue b/src/web/app/desktop/views/components/drive-contextmenu.vue deleted file mode 100644 index bdb3bd00dc..0000000000 --- a/src/web/app/desktop/views/components/drive-contextmenu.vue +++ /dev/null @@ -1,46 +0,0 @@ -<template> -<mk-contextmenu ref="menu" @closed="onClosed"> - <ul> - <li @click="createFolder"> - <p>%fa:R folder%%i18n:desktop.tags.mk-drive-browser-base-contextmenu.create-folder%</p> - </li> - <li @click="upload"> - <p>%fa:upload%%i18n:desktop.tags.mk-drive-browser-base-contextmenu.upload%</p> - </li> - <li @click="urlUpload"> - <p>%fa:cloud-upload-alt%%i18n:desktop.tags.mk-drive-browser-base-contextmenu.url-upload%</p> - </li> - </ul> -</mk-contextmenu> -</template> - -<script lang="ts"> -import Vue from 'vue'; -export default Vue.extend({ - props: ['browser'], - mounted() { - - }, - methods: { - close() { - (this.$refs.menu as any).close(); - }, - onClosed() { - this.$emit('closed'); - this.$destroy(); - }, - createFolder() { - this.browser.createFolder(); - this.close(); - }, - upload() { - this.browser.selectLocalFile(); - this.close(); - }, - urlUpload() { - this.browser.urlUpload(); - this.close(); - } - } -}); -</script> diff --git a/src/web/app/desktop/views/components/drive-file.vue b/src/web/app/desktop/views/components/drive-file.vue index cda561d31b..0681b5f036 100644 --- a/src/web/app/desktop/views/components/drive-file.vue +++ b/src/web/app/desktop/views/components/drive-file.vue @@ -3,24 +3,24 @@ :data-is-selected="isSelected" :data-is-contextmenu-showing="isContextmenuShowing" @click="onClick" - @contextmenu.prevent.stop="onContextmenu" draggable="true" @dragstart="onDragstart" @dragend="onDragend" + @contextmenu.prevent.stop="onContextmenu" :title="title" > - <div class="label" v-if="I.avatar_id == file.id"><img src="/assets/label.svg"/> + <div class="label" v-if="os.i.avatar_id == file.id"><img src="/assets/label.svg"/> <p>%i18n:desktop.tags.mk-drive-browser-file.avatar%</p> </div> - <div class="label" v-if="I.banner_id == file.id"><img src="/assets/label.svg"/> + <div class="label" v-if="os.i.banner_id == file.id"><img src="/assets/label.svg"/> <p>%i18n:desktop.tags.mk-drive-browser-file.banner%</p> </div> - <div class="thumbnail" ref="thumbnail" style="background-color:{ file.properties.average_color ? 'rgb(' + file.properties.average_color.join(',') + ')' : 'transparent' }"> - <img src={ file.url + '?thumbnail&size=128' } alt="" @load="onThumbnailLoaded"/> + <div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`"> + <img :src="`${file.url}?thumbnail&size=128`" alt="" @load="onThumbnailLoaded"/> </div> <p class="name"> - <span>{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }</span> - <span class="ext" v-if="file.name.lastIndexOf('.') != -1">{ file.name.substr(file.name.lastIndexOf('.')) }</span> + <span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span> + <span class="ext" v-if="file.name.lastIndexOf('.') != -1">{{ file.name.substr(file.name.lastIndexOf('.')) }}</span> </p> </div> </template> @@ -28,10 +28,12 @@ <script lang="ts"> import Vue from 'vue'; import * as anime from 'animejs'; +import contextmenu from '../../api/contextmenu'; +import copyToClipboard from '../../../common/scripts/copy-to-clipboard'; import bytesToSize from '../../../common/scripts/bytes-to-size'; export default Vue.extend({ - props: ['file', 'browser'], + props: ['file'], data() { return { isContextmenuShowing: false, @@ -39,11 +41,19 @@ export default Vue.extend({ }; }, computed: { + browser(): any { + return this.$parent; + }, isSelected(): boolean { return this.browser.selectedFiles.some(f => f.id == this.file.id); }, title(): string { return `${this.file.name}\n${this.file.type} ${bytesToSize(this.file.datasize)}`; + }, + background(): string { + return this.file.properties.average_color + ? `rgb(${this.file.properties.average_color.join(',')})'` + : 'transparent'; } }, methods: { @@ -53,18 +63,55 @@ export default Vue.extend({ onContextmenu(e) { this.isContextmenuShowing = true; - const ctx = new MkDriveFileContextmenu({ - parent: this, - propsData: { - browser: this.browser, - x: e.pageX - window.pageXOffset, - y: e.pageY - window.pageYOffset + contextmenu(e, [{ + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.rename%', + icon: '%fa:i-cursor%', + onClick: this.rename + }, { + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copy-url%', + icon: '%fa:link%', + onClick: this.copyUrl + }, { + type: 'link', + href: `${this.file.url}?download`, + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.download%', + icon: '%fa:download%', + }, { + type: 'divider', + }, { + type: 'item', + text: '%i18n:common.delete%', + icon: '%fa:R trash-alt%', + onClick: this.deleteFile + }, { + type: 'divider', + }, { + type: 'nest', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.else-files%', + menu: [{ + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.set-as-avatar%', + onClick: this.setAsAvatar + }, { + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.set-as-banner%', + onClick: this.setAsBanner + }] + }, { + type: 'nest', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.open-in-app%', + menu: [{ + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.add-app%...', + onClick: this.addApp + }] + }], { + closed: () => { + this.isContextmenuShowing = false; } - }).$mount(); - ctx.$once('closed', () => { - this.isContextmenuShowing = false; }); - document.body.appendChild(ctx.$el); }, onDragstart(e) { @@ -95,6 +142,46 @@ export default Vue.extend({ easing: 'linear' }); } + }, + + rename() { + (this as any).apis.input({ + title: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.rename-file%', + placeholder: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.input-new-file-name%', + default: this.file.name + }).then(name => { + (this as any).api('drive/files/update', { + file_id: this.file.id, + name: name + }) + }); + }, + + copyUrl() { + copyToClipboard(this.file.url); + (this as any).apis.dialog({ + title: '%fa:check%%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copied%', + text: '%i18n:desktop.tags.mk-drive-browser-file-contextmenu.copied-url-to-clipboard%', + actions: [{ + text: '%i18n:common.ok%' + }] + }); + }, + + setAsAvatar() { + (this as any).apis.updateAvatar(this.file); + }, + + setAsBanner() { + (this as any).apis.updateBanner(this.file); + }, + + addApp() { + alert('not implemented yet'); + }, + + deleteFile() { + alert('not implemented yet'); } } }); diff --git a/src/web/app/desktop/views/components/drive-folder.vue b/src/web/app/desktop/views/components/drive-folder.vue index e9e4f1de2c..bfb1345016 100644 --- a/src/web/app/desktop/views/components/drive-folder.vue +++ b/src/web/app/desktop/views/components/drive-folder.vue @@ -9,10 +9,10 @@ @dragenter.prevent="onDragenter" @dragleave="onDragleave" @drop.prevent.stop="onDrop" - @contextmenu.prevent.stop="onContextmenu" draggable="true" @dragstart="onDragstart" @dragend="onDragend" + @contextmenu.prevent.stop="onContextmenu" :title="title" > <p class="name"> @@ -25,10 +25,10 @@ <script lang="ts"> import Vue from 'vue'; -import dialog from '../../scripts/dialog'; +import contextmenu from '../../api/contextmenu'; export default Vue.extend({ - props: ['folder', 'browser'], + props: ['folder'], data() { return { hover: false, @@ -38,6 +38,9 @@ export default Vue.extend({ }; }, computed: { + browser(): any { + return this.$parent; + }, title(): string { return this.folder.name; } @@ -47,6 +50,39 @@ export default Vue.extend({ this.browser.move(this.folder); }, + onContextmenu(e) { + this.isContextmenuShowing = true; + contextmenu(e, [{ + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.move-to-this-folder%', + icon: '%fa:arrow-right%', + onClick: this.go + }, { + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.show-in-new-window%', + icon: '%fa:R window-restore%', + onClick: this.newWindow + }, { + type: 'divider', + }, { + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.rename%', + icon: '%fa:i-cursor%', + onClick: this.rename + }, { + type: 'divider', + }, { + type: 'item', + text: '%i18n:common.delete%', + icon: '%fa:R trash-alt%', + onClick: this.deleteFolder + }], { + closed: () => { + this.isContextmenuShowing = false; + } + }); + }, + onMouseover() { this.hover = true; }, @@ -102,7 +138,7 @@ export default Vue.extend({ if (obj.type == 'file') { const file = obj.id; this.browser.removeFile(file); - this.$root.$data.os.api('drive/files/update', { + (this as any).api('drive/files/update', { file_id: file, folder_id: this.folder.id }); @@ -112,7 +148,7 @@ export default Vue.extend({ // 移動先が自分自身ならreject if (folder == this.folder.id) return false; this.browser.removeFolder(folder); - this.$root.$data.os.api('drive/folders/update', { + (this as any).api('drive/folders/update', { folder_id: folder, parent_id: this.folder.id }).then(() => { @@ -120,10 +156,13 @@ export default Vue.extend({ }).catch(err => { switch (err) { case 'detected-circular-definition': - dialog('%fa:exclamation-triangle%%i18n:desktop.tags.mk-drive-browser-folder.unable-to-process%', - '%i18n:desktop.tags.mk-drive-browser-folder.circular-reference-detected%', [{ - text: '%i18n:common.ok%' - }]); + (this as any).apis.dialog({ + title: '%fa:exclamation-triangle%%i18n:desktop.tags.mk-drive-browser-folder.unable-to-process%', + text: '%i18n:desktop.tags.mk-drive-browser-folder.circular-reference-detected%', + actions: [{ + text: '%i18n:common.ok%' + }] + }); break; default: alert('%i18n:desktop.tags.mk-drive-browser-folder.unhandled-error% ' + err); @@ -152,21 +191,29 @@ export default Vue.extend({ this.browser.isDragSource = false; }, - onContextmenu(e) { - this.isContextmenuShowing = true; - const ctx = new MkDriveFolderContextmenu({ - parent: this, - propsData: { - browser: this.browser, - x: e.pageX - window.pageXOffset, - y: e.pageY - window.pageYOffset - } - }).$mount(); - ctx.$once('closed', () => { - this.isContextmenuShowing = false; + go() { + this.browser.move(this.folder.id); + }, + + newWindow() { + this.browser.newWindow(this.folder.id); + }, + + rename() { + (this as any).apis.input({ + title: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.rename-folder%', + placeholder: '%i18n:desktop.tags.mk-drive-browser-folder-contextmenu.input-new-folder-name%', + default: this.folder.name + }).then(name => { + (this as any).api('drive/folders/update', { + folder_id: this.folder.id, + name: name + }); }); - document.body.appendChild(ctx.$el); - return false; + }, + + deleteFolder() { + alert('not implemented yet'); } } }); diff --git a/src/web/app/desktop/views/components/drive-nav-folder.vue b/src/web/app/desktop/views/components/drive-nav-folder.vue index 556c64f119..b6eb36535f 100644 --- a/src/web/app/desktop/views/components/drive-nav-folder.vue +++ b/src/web/app/desktop/views/components/drive-nav-folder.vue @@ -73,7 +73,7 @@ export default Vue.extend({ if (obj.type == 'file') { const file = obj.id; this.browser.removeFile(file); - this.$root.$data.os.api('drive/files/update', { + (this as any).api('drive/files/update', { file_id: file, folder_id: this.folder ? this.folder.id : null }); @@ -83,7 +83,7 @@ export default Vue.extend({ // 移動先が自分自身ならreject if (this.folder && folder == this.folder.id) return false; this.browser.removeFolder(folder); - this.$root.$data.os.api('drive/folders/update', { + (this as any).api('drive/folders/update', { folder_id: folder, parent_id: this.folder ? this.folder.id : null }); diff --git a/src/web/app/desktop/views/components/drive-window.vue b/src/web/app/desktop/views/components/drive-window.vue new file mode 100644 index 0000000000..0f0d8d81b1 --- /dev/null +++ b/src/web/app/desktop/views/components/drive-window.vue @@ -0,0 +1,53 @@ +<template> +<mk-window ref="window" @closed="$destroy" width="800px" height="500px" :popout="popout"> + <span slot="header" :class="$style.header"> + <p class="info" v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:desktop.tags.mk-drive-browser-window.used%</p> + %fa:cloud%%i18n:desktop.tags.mk-drive-browser-window.drive% + </span> + <mk-drive-browser multiple :folder="folder" ref="browser"/> +</mk-window> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import { url } from '../../../config'; + +export default Vue.extend({ + props: ['folder'], + data() { + return { + usage: null + }; + }, + mounted() { + (this as any).api('drive').then(info => { + this.usage = info.usage / info.capacity * 100; + }); + }, + methods: { + popout() { + const folder = (this.$refs.browser as any).folder; + if (folder) { + return `${url}/i/drive/folder/${folder.id}`; + } else { + return `${url}/i/drive`; + } + } + } +}); +</script> + +<style lang="stylus" module> +.header + > [data-fa] + margin-right 4px + +.info + position absolute + top 0 + left 16px + margin 0 + font-size 80% + +</style> + diff --git a/src/web/app/desktop/views/components/drive.vue b/src/web/app/desktop/views/components/drive.vue index 5d398dab98..2b33265e5d 100644 --- a/src/web/app/desktop/views/components/drive.vue +++ b/src/web/app/desktop/views/components/drive.vue @@ -2,17 +2,17 @@ <div class="mk-drive"> <nav> <div class="path" @contextmenu.prevent.stop="() => {}"> - <mk-drive-browser-nav-folder :class="{ current: folder == null }" folder={ null }/> - <template each={ folder in hierarchyFolders }> - <span class="separator">%fa:angle-right%</span> - <mk-drive-browser-nav-folder folder={ folder }/> + <mk-drive-nav-folder :class="{ current: folder == null }"/> + <template v-for="folder in hierarchyFolders"> + <span class="separator" :key="folder.id + '>'">%fa:angle-right%</span> + <mk-drive-nav-folder :folder="folder" :key="folder.id"/> </template> <span class="separator" v-if="folder != null">%fa:angle-right%</span> - <span class="folder current" v-if="folder != null">{ folder.name }</span> + <span class="folder current" v-if="folder != null">{{ folder.name }}</span> </div> <input class="search" type="search" placeholder=" %i18n:desktop.tags.mk-drive-browser.search%"/> </nav> - <div class="main { uploading: uploads.length > 0, fetching: fetching }" + <div class="main" :class="{ uploading: uploadings.length > 0, fetching }" ref="main" @mousedown="onMousedown" @dragover.prevent.stop="onDragover" @@ -24,19 +24,15 @@ <div class="selection" ref="selection"></div> <div class="contents" ref="contents"> <div class="folders" ref="foldersContainer" v-if="folders.length > 0"> - <template each={ folder in folders }> - <mk-drive-browser-folder class="folder" folder={ folder }/> - </template> + <mk-drive-folder v-for="folder in folders" :key="folder.id" class="folder" :folder="folder"/> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid --> - <div class="padding" each={ Array(10).fill(16) }></div> + <div class="padding" v-for="n in 16" :key="n"></div> <button v-if="moreFolders">%i18n:desktop.tags.mk-drive-browser.load-more%</button> </div> <div class="files" ref="filesContainer" v-if="files.length > 0"> - <template each={ file in files }> - <mk-drive-browser-file class="file" file={ file }/> - </template> + <mk-drive-file v-for="file in files" :key="file.id" class="file" :file="file"/> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid --> - <div class="padding" each={ Array(10).fill(16) }></div> + <div class="padding" v-for="n in 16" :key="n"></div> <button v-if="moreFiles" @click="fetchMoreFiles">%i18n:desktop.tags.mk-drive-browser.load-more%</button> </div> <div class="empty" v-if="files.length == 0 && folders.length == 0 && !fetching"> @@ -60,16 +56,18 @@ <script lang="ts"> import Vue from 'vue'; +import MkDriveWindow from './drive-window.vue'; import contains from '../../../common/scripts/contains'; -import dialog from '../../scripts/dialog'; -import inputDialog from '../../scripts/input-dialog'; +import contextmenu from '../../api/contextmenu'; export default Vue.extend({ props: { initFolder: { + type: Object, required: false }, multiple: { + type: Boolean, default: false } }, @@ -106,8 +104,8 @@ export default Vue.extend({ }; }, mounted() { - this.connection = this.$root.$data.os.streams.driveStream.getConnection(); - this.connectionId = this.$root.$data.os.streams.driveStream.use(); + this.connection = (this as any).os.streams.driveStream.getConnection(); + this.connectionId = (this as any).os.streams.driveStream.use(); this.connection.on('file_created', this.onStreamDriveFileCreated); this.connection.on('file_updated', this.onStreamDriveFileUpdated); @@ -125,12 +123,32 @@ export default Vue.extend({ this.connection.off('file_updated', this.onStreamDriveFileUpdated); this.connection.off('folder_created', this.onStreamDriveFolderCreated); this.connection.off('folder_updated', this.onStreamDriveFolderUpdated); - this.$root.$data.os.streams.driveStream.dispose(this.connectionId); + (this as any).os.streams.driveStream.dispose(this.connectionId); }, methods: { + onContextmenu(e) { + contextmenu(e, [{ + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-base-contextmenu.create-folder%', + icon: '%fa:R folder%', + onClick: this.createFolder + }, { + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-base-contextmenu.upload%', + icon: '%fa:upload%', + onClick: this.selectLocalFile + }, { + type: 'item', + text: '%i18n:desktop.tags.mk-drive-browser-base-contextmenu.url-upload%', + icon: '%fa:cloud-upload-alt%', + onClick: this.urlUpload + }]); + }, + onStreamDriveFileCreated(file) { this.addFile(file, true); }, + onStreamDriveFileUpdated(file) { const current = this.folder ? this.folder.id : null; if (current != file.folder_id) { @@ -139,9 +157,11 @@ export default Vue.extend({ this.addFile(file, true); } }, + onStreamDriveFolderCreated(folder) { this.addFolder(folder, true); }, + onStreamDriveFolderUpdated(folder) { const current = this.folder ? this.folder.id : null; if (current != folder.parent_id) { @@ -150,12 +170,15 @@ export default Vue.extend({ this.addFolder(folder, true); } }, + onChangeUploaderUploads(uploads) { this.uploadings = uploads; }, + onUploaderUploaded(file) { this.addFile(file, true); }, + onMousedown(e): any { if (contains(this.$refs.foldersContainer, e.target) || contains(this.$refs.filesContainer, e.target)) return true; @@ -202,6 +225,7 @@ export default Vue.extend({ document.documentElement.addEventListener('mousemove', move); document.documentElement.addEventListener('mouseup', up); }, + onDragover(e): any { // ドラッグ元が自分自身の所有するアイテムかどうか if (!this.isDragSource) { @@ -214,12 +238,15 @@ export default Vue.extend({ return false; } }, + onDragenter(e) { if (!this.isDragSource) this.draghover = true; }, + onDragleave(e) { this.draghover = false; }, + onDrop(e): any { this.draghover = false; @@ -244,7 +271,7 @@ export default Vue.extend({ const file = obj.id; if (this.files.some(f => f.id == file)) return false; this.removeFile(file); - this.$root.$data.os.api('drive/files/update', { + (this as any).api('drive/files/update', { file_id: file, folder_id: this.folder ? this.folder.id : null }); @@ -255,7 +282,7 @@ export default Vue.extend({ if (this.folder && folder == this.folder.id) return false; if (this.folders.some(f => f.id == folder)) return false; this.removeFolder(folder); - this.$root.$data.os.api('drive/folders/update', { + (this as any).api('drive/folders/update', { folder_id: folder, parent_id: this.folder ? this.folder.id : null }).then(() => { @@ -263,10 +290,13 @@ export default Vue.extend({ }).catch(err => { switch (err) { case 'detected-circular-definition': - dialog('%fa:exclamation-triangle%%i18n:desktop.tags.mk-drive-browser.unable-to-process%', - '%i18n:desktop.tags.mk-drive-browser.circular-reference-detected%', [{ - text: '%i18n:common.ok%' - }]); + (this as any).apis.dialog({ + title: '%fa:exclamation-triangle%%i18n:desktop.tags.mk-drive-browser.unable-to-process%', + text: '%i18n:desktop.tags.mk-drive-browser.circular-reference-detected%', + actions: [{ + text: '%i18n:common.ok%' + }] + }); break; default: alert('%i18n:desktop.tags.mk-drive-browser.unhandled-error% ' + err); @@ -276,40 +306,37 @@ export default Vue.extend({ return false; }, - onContextmenu(e) { - document.body.appendChild(new MkDriveContextmenu({ - propsData: { - browser: this, - x: e.pageX - window.pageXOffset, - y: e.pageY - window.pageYOffset - } - }).$mount().$el); - return false; - }, selectLocalFile() { (this.$refs.fileInput as any).click(); }, - urlUpload() { - inputDialog('%i18n:desktop.tags.mk-drive-browser.url-upload%', - '%i18n:desktop.tags.mk-drive-browser.url-of-file%', null, url => { - this.$root.$data.os.api('drive/files/upload_from_url', { + urlUpload() { + (this as any).apis.input({ + title: '%i18n:desktop.tags.mk-drive-browser.url-upload%', + placeholder: '%i18n:desktop.tags.mk-drive-browser.url-of-file%' + }).then(url => { + (this as any).api('drive/files/upload_from_url', { url: url, folder_id: this.folder ? this.folder.id : undefined }); - dialog('%fa:check%%i18n:desktop.tags.mk-drive-browser.url-upload-requested%', - '%i18n:desktop.tags.mk-drive-browser.may-take-time%', [{ - text: '%i18n:common.ok%' - }]); + (this as any).apis.dialog({ + title: '%fa:check%%i18n:desktop.tags.mk-drive-browser.url-upload-requested%', + text: '%i18n:desktop.tags.mk-drive-browser.may-take-time%', + actions: [{ + text: '%i18n:common.ok%' + }] + }); }); }, - createFolder() { - inputDialog('%i18n:desktop.tags.mk-drive-browser.create-folder%', - '%i18n:desktop.tags.mk-drive-browser.folder-name%', null, name => { - this.$root.$data.os.api('drive/folders/create', { + createFolder() { + (this as any).apis.input({ + title: '%i18n:desktop.tags.mk-drive-browser.create-folder%', + placeholder: '%i18n:desktop.tags.mk-drive-browser.folder-name%' + }).then(name => { + (this as any).api('drive/folders/create', { name: name, folder_id: this.folder ? this.folder.id : undefined }).then(folder => { @@ -317,15 +344,18 @@ export default Vue.extend({ }); }); }, + onChangeFileInput() { Array.from((this.$refs.fileInput as any).files).forEach(file => { this.upload(file, this.folder); }); }, + upload(file, folder) { if (folder && typeof folder == 'object') folder = folder.id; (this.$refs.uploader as any).upload(file, folder); }, + chooseFile(file) { const isAlreadySelected = this.selectedFiles.some(f => f.id == file.id); if (this.multiple) { @@ -344,6 +374,7 @@ export default Vue.extend({ } } }, + newWindow(folderId) { document.body.appendChild(new MkDriveWindow({ propsData: { @@ -351,6 +382,7 @@ export default Vue.extend({ } }).$mount().$el); }, + move(target) { if (target == null) { this.goRoot(); @@ -361,7 +393,7 @@ export default Vue.extend({ this.fetching = true; - this.$root.$data.os.api('drive/folders/show', { + (this as any).api('drive/folders/show', { folder_id: target }).then(folder => { this.folder = folder; @@ -378,6 +410,7 @@ export default Vue.extend({ this.fetch(); }); }, + addFolder(folder, unshift = false) { const current = this.folder ? this.folder.id : null; if (current != folder.parent_id) return; @@ -394,6 +427,7 @@ export default Vue.extend({ this.folders.push(folder); } }, + addFile(file, unshift = false) { const current = this.folder ? this.folder.id : null; if (current != file.folder_id) return; @@ -410,26 +444,33 @@ export default Vue.extend({ this.files.push(file); } }, + removeFolder(folder) { if (typeof folder == 'object') folder = folder.id; this.folders = this.folders.filter(f => f.id != folder); }, + removeFile(file) { if (typeof file == 'object') file = file.id; this.files = this.files.filter(f => f.id != file); }, + appendFile(file) { this.addFile(file); }, + appendFolder(folder) { this.addFolder(folder); }, + prependFile(file) { this.addFile(file, true); }, + prependFolder(folder) { this.addFolder(folder, true); }, + goRoot() { // 既にrootにいるなら何もしない if (this.folder == null) return; @@ -439,6 +480,7 @@ export default Vue.extend({ this.$emit('move-root'); this.fetch(); }, + fetch() { this.folders = []; this.files = []; @@ -453,7 +495,7 @@ export default Vue.extend({ const filesMax = 30; // フォルダ一覧取得 - this.$root.$data.os.api('drive/folders', { + (this as any).api('drive/folders', { folder_id: this.folder ? this.folder.id : null, limit: foldersMax + 1 }).then(folders => { @@ -466,7 +508,7 @@ export default Vue.extend({ }); // ファイル一覧取得 - this.$root.$data.os.api('drive/files', { + (this as any).api('drive/files', { folder_id: this.folder ? this.folder.id : null, limit: filesMax + 1 }).then(files => { @@ -489,13 +531,14 @@ export default Vue.extend({ } }; }, + fetchMoreFiles() { this.fetching = true; const max = 30; // ファイル一覧取得 - this.$root.$data.os.api('drive/files', { + (this as any).api('drive/files', { folder_id: this.folder ? this.folder.id : null, limit: max + 1 }).then(files => { diff --git a/src/web/app/desktop/views/components/follow-button.vue b/src/web/app/desktop/views/components/follow-button.vue index 0fffbda911..c4c3063aef 100644 --- a/src/web/app/desktop/views/components/follow-button.vue +++ b/src/web/app/desktop/views/components/follow-button.vue @@ -29,8 +29,8 @@ export default Vue.extend({ }; }, mounted() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('follow', this.onFollow); this.connection.on('unfollow', this.onUnfollow); @@ -38,7 +38,7 @@ export default Vue.extend({ beforeDestroy() { this.connection.off('follow', this.onFollow); this.connection.off('unfollow', this.onUnfollow); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { @@ -57,7 +57,7 @@ export default Vue.extend({ onClick() { this.wait = true; if (this.user.is_following) { - this.$root.$data.os.api('following/delete', { + (this as any).api('following/delete', { user_id: this.user.id }).then(() => { this.user.is_following = false; @@ -67,7 +67,7 @@ export default Vue.extend({ this.wait = false; }); } else { - this.$root.$data.os.api('following/create', { + (this as any).api('following/create', { user_id: this.user.id }).then(() => { this.user.is_following = true; diff --git a/src/web/app/desktop/views/components/friends-maker.vue b/src/web/app/desktop/views/components/friends-maker.vue index caa5f4913c..b23373421d 100644 --- a/src/web/app/desktop/views/components/friends-maker.vue +++ b/src/web/app/desktop/views/components/friends-maker.vue @@ -39,7 +39,7 @@ export default Vue.extend({ this.fetching = true; this.users = []; - this.$root.$data.os.api('users/recommendation', { + (this as any).api('users/recommendation', { limit: this.limit, offset: this.limit * this.page }).then(users => { diff --git a/src/web/app/desktop/views/components/home.vue b/src/web/app/desktop/views/components/home.vue index 076cbabe8e..f5f33e5870 100644 --- a/src/web/app/desktop/views/components/home.vue +++ b/src/web/app/desktop/views/components/home.vue @@ -101,7 +101,7 @@ export default Vue.extend({ }, methods: { bakeHomeData() { - return JSON.stringify(this.$root.$data.os.i.client_settings.home); + return JSON.stringify((this as any).os.i.client_settings.home); }, onTlLoaded() { this.$emit('loaded'); @@ -123,7 +123,7 @@ export default Vue.extend({ data: {} }; - this.$root.$data.os.i.client_settings.home.unshift(widget); + (this as any).os.i.client_settings.home.unshift(widget); this.saveHome(); }, @@ -132,48 +132,48 @@ export default Vue.extend({ Array.from((this.$refs.left as Element).children).forEach(el => { const id = el.getAttribute('data-widget-id'); - const widget = this.$root.$data.os.i.client_settings.home.find(w => w.id == id); + const widget = (this as any).os.i.client_settings.home.find(w => w.id == id); widget.place = 'left'; data.push(widget); }); Array.from((this.$refs.right as Element).children).forEach(el => { const id = el.getAttribute('data-widget-id'); - const widget = this.$root.$data.os.i.client_settings.home.find(w => w.id == id); + const widget = (this as any).os.i.client_settings.home.find(w => w.id == id); widget.place = 'right'; data.push(widget); }); Array.from((this.$refs.maintop as Element).children).forEach(el => { const id = el.getAttribute('data-widget-id'); - const widget = this.$root.$data.os.i.client_settings.home.find(w => w.id == id); + const widget = (this as any).os.i.client_settings.home.find(w => w.id == id); widget.place = 'main'; data.push(widget); }); - this.$root.$data.os.api('i/update_home', { + (this as any).api('i/update_home', { home: data }); } }, computed: { leftWidgets(): any { - return this.$root.$data.os.i.client_settings.home.filter(w => w.place == 'left'); + return (this as any).os.i.client_settings.home.filter(w => w.place == 'left'); }, centerWidgets(): any { - return this.$root.$data.os.i.client_settings.home.filter(w => w.place == 'center'); + return (this as any).os.i.client_settings.home.filter(w => w.place == 'center'); }, rightWidgets(): any { - return this.$root.$data.os.i.client_settings.home.filter(w => w.place == 'right'); + return (this as any).os.i.client_settings.home.filter(w => w.place == 'right'); } }, created() { this.bakedHomeData = this.bakeHomeData(); }, mounted() { - this.$root.$data.os.i.on('refreshed', this.onMeRefreshed); + (this as any).os.i.on('refreshed', this.onMeRefreshed); - this.home = this.$root.$data.os.i.client_settings.home; + this.home = (this as any).os.i.client_settings.home; if (!this.customize) { if ((this.$refs.left as Element).children.length == 0) { @@ -214,14 +214,14 @@ export default Vue.extend({ const el = evt.item; const id = el.getAttribute('data-widget-id'); el.parentNode.removeChild(el); - this.$root.$data.os.i.client_settings.home = this.$root.$data.os.i.client_settings.home.filter(w => w.id != id); + (this as any).os.i.client_settings.home = (this as any).os.i.client_settings.home.filter(w => w.id != id); this.saveHome(); } })); } }, beforeDestroy() { - this.$root.$data.os.i.off('refreshed', this.onMeRefreshed); + (this as any).os.i.off('refreshed', this.onMeRefreshed); this.home.forEach(widget => { widget.unmount(); diff --git a/src/web/app/desktop/views/components/index.ts b/src/web/app/desktop/views/components/index.ts index 1e4c2bafcd..1e4bd96a19 100644 --- a/src/web/app/desktop/views/components/index.ts +++ b/src/web/app/desktop/views/components/index.ts @@ -27,6 +27,10 @@ import postForm from './post-form.vue'; import repostForm from './repost-form.vue'; import followButton from './follow-button.vue'; import postPreview from './post-preview.vue'; +import drive from './drive.vue'; +import driveFile from './drive-file.vue'; +import driveFolder from './drive-folder.vue'; +import driveNavFolder from './drive-nav-folder.vue'; Vue.component('mk-ui', ui); Vue.component('mk-ui-header', uiHeader); @@ -55,3 +59,7 @@ Vue.component('mk-post-form', postForm); Vue.component('mk-repost-form', repostForm); Vue.component('mk-follow-button', followButton); Vue.component('mk-post-preview', postPreview); +Vue.component('mk-drive', drive); +Vue.component('mk-drive-file', driveFile); +Vue.component('mk-drive-folder', driveFolder); +Vue.component('mk-drive-nav-folder', driveNavFolder); diff --git a/src/web/app/desktop/views/components/input-dialog.vue b/src/web/app/desktop/views/components/input-dialog.vue index a78c7dcba1..c00b1d4c14 100644 --- a/src/web/app/desktop/views/components/input-dialog.vue +++ b/src/web/app/desktop/views/components/input-dialog.vue @@ -33,12 +33,6 @@ export default Vue.extend({ }, type: { default: 'text' - }, - onOk: { - type: Function - }, - onCancel: { - type: Function } }, data() { @@ -63,9 +57,9 @@ export default Vue.extend({ }, beforeClose() { if (this.done) { - this.onOk(this.text); + this.$emit('done', this.text); } else { - if (this.onCancel) this.onCancel(); + this.$emit('canceled'); } }, onKeydown(e) { diff --git a/src/web/app/desktop/views/components/messaging-window.vue b/src/web/app/desktop/views/components/messaging-window.vue index f8df20bc1a..0dbcddbec4 100644 --- a/src/web/app/desktop/views/components/messaging-window.vue +++ b/src/web/app/desktop/views/components/messaging-window.vue @@ -11,7 +11,6 @@ export default Vue.extend({ methods: { navigate(user) { document.body.appendChild(new MkMessagingRoomWindow({ - parent: this, propsData: { user: user } diff --git a/src/web/app/desktop/views/components/mute-setting.vue b/src/web/app/desktop/views/components/mute-setting.vue index a8813172ae..3fcc34c9e6 100644 --- a/src/web/app/desktop/views/components/mute-setting.vue +++ b/src/web/app/desktop/views/components/mute-setting.vue @@ -22,7 +22,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('mute/list').then(x => { + (this as any).api('mute/list').then(x => { this.fetching = false; this.users = x.users; }); diff --git a/src/web/app/desktop/views/components/notifications.vue b/src/web/app/desktop/views/components/notifications.vue index f19766dc84..443ebea2a2 100644 --- a/src/web/app/desktop/views/components/notifications.vue +++ b/src/web/app/desktop/views/components/notifications.vue @@ -128,14 +128,14 @@ export default Vue.extend({ } }, mounted() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('notification', this.onNotification); const max = 10; - this.$root.$data.os.api('i/notifications', { + (this as any).api('i/notifications', { limit: max + 1 }).then(notifications => { if (notifications.length == max + 1) { @@ -149,7 +149,7 @@ export default Vue.extend({ }, beforeDestroy() { this.connection.off('notification', this.onNotification); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { fetchMoreNotifications() { @@ -157,7 +157,7 @@ export default Vue.extend({ const max = 30; - this.$root.$data.os.api('i/notifications', { + (this as any).api('i/notifications', { limit: max + 1, until_id: this.notifications[this.notifications.length - 1].id }).then(notifications => { diff --git a/src/web/app/desktop/views/components/password-setting.vue b/src/web/app/desktop/views/components/password-setting.vue index 2e3e4fb6fd..883a494cce 100644 --- a/src/web/app/desktop/views/components/password-setting.vue +++ b/src/web/app/desktop/views/components/password-setting.vue @@ -22,7 +22,7 @@ export default Vue.extend({ }]); return; } - this.$root.$data.os.api('i/change_password', { + (this as any).api('i/change_password', { current_password: currentPassword, new_password: newPassword }).then(() => { diff --git a/src/web/app/desktop/views/components/post-detail-sub.vue b/src/web/app/desktop/views/components/post-detail-sub.vue index 8d81e6860a..44ed5edd83 100644 --- a/src/web/app/desktop/views/components/post-detail-sub.vue +++ b/src/web/app/desktop/views/components/post-detail-sub.vue @@ -16,7 +16,7 @@ </div> </header> <div class="body"> - <mk-post-html v-if="post.ast" :ast="post.ast" :i="$root.$data.os.i"/> + <mk-post-html v-if="post.ast" :ast="post.ast" :i="os.i"/> <div class="media" v-if="post.media"> <mk-images images={ post.media }/> </div> diff --git a/src/web/app/desktop/views/components/post-detail.vue b/src/web/app/desktop/views/components/post-detail.vue index d23043dd40..dd4a32b6ea 100644 --- a/src/web/app/desktop/views/components/post-detail.vue +++ b/src/web/app/desktop/views/components/post-detail.vue @@ -35,7 +35,7 @@ </a> </header> <div class="body"> - <mk-post-html v-if="p.ast" :ast="p.ast" :i="$root.$data.os.i"/> + <mk-post-html v-if="p.ast" :ast="p.ast" :i="os.i"/> <mk-url-preview v-for="url in urls" :url="url" :key="url"/> <div class="media" v-if="p.media"> <mk-images images={ p.media }/> @@ -117,7 +117,7 @@ export default Vue.extend({ mounted() { // Get replies if (!this.compact) { - this.$root.$data.os.api('posts/replies', { + (this as any).api('posts/replies', { post_id: this.p.id, limit: 8 }).then(replies => { @@ -130,7 +130,7 @@ export default Vue.extend({ this.contextFetching = true; // Fetch context - this.$root.$data.os.api('posts/context', { + (this as any).api('posts/context', { post_id: this.p.reply_id }).then(context => { this.contextFetching = false; diff --git a/src/web/app/desktop/views/components/post-form.vue b/src/web/app/desktop/views/components/post-form.vue index 502851316e..456f0de821 100644 --- a/src/web/app/desktop/views/components/post-form.vue +++ b/src/web/app/desktop/views/components/post-form.vue @@ -113,18 +113,12 @@ export default Vue.extend({ chooseFile() { (this.$refs.file as any).click(); }, - chooseFileFromDrive() {/* - const w = new MkDriveFileSelectorWindow({ - propsData: { - multiple: true - } - }).$mount(); - - document.body.appendChild(w.$el); - - w.$once('selected', files => { + chooseFileFromDrive() { + (this as any).apis.chooseDriveFile({ + multiple: true + }).then(files => { files.forEach(this.attachMedia); - });*/ + }); }, attachMedia(driveFile) { this.files.push(driveFile); @@ -196,7 +190,7 @@ export default Vue.extend({ post() { this.posting = true; - this.$root.$data.os.api('posts/create', { + (this as any).api('posts/create', { text: this.text == '' ? undefined : this.text, media_ids: this.files.length > 0 ? this.files.map(f => f.id) : undefined, reply_id: this.reply ? this.reply.id : undefined, diff --git a/src/web/app/desktop/views/components/posts-post.vue b/src/web/app/desktop/views/components/posts-post.vue index e611b2513e..90db8088c7 100644 --- a/src/web/app/desktop/views/components/posts-post.vue +++ b/src/web/app/desktop/views/components/posts-post.vue @@ -32,7 +32,7 @@ <div class="text" ref="text"> <p class="channel" v-if="p.channel"><a :href="`${_CH_URL_}/${p.channel.id}`" target="_blank">{{ p.channel.title }}</a>:</p> <a class="reply" v-if="p.reply">%fa:reply%</a> - <mk-post-html v-if="p.ast" :ast="p.ast" :i="$root.$data.os.i"/> + <mk-post-html v-if="p.ast" :ast="p.ast" :i="os.i"/> <a class="quote" v-if="p.repost">RP:</a> <mk-url-preview v-for="url in urls" :url="url" :key="url"/> </div> @@ -133,24 +133,24 @@ export default Vue.extend({ } }, created() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); }, mounted() { this.capture(true); - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.on('_connected_', this.onStreamConnected); } }, beforeDestroy() { this.decapture(true); this.connection.off('_connected_', this.onStreamConnected); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { capture(withHandler = false) { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.send({ type: 'capture', id: this.post.id @@ -159,7 +159,7 @@ export default Vue.extend({ } }, decapture(withHandler = false) { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.send({ type: 'decapture', id: this.post.id @@ -178,7 +178,7 @@ export default Vue.extend({ }, reply() { document.body.appendChild(new MkPostFormWindow({ - parent: this, + propsData: { reply: this.p } @@ -186,7 +186,7 @@ export default Vue.extend({ }, repost() { document.body.appendChild(new MkRepostFormWindow({ - parent: this, + propsData: { post: this.p } @@ -194,7 +194,7 @@ export default Vue.extend({ }, react() { document.body.appendChild(new MkReactionPicker({ - parent: this, + propsData: { source: this.$refs.reactButton, post: this.p @@ -203,7 +203,7 @@ export default Vue.extend({ }, menu() { document.body.appendChild(new MkPostMenu({ - parent: this, + propsData: { source: this.$refs.menuButton, post: this.p diff --git a/src/web/app/desktop/views/components/profile-setting.vue b/src/web/app/desktop/views/components/profile-setting.vue index abf80d3162..403488ef14 100644 --- a/src/web/app/desktop/views/components/profile-setting.vue +++ b/src/web/app/desktop/views/components/profile-setting.vue @@ -1,7 +1,7 @@ <template> <div class="mk-profile-setting"> <label class="avatar ui from group"> - <p>%i18n:desktop.tags.mk-profile-setting.avatar%</p><img class="avatar" :src="`${$root.$data.os.i.avatar_url}?thumbnail&size=64`" alt="avatar"/> + <p>%i18n:desktop.tags.mk-profile-setting.avatar%</p><img class="avatar" :src="`${os.i.avatar_url}?thumbnail&size=64`" alt="avatar"/> <button class="ui" @click="updateAvatar">%i18n:desktop.tags.mk-profile-setting.choice-avatar%</button> </label> <label class="ui from group"> @@ -32,18 +32,18 @@ import notify from '../../scripts/notify'; export default Vue.extend({ data() { return { - name: this.$root.$data.os.i.name, - location: this.$root.$data.os.i.location, - description: this.$root.$data.os.i.description, - birthday: this.$root.$data.os.i.birthday, + name: (this as any).os.i.name, + location: (this as any).os.i.location, + description: (this as any).os.i.description, + birthday: (this as any).os.i.birthday, }; }, methods: { updateAvatar() { - updateAvatar(this.$root.$data.os.i); + updateAvatar((this as any).os.i); }, save() { - this.$root.$data.os.api('i/update', { + (this as any).api('i/update', { name: this.name, location: this.location || null, description: this.description || null, diff --git a/src/web/app/desktop/views/components/repost-form.vue b/src/web/app/desktop/views/components/repost-form.vue index 04b045ad40..d4a6186c4d 100644 --- a/src/web/app/desktop/views/components/repost-form.vue +++ b/src/web/app/desktop/views/components/repost-form.vue @@ -29,7 +29,7 @@ export default Vue.extend({ methods: { ok() { this.wait = true; - this.$root.$data.os.api('posts/create', { + (this as any).api('posts/create', { repost_id: this.post.id }).then(data => { this.$emit('posted'); diff --git a/src/web/app/desktop/views/components/sub-post-content.vue b/src/web/app/desktop/views/components/sub-post-content.vue index e5264cefcd..f048eb4f0f 100644 --- a/src/web/app/desktop/views/components/sub-post-content.vue +++ b/src/web/app/desktop/views/components/sub-post-content.vue @@ -2,7 +2,7 @@ <div class="mk-sub-post-content"> <div class="body"> <a class="reply" v-if="post.reply_id">%fa:reply%</a> - <mk-post-html :ast="post.ast" :i="$root.$data.os.i"/> + <mk-post-html :ast="post.ast" :i="os.i"/> <a class="quote" v-if="post.repost_id" :href="`/post:${post.repost_id}`">RP: ...</a> <mk-url-preview v-for="url in urls" :url="url" :key="url"/> </div> diff --git a/src/web/app/desktop/views/components/timeline.vue b/src/web/app/desktop/views/components/timeline.vue index 63b36ff547..3d792436e0 100644 --- a/src/web/app/desktop/views/components/timeline.vue +++ b/src/web/app/desktop/views/components/timeline.vue @@ -30,12 +30,12 @@ export default Vue.extend({ }, computed: { alone(): boolean { - return this.$root.$data.os.i.following_count == 0; + return (this as any).os.i.following_count == 0; } }, mounted() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('post', this.onPost); this.connection.on('follow', this.onChangeFollowing); @@ -50,7 +50,7 @@ export default Vue.extend({ this.connection.off('post', this.onPost); this.connection.off('follow', this.onChangeFollowing); this.connection.off('unfollow', this.onChangeFollowing); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); document.removeEventListener('keydown', this.onKeydown); window.removeEventListener('scroll', this.onScroll); @@ -59,7 +59,7 @@ export default Vue.extend({ fetch(cb?) { this.fetching = true; - this.$root.$data.os.api('posts/timeline', { + (this as any).api('posts/timeline', { until_date: this.date ? (this.date as any).getTime() : undefined }).then(posts => { this.fetching = false; @@ -70,7 +70,7 @@ export default Vue.extend({ more() { if (this.moreFetching || this.fetching || this.posts.length == 0) return; this.moreFetching = true; - this.$root.$data.os.api('posts/timeline', { + (this as any).api('posts/timeline', { until_id: this.posts[this.posts.length - 1].id }).then(posts => { this.moreFetching = false; diff --git a/src/web/app/desktop/views/components/ui-header-account.vue b/src/web/app/desktop/views/components/ui-header-account.vue index 8dbd9e5e34..420fa6994c 100644 --- a/src/web/app/desktop/views/components/ui-header-account.vue +++ b/src/web/app/desktop/views/components/ui-header-account.vue @@ -1,13 +1,13 @@ <template> <div class="mk-ui-header-account"> <button class="header" :data-active="isOpen" @click="toggle"> - <span class="username">{{ $root.$data.os.i.username }}<template v-if="!isOpen">%fa:angle-down%</template><template v-if="isOpen">%fa:angle-up%</template></span> - <img class="avatar" :src="`${ $root.$data.os.i.avatar_url }?thumbnail&size=64`" alt="avatar"/> + <span class="username">{{ os.i.username }}<template v-if="!isOpen">%fa:angle-down%</template><template v-if="isOpen">%fa:angle-up%</template></span> + <img class="avatar" :src="`${ os.i.avatar_url }?thumbnail&size=64`" alt="avatar"/> </button> <div class="menu" v-if="isOpen"> <ul> <li> - <a :href="`/${ $root.$data.os.i.username }`">%fa:user%%i18n:desktop.tags.mk-ui-header-account.profile%%fa:angle-right%</a> + <a :href="`/${ os.i.username }`">%fa:user%%i18n:desktop.tags.mk-ui-header-account.profile%%fa:angle-right%</a> </li> <li @click="drive"> <p>%fa:cloud%%i18n:desktop.tags.mk-ui-header-account.drive%%fa:angle-right%</p> diff --git a/src/web/app/desktop/views/components/ui-header-nav.vue b/src/web/app/desktop/views/components/ui-header-nav.vue index d0092ebd20..fe0c387786 100644 --- a/src/web/app/desktop/views/components/ui-header-nav.vue +++ b/src/web/app/desktop/views/components/ui-header-nav.vue @@ -1,7 +1,7 @@ <template> <div class="mk-ui-header-nav"> <ul> - <template v-if="$root.$data.os.isSignedIn"> + <template v-if="os.isSignedIn"> <li class="home" :class="{ active: page == 'home' }"> <a href="/"> %fa:home% @@ -44,15 +44,15 @@ export default Vue.extend({ }; }, mounted() { - if (this.$root.$data.os.isSignedIn) { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + if ((this as any).os.isSignedIn) { + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('read_all_messaging_messages', this.onReadAllMessagingMessages); this.connection.on('unread_messaging_message', this.onUnreadMessagingMessage); // Fetch count of unread messaging messages - this.$root.$data.os.api('messaging/unread').then(res => { + (this as any).api('messaging/unread').then(res => { if (res.count > 0) { this.hasUnreadMessagingMessages = true; } @@ -60,10 +60,10 @@ export default Vue.extend({ } }, beforeDestroy() { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages); this.connection.off('unread_messaging_message', this.onUnreadMessagingMessage); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); } }, methods: { diff --git a/src/web/app/desktop/views/components/ui-header-notifications.vue b/src/web/app/desktop/views/components/ui-header-notifications.vue index 5ffa28c917..d4dc553c53 100644 --- a/src/web/app/desktop/views/components/ui-header-notifications.vue +++ b/src/web/app/desktop/views/components/ui-header-notifications.vue @@ -23,15 +23,15 @@ export default Vue.extend({ }; }, mounted() { - if (this.$root.$data.os.isSignedIn) { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + if ((this as any).os.isSignedIn) { + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('read_all_notifications', this.onReadAllNotifications); this.connection.on('unread_notification', this.onUnreadNotification); // Fetch count of unread notifications - this.$root.$data.os.api('notifications/get_unread_count').then(res => { + (this as any).api('notifications/get_unread_count').then(res => { if (res.count > 0) { this.hasUnreadNotifications = true; } @@ -39,10 +39,10 @@ export default Vue.extend({ } }, beforeDestroy() { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.off('read_all_notifications', this.onReadAllNotifications); this.connection.off('unread_notification', this.onUnreadNotification); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); } }, methods: { diff --git a/src/web/app/desktop/views/components/ui-header.vue b/src/web/app/desktop/views/components/ui-header.vue index 0d9ecc4a59..6b89985adf 100644 --- a/src/web/app/desktop/views/components/ui-header.vue +++ b/src/web/app/desktop/views/components/ui-header.vue @@ -10,9 +10,9 @@ </div> <div class="right"> <mk-ui-header-search/> - <mk-ui-header-account v-if="$root.$data.os.isSignedIn"/> - <mk-ui-header-notifications v-if="$root.$data.os.isSignedIn"/> - <mk-ui-header-post-button v-if="$root.$data.os.isSignedIn"/> + <mk-ui-header-account v-if="os.isSignedIn"/> + <mk-ui-header-notifications v-if="os.isSignedIn"/> + <mk-ui-header-post-button v-if="os.isSignedIn"/> <mk-ui-header-clock/> </div> </div> diff --git a/src/web/app/desktop/views/components/ui.vue b/src/web/app/desktop/views/components/ui.vue index 76851a0f1e..af39dff7a5 100644 --- a/src/web/app/desktop/views/components/ui.vue +++ b/src/web/app/desktop/views/components/ui.vue @@ -4,7 +4,7 @@ <div class="content"> <slot></slot> </div> - <mk-stream-indicator v-if="$root.$data.os.isSignedIn"/> + <mk-stream-indicator v-if="os.isSignedIn"/> </div> </template> diff --git a/src/web/app/desktop/views/components/user-followers.vue b/src/web/app/desktop/views/components/user-followers.vue index 67e694cf41..4541a00072 100644 --- a/src/web/app/desktop/views/components/user-followers.vue +++ b/src/web/app/desktop/views/components/user-followers.vue @@ -14,7 +14,7 @@ export default Vue.extend({ props: ['user'], methods: { fetch(iknow, limit, cursor, cb) { - this.$root.$data.os.api('users/followers', { + (this as any).api('users/followers', { user_id: this.user.id, iknow: iknow, limit: limit, diff --git a/src/web/app/desktop/views/components/user-following.vue b/src/web/app/desktop/views/components/user-following.vue index 16cc3c42f1..e0b9f11695 100644 --- a/src/web/app/desktop/views/components/user-following.vue +++ b/src/web/app/desktop/views/components/user-following.vue @@ -14,7 +14,7 @@ export default Vue.extend({ props: ['user'], methods: { fetch(iknow, limit, cursor, cb) { - this.$root.$data.os.api('users/following', { + (this as any).api('users/following', { user_id: this.user.id, iknow: iknow, limit: limit, diff --git a/src/web/app/desktop/views/components/user-preview.vue b/src/web/app/desktop/views/components/user-preview.vue index 71b17503b3..df2c7e8971 100644 --- a/src/web/app/desktop/views/components/user-preview.vue +++ b/src/web/app/desktop/views/components/user-preview.vue @@ -21,7 +21,7 @@ <p>フォロワー</p><a>{{ u.followers_count }}</a> </div> </div> - <mk-follow-button v-if="$root.$data.os.isSignedIn && user.id != $root.$data.os.i.id" :user="u"/> + <mk-follow-button v-if="os.isSignedIn && user.id != os.i.id" :user="u"/> </template> </div> </template> @@ -49,7 +49,7 @@ export default Vue.extend({ this.open(); }); } else { - this.$root.$data.os.api('users/show', { + (this as any).api('users/show', { user_id: this.user[0] == '@' ? undefined : this.user, username: this.user[0] == '@' ? this.user.substr(1) : undefined }).then(user => { diff --git a/src/web/app/desktop/views/components/user-timeline.vue b/src/web/app/desktop/views/components/user-timeline.vue index bab32fd24e..fa5b32f225 100644 --- a/src/web/app/desktop/views/components/user-timeline.vue +++ b/src/web/app/desktop/views/components/user-timeline.vue @@ -60,7 +60,7 @@ export default Vue.extend({ } }, fetch(cb?) { - this.$root.$data.os.api('users/posts', { + (this as any).api('users/posts', { user_id: this.user.id, until_date: this.date ? this.date.getTime() : undefined, with_replies: this.mode == 'with-replies' @@ -73,7 +73,7 @@ export default Vue.extend({ more() { if (this.moreFetching || this.fetching || this.posts.length == 0) return; this.moreFetching = true; - this.$root.$data.os.api('users/posts', { + (this as any).api('users/posts', { user_id: this.user.id, with_replies: this.mode == 'with-replies', until_id: this.posts[this.posts.length - 1].id diff --git a/src/web/app/desktop/views/components/users-list.vue b/src/web/app/desktop/views/components/users-list.vue index 268fac4ec1..12abb372e7 100644 --- a/src/web/app/desktop/views/components/users-list.vue +++ b/src/web/app/desktop/views/components/users-list.vue @@ -3,7 +3,7 @@ <nav> <div> <span :data-is-active="mode == 'all'" @click="mode = 'all'">すべて<span>{{ count }}</span></span> - <span v-if="$root.$data.os.isSignedIn && youKnowCount" :data-is-active="mode == 'iknow'" @click="mode = 'iknow'">知り合い<span>{{ youKnowCount }}</span></span> + <span v-if="os.isSignedIn && youKnowCount" :data-is-active="mode == 'iknow'" @click="mode = 'iknow'">知り合い<span>{{ youKnowCount }}</span></span> </div> </nav> <div class="users" v-if="!fetching && users.length != 0"> diff --git a/src/web/app/desktop/views/components/window.vue b/src/web/app/desktop/views/components/window.vue index 946590d683..08e28007a7 100644 --- a/src/web/app/desktop/views/components/window.vue +++ b/src/web/app/desktop/views/components/window.vue @@ -80,7 +80,7 @@ export default Vue.extend({ created() { // ウィンドウをウィンドウシステムに登録 - this.$root.$data.os.windows.add(this); + (this as any).os.windows.add(this); }, mounted() { @@ -97,7 +97,7 @@ export default Vue.extend({ destroyed() { // ウィンドウをウィンドウシステムから削除 - this.$root.$data.os.windows.remove(this); + (this as any).os.windows.remove(this); window.removeEventListener('resize', this.onBrowserResize); }, @@ -191,7 +191,7 @@ export default Vue.extend({ top() { let z = 0; - this.$root.$data.os.windows.getAll().forEach(w => { + (this as any).os.windows.getAll().forEach(w => { if (w == this) return; const m = w.$refs.main; const mz = Number(document.defaultView.getComputedStyle(m, null).zIndex); diff --git a/src/web/app/desktop/views/pages/home.vue b/src/web/app/desktop/views/pages/home.vue index 7dc234ac03..e19b7fc8f0 100644 --- a/src/web/app/desktop/views/pages/home.vue +++ b/src/web/app/desktop/views/pages/home.vue @@ -26,8 +26,8 @@ export default Vue.extend({ mounted() { document.title = 'Misskey'; - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('post', this.onStreamPost); document.addEventListener('visibilitychange', this.onVisibilitychange, false); @@ -36,12 +36,12 @@ export default Vue.extend({ }, beforeDestroy() { this.connection.off('post', this.onStreamPost); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); document.removeEventListener('visibilitychange', this.onVisibilitychange); }, methods: { onStreamPost(post) { - if (document.hidden && post.user_id != this.$root.$data.os.i.id) { + if (document.hidden && post.user_id != (this as any).os.i.id) { this.unreadCount++; document.title = `(${this.unreadCount}) ${getPostSummary(post)}`; } diff --git a/src/web/app/desktop/views/pages/index.vue b/src/web/app/desktop/views/pages/index.vue index 6377b6a27b..bd32c17b3b 100644 --- a/src/web/app/desktop/views/pages/index.vue +++ b/src/web/app/desktop/views/pages/index.vue @@ -1,5 +1,5 @@ <template> - <component v-bind:is="$root.$data.os.isSignedIn ? 'home' : 'welcome'"></component> + <component v-bind:is="os.isSignedIn ? 'home' : 'welcome'"></component> </template> <script lang="ts"> diff --git a/src/web/app/desktop/views/pages/messaging-room.vue b/src/web/app/desktop/views/pages/messaging-room.vue index 86230cb546..3e4fb256ac 100644 --- a/src/web/app/desktop/views/pages/messaging-room.vue +++ b/src/web/app/desktop/views/pages/messaging-room.vue @@ -21,7 +21,7 @@ export default Vue.extend({ document.documentElement.style.background = '#fff'; - this.$root.$data.os.api('users/show', { + (this as any).api('users/show', { username: this.username }).then(user => { this.fetching = false; diff --git a/src/web/app/desktop/views/pages/post.vue b/src/web/app/desktop/views/pages/post.vue index 471f5a5c62..186ee332f6 100644 --- a/src/web/app/desktop/views/pages/post.vue +++ b/src/web/app/desktop/views/pages/post.vue @@ -23,7 +23,7 @@ export default Vue.extend({ mounted() { Progress.start(); - this.$root.$data.os.api('posts/show', { + (this as any).api('posts/show', { post_id: this.postId }).then(post => { this.fetching = false; diff --git a/src/web/app/desktop/views/pages/search.vue b/src/web/app/desktop/views/pages/search.vue index d8147e0d6a..828aac8fe1 100644 --- a/src/web/app/desktop/views/pages/search.vue +++ b/src/web/app/desktop/views/pages/search.vue @@ -44,7 +44,7 @@ export default Vue.extend({ document.addEventListener('keydown', this.onDocumentKeydown); window.addEventListener('scroll', this.onScroll); - this.$root.$data.os.api('posts/search', parse(this.query)).then(posts => { + (this as any).api('posts/search', parse(this.query)).then(posts => { this.fetching = false; this.posts = posts; }); @@ -65,7 +65,7 @@ export default Vue.extend({ if (this.moreFetching || this.fetching || this.posts.length == 0) return; this.offset += limit; this.moreFetching = true; - return this.$root.$data.os.api('posts/search', Object.assign({}, parse(this.query), { + return (this as any).api('posts/search', Object.assign({}, parse(this.query), { limit: limit, offset: this.offset })).then(posts => { diff --git a/src/web/app/desktop/views/pages/user/user-followers-you-know.vue b/src/web/app/desktop/views/pages/user/user-followers-you-know.vue index 4190081750..246ff865d1 100644 --- a/src/web/app/desktop/views/pages/user/user-followers-you-know.vue +++ b/src/web/app/desktop/views/pages/user/user-followers-you-know.vue @@ -22,7 +22,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/followers', { + (this as any).api('users/followers', { user_id: this.user.id, iknow: true, limit: 16 diff --git a/src/web/app/desktop/views/pages/user/user-friends.vue b/src/web/app/desktop/views/pages/user/user-friends.vue index 15fb7a96ea..d6b20aa27e 100644 --- a/src/web/app/desktop/views/pages/user/user-friends.vue +++ b/src/web/app/desktop/views/pages/user/user-friends.vue @@ -27,7 +27,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/get_frequently_replied_users', { + (this as any).api('users/get_frequently_replied_users', { user_id: this.user.id, limit: 4 }).then(docs => { diff --git a/src/web/app/desktop/views/pages/user/user-header.vue b/src/web/app/desktop/views/pages/user/user-header.vue index 07f206d241..b4a24459ce 100644 --- a/src/web/app/desktop/views/pages/user/user-header.vue +++ b/src/web/app/desktop/views/pages/user/user-header.vue @@ -51,9 +51,9 @@ export default Vue.extend({ }, onBannerClick() { - if (!this.$root.$data.os.isSignedIn || this.$root.$data.os.i.id != this.user.id) return; + if (!(this as any).os.isSignedIn || (this as any).os.i.id != this.user.id) return; - updateBanner(this.$root.$data.os.i, i => { + updateBanner((this as any).os.i, i => { this.user.banner_url = i.banner_url; }); } diff --git a/src/web/app/desktop/views/pages/user/user-home.vue b/src/web/app/desktop/views/pages/user/user-home.vue index dc0a03dabe..2e67b1ec3a 100644 --- a/src/web/app/desktop/views/pages/user/user-home.vue +++ b/src/web/app/desktop/views/pages/user/user-home.vue @@ -4,7 +4,7 @@ <div ref="left"> <mk-user-profile :user="user"/> <mk-user-photos :user="user"/> - <mk-user-followers-you-know v-if="$root.$data.os.isSignedIn && $root.$data.os.i.id != user.id" :user="user"/> + <mk-user-followers-you-know v-if="os.isSignedIn && os.i.id != user.id" :user="user"/> <p>%i18n:desktop.tags.mk-user.last-used-at%: <b><mk-time :time="user.last_used_at"/></b></p> </div> </div> diff --git a/src/web/app/desktop/views/pages/user/user-photos.vue b/src/web/app/desktop/views/pages/user/user-photos.vue index fc51b9789f..789d9af85f 100644 --- a/src/web/app/desktop/views/pages/user/user-photos.vue +++ b/src/web/app/desktop/views/pages/user/user-photos.vue @@ -23,7 +23,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/posts', { + (this as any).api('users/posts', { user_id: this.user.id, with_media: true, limit: 9 diff --git a/src/web/app/desktop/views/pages/user/user-profile.vue b/src/web/app/desktop/views/pages/user/user-profile.vue index 66385ab2ec..d389e01c19 100644 --- a/src/web/app/desktop/views/pages/user/user-profile.vue +++ b/src/web/app/desktop/views/pages/user/user-profile.vue @@ -1,6 +1,6 @@ <template> <div class="mk-user-profile"> - <div class="friend-form" v-if="$root.$data.os.isSignedIn && $root.$data.os.i.id != user.id"> + <div class="friend-form" v-if="os.isSignedIn && os.i.id != user.id"> <mk-follow-button :user="user" size="big"/> <p class="followed" v-if="user.is_followed">%i18n:desktop.tags.mk-user.follows-you%</p> <p v-if="user.is_muted">%i18n:desktop.tags.mk-user.muted% <a @click="unmute">%i18n:desktop.tags.mk-user.unmute%</a></p> @@ -35,7 +35,7 @@ export default Vue.extend({ methods: { showFollowing() { document.body.appendChild(new MkUserFollowingWindow({ - parent: this, + propsData: { user: this.user } @@ -44,7 +44,7 @@ export default Vue.extend({ showFollowers() { document.body.appendChild(new MkUserFollowersWindow({ - parent: this, + propsData: { user: this.user } @@ -52,7 +52,7 @@ export default Vue.extend({ }, mute() { - this.$root.$data.os.api('mute/create', { + (this as any).api('mute/create', { user_id: this.user.id }).then(() => { this.user.is_muted = true; @@ -62,7 +62,7 @@ export default Vue.extend({ }, unmute() { - this.$root.$data.os.api('mute/delete', { + (this as any).api('mute/delete', { user_id: this.user.id }).then(() => { this.user.is_muted = false; diff --git a/src/web/app/desktop/views/pages/user/user.vue b/src/web/app/desktop/views/pages/user/user.vue index 109ee6037e..3339c2dce0 100644 --- a/src/web/app/desktop/views/pages/user/user.vue +++ b/src/web/app/desktop/views/pages/user/user.vue @@ -29,7 +29,7 @@ export default Vue.extend({ }, mounted() { Progress.start(); - this.$root.$data.os.api('users/show', { + (this as any).api('users/show', { username: this.username }).then(user => { this.fetching = false; diff --git a/src/web/app/init.ts b/src/web/app/init.ts index 450327a588..8abb7f7aa5 100644 --- a/src/web/app/init.ts +++ b/src/web/app/init.ts @@ -78,37 +78,50 @@ if (localStorage.getItem('should-refresh') == 'true') { type API = { chooseDriveFile: (opts: { - title: string; - currentFolder: any; - multiple: boolean; + title?: string; + currentFolder?: any; + multiple?: boolean; }) => Promise<any>; chooseDriveFolder: (opts: { - title: string; - currentFolder: any; + title?: string; + currentFolder?: any; }) => Promise<any>; + + dialog: (opts: { + title: string; + text: string; + actions: Array<{ + text: string; + id: string; + }>; + }) => Promise<string>; + + input: (opts: { + title: string; + placeholder?: string; + default?: string; + }) => Promise<string>; }; // MiOSを初期化してコールバックする export default (callback: (launch: (api: API) => Vue) => void, sw = false) => { - const mios = new MiOS(sw); + const os = new MiOS(sw); - Vue.mixin({ - data: { - $os: mios - } - }); - - mios.init(() => { + os.init(() => { // アプリ基底要素マウント document.body.innerHTML = '<div id="app"></div>'; const launch = (api: API) => { + Vue.mixin({ + created() { + (this as any).os = os; + (this as any).api = os.api; + (this as any).apis = api; + } + }); + return new Vue({ - data: { - os: mios, - api: api - }, router: new VueRouter({ mode: 'history' }), @@ -124,7 +137,7 @@ export default (callback: (launch: (api: API) => Vue) => void, sw = false) => { // 更新チェック setTimeout(() => { - checkForUpdate(mios); + checkForUpdate(os); }, 3000); }); }; diff --git a/src/web/app/mobile/views/components/drive.vue b/src/web/app/mobile/views/components/drive.vue index c842caacb3..e581d3f053 100644 --- a/src/web/app/mobile/views/components/drive.vue +++ b/src/web/app/mobile/views/components/drive.vue @@ -87,8 +87,8 @@ export default Vue.extend({ } }, mounted() { - this.connection = this.$root.$data.os.streams.driveStream.getConnection(); - this.connectionId = this.$root.$data.os.streams.driveStream.use(); + this.connection = (this as any).os.streams.driveStream.getConnection(); + this.connectionId = (this as any).os.streams.driveStream.use(); this.connection.on('file_created', this.onStreamDriveFileCreated); this.connection.on('file_updated', this.onStreamDriveFileUpdated); @@ -112,7 +112,7 @@ export default Vue.extend({ this.connection.off('file_updated', this.onStreamDriveFileUpdated); this.connection.off('folder_created', this.onStreamDriveFolderCreated); this.connection.off('folder_updated', this.onStreamDriveFolderUpdated); - this.$root.$data.os.streams.driveStream.dispose(this.connectionId); + (this as any).os.streams.driveStream.dispose(this.connectionId); }, methods: { onStreamDriveFileCreated(file) { @@ -158,7 +158,7 @@ export default Vue.extend({ this.fetching = true; - this.$root.$data.os.api('drive/folders/show', { + (this as any).api('drive/folders/show', { folder_id: target }).then(folder => { this.folder = folder; @@ -253,7 +253,7 @@ export default Vue.extend({ const filesMax = 20; // フォルダ一覧取得 - this.$root.$data.os.api('drive/folders', { + (this as any).api('drive/folders', { folder_id: this.folder ? this.folder.id : null, limit: foldersMax + 1 }).then(folders => { @@ -266,7 +266,7 @@ export default Vue.extend({ }); // ファイル一覧取得 - this.$root.$data.os.api('drive/files', { + (this as any).api('drive/files', { folder_id: this.folder ? this.folder.id : null, limit: filesMax + 1 }).then(files => { @@ -296,7 +296,7 @@ export default Vue.extend({ if (this.folder == null) { // Fetch addtional drive info - this.$root.$data.os.api('drive').then(info => { + (this as any).api('drive').then(info => { this.info = info; }); } @@ -309,7 +309,7 @@ export default Vue.extend({ const max = 30; // ファイル一覧取得 - this.$root.$data.os.api('drive/files', { + (this as any).api('drive/files', { folder_id: this.folder ? this.folder.id : null, limit: max + 1, until_id: this.files[this.files.length - 1].id @@ -348,7 +348,7 @@ export default Vue.extend({ this.fetching = true; - this.$root.$data.os.api('drive/files/show', { + (this as any).api('drive/files/show', { file_id: file }).then(file => { this.fetching = false; @@ -394,7 +394,7 @@ export default Vue.extend({ createFolder() { const name = window.prompt('フォルダー名'); if (name == null || name == '') return; - this.$root.$data.os.api('drive/folders/create', { + (this as any).api('drive/folders/create', { name: name, parent_id: this.folder ? this.folder.id : undefined }).then(folder => { @@ -409,7 +409,7 @@ export default Vue.extend({ } const name = window.prompt('フォルダー名', this.folder.name); if (name == null || name == '') return; - this.$root.$data.os.api('drive/folders/update', { + (this as any).api('drive/folders/update', { name: name, folder_id: this.folder.id }).then(folder => { @@ -424,7 +424,7 @@ export default Vue.extend({ } const dialog = riot.mount(document.body.appendChild(document.createElement('mk-drive-folder-selector')))[0]; dialog.one('selected', folder => { - this.$root.$data.os.api('drive/folders/update', { + (this as any).api('drive/folders/update', { parent_id: folder ? folder.id : null, folder_id: this.folder.id }).then(folder => { @@ -436,7 +436,7 @@ export default Vue.extend({ urlUpload() { const url = window.prompt('アップロードしたいファイルのURL'); if (url == null || url == '') return; - this.$root.$data.os.api('drive/files/upload_from_url', { + (this as any).api('drive/files/upload_from_url', { url: url, folder_id: this.folder ? this.folder.id : undefined }); diff --git a/src/web/app/mobile/views/components/follow-button.vue b/src/web/app/mobile/views/components/follow-button.vue index 047005cc9e..2d45ea215d 100644 --- a/src/web/app/mobile/views/components/follow-button.vue +++ b/src/web/app/mobile/views/components/follow-button.vue @@ -28,8 +28,8 @@ export default Vue.extend({ }; }, mounted() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('follow', this.onFollow); this.connection.on('unfollow', this.onUnfollow); @@ -37,7 +37,7 @@ export default Vue.extend({ beforeDestroy() { this.connection.off('follow', this.onFollow); this.connection.off('unfollow', this.onUnfollow); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { @@ -56,7 +56,7 @@ export default Vue.extend({ onClick() { this.wait = true; if (this.user.is_following) { - this.$root.$data.os.api('following/delete', { + (this as any).api('following/delete', { user_id: this.user.id }).then(() => { this.user.is_following = false; @@ -66,7 +66,7 @@ export default Vue.extend({ this.wait = false; }); } else { - this.$root.$data.os.api('following/create', { + (this as any).api('following/create', { user_id: this.user.id }).then(() => { this.user.is_following = true; diff --git a/src/web/app/mobile/views/components/friends-maker.vue b/src/web/app/mobile/views/components/friends-maker.vue index 45ee4a6440..b069b988cc 100644 --- a/src/web/app/mobile/views/components/friends-maker.vue +++ b/src/web/app/mobile/views/components/friends-maker.vue @@ -32,7 +32,7 @@ export default Vue.extend({ this.fetching = true; this.users = []; - this.$root.$data.os.api('users/recommendation', { + (this as any).api('users/recommendation', { limit: this.limit, offset: this.limit * this.page }).then(users => { diff --git a/src/web/app/mobile/views/components/notifications.vue b/src/web/app/mobile/views/components/notifications.vue index 8813bef5b0..999dba4042 100644 --- a/src/web/app/mobile/views/components/notifications.vue +++ b/src/web/app/mobile/views/components/notifications.vue @@ -42,14 +42,14 @@ export default Vue.extend({ } }, mounted() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('notification', this.onNotification); const max = 10; - this.$root.$data.os.api('i/notifications', { + (this as any).api('i/notifications', { limit: max + 1 }).then(notifications => { if (notifications.length == max + 1) { @@ -63,7 +63,7 @@ export default Vue.extend({ }, beforeDestroy() { this.connection.off('notification', this.onNotification); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { fetchMoreNotifications() { @@ -71,7 +71,7 @@ export default Vue.extend({ const max = 30; - this.$root.$data.os.api('i/notifications', { + (this as any).api('i/notifications', { limit: max + 1, until_id: this.notifications[this.notifications.length - 1].id }).then(notifications => { diff --git a/src/web/app/mobile/views/components/post-detail.vue b/src/web/app/mobile/views/components/post-detail.vue index da4f3fee76..87a591ff68 100644 --- a/src/web/app/mobile/views/components/post-detail.vue +++ b/src/web/app/mobile/views/components/post-detail.vue @@ -33,7 +33,7 @@ </div> </header> <div class="body"> - <mk-post-html v-if="p.ast" :ast="p.ast" :i="$root.$data.os.i"/> + <mk-post-html v-if="p.ast" :ast="p.ast" :i="os.i"/> <mk-url-preview v-for="url in urls" :url="url" :key="url"/> <div class="media" v-if="p.media"> <mk-images images={ p.media }/> @@ -116,7 +116,7 @@ export default Vue.extend({ mounted() { // Get replies if (!this.compact) { - this.$root.$data.os.api('posts/replies', { + (this as any).api('posts/replies', { post_id: this.p.id, limit: 8 }).then(replies => { @@ -129,7 +129,7 @@ export default Vue.extend({ this.contextFetching = true; // Fetch context - this.$root.$data.os.api('posts/context', { + (this as any).api('posts/context', { post_id: this.p.reply_id }).then(context => { this.contextFetching = false; diff --git a/src/web/app/mobile/views/components/posts-post.vue b/src/web/app/mobile/views/components/posts-post.vue index 56b42d9c22..b252a6e97d 100644 --- a/src/web/app/mobile/views/components/posts-post.vue +++ b/src/web/app/mobile/views/components/posts-post.vue @@ -106,24 +106,24 @@ export default Vue.extend({ } }, created() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); }, mounted() { this.capture(true); - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.on('_connected_', this.onStreamConnected); } }, beforeDestroy() { this.decapture(true); this.connection.off('_connected_', this.onStreamConnected); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { capture(withHandler = false) { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.send({ type: 'capture', id: this.post.id @@ -132,7 +132,7 @@ export default Vue.extend({ } }, decapture(withHandler = false) { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.send({ type: 'decapture', id: this.post.id diff --git a/src/web/app/mobile/views/components/sub-post-content.vue b/src/web/app/mobile/views/components/sub-post-content.vue index 48f3791aa5..429e760050 100644 --- a/src/web/app/mobile/views/components/sub-post-content.vue +++ b/src/web/app/mobile/views/components/sub-post-content.vue @@ -2,7 +2,7 @@ <div class="mk-sub-post-content"> <div class="body"> <a class="reply" v-if="post.reply_id">%fa:reply%</a> - <mk-post-html v-if="post.ast" :ast="post.ast" :i="$root.$data.os.i"/> + <mk-post-html v-if="post.ast" :ast="post.ast" :i="os.i"/> <a class="quote" v-if="post.repost_id">RP: ...</a> </div> <details v-if="post.media"> diff --git a/src/web/app/mobile/views/components/timeline.vue b/src/web/app/mobile/views/components/timeline.vue index 77c24a4692..a04780e94d 100644 --- a/src/web/app/mobile/views/components/timeline.vue +++ b/src/web/app/mobile/views/components/timeline.vue @@ -37,12 +37,12 @@ export default Vue.extend({ }, computed: { alone(): boolean { - return this.$root.$data.os.i.following_count == 0; + return (this as any).os.i.following_count == 0; } }, mounted() { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('post', this.onPost); this.connection.on('follow', this.onChangeFollowing); @@ -54,13 +54,13 @@ export default Vue.extend({ this.connection.off('post', this.onPost); this.connection.off('follow', this.onChangeFollowing); this.connection.off('unfollow', this.onChangeFollowing); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); }, methods: { fetch(cb?) { this.fetching = true; - this.$root.$data.os.api('posts/timeline', { + (this as any).api('posts/timeline', { until_date: this.date ? (this.date as any).getTime() : undefined }).then(posts => { this.fetching = false; @@ -71,7 +71,7 @@ export default Vue.extend({ more() { if (this.moreFetching || this.fetching || this.posts.length == 0) return; this.moreFetching = true; - this.$root.$data.os.api('posts/timeline', { + (this as any).api('posts/timeline', { until_id: this.posts[this.posts.length - 1].id }).then(posts => { this.moreFetching = false; diff --git a/src/web/app/mobile/views/components/ui-header.vue b/src/web/app/mobile/views/components/ui-header.vue index 3bb1054c86..85fb45780d 100644 --- a/src/web/app/mobile/views/components/ui-header.vue +++ b/src/web/app/mobile/views/components/ui-header.vue @@ -31,9 +31,9 @@ export default Vue.extend({ }; }, mounted() { - if (this.$root.$data.os.isSignedIn) { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + if ((this as any).os.isSignedIn) { + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('read_all_notifications', this.onReadAllNotifications); this.connection.on('unread_notification', this.onUnreadNotification); @@ -41,14 +41,14 @@ export default Vue.extend({ this.connection.on('unread_messaging_message', this.onUnreadMessagingMessage); // Fetch count of unread notifications - this.$root.$data.os.api('notifications/get_unread_count').then(res => { + (this as any).api('notifications/get_unread_count').then(res => { if (res.count > 0) { this.hasUnreadNotifications = true; } }); // Fetch count of unread messaging messages - this.$root.$data.os.api('messaging/unread').then(res => { + (this as any).api('messaging/unread').then(res => { if (res.count > 0) { this.hasUnreadMessagingMessages = true; } @@ -56,12 +56,12 @@ export default Vue.extend({ } }, beforeDestroy() { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.off('read_all_notifications', this.onReadAllNotifications); this.connection.off('unread_notification', this.onUnreadNotification); this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages); this.connection.off('unread_messaging_message', this.onUnreadMessagingMessage); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); } }, methods: { diff --git a/src/web/app/mobile/views/components/ui-nav.vue b/src/web/app/mobile/views/components/ui-nav.vue index cab24787d1..1767e62242 100644 --- a/src/web/app/mobile/views/components/ui-nav.vue +++ b/src/web/app/mobile/views/components/ui-nav.vue @@ -2,7 +2,7 @@ <div class="mk-ui-nav" :style="{ display: isOpen ? 'block' : 'none' }"> <div class="backdrop" @click="parent.toggleDrawer"></div> <div class="body"> - <a class="me" v-if="$root.$data.os.isSignedIn" href={ '/' + I.username }> + <a class="me" v-if="os.isSignedIn" href={ '/' + I.username }> <img class="avatar" src={ I.avatar_url + '?thumbnail&size=128' } alt="avatar"/> <p class="name">{ I.name }</p> </a> @@ -41,9 +41,9 @@ export default Vue.extend({ }; }, mounted() { - if (this.$root.$data.os.isSignedIn) { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + if ((this as any).os.isSignedIn) { + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('read_all_notifications', this.onReadAllNotifications); this.connection.on('unread_notification', this.onUnreadNotification); @@ -51,14 +51,14 @@ export default Vue.extend({ this.connection.on('unread_messaging_message', this.onUnreadMessagingMessage); // Fetch count of unread notifications - this.$root.$data.os.api('notifications/get_unread_count').then(res => { + (this as any).api('notifications/get_unread_count').then(res => { if (res.count > 0) { this.hasUnreadNotifications = true; } }); // Fetch count of unread messaging messages - this.$root.$data.os.api('messaging/unread').then(res => { + (this as any).api('messaging/unread').then(res => { if (res.count > 0) { this.hasUnreadMessagingMessages = true; } @@ -66,12 +66,12 @@ export default Vue.extend({ } }, beforeDestroy() { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.off('read_all_notifications', this.onReadAllNotifications); this.connection.off('unread_notification', this.onUnreadNotification); this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages); this.connection.off('unread_messaging_message', this.onUnreadMessagingMessage); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); } }, methods: { diff --git a/src/web/app/mobile/views/components/ui.vue b/src/web/app/mobile/views/components/ui.vue index 52443430a3..a07c9ed5a2 100644 --- a/src/web/app/mobile/views/components/ui.vue +++ b/src/web/app/mobile/views/components/ui.vue @@ -7,7 +7,7 @@ <div class="content"> <slot></slot> </div> - <mk-stream-indicator v-if="$root.$data.os.isSignedIn"/> + <mk-stream-indicator v-if="os.isSignedIn"/> </div> </template> @@ -23,17 +23,17 @@ export default Vue.extend({ }; }, mounted() { - if (this.$root.$data.os.isSignedIn) { - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + if ((this as any).os.isSignedIn) { + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('notification', this.onNotification); } }, beforeDestroy() { - if (this.$root.$data.os.isSignedIn) { + if ((this as any).os.isSignedIn) { this.connection.off('notification', this.onNotification); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); } }, methods: { diff --git a/src/web/app/mobile/views/components/user-followers.vue b/src/web/app/mobile/views/components/user-followers.vue index 22629af9df..771291b498 100644 --- a/src/web/app/mobile/views/components/user-followers.vue +++ b/src/web/app/mobile/views/components/user-followers.vue @@ -14,7 +14,7 @@ export default Vue.extend({ props: ['user'], methods: { fetch(iknow, limit, cursor, cb) { - this.$root.$data.os.api('users/followers', { + (this as any).api('users/followers', { user_id: this.user.id, iknow: iknow, limit: limit, diff --git a/src/web/app/mobile/views/components/user-following.vue b/src/web/app/mobile/views/components/user-following.vue index bb739bc4ca..dfd6135da2 100644 --- a/src/web/app/mobile/views/components/user-following.vue +++ b/src/web/app/mobile/views/components/user-following.vue @@ -14,7 +14,7 @@ export default Vue.extend({ props: ['user'], methods: { fetch(iknow, limit, cursor, cb) { - this.$root.$data.os.api('users/following', { + (this as any).api('users/following', { user_id: this.user.id, iknow: iknow, limit: limit, diff --git a/src/web/app/mobile/views/components/user-timeline.vue b/src/web/app/mobile/views/components/user-timeline.vue index 9a31ace4d1..fb2a214198 100644 --- a/src/web/app/mobile/views/components/user-timeline.vue +++ b/src/web/app/mobile/views/components/user-timeline.vue @@ -27,7 +27,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/posts', { + (this as any).api('users/posts', { user_id: this.user.id, with_media: this.withMedia }).then(posts => { diff --git a/src/web/app/mobile/views/components/users-list.vue b/src/web/app/mobile/views/components/users-list.vue index 54af40ec48..45629c5586 100644 --- a/src/web/app/mobile/views/components/users-list.vue +++ b/src/web/app/mobile/views/components/users-list.vue @@ -2,7 +2,7 @@ <div class="mk-users-list"> <nav> <span :data-is-active="mode == 'all'" @click="mode = 'all'">%i18n:mobile.tags.mk-users-list.all%<span>{{ count }}</span></span> - <span v-if="$root.$data.os.isSignedIn && youKnowCount" :data-is-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:mobile.tags.mk-users-list.known%<span>{{ youKnowCount }}</span></span> + <span v-if="os.isSignedIn && youKnowCount" :data-is-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:mobile.tags.mk-users-list.known%<span>{{ youKnowCount }}</span></span> </nav> <div class="users" v-if="!fetching && users.length != 0"> <mk-user-preview v-for="u in users" :user="u" :key="u.id"/> diff --git a/src/web/app/mobile/views/pages/followers.vue b/src/web/app/mobile/views/pages/followers.vue index dcaca16a24..e9696dbd3c 100644 --- a/src/web/app/mobile/views/pages/followers.vue +++ b/src/web/app/mobile/views/pages/followers.vue @@ -23,7 +23,7 @@ export default Vue.extend({ mounted() { Progress.start(); - this.$root.$data.os.api('users/show', { + (this as any).api('users/show', { username: this.username }).then(user => { this.fetching = false; diff --git a/src/web/app/mobile/views/pages/following.vue b/src/web/app/mobile/views/pages/following.vue index b11e3b95f6..c278abfd25 100644 --- a/src/web/app/mobile/views/pages/following.vue +++ b/src/web/app/mobile/views/pages/following.vue @@ -23,7 +23,7 @@ export default Vue.extend({ mounted() { Progress.start(); - this.$root.$data.os.api('users/show', { + (this as any).api('users/show', { username: this.username }).then(user => { this.fetching = false; diff --git a/src/web/app/mobile/views/pages/home.vue b/src/web/app/mobile/views/pages/home.vue index 3b069c6143..4313ab699c 100644 --- a/src/web/app/mobile/views/pages/home.vue +++ b/src/web/app/mobile/views/pages/home.vue @@ -23,8 +23,8 @@ export default Vue.extend({ document.title = 'Misskey'; document.documentElement.style.background = '#313a42'; - this.connection = this.$root.$data.os.stream.getConnection(); - this.connectionId = this.$root.$data.os.stream.use(); + this.connection = (this as any).os.stream.getConnection(); + this.connectionId = (this as any).os.stream.use(); this.connection.on('post', this.onStreamPost); document.addEventListener('visibilitychange', this.onVisibilitychange, false); @@ -33,7 +33,7 @@ export default Vue.extend({ }, beforeDestroy() { this.connection.off('post', this.onStreamPost); - this.$root.$data.os.stream.dispose(this.connectionId); + (this as any).os.stream.dispose(this.connectionId); document.removeEventListener('visibilitychange', this.onVisibilitychange); }, methods: { @@ -44,7 +44,7 @@ export default Vue.extend({ Progress.done(); }, onStreamPost(post) { - if (document.hidden && post.user_id !== this.$root.$data.os.i.id) { + if (document.hidden && post.user_id !== (this as any).os.i.id) { this.unreadCount++; document.title = `(${this.unreadCount}) ${getPostSummary(post)}`; } diff --git a/src/web/app/mobile/views/pages/notification.vue b/src/web/app/mobile/views/pages/notification.vue index 03d8b6cad8..0685bd1278 100644 --- a/src/web/app/mobile/views/pages/notification.vue +++ b/src/web/app/mobile/views/pages/notification.vue @@ -21,7 +21,7 @@ export default Vue.extend({ const ok = window.confirm('%i18n:mobile.tags.mk-notifications-page.read-all%'); if (!ok) return; - this.$root.$data.os.api('notifications/mark_as_read_all'); + (this as any).api('notifications/mark_as_read_all'); }, onFetched() { Progress.done(); diff --git a/src/web/app/mobile/views/pages/post.vue b/src/web/app/mobile/views/pages/post.vue index f291a489b5..c5b6750afa 100644 --- a/src/web/app/mobile/views/pages/post.vue +++ b/src/web/app/mobile/views/pages/post.vue @@ -29,7 +29,7 @@ export default Vue.extend({ Progress.start(); - this.$root.$data.os.api('posts/show', { + (this as any).api('posts/show', { post_id: this.postId }).then(post => { this.fetching = false; diff --git a/src/web/app/mobile/views/pages/search.vue b/src/web/app/mobile/views/pages/search.vue index 02cdb16004..b6e114a82b 100644 --- a/src/web/app/mobile/views/pages/search.vue +++ b/src/web/app/mobile/views/pages/search.vue @@ -35,7 +35,7 @@ export default Vue.extend({ Progress.start(); - this.$root.$data.os.api('posts/search', Object.assign({}, parse(this.query), { + (this as any).api('posts/search', Object.assign({}, parse(this.query), { limit: limit })).then(posts => { this.posts = posts; @@ -46,7 +46,7 @@ export default Vue.extend({ methods: { more() { this.offset += limit; - return this.$root.$data.os.api('posts/search', Object.assign({}, parse(this.query), { + return (this as any).api('posts/search', Object.assign({}, parse(this.query), { limit: limit, offset: this.offset })); diff --git a/src/web/app/mobile/views/pages/user.vue b/src/web/app/mobile/views/pages/user.vue index 6c784b05f4..f5babbd67f 100644 --- a/src/web/app/mobile/views/pages/user.vue +++ b/src/web/app/mobile/views/pages/user.vue @@ -9,7 +9,7 @@ <a class="avatar"> <img :src="`${user.avatar_url}?thumbnail&size=200`" alt="avatar"/> </a> - <mk-follow-button v-if="$root.$data.os.isSignedIn && $root.$data.os.i.id != user.id" :user="user"/> + <mk-follow-button v-if="os.isSignedIn && os.i.id != user.id" :user="user"/> </div> <div class="title"> <h1>{{ user.name }}</h1> @@ -85,7 +85,7 @@ export default Vue.extend({ document.documentElement.style.background = '#313a42'; Progress.start(); - this.$root.$data.os.api('users/show', { + (this as any).api('users/show', { username: this.username }).then(user => { this.fetching = false; diff --git a/src/web/app/mobile/views/pages/user/followers-you-know.vue b/src/web/app/mobile/views/pages/user/followers-you-know.vue index a4358f5d90..eb0ff68bdf 100644 --- a/src/web/app/mobile/views/pages/user/followers-you-know.vue +++ b/src/web/app/mobile/views/pages/user/followers-you-know.vue @@ -21,7 +21,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/followers', { + (this as any).api('users/followers', { user_id: this.user.id, iknow: true, limit: 30 diff --git a/src/web/app/mobile/views/pages/user/home-activity.vue b/src/web/app/mobile/views/pages/user/home-activity.vue index 00a2dafc12..f38c5568ea 100644 --- a/src/web/app/mobile/views/pages/user/home-activity.vue +++ b/src/web/app/mobile/views/pages/user/home-activity.vue @@ -28,7 +28,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('aggregation/users/activity', { + (this as any).api('aggregation/users/activity', { user_id: this.user.id, limit: 30 }).then(data => { diff --git a/src/web/app/mobile/views/pages/user/home-friends.vue b/src/web/app/mobile/views/pages/user/home-friends.vue index 7c5a50559d..4f2f12a642 100644 --- a/src/web/app/mobile/views/pages/user/home-friends.vue +++ b/src/web/app/mobile/views/pages/user/home-friends.vue @@ -19,7 +19,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/get_frequently_replied_users', { + (this as any).api('users/get_frequently_replied_users', { user_id: this.user.id }).then(res => { this.fetching = false; diff --git a/src/web/app/mobile/views/pages/user/home-photos.vue b/src/web/app/mobile/views/pages/user/home-photos.vue index fc2d0e139a..eb53eb89a9 100644 --- a/src/web/app/mobile/views/pages/user/home-photos.vue +++ b/src/web/app/mobile/views/pages/user/home-photos.vue @@ -23,7 +23,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/posts', { + (this as any).api('users/posts', { user_id: this.user.id, with_media: true, limit: 6 diff --git a/src/web/app/mobile/views/pages/user/home-posts.vue b/src/web/app/mobile/views/pages/user/home-posts.vue index b1451b0887..c60f114b88 100644 --- a/src/web/app/mobile/views/pages/user/home-posts.vue +++ b/src/web/app/mobile/views/pages/user/home-posts.vue @@ -19,7 +19,7 @@ export default Vue.extend({ }; }, mounted() { - this.$root.$data.os.api('users/posts', { + (this as any).api('users/posts', { user_id: this.user.id }).then(posts => { this.fetching = false; diff --git a/src/web/app/mobile/views/pages/user/home.vue b/src/web/app/mobile/views/pages/user/home.vue index a23825f227..44ddd54dc3 100644 --- a/src/web/app/mobile/views/pages/user/home.vue +++ b/src/web/app/mobile/views/pages/user/home.vue @@ -37,7 +37,7 @@ <mk-user-home-frequently-replied-users :user="user"/> </div> </section> - <section class="followers-you-know" v-if="$root.$data.os.isSignedIn && $root.$data.os.i.id !== user.id"> + <section class="followers-you-know" v-if="os.isSignedIn && os.i.id !== user.id"> <h2>%fa:users%%i18n:mobile.tags.mk-user-overview.followers-you-know%</h2> <div> <mk-user-home-followers-you-know :user="user"/> |