mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Extract logic to EmbedComponent to separate concerns
- Co-authored-by: senderfm <dev@sender.fm>
This commit is contained in:
parent
18cfa0b8c8
commit
da1df27799
@ -1,42 +1,11 @@
|
||||
import { Node } from 'tiptap'
|
||||
import pasteRule from '../commands/pasteRule'
|
||||
import { compileToFunctions } from 'vue-template-compiler'
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { allowEmbedIframesMutation } from '~/graphql/User.js'
|
||||
import Vue from 'vue'
|
||||
import EmbedComponent from '~/components/Embed/EmbedComponent'
|
||||
|
||||
const template = `
|
||||
<a
|
||||
v-if="showLinkOnly"
|
||||
:href="dataEmbedUrl"
|
||||
rel="noopener noreferrer nofollow"
|
||||
target="_blank"
|
||||
>{{dataEmbedUrl}}</a>
|
||||
<ds-container v-else width="small" class="embed-container">
|
||||
<section class="embed-content">
|
||||
<div v-if="showEmbed" v-html="embedHtml" class="embed-html" />
|
||||
<template v-else>
|
||||
<img v-if="embedHtml && embedImage" :src="embedImage" class="embed-preview-image embed-preview-image--clickable" @click.prevent="openOverlay()" />
|
||||
<img v-else-if="embedImage" :src="embedImage" class="embed-preview-image" />
|
||||
</template>
|
||||
<h4 v-if="embedTitle">{{embedTitle}}</h4>
|
||||
<p v-if="embedDescription">{{embedDescription}}</p>
|
||||
<a class="embed" :href="dataEmbedUrl" rel="noopener noreferrer nofollow" target="_blank">{{dataEmbedUrl}}</a>
|
||||
</section>
|
||||
<aside v-if="showOverlay" class="embed-overlay">
|
||||
<h3>{{ $t('editor.embed.data_privacy_warning') }}</h3>
|
||||
<ds-text>{{ $t('editor.embed.data_privacy_info') }} {{embedPublisher}}</ds-text>
|
||||
<div class="embed-buttons">
|
||||
<ds-button primary @click.prevent="allowEmbed()">{{ $t('editor.embed.play_now') }}</ds-button>
|
||||
<ds-button ghost @click.prevent="closeOverlay()">{{ $t('actions.cancel') }}</ds-button>
|
||||
</div>
|
||||
<label class="embed-checkbox">
|
||||
<input type="checkbox" v-model="checkedAlwaysAllowEmbeds" />
|
||||
<span>{{ $t('editor.embed.always_allow') }}</span>
|
||||
</label>
|
||||
</aside>
|
||||
<ds-button icon="close" ghost size="small" class="embed-close-button" @click.prevent="removeEmbed()" />
|
||||
</ds-container>
|
||||
`
|
||||
Vue.component(EmbedComponent)
|
||||
const template = `<component :dataEmbedUrl="dataEmbedUrl" :embedData="embedData" :is="componentType" />`
|
||||
|
||||
const compiledTemplate = compileToFunctions(template)
|
||||
|
||||
@ -95,45 +64,15 @@ export default class Embed extends Node {
|
||||
props: ['node', 'updateAttrs', 'options'],
|
||||
data: () => ({
|
||||
embedData: {},
|
||||
checkedAlwaysAllowEmbeds: false,
|
||||
showEmbed: false,
|
||||
showOverlay: false,
|
||||
showLinkOnly: false,
|
||||
}),
|
||||
async created() {
|
||||
if (this.options) {
|
||||
this.embedData = await this.options.onEmbed({ url: this.dataEmbedUrl })
|
||||
this.showEmbed = this.currentUser.allowEmbedIframes
|
||||
this.checkedAlwaysAllowEmbeds = this.currentUser.allowEmbedIframes
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentUser: 'auth/user',
|
||||
}),
|
||||
embedHtml() {
|
||||
const { html = '' } = this.embedData
|
||||
return html
|
||||
},
|
||||
embedImage() {
|
||||
const { image = '' } = this.embedData
|
||||
return image
|
||||
},
|
||||
embedPublisher() {
|
||||
const { publisher = '' } = this.embedData
|
||||
return publisher
|
||||
},
|
||||
embedTitle() {
|
||||
const { title = '' } = this.embedData
|
||||
return title
|
||||
},
|
||||
embedAuthor() {
|
||||
const { author = '' } = this.embedData
|
||||
return author
|
||||
},
|
||||
embedDescription() {
|
||||
const { description = '' } = this.embedData
|
||||
return description
|
||||
componentType() {
|
||||
return EmbedComponent
|
||||
},
|
||||
dataEmbedUrl: {
|
||||
get() {
|
||||
@ -146,50 +85,6 @@ export default class Embed extends Node {
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
setCurrentUser: 'auth/SET_USER',
|
||||
}),
|
||||
openOverlay() {
|
||||
this.showOverlay = true
|
||||
},
|
||||
closeOverlay() {
|
||||
this.showOverlay = false
|
||||
},
|
||||
allowEmbed() {
|
||||
this.showEmbed = true
|
||||
this.closeOverlay()
|
||||
|
||||
if (this.checkedAlwaysAllowEmbeds !== this.currentUser.allowEmbedIframes) {
|
||||
this.updateEmbedSettings(this.checkedAlwaysAllowEmbeds)
|
||||
}
|
||||
},
|
||||
removeEmbed() {
|
||||
this.showLinkOnly = true
|
||||
},
|
||||
async updateEmbedSettings(allowEmbedIframes) {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: allowEmbedIframesMutation(),
|
||||
variables: {
|
||||
id: this.currentUser.id,
|
||||
allowEmbedIframes,
|
||||
},
|
||||
update: (store, { data: { UpdateUser } }) => {
|
||||
const { allowEmbedIframes } = UpdateUser
|
||||
this.setCurrentUser({
|
||||
...this.currentUser,
|
||||
allowEmbedIframes,
|
||||
})
|
||||
},
|
||||
})
|
||||
this.$toast.success(this.$t('contribution.success'))
|
||||
this.showEmbed = this.currentUser.allowEmbedIframes
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
render(createElement) {
|
||||
return compiledTemplate.render.call(this, createElement)
|
||||
},
|
||||
|
||||
@ -1,31 +1,35 @@
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils'
|
||||
import Vuex from 'vuex'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
import Embed from './Embed'
|
||||
|
||||
let Wrapper
|
||||
let propsData
|
||||
let Wrapper, propsData, component
|
||||
const someUrl = 'https://www.youtube.com/watch?v=qkdXAtO40Fo'
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Vuex)
|
||||
localVue.use(Styleguide)
|
||||
|
||||
describe('Embed.vue', () => {
|
||||
beforeEach(() => {
|
||||
propsData = {}
|
||||
const component = new Embed()
|
||||
Wrapper = ({ mocks, propsData }) => {
|
||||
component = new Embed()
|
||||
// computed = {
|
||||
// currentUser: () => {
|
||||
// return { id: 'im a user', allowEmbedIframes: false }
|
||||
// },
|
||||
// }
|
||||
Wrapper = ({ propsData }) => {
|
||||
return shallowMount(component.view, { propsData })
|
||||
}
|
||||
})
|
||||
|
||||
it('renders ds-container', () => {
|
||||
propsData = {
|
||||
node: { attrs: { href: someUrl } },
|
||||
}
|
||||
expect(Wrapper({ propsData }).is('ds-container')).toBe(true)
|
||||
})
|
||||
|
||||
describe('given a href', () => {
|
||||
describe('onEmbed returned embed data', () => {
|
||||
beforeEach(() => {
|
||||
propsData.options = {
|
||||
onEmbed: () => ({
|
||||
__typename: 'Embed',
|
||||
type: 'video',
|
||||
title: 'Baby Loves Cat',
|
||||
author: 'Merkley Family',
|
||||
@ -49,9 +53,7 @@ describe('Embed.vue', () => {
|
||||
propsData.node = { attrs: { href: 'https://www.youtube.com/watch?v=qkdXAtO40Fo' } }
|
||||
const wrapper = Wrapper({ propsData })
|
||||
await wrapper.html()
|
||||
expect(wrapper.find('ds-container img').attributes('src')).toEqual(
|
||||
'https://i.ytimg.com/vi/qkdXAtO40Fo/maxresdefault.jpg',
|
||||
)
|
||||
expect(wrapper.contains('embed-component-stub')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
153
webapp/components/Embed/EmbedComponent.vue
Normal file
153
webapp/components/Embed/EmbedComponent.vue
Normal file
@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<a v-if="showLinkOnly" :href="dataEmbedUrl" rel="noopener noreferrer nofollow" target="_blank">
|
||||
{{ dataEmbedUrl }}
|
||||
</a>
|
||||
<ds-container v-else width="small" class="embed-container">
|
||||
<section class="embed-content">
|
||||
<div v-if="showEmbed" v-html="embedHtml" class="embed-html" />
|
||||
<template v-else>
|
||||
<img
|
||||
v-if="embedHtml && embedImage"
|
||||
:src="embedImage"
|
||||
class="embed-preview-image embed-preview-image--clickable"
|
||||
@click.prevent="openOverlay()"
|
||||
/>
|
||||
<img v-else-if="embedImage" :src="embedImage" class="embed-preview-image" />
|
||||
</template>
|
||||
<h4 v-if="embedTitle">{{ embedTitle }}</h4>
|
||||
<p v-if="embedDescription">{{ embedDescription }}</p>
|
||||
<a class="embed" :href="dataEmbedUrl" rel="noopener noreferrer nofollow" target="_blank">
|
||||
{{ dataEmbedUrl }}
|
||||
</a>
|
||||
</section>
|
||||
<aside v-if="showOverlay" class="embed-overlay">
|
||||
<h3>{{ $t('editor.embed.data_privacy_warning') }}</h3>
|
||||
<ds-text>{{ $t('editor.embed.data_privacy_info') }} {{ embedPublisher }}</ds-text>
|
||||
<div class="embed-buttons">
|
||||
<ds-button primary @click.prevent="allowEmbed()">
|
||||
{{ $t('editor.embed.play_now') }}
|
||||
</ds-button>
|
||||
<ds-button ghost @click.prevent="closeOverlay()">{{ $t('actions.cancel') }}</ds-button>
|
||||
</div>
|
||||
<label class="embed-checkbox">
|
||||
<input type="checkbox" v-model="checkedAlwaysAllowEmbeds" />
|
||||
<span>{{ $t('editor.embed.always_allow') }}</span>
|
||||
</label>
|
||||
</aside>
|
||||
<ds-button
|
||||
icon="close"
|
||||
ghost
|
||||
size="small"
|
||||
class="embed-close-button"
|
||||
@click.prevent="removeEmbed()"
|
||||
/>
|
||||
</ds-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import { allowEmbedIframesMutation } from '~/graphql/User.js'
|
||||
|
||||
export default {
|
||||
name: 'embed-component',
|
||||
props: {
|
||||
dataEmbedUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
embedData: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkedAlwaysAllowEmbeds: false,
|
||||
showEmbed: false,
|
||||
showOverlay: false,
|
||||
showLinkOnly: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.embedData.options) {
|
||||
this.showEmbed = this.currentUser.allowEmbedIframes
|
||||
this.checkedAlwaysAllowEmbeds = this.currentUser.allowEmbedIframes
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentUser: 'auth/user',
|
||||
}),
|
||||
embedHtml() {
|
||||
const { html = '' } = this.embedData
|
||||
return html
|
||||
},
|
||||
embedImage() {
|
||||
const { image = '' } = this.embedData
|
||||
return image
|
||||
},
|
||||
embedPublisher() {
|
||||
const { publisher = '' } = this.embedData
|
||||
return publisher
|
||||
},
|
||||
embedTitle() {
|
||||
const { title = '' } = this.embedData
|
||||
return title
|
||||
},
|
||||
embedAuthor() {
|
||||
const { author = '' } = this.embedData
|
||||
return author
|
||||
},
|
||||
embedDescription() {
|
||||
const { description = '' } = this.embedData
|
||||
return description
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
setCurrentUser: 'auth/SET_USER',
|
||||
}),
|
||||
openOverlay() {
|
||||
this.showOverlay = true
|
||||
},
|
||||
closeOverlay() {
|
||||
this.showOverlay = false
|
||||
},
|
||||
allowEmbed() {
|
||||
this.showEmbed = true
|
||||
this.closeOverlay()
|
||||
|
||||
if (this.checkedAlwaysAllowEmbeds !== this.currentUser.allowEmbedIframes) {
|
||||
this.updateEmbedSettings(this.checkedAlwaysAllowEmbeds)
|
||||
}
|
||||
},
|
||||
removeEmbed() {
|
||||
this.showLinkOnly = true
|
||||
},
|
||||
async updateEmbedSettings(allowEmbedIframes) {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: allowEmbedIframesMutation(),
|
||||
variables: {
|
||||
id: this.currentUser.id,
|
||||
allowEmbedIframes,
|
||||
},
|
||||
update: (store, { data: { UpdateUser } }) => {
|
||||
const { allowEmbedIframes } = UpdateUser
|
||||
this.setCurrentUser({
|
||||
...this.currentUser,
|
||||
allowEmbedIframes,
|
||||
})
|
||||
},
|
||||
})
|
||||
this.$toast.success(this.$t('contribution.success'))
|
||||
this.showEmbed = this.currentUser.allowEmbedIframes
|
||||
} catch (err) {
|
||||
this.$toast.error(err.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Loading…
x
Reference in New Issue
Block a user