init
This commit is contained in:
99
site/plugins/embed/src/components/embedField.vue
Normal file
99
site/plugins/embed/src/components/embedField.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<k-field :input="_uid" v-bind="$props" class="k-embed-field k-url-field k-field">
|
||||
|
||||
<div class="preview" v-if="hasMedia" :data-provider="providerName">
|
||||
<div class="preview-content" v-html="media.code"></div>
|
||||
<div class="preview-background"></div>
|
||||
</div>
|
||||
|
||||
<k-input ref="input" :id="_uid" v-bind="$props" :value="inputValue" :media="media" theme="field" v-on="$listeners" @setMedia="setMedia" @startLoading="startLoading">
|
||||
<div class="k-embed-infos" slot="icon">
|
||||
<div class="k-embed-status">
|
||||
<span v-if="loading" class="k-embed-status-loading"><span class="loader"></span></span>
|
||||
<span v-else-if="hasMedia" class="k-embed-status-synced">{{ $t('embed.synced') }} <span class="checkmark"></span></span>
|
||||
<span v-else-if="syncFailed" class="k-embed-status-failed">{{ $t('embed.failed') }} <span class="cross"></span></span>
|
||||
</div>
|
||||
<k-button v-if="link"
|
||||
:icon="icon"
|
||||
:link="inputValue"
|
||||
:tooltip="$t('open')"
|
||||
class="k-input-icon-button"
|
||||
tabindex="-1"
|
||||
target="_blank"
|
||||
rel="noopener" />
|
||||
</div>
|
||||
|
||||
</k-input>
|
||||
|
||||
</k-field>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isUrl, matchProvider } from '../helpers/validators.js'
|
||||
|
||||
export default {
|
||||
extends: 'k-url-field',
|
||||
data() {
|
||||
return {
|
||||
media: Object,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
provider: String,
|
||||
},
|
||||
created() {
|
||||
if(this.value && this.value.media && this.hasLength(this.value.media)) {
|
||||
this.media = this.value.media
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
inputValue() {
|
||||
if(this.value && this.value.media && this.hasLength(this.value.media)) {
|
||||
this.media = this.value.media
|
||||
}
|
||||
else {
|
||||
this.media = {}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasMedia() {
|
||||
return this.hasLength(this.media) && this.media.code
|
||||
},
|
||||
providerName() {
|
||||
return this.hasMedia && this.media.providerName ? this.media.providerName.toLowerCase() : null
|
||||
},
|
||||
syncFailed() {
|
||||
return this.inputValue != '' && this.isEmbeddableUrl(this.inputValue) && !this.hasMedia
|
||||
},
|
||||
inputValue() {
|
||||
return this.value && this.value.input ? this.value.input : ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setMedia(media) {
|
||||
this.media = media
|
||||
this.stopLoading()
|
||||
},
|
||||
hasLength(obj) {
|
||||
return Object.keys(obj).length
|
||||
},
|
||||
startLoading() {
|
||||
this.loading = true
|
||||
},
|
||||
stopLoading() {
|
||||
this.loading = false
|
||||
},
|
||||
isEmbeddableUrl(value) {
|
||||
if(!isUrl(value)) return false
|
||||
if(this.provider && !matchProvider(value, this.provider)) return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../assets/css/styles.scss'
|
||||
</style>
|
||||
88
site/plugins/embed/src/components/embedInput.vue
Normal file
88
site/plugins/embed/src/components/embedInput.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<script>
|
||||
import { isUrl, matchProvider } from '../helpers/validators.js'
|
||||
|
||||
export default {
|
||||
extends: 'k-url-input',
|
||||
props: {
|
||||
provider: String,
|
||||
media: Object,
|
||||
},
|
||||
mounted() {
|
||||
this.loadEmbedScripts()
|
||||
},
|
||||
methods: {
|
||||
onInput(value) {
|
||||
if(value == '' || !this.isEmbeddableUrl(value)) {
|
||||
this.media = {}
|
||||
this.emitInput(value)
|
||||
return false;
|
||||
}
|
||||
if(value.includes('https://www.instagram.com')) {
|
||||
value = value.split('?')[0].replace(/\/$/, "");
|
||||
}
|
||||
|
||||
this.$emit('startLoading')
|
||||
this.$api
|
||||
.get('kirby-embed/get-data', { url: value })
|
||||
.then(response => {
|
||||
if(response['status'] == 'success' && response['data']) {
|
||||
if(response['data']['providerName'] == 'Vimeo') {
|
||||
let iframe = response['data']['code']
|
||||
iframe = this.htmlToElement(iframe)
|
||||
iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin')
|
||||
|
||||
response['data']['code'] = iframe.outerHTML
|
||||
}
|
||||
this.media = response['data']
|
||||
}
|
||||
else {
|
||||
this.media = {}
|
||||
}
|
||||
|
||||
this.emitInput(value)
|
||||
})
|
||||
.catch(error => {
|
||||
this.media = {}
|
||||
this.emitInput(value)
|
||||
})
|
||||
},
|
||||
emitInput(value) {
|
||||
this.$emit("input", { input: value, media: this.media });
|
||||
this.$emit("setMedia", this.media)
|
||||
|
||||
this.loadEmbedScripts()
|
||||
},
|
||||
loadEmbedScripts() {
|
||||
if (window.twttr) {
|
||||
window.twttr.widgets.load();
|
||||
}
|
||||
else if (this.media && Object.keys(this.media).length && this.media.providerName.toLowerCase() == 'twitter') {
|
||||
const embed = document.createElement('script');
|
||||
embed.src = 'https://platform.twitter.com/widgets.js';
|
||||
document.body.appendChild(embed);
|
||||
}
|
||||
|
||||
if (window.instgrm) {
|
||||
window.instgrm.Embeds.process();
|
||||
}
|
||||
else if (this.media && Object.keys(this.media).length && this.media.providerName.toLowerCase() == 'instagram') {
|
||||
const embed = document.createElement('script');
|
||||
embed.src = 'https://www.instagram.com/embed.js';
|
||||
document.body.appendChild(embed);
|
||||
}
|
||||
},
|
||||
isEmbeddableUrl(value) {
|
||||
if(!isUrl(value)) return false
|
||||
if(this.provider && !matchProvider(value, this.provider)) return false
|
||||
return true
|
||||
},
|
||||
htmlToElement(html) {
|
||||
let template = document.createElement('template')
|
||||
html = html.trim()
|
||||
|
||||
template.innerHTML = html
|
||||
return template.content.firstChild
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
53
site/plugins/embed/src/components/embedPreview.vue
Normal file
53
site/plugins/embed/src/components/embedPreview.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="k-embed-field-preview">
|
||||
<div class="k-embed-field-preview-inner k-bubble" data-has-text="true">
|
||||
<div class="k-embed-icon k-frame">
|
||||
<img :src="iconSrc">
|
||||
</div>
|
||||
<div class="k-embed-url">
|
||||
{{ url }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: String,
|
||||
field: Object
|
||||
},
|
||||
computed: {
|
||||
url() {
|
||||
return this.value.input.replace(/^\/\/|^.*?:\/\//, '')
|
||||
},
|
||||
isSynced() {
|
||||
return Object.keys(this.value.media).length && this.value.media.code !== null
|
||||
},
|
||||
iconSrc() {
|
||||
return this.$panel.$urls.site +'/media/plugins/sylvainjule/embed/svg/'+ this.providerIcon;
|
||||
},
|
||||
providerIcon() {
|
||||
if(this.isSynced) {
|
||||
if(this.field.icons) {
|
||||
let provider = this.value.media.providerName
|
||||
let icons = ['Vimeo', 'Flickr', 'Instagram', 'SoundCloud', 'Spotify', 'Twitter', 'YouTube'];
|
||||
|
||||
if(icons.includes(provider)) {
|
||||
return 'embed-icon-'+ provider.toLowerCase() +'.svg'
|
||||
}
|
||||
else {
|
||||
return 'embed-icon-synced.svg';
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 'embed-icon-synced.svg'
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 'embed-icon-failed.svg'
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user