diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2020-10-17 20:12:00 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-17 20:12:00 +0900 |
| commit | 7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a (patch) | |
| tree | 2263a06acec7fa21882366bae26d1a983ce21135 /src/client/components/post-form.vue | |
| parent | CW の input でも投稿ショートカットが動作するように (#6690) (diff) | |
| download | misskey-7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a.tar.gz misskey-7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a.tar.bz2 misskey-7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a.zip | |
Migrate to Vue3 (#6587)
* Update reaction.vue
* fix bug
* wip
* wip
* wjio
* wip
* Revert "wip"
This reverts commit e427f2160adf4e8a4147006e25a89854edab0033.
* wip
* wip
* wip
* Update init.ts
* Update drive-window.vue
* wip
* wip
* Use PascalCase for components
* Use PascalCase for components
* update dep
* wip
* wip
* wip
* Update init.ts
* wip
* Update paging.ts
* Update test.vue
* watch deep
* wip
* lint
* wip
* wip
* wip
* wip
* wiop
* wip
* Update webpack.config.ts
* alllow null poll
* wip
* wip
* wip
* wiop
* UI redesign & refactor (#6714)
* wip
* wip
* wip
* wip
* wip
* Update drive.vue
* Update word-mute.vue
* wip
* wip
* wip
* clean up
* wip
* Update default.vue
* wip
* Update notes.vue
* Update mfm.ts
* Update index.home.vue
* Update post-form.vue
* Update post-form-attaches.vue
* wip
* Update post-form.vue
* Update sidebar.vue
* wip
* wip
* Update index.vue
* wip
* Update default.vue
* Update index.vue
* Update index.vue
* wip
* Update post-form-attaches.vue
* Update note.vue
* wip
* clean up
* Update notes.vue
* wip
* wip
* Update ja-JP.yml
* wip
* wip
* Update index.vue
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* Update default.vue
* wip
* Update _dark.json5
* wip
* wip
* wip
* clean up
* wip
* wip
* Update index.vue
* Update test.vue
* wip
* wip
* fix
* wip
* wip
* wip
* wip
* clena yop
* wip
* wip
* Update store.ts
* Update messaging-room.vue
* Update default.widgets.vue
* fix
* wip
* wip
* Update modal.vue
* wip
* Update os.ts
* Update os.ts
* Update deck.vue
* Update init.ts
* wip
* Update ja-JP.yml
* v-sizeは単にwindowのresizeを監視するだけで良いかもしれない
* Update modal.vue
* wip
* Update tooltip.ts
* wip
* wip
* wip
* wip
* wip
* Update image-viewer.vue
* wip
* wip
* Update style.scss
* Update style.scss
* Update visitor.vue
* wip
* Update init.ts
* Update init.ts
* wip
* wip
* Update visitor.vue
* Update visitor.vue
* Update visitor.vue
* Update visitor.vue
* wip
* wip
* Update modal.vue
* Update header.vue
* Update menu.vue
* Update about.vue
* Update about-misskey.vue
* wip
* wip
* Update visitor.vue
* Update tooltip.ts
* wip
* Update drive.vue
* wip
* Update style.scss
* Update header.vue
* wip
* wip
* Update users.user.vue
* Update announcements.vue
* wip
* wip
* wip
* Update emojis.vue
* wip
* Update emojis.vue
* Update style.scss
* Update users.vue
* wip
* Update style.scss
* wip
* Update welcome.entrance.vue
* Update radio.vue
* Update size.ts
* Update emoji-edit-dialog.vue
* wip
* Update emojis.vue
* wip
* Update emojis.vue
* Update emojis.vue
* Update emojis.vue
* wip
* wip
* wip
* wip
* Update file-dialog.vue
* wip
* wip
* Update token-generate-window.vue
* Update notification-setting-window.vue
* wip
* wip
* Update _error_.vue
* Update ja-JP.yml
* wip
* wip
* Update store.ts
* Update emojis.vue
* Update emojis.vue
* Update emojis.vue
* Update announcements.vue
* Update store.ts
* wip
* Update page-editor.vue
* wip
* wip
* Update modal.vue
* wip
* Update select-file.ts
* Update timeline.vue
* Update emojis.vue
* Update os.ts
* wip
* Update user-select.vue
* Update mfm.ts
* Update get-file-info.ts
* Update drive.vue
* Update init.ts
* Update mfm.ts
* wip
* wip
* Update window.vue
* Update note.vue
* wip
* wip
* Update user-info.vue
* wip
* wip
* wip
* wip
* wip
* Update header.vue
* Update header.vue
* wip
* Update explore.vue
* wip
* wip
* wip
* Update webpack.config.ts
* wip
* wip
* wip
* wip
* wip
* wip
* Update autocomplete.ts
* wip
* wip
* wip
* Update toast.vue
* wip
* Update post-form-dialog.vue
* wip
* wip
* wip
* wip
* wip
* Update users.vue
* wip
* Update explore.vue
* wip
* wip
* wip
* Update package.json
* wip
* Update icon-dialog.vue
* wip
* wip
* Update user-preview.ts
* wip
* wip
* wip
* wip
* wip
* Update instance.vue
* Update user-name.vue
* Update federation.vue
* Update instance.vue
* wip
* wip
* Update tag.vue
* wip
* wip
* wip
* wip
* wip
* Update instance.vue
* wip
* Update os.ts
* Update os.ts
* wip
* wip
* wip
* Update router.ts
* wip
* Update init.ts
* Update note.vue
* Update messages.vue
* wip
* wip
* wip
* wip
* wip
* google
* wip
* wip
* wip
* wip
* Update theme-editor.vue
* wip
* wip
* Update room.vue
* Update channel-editor.vue
* wip
* Update window.vue
* Update window.vue
* wip
* Update window.vue
* Update window.vue
* wip
* Update menu.vue
* wip
* wip
* wip
* wip
* Update messaging-room.vue
* wip
* Update post-form.vue
* Update default.widgets.vue
* Update window.vue
* wip
Diffstat (limited to 'src/client/components/post-form.vue')
| -rw-r--r-- | src/client/components/post-form.vue | 384 |
1 files changed, 177 insertions, 207 deletions
diff --git a/src/client/components/post-form.vue b/src/client/components/post-form.vue index a0d2cd153c..ba7770345a 100644 --- a/src/client/components/post-form.vue +++ b/src/client/components/post-form.vue @@ -1,84 +1,84 @@ <template> -<div class="gafaadew" +<div class="gafaadew" :class="{ modal, _popup: modal }" + v-size="{ max: [500] }" @dragover.stop="onDragover" @dragenter="onDragenter" @dragleave="onDragleave" @drop.stop="onDrop" > <header> - <button v-if="!fixed" class="cancel _button" @click="cancel"><fa :icon="faTimes"/></button> + <button v-if="!fixed" class="cancel _button" @click="cancel"><Fa :icon="faTimes"/></button> <div> - <span class="local-only" v-if="localOnly" v-text="$t('_visibility.localOnly')" /> <span class="text-count" :class="{ over: trimmedLength(text) > max }">{{ max - trimmedLength(text) }}</span> + <span class="local-only" v-if="localOnly"><Fa :icon="faBiohazard"/></span> <button class="_button visibility" @click="setVisibility" ref="visibilityButton" v-tooltip="$t('visibility')" :disabled="channel != null"> - <span v-if="visibility === 'public'"><fa :icon="faGlobe"/></span> - <span v-if="visibility === 'home'"><fa :icon="faHome"/></span> - <span v-if="visibility === 'followers'"><fa :icon="faUnlock"/></span> - <span v-if="visibility === 'specified'"><fa :icon="faEnvelope"/></span> + <span v-if="visibility === 'public'"><Fa :icon="faGlobe"/></span> + <span v-if="visibility === 'home'"><Fa :icon="faHome"/></span> + <span v-if="visibility === 'followers'"><Fa :icon="faUnlock"/></span> + <span v-if="visibility === 'specified'"><Fa :icon="faEnvelope"/></span> </button> - <button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<fa :icon="reply ? faReply : renote ? faQuoteRight : faPaperPlane"/></button> + <button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<Fa :icon="reply ? faReply : renote ? faQuoteRight : faPaperPlane"/></button> </div> </header> <div class="form" :class="{ fixed }"> - <x-note-preview class="preview" v-if="reply" :note="reply"/> - <x-note-preview class="preview" v-if="renote" :note="renote"/> - <div class="with-quote" v-if="quoteId"><fa icon="quote-left"/> {{ $t('quoteAttached') }}<button @click="quoteId = null"><fa icon="times"/></button></div> + <XNotePreview class="preview" v-if="reply" :note="reply"/> + <XNotePreview class="preview" v-if="renote" :note="renote"/> + <div class="with-quote" v-if="quoteId"><Fa icon="quote-left"/> {{ $t('quoteAttached') }}<button @click="quoteId = null"><Fa icon="times"/></button></div> <div v-if="visibility === 'specified'" class="to-specified"> <span style="margin-right: 8px;">{{ $t('recipient') }}</span> <div class="visibleUsers"> <span v-for="u in visibleUsers" :key="u.id"> - <mk-acct :user="u"/> - <button class="_button" @click="removeVisibleUser(u)"><fa :icon="faTimes"/></button> + <MkAcct :user="u"/> + <button class="_button" @click="removeVisibleUser(u)"><Fa :icon="faTimes"/></button> </span> - <button @click="addVisibleUser" class="_buttonPrimary"><fa :icon="faPlus" fixed-width/></button> + <button @click="addVisibleUser" class="_buttonPrimary"><Fa :icon="faPlus" fixed-width/></button> </div> </div> - <input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$t('annotation')" v-autocomplete="{ model: 'cw' }" @keydown="onKeydown"> - <textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" v-autocomplete="{ model: 'text' }" @keydown="onKeydown" @paste="onPaste"></textarea> - <x-post-form-attaches class="attaches" :files="files"/> - <x-poll-editor v-if="poll" ref="poll" @destroyed="poll = false" @updated="onPollUpdate()"/> - <x-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/> + <input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$t('annotation')" @keydown="onKeydown"> + <textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste"></textarea> + <XPostFormAttaches class="attaches" :files="files" @updated="updateMedia" @detach="detachMedia"/> + <XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/> <footer> - <button class="_button" @click="chooseFileFrom" v-tooltip="$t('attachFile')"><fa :icon="faPhotoVideo"/></button> - <button class="_button" @click="poll = !poll" :class="{ active: poll }" v-tooltip="$t('poll')"><fa :icon="faPollH"/></button> - <button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$t('useCw')"><fa :icon="faEyeSlash"/></button> - <button class="_button" @click="insertMention" v-tooltip="$t('mention')"><fa :icon="faAt"/></button> - <button class="_button" @click="insertEmoji" v-tooltip="$t('emoji')"><fa :icon="faLaughSquint"/></button> - <button class="_button" @click="showActions" v-tooltip="$t('plugin')" v-if="$store.state.postFormActions.length > 0"><fa :icon="faPlug"/></button> + <button class="_button" @click="chooseFileFrom" v-tooltip="$t('attachFile')"><Fa :icon="faPhotoVideo"/></button> + <button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$t('poll')"><Fa :icon="faPollH"/></button> + <button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$t('useCw')"><Fa :icon="faEyeSlash"/></button> + <button class="_button" @click="insertMention" v-tooltip="$t('mention')"><Fa :icon="faAt"/></button> + <button class="_button" @click="insertEmoji" v-tooltip="$t('emoji')"><Fa :icon="faLaughSquint"/></button> + <button class="_button" @click="showActions" v-tooltip="$t('plugin')" v-if="postFormActions.length > 0"><Fa :icon="faPlug"/></button> </footer> - <input ref="file" class="file _button" type="file" multiple="multiple" @change="onChangeFile"/> </div> </div> </template> <script lang="ts"> -import Vue from 'vue'; -import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons'; +import { defineComponent, defineAsyncComponent } from 'vue'; +import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faAt, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons'; import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons'; import insertTextAtCursor from 'insert-text-at-cursor'; import { length } from 'stringz'; import { toASCII } from 'punycode'; -import MkVisibilityChooser from './visibility-chooser.vue'; -import MkUserSelect from './user-select.vue'; import XNotePreview from './note-preview.vue'; import { parse } from '../../mfm/parse'; -import { host, url } from '../config'; +import { host, url } from '@/config'; import { erase, unique } from '../../prelude/array'; import extractMentions from '../../misc/extract-mentions'; import getAcct from '../../misc/acct/render'; import { formatTimeString } from '../../misc/format-time-string'; -import { selectDriveFile } from '../scripts/select-drive-file'; +import { Autocomplete } from '@/scripts/autocomplete'; import { noteVisibilities } from '../../types'; -import { utils } from '@syuilo/aiscript'; +import * as os from '@/os'; +import { selectFile } from '@/scripts/select-file'; +import { notePostInterruptors, postFormActions } from '@/store'; -export default Vue.extend({ +export default defineComponent({ components: { XNotePreview, - XUploader: () => import('./uploader.vue').then(m => m.default), - XPostFormAttaches: () => import('./post-form-attaches.vue').then(m => m.default), - XPollEditor: () => import('./poll-editor.vue').then(m => m.default) + XPostFormAttaches: defineAsyncComponent(() => import('./post-form-attaches.vue')), + XPollEditor: defineAsyncComponent(() => import('./poll-editor.vue')) }, + inject: ['modal'], + props: { reply: { type: Object, @@ -117,19 +117,22 @@ export default Vue.extend({ type: Boolean, required: false, default: false - } + }, + autofocus: { + type: Boolean, + required: false, + default: true + }, }, + emits: ['posted', 'done', 'esc'], + data() { return { posting: false, text: '', files: [], - uploadings: [], - poll: false, - pollChoices: [], - pollMultiple: false, - pollExpiration: [], + poll: null, useCw: false, cw: null, localOnly: false, @@ -139,7 +142,8 @@ export default Vue.extend({ draghover: false, quoteId: null, recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]'), - faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faCloud, faLink, faAt, faBiohazard, faPlug + postFormActions, + faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faAt, faBiohazard, faPlug }; }, @@ -190,7 +194,7 @@ export default Vue.extend({ return !this.posting && (1 <= this.text.length || 1 <= this.files.length || this.poll || this.renote) && (length(this.text.trim()) <= this.max) && - (!this.poll || this.pollChoices.length >= 2); + (!this.poll || this.poll.choices.length >= 2); }, max(): number { @@ -246,14 +250,14 @@ export default Vue.extend({ if (this.reply && ['home', 'followers', 'specified'].includes(this.reply.visibility)) { this.visibility = this.reply.visibility; if (this.reply.visibility === 'specified') { - this.$root.api('users/show', { + os.api('users/show', { userIds: this.reply.visibleUserIds.filter(uid => uid !== this.$store.state.i.id && uid !== this.reply.userId) }).then(users => { this.visibleUsers.push(...users); }); if (this.reply.userId !== this.$store.state.i.id) { - this.$root.api('users/show', { userId: this.reply.userId }).then(user => { + os.api('users/show', { userId: this.reply.userId }).then(user => { this.visibleUsers.push(user); }); } @@ -271,15 +275,21 @@ export default Vue.extend({ this.cw = this.reply.cw; } - this.focus(); - - this.$nextTick(() => { + if (this.autofocus) { this.focus(); - }); + + this.$nextTick(() => { + this.focus(); + }); + } + + // TODO: detach when unmount + new Autocomplete(this.$refs.text, this, { model: 'text' }); + new Autocomplete(this.$refs.cw, this, { model: 'cw' }); this.$nextTick(() => { // 書きかけの投稿を復元 - if (!this.instant && !this.mention) { + if (!this.instant && !this.mention && !this.specified) { const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[this.draftKey]; if (draft) { this.text = draft.data.text; @@ -289,10 +299,7 @@ export default Vue.extend({ this.localOnly = draft.data.localOnly; this.files = (draft.data.files || []).filter(e => e); if (draft.data.poll) { - this.poll = true; - this.$nextTick(() => { - (this.$refs.poll as any).set(draft.data.poll); - }); + this.poll = draft.data.poll; } } } @@ -305,13 +312,7 @@ export default Vue.extend({ this.cw = init.cw; this.useCw = init.cw != null; if (init.poll) { - this.poll = true; - this.$nextTick(() => { - (this.$refs.poll as any).set({ - choices: init.poll.choices.map(c => c.text), - multiple: init.poll.multiple - }); - }); + this.poll = init.poll; } this.visibility = init.visibility; this.localOnly = init.localOnly; @@ -328,11 +329,24 @@ export default Vue.extend({ this.$watch('useCw', () => this.saveDraft()); this.$watch('cw', () => this.saveDraft()); this.$watch('poll', () => this.saveDraft()); - this.$watch('files', () => this.saveDraft()); + this.$watch('files', () => this.saveDraft(), { deep: true }); this.$watch('visibility', () => this.saveDraft()); this.$watch('localOnly', () => this.saveDraft()); }, + togglePoll() { + if (this.poll) { + this.poll = null; + } else { + this.poll = { + choices: ['', ''], + multiple: false, + expiresAt: null, + expiredAfter: null, + }; + } + }, + trimmedLength(text: string) { return length(text.trim()); }, @@ -346,85 +360,50 @@ export default Vue.extend({ }, chooseFileFrom(ev) { - this.$root.menu({ - items: [{ - type: 'label', - text: this.$t('attachFile'), - }, { - text: this.$t('upload'), - icon: faUpload, - action: () => { this.chooseFileFromPc() } - }, { - text: this.$t('fromDrive'), - icon: faCloud, - action: () => { this.chooseFileFromDrive() } - }, { - text: this.$t('fromUrl'), - icon: faLink, - action: () => { this.chooseFileFromUrl() } - }], - source: ev.currentTarget || ev.target - }); - }, - - chooseFileFromPc() { - (this.$refs.file as any).click(); - }, - - chooseFileFromDrive() { - selectDriveFile(this.$root, true).then(files => { + selectFile(ev.currentTarget || ev.target, this.$t('attachFile'), true).then(files => { for (const file of files) { - this.attachMedia(file); + this.files.push(file); } }); }, - attachMedia(driveFile) { - this.files.push(driveFile); - }, - detachMedia(id) { this.files = this.files.filter(x => x.id != id); }, updateMedia(file) { - Vue.set(this.files, this.files.findIndex(x => x.id === file.id), file); - }, - - onChangeFile() { - for (const x of Array.from((this.$refs.file as any).files)) this.upload(x); + this.files[this.files.findIndex(x => x.id === file.id)] = file; }, upload(file: File, name?: string) { - (this.$refs.uploader as any).upload(file, this.$store.state.settings.uploadFolder, name); - }, - - onChangeUploadings(uploads) { - this.$emit('change-uploadings', uploads); + os.upload(file, this.$store.state.settings.uploadFolder, name).then(res => { + this.files.push(res); + }); }, - onPollUpdate() { - const got = this.$refs.poll.get(); - this.pollChoices = got.choices; - this.pollMultiple = got.multiple; - this.pollExpiration = [got.expiration, got.expiresAt || got.expiredAfter]; + onPollUpdate(poll) { + this.poll = poll; this.saveDraft(); }, - setVisibility() { + async setVisibility() { if (this.channel) { // TODO: information dialog return; } - const w = this.$root.new(MkVisibilityChooser, { - source: this.$refs.visibilityButton, + + os.popup(await import('./visibility-picker.vue'), { currentVisibility: this.visibility, - currentLocalOnly: this.localOnly - }); - w.$once('chosen', ({ visibility, localOnly }) => { - this.applyVisibility(visibility); - this.localOnly = localOnly; - }); + currentLocalOnly: this.localOnly, + src: this.$refs.visibilityButton + }, { + changeVisibility: visibility => { + this.applyVisibility(visibility); + }, + changeLocalOnly: localOnly => { + this.localOnly = localOnly; + } + }, 'closed'); }, applyVisibility(v: string) { @@ -432,8 +411,7 @@ export default Vue.extend({ }, addVisibleUser() { - const vm = this.$root.new(MkUserSelect, {}); - vm.$once('selected', user => { + os.selectUser().then(user => { this.visibleUsers.push(user); }); }, @@ -445,12 +423,13 @@ export default Vue.extend({ clear() { this.text = ''; this.files = []; - this.poll = false; + this.poll = null; this.quoteId = null; }, onKeydown(e) { - if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey) && this.canPost) this.post(); + if ((e.which === 10 || e.which === 13) && (e.ctrlKey || e.metaKey) && this.canPost) this.post(); + if (e.which === 27) this.$emit('esc'); }, async onPaste(e: ClipboardEvent) { @@ -469,7 +448,7 @@ export default Vue.extend({ if (!this.renote && !this.quoteId && paste.startsWith(url + '/notes/')) { e.preventDefault(); - this.$root.dialog({ + os.dialog({ type: 'info', text: this.$t('quoteQuestion'), showCancelButton: true @@ -487,7 +466,7 @@ export default Vue.extend({ onDragover(e) { if (!e.dataTransfer.items[0]) return; const isFile = e.dataTransfer.items[0].kind == 'file'; - const isDriveFile = e.dataTransfer.types[0] == 'mk_drive_file'; + const isDriveFile = e.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FILE_; if (isFile || isDriveFile) { e.preventDefault(); this.draghover = true; @@ -514,7 +493,7 @@ export default Vue.extend({ } //#region ドライブのファイル - const driveFile = e.dataTransfer.getData('mk_drive_file'); + const driveFile = e.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_); if (driveFile != null && driveFile != '') { const file = JSON.parse(driveFile); this.files.push(file); @@ -537,7 +516,7 @@ export default Vue.extend({ visibility: this.visibility, localOnly: this.localOnly, files: this.files, - poll: this.poll && this.$refs.poll ? (this.$refs.poll as any).get() : undefined + poll: this.poll } }; @@ -559,29 +538,30 @@ export default Vue.extend({ replyId: this.reply ? this.reply.id : undefined, renoteId: this.renote ? this.renote.id : this.quoteId ? this.quoteId : undefined, channelId: this.channel ? this.channel.id : undefined, - poll: this.poll ? (this.$refs.poll as any).get() : undefined, + poll: this.poll, cw: this.useCw ? this.cw || '' : undefined, localOnly: this.localOnly, visibility: this.visibility, visibleUserIds: this.visibility == 'specified' ? this.visibleUsers.map(u => u.id) : undefined, - viaMobile: this.$root.isMobile + viaMobile: os.isMobile }; // plugin - if (this.$store.state.notePostInterruptors.length > 0) { - for (const interruptor of this.$store.state.notePostInterruptors) { - data = utils.valToJs(await interruptor.handler(JSON.parse(JSON.stringify(data)))); + if (notePostInterruptors.length > 0) { + for (const interruptor of notePostInterruptors) { + data = await interruptor.handler(JSON.parse(JSON.stringify(data))); } } this.posting = true; - this.$root.api('notes/create', data).then(() => { + os.api('notes/create', data).then(() => { this.clear(); this.deleteDraft(); this.$emit('posted'); }).catch(err => { }).then(() => { this.posting = false; + this.$emit('done'); }); if (this.text && this.text != '') { @@ -592,39 +572,32 @@ export default Vue.extend({ }, cancel() { - this.$emit('cancel'); + this.$emit('done'); }, insertMention() { - const vm = this.$root.new(MkUserSelect, {}); - vm.$once('selected', user => { - insertTextAtCursor(this.$refs.text, getAcct(user) + ' '); + os.selectUser().then(user => { + insertTextAtCursor(this.$refs.text, '@' + getAcct(user) + ' '); }); }, async insertEmoji(ev) { - const vm = this.$root.new(await import('./emoji-picker.vue').then(m => m.default), { - source: ev.currentTarget || ev.target - }).$once('chosen', emoji => { + os.pickEmoji(ev.currentTarget || ev.target).then(emoji => { insertTextAtCursor(this.$refs.text, emoji); - vm.close(); }); }, showActions(ev) { - this.$root.menu({ - items: this.$store.state.postFormActions.map(action => ({ - text: action.title, - action: () => { - action.handler({ - text: this.text - }, (key, value) => { - if (key === 'text') { this.text = value; } - }); - } - })), - source: ev.currentTarget || ev.target, - }); + os.modalMenu(postFormActions.map(action => ({ + text: action.title, + action: () => { + action.handler({ + text: this.text + }, (key, value) => { + if (key === 'text') { this.text = value; } + }); + } + })), ev.currentTarget || ev.target); } } }); @@ -632,26 +605,22 @@ export default Vue.extend({ <style lang="scss" scoped> .gafaadew { - background: var(--panel); + position: relative; + + &.modal { + width: 100%; + max-width: 520px; + } > header { z-index: 1000; height: 66px; - @media (max-width: 500px) { - height: 50px; - } - > .cancel { padding: 0; font-size: 20px; width: 64px; line-height: 66px; - - @media (max-width: 500px) { - width: 50px; - line-height: 50px; - } } > div { @@ -662,10 +631,6 @@ export default Vue.extend({ > .text-count { opacity: 0.7; line-height: 66px; - - @media (max-width: 500px) { - line-height: 50px; - } } > .visibility { @@ -678,8 +643,9 @@ export default Vue.extend({ } } - .local-only { - margin: 0 8px; + > .local-only { + margin: 0 0 0 12px; + opacity: 0.7; } > .submit { @@ -690,10 +656,6 @@ export default Vue.extend({ vertical-align: bottom; border-radius: 4px; - @media (max-width: 500px) { - margin: 8px; - } - &:disabled { opacity: 0.7; } @@ -706,13 +668,6 @@ export default Vue.extend({ } > .form { - max-width: 500px; - margin: 0 auto; - - &.fixed { - max-width: unset; - } - > .preview { padding: 16px; } @@ -741,10 +696,6 @@ export default Vue.extend({ overflow: auto; white-space: nowrap; - @media (max-width: 500px) { - padding: 6px 16px; - } - > .visibleUsers { display: inline; top: -1px; @@ -782,10 +733,6 @@ export default Vue.extend({ color: var(--fg); font-family: inherit; - @media (max-width: 500px) { - padding: 0 16px; - } - &:focus { outline: none; } @@ -806,31 +753,14 @@ export default Vue.extend({ min-width: 100%; min-height: 90px; - @media (max-width: 500px) { - min-height: 80px; - } - &.withCw { padding-top: 8px; } } - > .mk-uploader { - margin: 8px 0 0 0; - padding: 8px; - } - - > .file { - display: none; - } - > footer { padding: 0 16px 16px 16px; - @media (max-width: 500px) { - padding: 0 8px 8px 8px; - } - > button { display: inline-block; padding: 0; @@ -850,5 +780,45 @@ export default Vue.extend({ } } } + + &.max-width_500px { + > header { + height: 50px; + + > .cancel { + width: 50px; + line-height: 50px; + } + + > div { + > .text-count { + line-height: 50px; + } + + > .submit { + margin: 8px; + } + } + } + + > .form { + > .to-specified { + padding: 6px 16px; + } + + > .cw, + > .text { + padding: 0 16px; + } + + > .text { + min-height: 80px; + } + + > footer { + padding: 0 8px 8px 8px; + } + } + } } </style> |