This commit is contained in:
syuilo 2018-03-05 08:44:37 +09:00
parent cb0d237b6a
commit b0c7cb8803
6 changed files with 117 additions and 6 deletions

View file

@ -39,6 +39,18 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
const [tags = [], tagsErr] = $(params.tags).optional.array('string').unique().eachQ(t => t.range(1, 32)).$; const [tags = [], tagsErr] = $(params.tags).optional.array('string').unique().eachQ(t => t.range(1, 32)).$;
if (tagsErr) return rej('invalid tags'); if (tagsErr) return rej('invalid tags');
// Get 'geo' parameter
const [geo, geoErr] = $(params.geo).optional.nullable.strict.object()
.have('latitude', $().number().range(-180, 180))
.have('longitude', $().number().range(-90, 90))
.have('altitude', $().nullable.number())
.have('accuracy', $().nullable.number())
.have('altitudeAccuracy', $().nullable.number())
.have('heading', $().nullable.number().range(0, 360))
.have('speed', $().nullable.number())
.$;
if (geoErr) return rej('invalid geo');
// Get 'media_ids' parameter // Get 'media_ids' parameter
const [mediaIds, mediaIdsErr] = $(params.media_ids).optional.array('id').unique().range(1, 4).$; const [mediaIds, mediaIdsErr] = $(params.media_ids).optional.array('id').unique().range(1, 4).$;
if (mediaIdsErr) return rej('invalid media_ids'); if (mediaIdsErr) return rej('invalid media_ids');
@ -244,6 +256,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
user_id: user._id, user_id: user._id,
app_id: app ? app._id : null, app_id: app ? app._id : null,
via_mobile: viaMobile, via_mobile: viaMobile,
geo,
// 以下非正規化データ // 以下非正規化データ
_reply: reply ? { user_id: reply.user_id } : undefined, _reply: reply ? { user_id: reply.user_id } : undefined,

View file

