149 lines
3.9 KiB
Vue
149 lines
3.9 KiB
Vue
<template>
|
|
<div class="ui container share-target">
|
|
|
|
<div class="ui basic center aligned segment">
|
|
|
|
<div v-if="status === 'working'">
|
|
<loading-icon message="Saving to Scratch Pad" />
|
|
</div>
|
|
|
|
<div v-else-if="status === 'error'">
|
|
<h3 class="ui header">
|
|
<i class="exclamation triangle icon"></i>
|
|
Couldn't save that
|
|
</h3>
|
|
<p>You may be offline. Your text is safe below — retry when you have a connection.</p>
|
|
|
|
<textarea class="shared-text" rows="8" readonly :value="pushText"></textarea>
|
|
|
|
<div class="ui buttons">
|
|
<div class="ui green button" v-on:click="save()">
|
|
<i class="redo icon"></i> Retry
|
|
</div>
|
|
<div class="ui basic button" v-on:click="discard()">
|
|
Discard
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-else>
|
|
<loading-icon message="Working" />
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { defineAsyncComponent } from 'vue'
|
|
import axios from 'axios'
|
|
|
|
// Shared text is parked here when the share arrives while logged out. The
|
|
// share's query string does not survive the bounce through /login, so a
|
|
// redirect param alone would lose it.
|
|
const STASH_KEY = 'pendingShareText'
|
|
|
|
// Guard against a pathological share wedging localStorage
|
|
const MAX_STASH = 100 * 1024
|
|
|
|
export default {
|
|
name: 'ShareTargetPage',
|
|
components: {
|
|
'loading-icon': defineAsyncComponent(() => import('@/components/LoadingIconComponent.vue')),
|
|
},
|
|
data(){
|
|
return {
|
|
status: 'working',
|
|
pushText: '',
|
|
}
|
|
},
|
|
// Deliberately NOT calling $root.loginGateway() the way other pages do --
|
|
// it would bounce away and discard the shared payload before we read it.
|
|
mounted(){
|
|
|
|
const text = this.composeSharedText()
|
|
|
|
if(!text){
|
|
this.$router.replace('/quick')
|
|
return
|
|
}
|
|
|
|
this.pushText = text
|
|
|
|
// getLoggedIn is reliable here: App.vue's beforeCreate populates the
|
|
// username from localStorage before any route component mounts.
|
|
if(!this.$store.getters.getLoggedIn){
|
|
this.stash(text)
|
|
this.$router.replace({ path: '/login', query: { redirect: '/share-target' } })
|
|
return
|
|
}
|
|
|
|
this.save()
|
|
},
|
|
methods: {
|
|
// Android routinely duplicates content across these fields -- the URL
|
|
// lands in both `text` and `url`, the page title in both `title` and
|
|
// `text`. Without the dedupe every shared link is saved twice.
|
|
composeSharedText(){
|
|
|
|
const query = this.$route.query
|
|
|
|
const parts = ['title', 'text', 'url']
|
|
.map(key => String(query[key] ?? '').trim())
|
|
.filter(value => value.length > 0)
|
|
.filter((value, index, all) => all.indexOf(value) === index)
|
|
|
|
if(parts.length > 0){ return parts.join('\n') }
|
|
|
|
// Nothing in the URL: this is the replay after logging in
|
|
return localStorage.getItem(STASH_KEY) || ''
|
|
},
|
|
stash(text){
|
|
if(text.length > MAX_STASH){ return }
|
|
localStorage.setItem(STASH_KEY, text)
|
|
},
|
|
save(){
|
|
|
|
this.status = 'working'
|
|
|
|
// Same call the paste button makes. The server prepends to the
|
|
// scratch pad, strips HTML and auto-links URLs, so nothing needs
|
|
// formatting here.
|
|
axios.post('/api/quick-note/update', { 'pushText': this.pushText })
|
|
.then(() => {
|
|
localStorage.removeItem(STASH_KEY)
|
|
this.$bus.$emit('notification', 'Saved To Scratch Pad')
|
|
this.$router.replace('/quick')
|
|
})
|
|
.catch(error => {
|
|
// Keep the stash: offline is the likely cause and the service
|
|
// worker means the app boots without a connection.
|
|
console.error('[ShareTarget] save failed:', error)
|
|
this.stash(this.pushText)
|
|
this.status = 'error'
|
|
})
|
|
},
|
|
discard(){
|
|
localStorage.removeItem(STASH_KEY)
|
|
this.$router.replace('/quick')
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.share-target {
|
|
padding-top: 3em;
|
|
}
|
|
.shared-text {
|
|
width: 100%;
|
|
margin: 1em 0;
|
|
padding: 0.75em;
|
|
border: 1px solid var(--border_color);
|
|
border-radius: 4px;
|
|
background-color: var(--small_element_bg_color);
|
|
color: var(--text_color);
|
|
font-family: inherit;
|
|
}
|
|
</style>
|