Add video block to frontend and backend
This commit is contained in:
parent
4cb5c6ad63
commit
4010b21cce
|
|
@ -23,11 +23,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TextBlock from '@/components/content-blocks/TextBlock.vue';
|
import TextBlock from '@/components/content-blocks/TextBlock';
|
||||||
import BasicKnowledgeWidget from '@/components/content-blocks/BasicKnowledgeWidget.vue';
|
import BasicKnowledgeWidget from '@/components/content-blocks/BasicKnowledgeWidget';
|
||||||
import Task from '@/components/content-blocks/Task.vue';
|
import Task from '@/components/content-blocks/Task';
|
||||||
import ImageBlock from '@/components/content-blocks/ImageBlock.vue';
|
import ImageBlock from '@/components/content-blocks/ImageBlock';
|
||||||
import StudentEntry from '@/components/content-blocks/StudentEntry.vue';
|
import VideoBlock from '@/components/content-blocks/VideoBlock';
|
||||||
|
import StudentEntry from '@/components/content-blocks/StudentEntry';
|
||||||
import AddContentBlockButton from '@/components/AddContentBlockButton';
|
import AddContentBlockButton from '@/components/AddContentBlockButton';
|
||||||
import EyeIcon from '@/components/icons/EyeIcon';
|
import EyeIcon from '@/components/icons/EyeIcon';
|
||||||
|
|
||||||
|
|
@ -39,6 +40,7 @@
|
||||||
'basic_knowledge': BasicKnowledgeWidget,
|
'basic_knowledge': BasicKnowledgeWidget,
|
||||||
'student_entry': StudentEntry,
|
'student_entry': StudentEntry,
|
||||||
'image_block': ImageBlock,
|
'image_block': ImageBlock,
|
||||||
|
'video_block': VideoBlock,
|
||||||
Task,
|
Task,
|
||||||
AddContentBlockButton,
|
AddContentBlockButton,
|
||||||
EyeIcon
|
EyeIcon
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import ContentBlockChooserWidget from '@/components/ContentBlockChooserWidget';
|
import ContentBlockChooserWidget from '@/components/content-forms/ContentBlockChooserWidget';
|
||||||
import ContentBlockTitleInput from '@/components/ContentBlockTitleInput';
|
import ContentBlockTitleInput from '@/components/ContentBlockTitleInput';
|
||||||
import AddContentElement from '@/components/AddContentElement';
|
import AddContentElement from '@/components/AddContentElement';
|
||||||
import LinkForm from '@/components/content-forms/LinkForm';
|
import LinkForm from '@/components/content-forms/LinkForm';
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
switch (element.type) {
|
switch (element.type) {
|
||||||
case 'link':
|
case 'link':
|
||||||
return 'link-form';
|
return 'link-form';
|
||||||
case 'video':
|
case 'video_block':
|
||||||
return 'video-form';
|
return 'video-form';
|
||||||
case 'image':
|
case 'image':
|
||||||
return 'image-form';
|
return 'image-form';
|
||||||
|
|
@ -124,6 +124,12 @@
|
||||||
url: ''
|
url: ''
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case 'video_block':
|
||||||
|
el = {
|
||||||
|
...el,
|
||||||
|
url: ''
|
||||||
|
};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.elements.splice(index, 1, el);
|
this.elements.splice(index, 1, el);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<template>
|
||||||
|
<div class="video-block">
|
||||||
|
<youtube-embed v-if="isYoutube" :url="value.url"></youtube-embed>
|
||||||
|
<vimeo-embed v-if="isVimeo" :url="value.url"></vimeo-embed>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
||||||
|
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
||||||
|
import {isVimeoUrl, isYoutubeUrl} from '@/helpers/video';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['value'],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
YoutubeEmbed,
|
||||||
|
VimeoEmbed
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isYoutube() {
|
||||||
|
return isYoutubeUrl(this.value.url);
|
||||||
|
},
|
||||||
|
isVimeo() {
|
||||||
|
return isVimeoUrl(this.value.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.video-block {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<link-icon class="content-block-chooser-widget__link-icon"></link-icon>
|
<link-icon class="content-block-chooser-widget__link-icon"></link-icon>
|
||||||
<div class="content-block-chooser-widget__link-title">Link</div>
|
<div class="content-block-chooser-widget__link-title">Link</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-block-chooser-widget__link" v-on:click="$emit('change-type', index, 'video')">
|
<div class="content-block-chooser-widget__link" v-on:click="$emit('change-type', index, 'video_block')">
|
||||||
<video-icon class="content-block-chooser-widget__link-icon"></video-icon>
|
<video-icon class="content-block-chooser-widget__link-icon"></video-icon>
|
||||||
<div class="content-block-chooser-widget__link-title">Video</div>
|
<div class="content-block-chooser-widget__link-title">Video</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -15,14 +15,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isYoutube">
|
<div v-if="isYoutube">
|
||||||
<iframe id="ytplayer" type="text/html"
|
<youtube-embed :url="url"></youtube-embed>
|
||||||
rel="0"
|
|
||||||
:src="`https://www.youtube.com/embed/${videoId}`"
|
|
||||||
frameborder="0"></iframe>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isVimeo">
|
<div v-if="isVimeo">
|
||||||
<iframe :src="`https://player.vimeo.com/video/${videoId}`" frameborder="0"
|
<vimeo-embed :url="url"></vimeo-embed>
|
||||||
webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -30,32 +26,25 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import InfoIcon from '@/components/icons/InfoIcon';
|
import InfoIcon from '@/components/icons/InfoIcon';
|
||||||
|
import YoutubeEmbed from '@/components/videos/YoutubeEmbed';
|
||||||
const YOUTUBE = /^(?:https:\/\/)?(?:www.)?youtube.com\/watch\?v=([a-zA-Z0-9]*)$/;
|
import VimeoEmbed from '@/components/videos/VimeoEmbed';
|
||||||
const VIMEO = /^(?:https:\/\/)?(?:www.)?vimeo.com\/([a-zA-Z0-9]*)$/;
|
import {isVimeoUrl, isYoutubeUrl} from '@/helpers/video';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['url', 'index'],
|
props: ['url', 'index'],
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
InfoIcon
|
InfoIcon,
|
||||||
|
YoutubeEmbed,
|
||||||
|
VimeoEmbed
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
isYoutube() {
|
isYoutube() {
|
||||||
return YOUTUBE.test(this.url);
|
return isYoutubeUrl(this.url);
|
||||||
},
|
},
|
||||||
isVimeo() {
|
isVimeo() {
|
||||||
return VIMEO.test(this.url);
|
return isVimeoUrl(this.url);
|
||||||
},
|
|
||||||
videoId() {
|
|
||||||
if (this.isYoutube) {
|
|
||||||
return YOUTUBE.exec(this.url)[1];
|
|
||||||
} else if (this.isVimeo) {
|
|
||||||
return VIMEO.exec(this.url)[1];
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,9 +84,5 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iframe {
|
|
||||||
width: 100%;
|
|
||||||
height: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<template>
|
||||||
|
<iframe class="vimeo-embed" :src="`https://player.vimeo.com/video/${videoId}`" frameborder="0"
|
||||||
|
webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {getVideoId} from '@/helpers/video';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['url'],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
videoId() {
|
||||||
|
return getVideoId(this.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.vimeo-embed {
|
||||||
|
width: 100%;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<iframe class="youtube-embed" id="ytplayer" type="text/html"
|
||||||
|
rel="0"
|
||||||
|
:src="`https://www.youtube.com/embed/${videoId}`"
|
||||||
|
frameborder="0"></iframe>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {getVideoId} from '@/helpers/video';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['url'],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
videoId() {
|
||||||
|
return getVideoId(this.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.youtube-embed {
|
||||||
|
width: 100%;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
const YOUTUBE = /^(?:https:\/\/)?(?:www.)?youtube.com\/watch\?v=([a-zA-Z0-9_-]{11})$/;
|
||||||
|
const VIMEO = /^(?:https:\/\/)?(?:www.)?vimeo.com\/([a-zA-Z0-9]*)$/;
|
||||||
|
|
||||||
|
export function isYoutubeUrl(url) {
|
||||||
|
return YOUTUBE.test(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVimeoUrl(url) {
|
||||||
|
return VIMEO.test(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVideoId(url) {
|
||||||
|
if (isYoutubeUrl(url)) {
|
||||||
|
return YOUTUBE.exec(url)[1];
|
||||||
|
} else if (isVimeoUrl(url)) {
|
||||||
|
return VIMEO.exec(url)[1];
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,6 +31,11 @@ class StudentEntryBlock(blocks.StructBlock):
|
||||||
task_text = blocks.RichTextBlock()
|
task_text = blocks.RichTextBlock()
|
||||||
|
|
||||||
|
|
||||||
|
# 'video_block'
|
||||||
|
class VideoBlock(blocks.StructBlock):
|
||||||
|
url = blocks.URLBlock()
|
||||||
|
|
||||||
|
|
||||||
# 'text_block' 'task' 'basic_knowledge' 'student_entry' 'image_block'
|
# 'text_block' 'task' 'basic_knowledge' 'student_entry' 'image_block'
|
||||||
#
|
#
|
||||||
# url = blocks.URLBlock()
|
# url = blocks.URLBlock()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from wagtail.admin.edit_handlers import FieldPanel, TabbedInterface, ObjectList,
|
||||||
from wagtail.core.fields import StreamField
|
from wagtail.core.fields import StreamField
|
||||||
from wagtail.images.blocks import ImageChooserBlock
|
from wagtail.images.blocks import ImageChooserBlock
|
||||||
|
|
||||||
from book.blocks import TextBlock, BasicKnowledgeBlock, StudentEntryBlock, LinkBlock
|
from book.blocks import TextBlock, BasicKnowledgeBlock, StudentEntryBlock, LinkBlock, VideoBlock
|
||||||
from core.wagtail_utils import StrictHierarchyPage
|
from core.wagtail_utils import StrictHierarchyPage
|
||||||
from user.models import UserGroup
|
from user.models import UserGroup
|
||||||
|
|
||||||
|
|
@ -35,7 +35,8 @@ class ContentBlock(StrictHierarchyPage):
|
||||||
('student_entry', StudentEntryBlock(icon='download')),
|
('student_entry', StudentEntryBlock(icon='download')),
|
||||||
('image_block', ImageChooserBlock(icon='image')),
|
('image_block', ImageChooserBlock(icon='image')),
|
||||||
('link_block', LinkBlock(icon='link')),
|
('link_block', LinkBlock(icon='link')),
|
||||||
('task', TextBlock(icon='tick'))
|
('task', TextBlock(icon='tick')),
|
||||||
|
('video_block', VideoBlock(icon='media')),
|
||||||
], null=True, blank=True)
|
], null=True, blank=True)
|
||||||
|
|
||||||
type = models.CharField(
|
type = models.CharField(
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,11 @@ def handle_content_blocks(content_data):
|
||||||
elif content['type'] == 'task':
|
elif content['type'] == 'task':
|
||||||
pass
|
pass
|
||||||
elif content['type'] == 'video_block':
|
elif content['type'] == 'video_block':
|
||||||
pass
|
new_contents.append({
|
||||||
|
'type': 'video_block',
|
||||||
|
'value': {
|
||||||
|
'url': bleach.clean(content['url'])
|
||||||
|
}})
|
||||||
elif content['type'] == 'document_block':
|
elif content['type'] == 'document_block':
|
||||||
pass
|
pass
|
||||||
return new_contents
|
return new_contents
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue