using event bus

This commit is contained in:
sheychen 2019-04-17 12:08:30 +02:00
parent a92369b284
commit e95b8a606d
20 changed files with 179 additions and 147 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,24 +1,18 @@
<script> <script>
import { emitErrorMixin, handleOptionsMixin } from '../core/tools' import serviceEmiterVue from './serviceEmiter.vue'
import serviceHeaderVue from '../core/serviceHeader.vue' import serviceHeaderVue from '../core/serviceHeader.vue'
import settingBooleanVue from '../core/input/settingBoolean.vue' import settingBooleanVue from '../core/input/settingBoolean.vue'
import settingIntVue from '../core/input/settingInt.vue' import settingIntVue from '../core/input/settingInt.vue'
import settingStringVue from './input/settingString.vue' import settingStringVue from './input/settingString.vue'
export default { export default {
mixins: [ emitErrorMixin, handleOptionsMixin ], extends: serviceEmiterVue,
components: { components: {
serviceHeader: serviceHeaderVue, serviceHeader: serviceHeaderVue,
settingBoolean: settingBooleanVue, settingBoolean: settingBooleanVue,
settingInt: settingIntVue, settingInt: settingIntVue,
settingString: settingStringVue settingString: settingStringVue
},
methods:{
passMove(move) {
this.$emit('move', move)
}
} }
} }
</script> </script>

View File

@ -6,7 +6,7 @@ export default {
}, },
methods: { methods: {
sendChange(value) { sendChange(value) {
this.$emit('change', { name: this.id, value: value }) this.$emit('change', { key: this.id, value: value })
} }
} }
} }

View File

@ -0,0 +1,23 @@
<script>
export default {
props: {
emit: Function
},
methods:{
emitError(err) {
this.emit('error', err)
},
saveOptions(options) {
this.emit('saveAll', options)
},
saveOption(key, value) {
this.saveOptionCouple({
key: key, value: value
})
},
saveOptionCouple(couple) {
this.emit('save', couple)
}
}
}
</script>

View File

@ -17,9 +17,12 @@ export default {
data() { return { data() { return {
showSettings: false showSettings: false
} }, } },
props: {
emit: Function
},
methods: { methods: {
onMove(type, direction) { onMove(type, direction) {
this.$emit('move', { type: type, direction: direction }) this.emit('move', { type: type, direction: direction })
}, },
} }
} }

View File

@ -1,23 +0,0 @@
export const emitErrorMixin = {
methods: {
emitError(err) {
this.$emit('error', err.toString())
}
}
}
export const handleOptionsMixin = {
methods: {
saveOptions(options) {
this.$emit('save', options)
},
setOption(name, value) {
const options = {...this.$props}
options[name] = value
this.saveOptions(options)
},
setOptionCouple(couple) {
this.setOption(couple.name, couple.value)
}
}
}

View File

