リファクタリングなど

This commit is contained in:
syuilo
2018-04-29 17:17:15 +09:00
parent 1625b37b44
commit 372bfaceda
64 changed files with 521 additions and 570 deletions

View File

@ -18,61 +18,65 @@ export default function<T extends object>(data: {
default: false
}
},
computed: {
id(): string {
return this.widget.id;
},
props(): T {
return this.widget.data;
}
},
data() {
return {
props: data.props ? data.props() : {} as T,
bakedOldProps: null,
preventSave: false
bakedOldProps: null
};
},
created() {
if (this.props) {
Object.keys(this.props).forEach(prop => {
if (this.widget.data.hasOwnProperty(prop)) {
this.props[prop] = this.widget.data[prop];
}
});
}
this.mergeProps();
this.$watch('props', () => {
this.mergeProps();
});
this.bakeProps();
},
this.$watch('props', newProps => {
if (this.preventSave) {
this.preventSave = false;
this.bakeProps();
return;
methods: {
bakeProps() {
this.bakedOldProps = JSON.stringify(this.props);
},
mergeProps() {
if (data.props) {
const defaultProps = data.props();
Object.keys(defaultProps).forEach(prop => {
if (!this.props.hasOwnProperty(prop)) {
Vue.set(this.props, prop, defaultProps[prop]);
}
});
}
if (this.bakedOldProps == JSON.stringify(newProps)) return;
},
save() {
if (this.bakedOldProps == JSON.stringify(this.props)) return;
this.bakeProps();
if (this.isMobile) {
(this as any).api('i/update_mobile_home', {
id: this.id,
data: newProps
}).then(() => {
(this as any).os.i.clientSettings.mobileHome.find(w => w.id == this.id).data = newProps;
data: this.props
});
} else {
(this as any).api('i/update_home', {
id: this.id,
data: newProps
}).then(() => {
(this as any).os.i.clientSettings.home.find(w => w.id == this.id).data = newProps;
data: this.props
});
}
}, {
deep: true
});
},
methods: {
bakeProps() {
this.bakedOldProps = JSON.stringify(this.props);
}
}
});

View File

