diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2019-04-18 19:40:23 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2019-04-18 19:40:23 +0900 |
| commit | 7827aeb6951bfd0dae1799601dff3f207a3d2363 (patch) | |
| tree | fa81558061c2743bc5d6566d916f7df4a3dad34e /src | |
| parent | Fix API definition (diff) | |
| download | sharkey-7827aeb6951bfd0dae1799601dff3f207a3d2363.tar.gz sharkey-7827aeb6951bfd0dae1799601dff3f207a3d2363.tar.bz2 sharkey-7827aeb6951bfd0dae1799601dff3f207a3d2363.zip | |
Resolve #4735
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/app/common/scripts/search.ts | 64 | ||||
| -rw-r--r-- | src/client/app/common/views/components/dialog.vue | 50 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/ui.header.search.vue | 27 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/timeline.core.vue | 15 | ||||
| -rw-r--r-- | src/client/app/init.ts | 6 | ||||
| -rw-r--r-- | src/client/app/mobile/views/components/ui.nav.vue | 26 | ||||
| -rw-r--r-- | src/client/app/mobile/views/pages/home.timeline.vue | 10 |
7 files changed, 127 insertions, 71 deletions
diff --git a/src/client/app/common/scripts/search.ts b/src/client/app/common/scripts/search.ts new file mode 100644 index 0000000000..c44581817b --- /dev/null +++ b/src/client/app/common/scripts/search.ts @@ -0,0 +1,64 @@ +import { faHistory } from '@fortawesome/free-solid-svg-icons'; + +export async function search(v: any, q: string) { + q = q.trim(); + + if (q.startsWith('@')) { + v.$router.push(`/${q}`); + return; + } + + if (q.startsWith('#')) { + v.$router.push(`/tags/${encodeURIComponent(q.substr(1))}`); + return; + } + + // like 2018/03/12 + if (/^[0-9]{4}\/[0-9]{2}\/[0-9]{2}/.test(q.replace(/-/g, '/'))) { + const date = new Date(q.replace(/-/g, '/')); + + // 日付しか指定されてない場合、例えば 2018/03/12 ならユーザーは + // 2018/03/12 のコンテンツを「含む」結果になることを期待するはずなので + // 23時間59分進める(そのままだと 2018/03/12 00:00:00 「まで」の + // 結果になってしまい、2018/03/12 のコンテンツは含まれない) + if (q.replace(/-/g, '/').match(/^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$/)) { + date.setHours(23, 59, 59, 999); + } + + v.$root.$emit('warp', date); + v.$root.dialog({ + icon: faHistory, + splash: true, + }); + return; + } + + if (q.startsWith('https://')) { + const dialog = v.$root.dialog({ + type: 'waiting', + text: v.$t('@.fetching-as-ap-object'), + showOkButton: false, + showCancelButton: false, + cancelableByBgClick: false + }); + + try { + const res = await v.$root.api('ap/show', { + uri: q + }); + dialog.close(); + if (res.type == 'User') { + v.$router.push(`/@${res.object.username}@${res.object.host}`); + } else if (res.type == 'Note') { + v.$router.push(`/notes/${res.object.id}`); + } + } catch (e) { + dialog.close(); + // TODO: Show error + } + + return; + } + + v.$router.push(`/search?q=${encodeURIComponent(q)}`); +} diff --git a/src/client/app/common/views/components/dialog.vue b/src/client/app/common/views/components/dialog.vue index 771b1237ee..c1ee7958c0 100644 --- a/src/client/app/common/views/components/dialog.vue +++ b/src/client/app/common/views/components/dialog.vue @@ -6,7 +6,17 @@ <mk-signin/> </template> <template v-else> - <div class="icon" v-if="!input && !select && !user" :class="type"><fa :icon="icon"/></div> + <div class="icon" v-if="icon"> + <fa :icon="icon"/> + </div> + <div class="icon" v-else-if="!input && !select && !user" :class="type"> + <fa icon="check" v-if="type === 'success'"/> + <fa :icon="faTimesCircle" v-if="type === 'error'"/> + <fa icon="exclamation-triangle" v-if="type === 'warning'"/> + <fa icon="info-circle" v-if="type === 'info'"/> + <fa :icon="faQuestionCircle" v-if="type === 'question'"/> + <fa icon="spinner" pulse v-if="type === 'waiting'"/> + </div> <header v-if="title" v-html="title"></header> <div class="body" v-if="text" v-html="text"></div> <ui-input v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></ui-input> @@ -14,8 +24,8 @@ <ui-select v-if="select" v-model="selectedValue" autofocus> <option v-for="item in select.items" :value="item.value">{{ item.text }}</option> </ui-select> - <ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash"> - <ui-button @click="ok" primary :autofocus="!input && !select && !user">{{ (showCancelButton || input || select || user) ? $t('@.ok') : $t('@.got-it') }}</ui-button> + <ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash && (showOkButton || showCancelButton)"> + <ui-button @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user">{{ (showCancelButton || input || select || user) ? $t('@.ok') : $t('@.got-it') }}</ui-button> <ui-button @click="cancel" v-if="showCancelButton || input || select || user">{{ $t('@.cancel') }}</ui-button> </ui-horizon-group> </template> @@ -55,10 +65,21 @@ export default Vue.extend({ user: { required: false }, + icon: { + required: false + }, + showOkButton: { + type: Boolean, + default: true + }, showCancelButton: { type: Boolean, default: false }, + cancelableByBgClick: { + type: Boolean, + default: true + }, splash: { type: Boolean, default: false @@ -69,22 +90,11 @@ export default Vue.extend({ return { inputValue: this.input && this.input.default ? this.input.default : null, userInputValue: null, - selectedValue: null + selectedValue: null, + faTimesCircle, faQuestionCircle }; }, - computed: { - icon(): any { - switch (this.type) { - case 'success': return 'check'; - case 'error': return faTimesCircle; - case 'warning': return 'exclamation-triangle'; - case 'info': return 'info-circle'; - case 'question': return faQuestionCircle; - } - } - }, - mounted() { this.$nextTick(() => { (this.$refs.bg as any).style.pointerEvents = 'auto'; @@ -113,6 +123,8 @@ export default Vue.extend({ methods: { async ok() { + if (!this.showOkButton) return; + if (this.user) { const user = await this.$root.api('users/show', parseAcct(this.userInputValue)); if (user) { @@ -156,7 +168,9 @@ export default Vue.extend({ }, onBgClick() { - this.cancel(); + if (this.cancelableByBgClick) { + this.cancel(); + } }, onInputKeydown(e) { @@ -240,7 +254,7 @@ export default Vue.extend({ margin-top 8px > .body - margin 16px 0 + margin 16px 0 0 0 > .buttons margin-top 16px diff --git a/src/client/app/desktop/views/components/ui.header.search.vue b/src/client/app/desktop/views/components/ui.header.search.vue index 4ade74bc64..0cf5ca6f32 100644 --- a/src/client/app/desktop/views/components/ui.header.search.vue +++ b/src/client/app/desktop/views/components/ui.header.search.vue @@ -9,6 +9,7 @@ <script lang="ts"> import Vue from 'vue'; import i18n from '../../../i18n'; +import { search } from '../../../common/scripts/search'; export default Vue.extend({ i18n: i18n('desktop/views/components/ui.header.search.vue'), @@ -22,29 +23,11 @@ export default Vue.extend({ async onSubmit() { if (this.wait) return; - const q = this.q.trim(); - if (q.startsWith('@')) { - this.$router.push(`/${q}`); - } else if (q.startsWith('#')) { - this.$router.push(`/tags/${encodeURIComponent(q.substr(1))}`); - } else if (q.startsWith('https://')) { - this.wait = true; - try { - const res = await this.$root.api('ap/show', { - uri: q - }); - if (res.type == 'User') { - this.$router.push(`/@${res.object.username}@${res.object.host}`); - } else if (res.type == 'Note') { - this.$router.push(`/notes/${res.object.id}`); - } - } catch (e) { - // TODO - } + this.wait = true; + search(this, this.q).finally(() => { this.wait = false; - } else { - this.$router.push(`/search?q=${encodeURIComponent(q)}`); - } + this.q = ''; + }); } } }); diff --git a/src/client/app/desktop/views/home/timeline.core.vue b/src/client/app/desktop/views/home/timeline.core.vue index 12806365d4..654a1cc434 100644 --- a/src/client/app/desktop/views/home/timeline.core.vue +++ b/src/client/app/desktop/views/home/timeline.core.vue @@ -53,6 +53,12 @@ export default Vue.extend({ }, created() { + this.$root.$on('warp', this.warp); + this.$once('hook:beforeDestroy', () => { + this.$root.$off('warp', this.warp); + this.connection.dispose(); + }); + const prepend = note => { (this.$refs.timeline as any).prepend(note); }; @@ -124,13 +130,14 @@ export default Vue.extend({ }); }, - beforeDestroy() { - this.connection.dispose(); - }, - methods: { focus() { (this.$refs.timeline as any).focus(); + }, + + warp(date) { + this.date = date; + (this.$refs.timeline as any).reload(); } } }); diff --git a/src/client/app/init.ts b/src/client/app/init.ts index 4b9f341612..230d8c3f1e 100644 --- a/src/client/app/init.ts +++ b/src/client/app/init.ts @@ -458,10 +458,14 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS], os: MiOS) }, dialog(opts) { const vm = this.new(Dialog, opts); - return new Promise((res) => { + const p: any = new Promise((res) => { vm.$once('ok', result => res({ canceled: false, result })); vm.$once('cancel', () => res({ canceled: true })); }); + p.close = () => { + vm.close(); + }; + return p; } }, router, diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue index 169c7fc07d..b26e2380ab 100644 --- a/src/client/app/mobile/views/components/ui.nav.vue +++ b/src/client/app/mobile/views/components/ui.nav.vue @@ -66,6 +66,7 @@ import i18n from '../../../i18n'; import { lang } from '../../../config'; import { faNewspaper, faHashtag, faHome, faColumns } from '@fortawesome/free-solid-svg-icons'; import { faMoon, faSun } from '@fortawesome/free-regular-svg-icons'; +import { search } from '../../../common/scripts/search'; export default Vue.extend({ i18n: i18n('mobile/views/components/ui.nav.vue'), @@ -133,29 +134,10 @@ export default Vue.extend({ }).then(async ({ canceled, result: query }) => { if (canceled) return; - const q = query.trim(); - if (q.startsWith('@')) { - this.$router.push(`/${q}`); - } else if (q.startsWith('#')) { - this.$router.push(`/tags/${encodeURIComponent(q.substr(1))}`); - } else if (q.startsWith('https://')) { - this.searching = true; - try { - const res = await this.$root.api('ap/show', { - uri: q - }); - if (res.type == 'User') { - this.$router.push(`/@${res.object.username}@${res.object.host}`); - } else if (res.type == 'Note') { - this.$router.push(`/notes/${res.object.id}`); - } - } catch (e) { - // TODO - } + this.searching = true; + search(this, query).finally(() => { this.searching = false; - } else { - this.$router.push(`/search?q=${encodeURIComponent(q)}`); - } + }); }); }, diff --git a/src/client/app/mobile/views/pages/home.timeline.vue b/src/client/app/mobile/views/pages/home.timeline.vue index 809158dd29..e0754e88b4 100644 --- a/src/client/app/mobile/views/pages/home.timeline.vue +++ b/src/client/app/mobile/views/pages/home.timeline.vue @@ -54,6 +54,12 @@ export default Vue.extend({ }, created() { + this.$root.$on('warp', this.warp); + this.$once('hook:beforeDestroy', () => { + this.$root.$off('warp', this.warp); + this.connection.dispose(); + }); + const prepend = note => { (this.$refs.timeline as any).prepend(note); }; @@ -125,10 +131,6 @@ export default Vue.extend({ }); }, - beforeDestroy() { - this.connection.dispose(); - }, - methods: { focus() { (this.$refs.timeline as any).focus(); |