@ -9,6 +9,7 @@ a.account(target="_blank" :href="account.url")
import { parseEmojisMixin } from './tools' import { parseEmojisMixin } from './tools'
export default { export default {
mixins: [ parseEmojisMixin ],
props: { props: {
account: Object, account: Object,
showMedia: { showMedia: {
@ -16,7 +17,6 @@ export default {
default: true default: true
} }
}, },
mixins: [ parseEmojisMixin ],
methods: { methods: {
avatarStyle(avatar) { avatarStyle(avatar) {
return { return {

View File

@ -19,12 +19,14 @@
<script> <script>
import { timerMinin } from '../core/fromNow.vue' import { timerMinin } from '../core/fromNow.vue'
import { emitErrorMixin } from '../core/tools' import serviceEmiterVue from '../core/serviceEmiter.vue'
import statusVue from './status.vue' import statusVue from './status.vue'
import notificationVue from './notification.vue' import notificationVue from './notification.vue'
export default { export default {
mixins: [ timerMinin, emitErrorMixin ], extends: serviceEmiterVue,
mixins: [ timerMinin ],
components: { components: {
status: statusVue, status: statusVue,
notification: notificationVue notification: notificationVue

View File

@ -1,17 +1,17 @@
<template lang="pug"> <template lang="pug">
.mastodon .mastodon
service-header(@move="passMove") service-header(:emit="emit")
template(#title) template(#title)
| Mastodon: | Mastodon:
span(v-html="parseEmojis(account.display_name, account.emojis)") span(v-html="parseEmojis(account.display_name, account.emojis)")
| {{ server ? '@' + server : '' }} | {{ server ? '@' + server : '' }}
template(#settings) template(#settings)
setting-boolean(:id="'reconnect'" :title="'Reconnect'" :value="reconnect" @change="setOptionCouple") setting-boolean(:id="'reconnect'" :title="'Reconnect'" :value="reconnect" @change="saveOptionCouple")
setting-boolean(:id="'reblog'" :title="'Show reblogs'" :value="reblog" @change="setOptionCouple") setting-boolean(:id="'reblog'" :title="'Show reblogs'" :value="reblog" @change="saveOptionCouple")
setting-boolean(:id="'reply'" :title="'Show replies'" :value="reply" @change="setOptionCouple") setting-boolean(:id="'reply'" :title="'Show replies'" :value="reply" @change="saveOptionCouple")
setting-int(:id="'buffer'" :title="'Buffer size'" :value="buffer" @change="setOptionCouple") setting-int(:id="'buffer'" :title="'Buffer size'" :value="buffer" @change="saveOptionCouple")
setting-boolean(:id="'showMedia'" :title="'Show medias'" :value="showMedia" @change="setOptionCouple") setting-boolean(:id="'showMedia'" :title="'Show medias'" :value="showMedia" @change="saveOptionCouple")
client(v-if="server && token" v-bind="$props" @error="emitError") client(v-if="server && token" v-bind="$props")
.auth(v-else) .auth(v-else)
form(@submit.prevent="setServer") form(@submit.prevent="setServer")
p p
@ -77,8 +77,8 @@ export default { //TODO: Use oauth
axios.get(`https://${this.newServer}/api/v1/accounts/verify_credentials`, { axios.get(`https://${this.newServer}/api/v1/accounts/verify_credentials`, {
headers: { Authorization: "Bearer " + this.newToken }, headers: { Authorization: "Bearer " + this.newToken },
timeout: this.timeout timeout: this.timeout
}).then(() => this.saveOptions({...this.$props, }).then(() => this.saveOptions({ ...this.$props,
server: this.newServer, token: this.newToken})) server: this.newServer, token: this.newToken }))
.catch(this.emitError) .catch(this.emitError)
} }
}, },

View File

@ -8,7 +8,7 @@ div
a.date(target="_blank" :href="status.uri") a.date(target="_blank" :href="status.uri")
from-now(:date="status.created_at" :now="now") from-now(:date="status.created_at" :now="now")
.content .content(:class="{ avatared: showMedia }")
template(v-if="!status.reblog") template(v-if="!status.reblog")
.spoiler(v-if="status.spoiler_text" @click.stop.prevent="status.sensitive = !status.sensitive"). .spoiler(v-if="status.spoiler_text" @click.stop.prevent="status.sensitive = !status.sensitive").
{{ status.spoiler_text || 'Spoiler' }} {{ status.sensitive ? '&rarr;' : '&darr;' }} {{ status.spoiler_text || 'Spoiler' }} {{ status.sensitive ? '&rarr;' : '&darr;' }}
@ -49,11 +49,11 @@ export default {
}, },
props: { props: {
status: Object, status: Object,
showMedia: { withAccount: {
type: Boolean, type: Boolean,
default: true default: true
}, },
withAccount: { showMedia: {
type: Boolean, type: Boolean,
default: true default: true
} }

View File

@ -1,12 +1,12 @@
export const parseEmojisMixin = { export const parseEmojisMixin = {
methods: { methods: {
parseEmojis(text, emojis) { parseEmojis(text, emojis) {
for (const emoji of emojis) { for (const emoji of emojis) {
text = text.split(`:${emoji.shortcode}:`).join( text = text.split(`:${emoji.shortcode}:`).join(
`<img draggable="false" class="icon" alt="${emoji.shortcode}" title="${emoji.shortcode}" src="${emoji.static_url}">` `<img draggable="false" class="icon" alt="${emoji.shortcode}" title="${emoji.shortcode}" src="${emoji.static_url}">`
) )
} }
return text return text
}
} }
}
} }

View File

@ -1,11 +1,11 @@
<template lang="pug"> <template lang="pug">
.nextcloud-news(v-show="showEmpty || unreaded.length > 0 || !server || !token || !username") .nextcloud-news(v-show="showEmpty || unreaded.length > 0 || !server || !token || !username")
service-header(@move="passMove") service-header(:emit="emit")
template(#title) Nextcloud News template(#title) Nextcloud News
template(#settings) template(#settings)
setting-int(:id="'update'" :title="'Update interval'" :value="update" @change="setOptionCouple") setting-int(:id="'update'" :title="'Update interval'" :value="update" @change="saveOptionCouple")
setting-int(:id="'buffer'" :title="'Buffer size'" :value="buffer" @change="setOptionCouple") setting-int(:id="'buffer'" :title="'Buffer size'" :value="buffer" @change="saveOptionCouple")
setting-boolean(:id="'showEmpty'" :title="'Show empty'" :value="showEmpty" @change="setOptionCouple") setting-boolean(:id="'showEmpty'" :title="'Show empty'" :value="showEmpty" @change="saveOptionCouple")
.unreaded .unreaded
.news(v-for="news in unreaded") .news(v-for="news in unreaded")
a(:href="news.url" target="_blank") a(:href="news.url" target="_blank")
@ -102,7 +102,7 @@ export default {
axios.get(`https://${this.newServer}/index.php/apps/news/api/v1-2/folders`, { axios.get(`https://${this.newServer}/index.php/apps/news/api/v1-2/folders`, {
headers: { Authorization: 'Basic ' + btoa(this.newUsername + ':' + this.newToken) }, headers: { Authorization: 'Basic ' + btoa(this.newUsername + ':' + this.newToken) },
timeout: this.timeout timeout: this.timeout
}).then(() => this.saveOptions({...this.$props, }).then(() => this.saveOptions({ ...this.$props,
server: this.newServer, token: this.newToken, username: this.newUsername })) server: this.newServer, token: this.newToken, username: this.newUsername }))
.catch(this.emitError) .catch(this.emitError)
} }

View File

@ -1,11 +1,11 @@
<template lang="pug"> <template lang="pug">
.openweathermap .openweathermap
service-header(@move="passMove") service-header(:emit="emit")
template(#title) OpenWeatherMap template(#title) OpenWeatherMap
template(#settings) template(#settings)
setting-string(:id="'token'" :title="'Token'" :value="token" @change="setOptionCouple") setting-string(:id="'token'" :title="'Token'" :value="token" @change="saveOptionCouple")
setting-int(:id="'update'" :title="'Update interval'" :value="update" @change="setOptionCouple") setting-int(:id="'update'" :title="'Update interval'" :value="update" @change="saveOptionCouple")
setting-int(:id="'forecastLimit'" :title="'Forecast limit'" :value="forecastLimit" @change="setOptionCouple") setting-int(:id="'forecastLimit'" :title="'Forecast limit'" :value="forecastLimit" @change="saveOptionCouple")
p.setting p.setting
button(@click="showAdd = true") Add city button(@click="showAdd = true") Add city
template(v-if="weathers.length > 0 || cities.length == 0") template(v-if="weathers.length > 0 || cities.length == 0")
@ -137,14 +137,12 @@ export default {
return `${date.toLocaleDateString()} ${date.getHours()}h` return `${date.toLocaleDateString()} ${date.getHours()}h`
}, },
addCity(id) { addCity(id) {
const options = {...this.$props} this.cities.push({ id: id })
options.cities.push({id: id}) this.saveOption('cities', this.cities)
this.saveOptions(options)
}, },
removeCity(i) { removeCity(key) {
const options = {...this.$props} this.cities.splice(key, 1)
options.cities.splice(i, 1) this.saveOption('cities', this.cities)
this.saveOptions(options)
} }
}, },
created() { created() {

View File

@ -26,9 +26,8 @@
</div> </div>
<div id="services"> <div id="services">
<component <component
v-for="(service, key) in services" :is="service.type" :key="key" v-for="(service, key) in services" :is="service.type" :emit="makeEmiter(key)"
@error="addError" @save="setService(key, $event)" @move="moveService(key, $event)" :key="key" v-bind="service.options" :style="gridPos(key, service.position)"
v-bind="service.options" :style="gridPos(key, service.position)"
/> />
</div> </div>
</div> </div>

View File

@ -15,6 +15,12 @@ a {
color: #aaa; color: #aaa;
} }
input, select, button {
background-color: #333;
color: #eee;
border: 1px solid #999;
}
.icon { .icon {
width: 1em; width: 1em;
height: 1em; height: 1em;
@ -188,7 +194,11 @@ a {
} }
.mastodon .client .status .content, .mastodon .client .notification .content { .mastodon .client .status .content, .mastodon .client .notification .content {
margin: 0.5em 0.5em 0.5em 3.5em; margin: .5em .5em .5em 1em;
}
.mastodon .client .status .content.avatared, .mastodon .client .notification .content.avatared {
margin-left: 3.5em;
} }
.mastodon .client .status .content .reblog, .mastodon .client .notification .content .reblog { .mastodon .client .status .content .reblog, .mastodon .client .notification .content .reblog {

File diff suppressed because one or more lines are too long

147
main.js
View File

@ -2,69 +2,88 @@
const servicesStorage = 'services' const servicesStorage = 'services'
var app = new Vue({ var app = new Vue({
el: '#app', el: '#app',
data: { data: {
showManager: false, showManager: false,
newService: '', newService: '',
services: [], services: [],
errors: [] errors: [],
}, bus: new Vue()
mounted() { },
if (localStorage.getItem(servicesStorage)) { mounted() {
try { if (localStorage.getItem(servicesStorage)) { //TODO: allow external storage
this.services = JSON.parse(localStorage.getItem(servicesStorage)) try {
} catch (e) { this.services = JSON.parse(localStorage.getItem(servicesStorage))
localStorage.removeItem(servicesStorage) } catch (e) {
} localStorage.removeItem(servicesStorage)
} }
},
methods: {
addError(err) {
this.errors.push(err)
},
removeError(id) {
this.errors.splice(id, 1)
},
addService() {
// ensure they actually typed something
if (!this.newService) {
return;
}
this.services.push({
type: this.newService,
options: {}, position: {}
})
this.newService = ''
this.showManager = false
this.saveServices()
},
setService(id, options) {
this.$set(this.services, id, {
...this.services[id],
options: options
})
this.saveServices()
},
moveService(id, move) {
const service = { ...this.services[id] }
service.position[move.type] = Math.max(1, (service.position[move.type] || 1) + move.direction)
this.$set(this.services, id, service)
this.saveServices()
},
removeService(id) {
this.services.splice(id, 1)
this.saveServices()
},
saveServices() {
localStorage.setItem(servicesStorage, JSON.stringify(this.services))
this.$forceUpdate()
},
gridPos(id, position = {}) {
return {
"grid-row": `${position.x || 1} / span ${position.h || 2}`,
"grid-column": `${position.y || id*2+1} / span ${position.w || 2}`
}
}
} }
this.bus.$on('error', this.onError)
this.bus.$on('saveAll', this.onSaveAll)
this.bus.$on('save', this.onSave)
this.bus.$on('move', this.onMove)
},
methods: {
//Errors
onError(event) {
this.addError(event.msg.toString())
},
addError(err) {
this.errors.push(err)
},
removeError(id) {
this.errors.splice(id, 1)
},
//Services
addService() {
if (!this.newService)
return
this.services.push({
type: this.newService,
options: {}, position: {}
})
this.newService = ''
this.showManager = false
this.saveServices()
},
onSave({ key, msg }) {
this.$set(this.services[key].options, msg.key, msg.value)
this.saveServices()
},
onSaveAll({ key, msg }) {
this.$set(this.services, key, {
...this.services[key],
options: msg
})
this.saveServices()
},
onMove({ key, msg }) {
this.$set(this.services[key].position, msg.type, Math.max(1,
(this.services[key].position[msg.type] || 1) + msg.direction
))
this.saveServices()
},
removeService(id) {
this.services.splice(id, 1)
this.saveServices()
},
saveServices() {
localStorage.setItem(servicesStorage, JSON.stringify(this.services))
this.$forceUpdate()
},
gridPos(id, position = {}) {
return {
"grid-row": `${position.x || 1} / span ${position.h || 2}`,
"grid-column": `${position.y || id*2+1} / span ${position.w || 2}`
}
},
makeEmiter(key) {
const self = this
return function(name, msg) {
self.bus.$emit(name, { msg: msg, key: key })
}
}
}
}) })

View File

@ -28,6 +28,11 @@ a
text-decoration: none text-decoration: none
color: $noneColor color: $noneColor
input, select, button
background-color: $backColor
color: $foreColor
border: 1px solid $halfColor
.icon .icon
width: 1em width: 1em
height: 1em height: 1em
@ -123,7 +128,9 @@ a
.status, .notification .status, .notification
min-height: $avatarSize min-height: $avatarSize
.content .content
margin: .5em .5em .5em .5em + $avatarSize margin: .5em .5em .5em 1em
&.avatared
margin-left: .5em + $avatarSize
.reblog .reblog
font-size: .8em font-size: .8em
.spoiler .spoiler