@ -3,6 +3,7 @@ import { EventEmitter } from 'eventemitter3';
import * as merge from 'object-assign-deep';
import * as uuid from 'uuid';
import initStore from '../store';
import { hostname, apiUrl, swPublickey, version, lang, googleMapsApiKey } from '../config';
import Progress from './scripts/loading';
import Connection from './scripts/streaming/stream';
@ -16,16 +17,6 @@ import Err from '../common/views/components/connect-failed.vue';
import { LocalTimelineStreamManager } from './scripts/streaming/local-timeline';
import { GlobalTimelineStreamManager } from './scripts/streaming/global-timeline';
const defaultSettings = {
fetchOnScroll: true,
showMaps: true,
showPostFormOnTopOfTl: false,
gradientWindowHeader: false,
showReplyTarget: true,
showMyRenotes: true,
showRenotedMyNotes: true
};
//#region api requests
let spinner = null;
let pending = 0;
@ -117,6 +108,8 @@ export default class MiOS extends EventEmitter {
return localStorage.getItem('enableSounds') == 'true';
}
public store: ReturnType<typeof initStore>;
public apis: API;
/**
@ -232,6 +225,11 @@ export default class MiOS extends EventEmitter {
console.error.apply(null, args);
}
public bakeMe() {
// ローカルストレージにキャッシュ
localStorage.setItem('me', JSON.stringify(this.i));
}
public signout() {
localStorage.removeItem('me');
document.cookie = `i=; domain=${hostname}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
@ -243,6 +241,8 @@ export default class MiOS extends EventEmitter {
* @param callback A function that call when initialized
*/
public async init(callback) {
this.store = initStore(this);
//#region Init stream managers
this.streams.serverStream = new ServerStreamManager(this);
@ -307,16 +307,11 @@ export default class MiOS extends EventEmitter {
// フェッチが完了したとき
const fetched = me => {
if (me) {
// デフォルトの設定をマージ
me.clientSettings = Object.assign(defaultSettings, me.clientSettings);
// ローカルストレージにキャッシュ
localStorage.setItem('me', JSON.stringify(me));
}
this.i = me;
// ローカルストレージにキャッシュ
this.bakeMe();
this.emit('signedin');
// Finish init
@ -333,6 +328,14 @@ export default class MiOS extends EventEmitter {
// Get cached account data
const cachedMe = JSON.parse(localStorage.getItem('me'));
//#region キャッシュされた設定を復元
const cachedSettings = JSON.parse(localStorage.getItem('settings'));
if (cachedSettings) {
this.store.commit('settings/init', cachedSettings);
}
//#endregion
// キャッシュがあったとき
if (cachedMe) {
if (cachedMe.token == null) {
@ -346,12 +349,25 @@ export default class MiOS extends EventEmitter {
// 後から新鮮なデータをフェッチ
fetchme(cachedMe.token, freshData => {
merge(cachedMe, freshData);
this.store.commit('settings/init', freshData.clientSettings);
});
} else {
// Get token from cookie
const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1];
fetchme(i, fetched);
fetchme(i, me => {
if (me) {
Object.entries(me.clientSettings).forEach(([key, value]) => {
this.store.commit('settings/set', { key, value });
});
fetched(me);
} else {
// Finish init
callback();
}
});
}
}
@ -456,7 +472,7 @@ export default class MiOS extends EventEmitter {
};
const promise = new Promise((resolve, reject) => {
const viaStream = this.stream.hasConnection &&
const viaStream = this.stream && this.stream.hasConnection &&
(localStorage.getItem('apiViaStream') ? localStorage.getItem('apiViaStream') == 'true' : true);
if (viaStream) {

View File

@ -25,10 +25,31 @@ export class HomeStream extends Stream {
console.log('I updated:', i);
}
merge(me, i);
// キャッシュ更新
os.bakeMe();
});
this.on('clientSettingUpdated', x => {
os.store.commit('settings/set', {
key: x.key,
value: x.value
});
});
this.on('home_updated', x => {
if (x.home) {
os.store.commit('settings/setHome', x.home);
} else {
os.store.commit('settings/setHomeWidget', {
id: x.id,
data: x.data
});
}
});
// トークンが再生成されたとき
// このままではAPIが利用できないので強制的にサインアウトさせる
// このままではMisskeyが利用できないので強制的にサインアウトさせる
this.on('my_token_regenerated', () => {
alert('%i18n:!common.my-token-regenerated%');
os.signout();

View File

@ -0,0 +1,38 @@
<template>
<router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="{ borderRadius: clientSettings.circleIcons ? '100%' : null }">
<img v-if="disablePreview" :src="`${user.avatarUrl}?thumbnail&size=128`" alt=""/>
<img v-else :src="`${user.avatarUrl}?thumbnail&size=128`" alt="" v-user-preview="user.id"/>
</router-link>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
user: {
required: true
},
target: {
required: false,
default: null
},
disablePreview: {
required: false,
default: false
}
}
});
</script>
<style lang="stylus" scoped>
.mk-avatar
display block
> img
display inline-block
width 100%
height 100%
margin 0
border-radius inherit
vertical-align bottom
</style>

View File

@ -3,6 +3,7 @@ import Vue from 'vue';
import signin from './signin.vue';
import signup from './signup.vue';
import forkit from './forkit.vue';
import avatar from './avatar.vue';
import nav from './nav.vue';
import noteHtml from './note-html';
import poll from './poll.vue';
@ -28,6 +29,7 @@ import welcomeTimeline from './welcome-timeline.vue';
Vue.component('mk-signin', signin);
Vue.component('mk-signup', signup);
Vue.component('mk-forkit', forkit);
Vue.component('mk-avatar', avatar);
Vue.component('mk-nav', nav);
Vue.component('mk-note-html', noteHtml);
Vue.component('mk-poll', poll);

View File

@ -1,8 +1,6 @@
<template>
<div class="message" :data-is-me="isMe">
<router-link class="avatar-anchor" :to="message.user | userPage" :title="message.user | acct" target="_blank">
<img class="avatar" :src="`${message.user.avatarUrl}?thumbnail&size=80`" alt=""/>
</router-link>
<mk-avatar class="avatar" :user="message.user" target="_blank"/>
<div class="content">
<div class="balloon" :data-no-text="message.text == null">
<p class="read" v-if="isMe && message.isRead">%i18n:@is-read%</p>
@ -67,20 +65,14 @@ export default Vue.extend({
padding 10px 12px 10px 12px
background-color transparent
> .avatar-anchor
> .avatar
display block
position absolute
top 10px
> .avatar
display block
min-width 54px
min-height 54px
max-width 54px
max-height 54px
margin 0
border-radius 8px
transition all 0.1s ease
width 54px
height 54px
border-radius 8px
transition all 0.1s ease
> .content
@ -201,7 +193,7 @@ export default Vue.extend({
margin-left 4px
&:not([data-is-me])
> .avatar-anchor
> .avatar
left 12px
> .content
@ -225,7 +217,7 @@ export default Vue.extend({
text-align left
&[data-is-me]
> .avatar-anchor
> .avatar
right 12px
> .content

View File

@ -13,7 +13,7 @@
@click="navigate(user)"
tabindex="-1"
>
<img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=32`" alt=""/>
<mk-avatar class="avatar" :user="user"/>
<span class="name">{{ user | userName }}</span>
<span class="username">@{{ user | acct }}</span>
</li>
@ -31,7 +31,7 @@
:key="message.id"
>
<div>
<img class="avatar" :src="`${isMe(message) ? message.recipient.avatarUrl : message.user.avatarUrl}?thumbnail&size=64`" alt=""/>
<mk-avatar class="avatar" :user="isMe(message) ? message.recipient : message.user"/>
<header>
<span class="name">{{ isMe(message) ? message.recipient : message.user | userName }}</span>
<span class="username">@{{ isMe(message) ? message.recipient : message.user | acct }}</span>

View File

@ -1,9 +1,7 @@
<template>
<div class="mk-welcome-timeline">
<div v-for="note in notes">
<router-link class="avatar-anchor" :to="note.user | userPage" v-user-preview="note.user.id">
<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=96`" alt="avatar"/>
</router-link>
<mk-avatar class="avatar" :user="note.user" target="_blank"/>
<div class="body">
<header>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link>
@ -69,18 +67,15 @@ export default Vue.extend({
display block
clear both
> .avatar-anchor
> .avatar
display block
float left
position -webkit-sticky
position sticky
top 16px
> img
display block
width 42px
height 42px
border-radius 6px
width 42px
height 42px
border-radius 6px
> .body
float right

View File

@ -61,6 +61,7 @@ export default define({
} else {
this.props.design++;
}
this.save();
}
}
});

View File

@ -68,6 +68,7 @@ export default define({
} else {
this.props.design++;
}
this.save();
}
}
});

View File

@ -73,6 +73,7 @@ export default define({
} else {
this.props.design++;
}
this.save();
},
tick() {
const now = new Date();

View File

@ -59,6 +59,8 @@ export default define({
} else {
this.props.design++;
}
this.save();
}
}
});

View File

@ -40,6 +40,7 @@ export default define({
methods: {
func() {
this.props.compact = !this.props.compact;
this.save();
},
fetch() {
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${this.url}`, {

View File

@ -68,6 +68,7 @@ export default define({
} else {
this.props.view++;
}
this.save();
},
func() {
if (this.props.design == 2) {
@ -75,6 +76,7 @@ export default define({
} else {
this.props.design++;
}
this.save();
}
}
});

View File

@ -64,6 +64,7 @@ export default define({
} else {
this.props.size++;
}
this.save();
this.applySize();
},
@ -111,6 +112,7 @@ export default define({
choose() {
(this as any).apis.chooseDriveFolder().then(folder => {
this.props.folder = folder ? folder.id : null;
this.save();
this.fetch();
});
}