@ -32,6 +32,15 @@ export type IPost = {
category: string; category: string;
is_category_verified: boolean; is_category_verified: boolean;
via_mobile: boolean; via_mobile: boolean;
geo: {
latitude: number;
longitude: number;
altitude: number;
accuracy: number;
altitudeAccuracy: number;
heading: number;
speed: number;
};
}; };
/** /**

View file

@ -1,6 +1,7 @@
<template> <template>
<mk-window ref="window" is-modal @closed="$destroy"> <mk-window ref="window" is-modal @closed="$destroy">
<span slot="header"> <span slot="header">
<span :class="$style.icon" v-if="geo">%fa:map-marker-alt%</span>
<span v-if="!reply">%i18n:desktop.tags.mk-post-form-window.post%</span> <span v-if="!reply">%i18n:desktop.tags.mk-post-form-window.post%</span>
<span v-if="reply">%i18n:desktop.tags.mk-post-form-window.reply%</span> <span v-if="reply">%i18n:desktop.tags.mk-post-form-window.reply%</span>
<span :class="$style.count" v-if="media.length != 0">{{ '%i18n:desktop.tags.mk-post-form-window.attaches%'.replace('{}', media.length) }}</span> <span :class="$style.count" v-if="media.length != 0">{{ '%i18n:desktop.tags.mk-post-form-window.attaches%'.replace('{}', media.length) }}</span>
@ -12,7 +13,8 @@
:reply="reply" :reply="reply"
@posted="onPosted" @posted="onPosted"
@change-uploadings="onChangeUploadings" @change-uploadings="onChangeUploadings"
@change-attached-media="onChangeMedia"/> @change-attached-media="onChangeMedia"
@geo-attached="onGeoAttached"/>
</mk-window> </mk-window>
</template> </template>
@ -24,7 +26,8 @@ export default Vue.extend({
data() { data() {
return { return {
uploadings: [], uploadings: [],
media: [] media: [],
geo: null
}; };
}, },
mounted() { mounted() {
@ -39,6 +42,9 @@ export default Vue.extend({
onChangeMedia(media) { onChangeMedia(media) {
this.media = media; this.media = media;
}, },
onGeoAttached(geo) {
this.geo = geo;
},
onPosted() { onPosted() {
(this.$refs.window as any).close(); (this.$refs.window as any).close();
} }
@ -47,6 +53,9 @@ export default Vue.extend({
</script> </script>
<style lang="stylus" module> <style lang="stylus" module>
.icon
margin-right 8px
.count .count
margin-left 8px margin-left 8px
opacity 0.8 opacity 0.8

View file

@ -27,6 +27,7 @@
<button class="drive" title="%i18n:desktop.tags.mk-post-form.attach-media-from-drive%" @click="chooseFileFromDrive">%fa:cloud%</button> <button class="drive" title="%i18n:desktop.tags.mk-post-form.attach-media-from-drive%" @click="chooseFileFromDrive">%fa:cloud%</button>
<button class="kao" title="%i18n:desktop.tags.mk-post-form.insert-a-kao%" @click="kao">%fa:R smile%</button> <button class="kao" title="%i18n:desktop.tags.mk-post-form.insert-a-kao%" @click="kao">%fa:R smile%</button>
<button class="poll" title="%i18n:desktop.tags.mk-post-form.create-poll%" @click="poll = true">%fa:chart-pie%</button> <button class="poll" title="%i18n:desktop.tags.mk-post-form.create-poll%" @click="poll = true">%fa:chart-pie%</button>
<button class="geo" title="位置情報を添付する" @click="setGeo">%fa:map-marker-alt%</button>
<p class="text-count" :class="{ over: text.length > 1000 }">{{ '%i18n:desktop.tags.mk-post-form.text-remain%'.replace('{}', 1000 - text.length) }}</p> <p class="text-count" :class="{ over: text.length > 1000 }">{{ '%i18n:desktop.tags.mk-post-form.text-remain%'.replace('{}', 1000 - text.length) }}</p>
<button :class="{ posting }" class="submit" :disabled="!canPost" @click="post"> <button :class="{ posting }" class="submit" :disabled="!canPost" @click="post">
{{ posting ? '%i18n:desktop.tags.mk-post-form.posting%' : submitText }}<mk-ellipsis v-if="posting"/> {{ posting ? '%i18n:desktop.tags.mk-post-form.posting%' : submitText }}<mk-ellipsis v-if="posting"/>
@ -53,6 +54,7 @@ export default Vue.extend({
files: [], files: [],
uploadings: [], uploadings: [],
poll: false, poll: false,
geo: null,
autocomplete: null, autocomplete: null,
draghover: false draghover: false
}; };
@ -193,6 +195,21 @@ export default Vue.extend({
} }
//#endregion //#endregion
}, },
setGeo() {
if (navigator.geolocation == null) {
alert('お使いの端末は位置情報に対応していません');
return;
}
navigator.geolocation.getCurrentPosition(pos => {
this.geo = pos.coords;
this.$emit('geo-attached', this.geo);
}, err => {
alert('エラー: ' + err.message);
}, {
enableHighAccuracy: true
});
},
post() { post() {
this.posting = true; this.posting = true;
@ -201,7 +218,8 @@ export default Vue.extend({
media_ids: this.files.length > 0 ? this.files.map(f => f.id) : undefined, media_ids: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
reply_id: this.reply ? this.reply.id : undefined, reply_id: this.reply ? this.reply.id : undefined,
repost_id: this.repost ? this.repost.id : undefined, repost_id: this.repost ? this.repost.id : undefined,
poll: this.poll ? (this.$refs.poll as any).get() : undefined poll: this.poll ? (this.$refs.poll as any).get() : undefined,
geo: this.geo,
}).then(data => { }).then(data => {
this.clear(); this.clear();
this.deleteDraft(); this.deleteDraft();
@ -459,6 +477,7 @@ export default Vue.extend({
> .drive > .drive
> .kao > .kao
> .poll > .poll
> .geo
display inline-block display inline-block
cursor pointer cursor pointer
padding 0 padding 0

View file

@ -23,6 +23,7 @@
<button class="drive" @click="chooseFileFromDrive">%fa:cloud%</button> <button class="drive" @click="chooseFileFromDrive">%fa:cloud%</button>
<button class="kao" @click="kao">%fa:R smile%</button> <button class="kao" @click="kao">%fa:R smile%</button>
<button class="poll" @click="poll = true">%fa:chart-pie%</button> <button class="poll" @click="poll = true">%fa:chart-pie%</button>
<button class="geo" @click="setGeo">%fa:map-marker-alt%</button>
<input ref="file" class="file" type="file" accept="image/*" multiple="multiple" @change="onChangeFile"/> <input ref="file" class="file" type="file" accept="image/*" multiple="multiple" @change="onChangeFile"/>
</div> </div>
</div> </div>
@ -44,7 +45,8 @@ export default Vue.extend({
text: '', text: '',
uploadings: [], uploadings: [],
files: [], files: [],
poll: false poll: false,
geo: null
}; };
}, },
mounted() { mounted() {
@ -83,6 +85,20 @@ export default Vue.extend({
onChangeUploadings(uploads) { onChangeUploadings(uploads) {
this.$emit('change-uploadings', uploads); this.$emit('change-uploadings', uploads);
}, },
setGeo() {
if (navigator.geolocation == null) {
alert('お使いの端末は位置情報に対応していません');
return;
}
navigator.geolocation.getCurrentPosition(pos => {
this.geo = pos.coords;
}, err => {
alert('エラー: ' + err.message);
}, {
enableHighAccuracy: true
});
},
clear() { clear() {
this.text = ''; this.text = '';
this.files = []; this.files = [];
@ -97,6 +113,7 @@ export default Vue.extend({
media_ids: this.files.length > 0 ? this.files.map(f => f.id) : undefined, media_ids: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
reply_id: this.reply ? this.reply.id : undefined, reply_id: this.reply ? this.reply.id : undefined,
poll: this.poll ? (this.$refs.poll as any).get() : undefined, poll: this.poll ? (this.$refs.poll as any).get() : undefined,
geo: this.geo,
via_mobile: viaMobile via_mobile: viaMobile
}).then(data => { }).then(data => {
this.$emit('post'); this.$emit('post');
@ -223,8 +240,9 @@ export default Vue.extend({
> .upload > .upload
> .drive > .drive
.kao > .kao
.poll > .poll
> .geo
display inline-block display inline-block
padding 0 padding 0
margin 0 margin 0

View file

@ -128,3 +128,46 @@ props:
desc: desc:
ja: "この選択肢に投票された数" ja: "この選択肢に投票された数"
en: "The number voted for this choice" en: "The number voted for this choice"
- name: "geo"
type: "object"
optional: true
desc:
ja: "位置情報"
en: "Geo location"
defName: "geo"
def:
- name: "latitude"
type: "number"
optional: false
desc:
ja: "緯度。-180〜180で表す。"
- name: "longitude"
type: "number"
optional: false
desc:
ja: "経度。-90〜90で表す。"
- name: "altitude"
type: "number"
optional: false
desc:
ja: "高度。メートル単位で表す。"
- name: "accuracy"
type: "number"
optional: false
desc:
ja: "緯度、経度の精度。メートル単位で表す。"
- name: "altitudeAccuracy"
type: "number"
optional: false
desc:
ja: "高度の精度。メートル単位で表す。"
- name: "heading"
type: "number"
optional: false
desc:
ja: "方角。0〜360の角度で表す。0が北、90が東、180が南、270が西。"
- name: "speed"
type: "number"
optional: false
desc:
ja: "速度。メートル / 秒数で表す。"