Add subtitle block to user content block form

This commit is contained in:
Ramon Wenger 2022-02-03 16:24:46 +01:00
parent c3bac02826
commit 1112c6754e
13 changed files with 134 additions and 31 deletions

View File

@ -57,7 +57,7 @@
<content-block
:content-block="contentBlock"
:parent="chapter.id"
:parent="chapter"
:edit-mode="editMode"
v-for="contentBlock in filteredContentBlocks"
:key="contentBlock.id"

View File

@ -52,6 +52,7 @@
const DocumentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/DocumentForm');
const AssignmentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/AssignmentForm');
const TextForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/TextForm');
const SubtitleForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/SubtitleForm');
const CHOOSER = 'content-block-element-chooser-widget';
@ -73,6 +74,7 @@
DocumentForm,
AssignmentForm,
TextForm,
SubtitleForm
},
computed: {
@ -96,6 +98,12 @@
methods: {
getType(element) {
switch (element.type) {
case 'subtitle':
return {
component: 'subtitle-form',
title: 'Untertitel',
icon: 'title-icon'
};
case 'link_block':
return {
component: 'link-form',
@ -168,6 +176,14 @@
value: Object.assign({}, value),
};
switch (type) {
case 'subtitle':
el = {
...el,
value: {
text: '',
},
};
break;
case 'text_block':
el = {
...el,

View File

@ -137,7 +137,7 @@ export default {
</script>
<style lang="scss" scoped>
@import "@/styles/_variables.scss";
@import "~styles/helpers";
.content-component {
position: relative;

View File

@ -12,7 +12,7 @@
computed: {
sanitizedText() {
// todo: we can't just sanitize, because there are some elements in there that come from the server
// don't need to sanitize the input, server does this
return this.value.text;
}
}

View File

@ -18,6 +18,16 @@
:class="{'content-block-element-chooser-widget--no-assignment': hideAssignment}"
class="content-block-element-chooser-widget"
>
<div
class="content-block-element-chooser-widget__link content-block-element-chooser-widget__link--subtitle"
data-cy="choose-subtitle-widget"
@click="changeType('subtitle')"
>
<title-icon class="content-block-element-chooser-widget__link-icon" />
<div class="content-block-element-chooser-widget__link-title">
Untertitel
</div>
</div>
<div
class="content-block-element-chooser-widget__link content-block-element-chooser-widget__link--link"
data-cy="choose-link-widget"
@ -87,6 +97,7 @@
import Checkbox from '@/components/ui/Checkbox';
import formElementIcons from '@/components/ui/form-element-icons';
import TitleIcon from '@/components/icons/TitleIcon';
export default {
props: {
@ -103,6 +114,7 @@
},
components: {
TitleIcon,
Checkbox,
...formElementIcons
},
@ -131,8 +143,8 @@
@supports (display: grid) {
display: grid;
}
grid-template-columns: repeat(6, 1fr);
-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(7, 1fr);
-ms-grid-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-column-gap: 0px;
font-family: $sans-serif-font-family;
text-align: center;

View File

@ -0,0 +1,49 @@
<template>
<div class="subtitle-form">
<input-with-label
:value="text"
class="subtitle-form__input"
data-cy="subtitle-form-input"
label="Text"
placeholder="z.b. Vor dem Lesen"
@input="$emit('change-text', $event)"
/>
</div>
</template>
<script>
import InputWithLabel from '@/components/ui/InputWithLabel';
export default {
props: {
value: {
type: Object,
default: null,
validator(value) {
return Object.prototype.hasOwnProperty.call(value, 'text');
}
},
index: {
type: Number,
default: -1
}
},
components: {InputWithLabel},
computed: {
text() {
return this.value.text;
}
}
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
.subtitle-form {
&__input {
width: 100%;
}
}
</style>

View File

@ -0,0 +1,14 @@
<template>
<svg
width="50"
height="50"
viewBox="0 0 50 50"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M40.875 6.50635H9.125C8.96084 6.50634 8.79829 6.53866 8.64663 6.60147C8.49497 6.66429 8.35716 6.75636 8.24109 6.87244C8.12501 6.98851 8.03294 7.12632 7.97013 7.27798C7.90731 7.42964 7.87499 7.59219 7.875 7.75635V13.8828C7.875 14.2143 8.0067 14.5323 8.24112 14.7667C8.47554 15.0011 8.79348 15.1328 9.125 15.1328C9.45652 15.1328 9.77446 15.0011 10.0089 14.7667C10.2433 14.5323 10.375 14.2143 10.375 13.8828V9.00635H23.75V40.9936H18.4312C18.0996 40.9936 17.7817 41.1253 17.5473 41.3598C17.3128 41.5942 17.1812 41.9121 17.1812 42.2436C17.1812 42.5752 17.3128 42.8931 17.5473 43.1275C17.7817 43.3619 18.0996 43.4936 18.4312 43.4936H31.5688C31.9004 43.4936 32.2183 43.3619 32.4527 43.1275C32.6872 42.8931 32.8189 42.5752 32.8189 42.2436C32.8189 41.9121 32.6872 41.5942 32.4527 41.3598C32.2183 41.1253 31.9004 40.9936 31.5688 40.9936H26.25V9.00635H39.625V13.8828C39.625 14.2143 39.7567 14.5323 39.9911 14.7667C40.2255 15.0011 40.5435 15.1328 40.875 15.1328C41.2065 15.1328 41.5245 15.0011 41.7589 14.7667C41.9933 14.5323 42.125 14.2143 42.125 13.8828V7.75635C42.125 7.59219 42.0927 7.42964 42.0299 7.27798C41.9671 7.12632 41.875 6.98851 41.7589 6.87244C41.6428 6.75636 41.505 6.66429 41.3534 6.60147C41.2017 6.53866 41.0392 6.50634 40.875 6.50635V6.50635Z"
fill="#333333"
/>
</svg>
</template>

View File

@ -4,6 +4,7 @@ const ImageIcon = () => import(/* webpackChunkName: "icons" */'@/components/icon
const TextIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TextIcon');
const SpeechBubbleIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/SpeechBubbleIcon');
const DocumentIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/DocumentIcon');
const TitleIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TitleIcon');
export default {
LinkIcon,
@ -11,5 +12,6 @@ export default {
ImageIcon,
TextIcon,
SpeechBubbleIcon,
DocumentIcon
DocumentIcon,
TitleIcon
};

View File

@ -43,7 +43,7 @@ export default function (uri, networkErrorCallback) {
return forward(operation);
});
const errorLink = onError(({networkError, graphQLErrors, forward, operation}) => {
const errorLink = onError(({networkError, graphQLErrors}) => {
if (networkError && networkErrorCallback) {
networkErrorCallback(networkError.statusCode);
}

View File

@ -96,7 +96,7 @@ function redirectUsersToOnboarding() {
function networkErrorCallback(statusCode) {
if (statusCode === 402) {
Vue.$log.debug('status code 402, redirecting');
router.push({name: 'licenseActivation'}, 0);
router.push({name: 'licenseActivation'});
}
}

View File

@ -12,6 +12,7 @@ class InputTypes(graphene.Enum):
video_block = 'video_block'
document_block = 'document_block'
content_list_item = 'content_list_item'
subtitle= 'subtitle'
class ContentElementValueInput(InputObjectType):

View File

@ -34,7 +34,8 @@ ALLOWED_BLOCKS = (
'video_block',
'assignment',
'document_block',
'content_list_item'
'content_list_item',
'subtitle'
)
@ -101,6 +102,13 @@ def handle_content_block(content, context=None, module=None, allowed_blocks=ALLO
'value': {
'url': bleach.clean(content['value']['url'])
}}
elif content['type'] == 'subtitle':
return {
'type': 'subtitle',
'value': {
'text': bleach.clean(content['value']['text'])
}
}
elif content['type'] == 'content_list_item':
return {
'type': 'content_list_item',

View File

@ -478,6 +478,7 @@ enum InputTypes {
video_block
document_block
content_list_item
subtitle
}
type InstrumentBookmarkNode implements Node {