Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
v-model="answer.answer"
class="editor"
:mode="isAnswerOpen(answerIdx) ? 'edit' : 'view'"
:imageProcessor="EditorImageProcessor"
@update="updateAnswerText($event, answerIdx)"
@minimize="emitClose"
@open-editor="emitOpen(answerIdx)"
Expand Down Expand Up @@ -127,6 +128,7 @@
import { AssessmentItemTypes } from 'shared/constants';
import { swapElements } from 'shared/utils/helpers';
import Checkbox from 'shared/views/form/Checkbox';
import EditorImageProcessor from 'shared/views/TipTapEditor/TipTapEditor/services/imageService';

import TipTapEditor from 'shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue';

Expand Down Expand Up @@ -169,6 +171,7 @@
},
data() {
return {
EditorImageProcessor, // Make it available in the template
correctAnswersIndices: getCorrectAnswersIndices(this.questionKind, this.answers),
numericRule: val => floatOrIntRegex.test(val) || this.$tr('numberFieldErrorLabel'),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,124 +1,119 @@
<template>

<Uploader
ref="uploader"
:presetID="imagePreset"
>
<template #default="{ handleFiles }">
<VLayout>
<DropdownWrapper
component="VFlex"
xs7
lg5
>
<template #default="{ attach, menuProps }">
<VSelect
:key="kindSelectKey"
:items="kindSelectItems"
:value="kind"
:label="$tr('questionTypeLabel')"
data-test="kindSelect"
:menu-props="menuProps"
:attach="attach"
box
@input="onKindUpdate"
/>
</template>
</DropdownWrapper>
</VLayout>

<VLayout>
<VFlex>
<ErrorList
:errors="questionErrorMessages"
data-test="questionErrors"
<div>
<VLayout>
<DropdownWrapper
component="VFlex"
xs7
lg5
>
<template #default="{ attach, menuProps }">
<VSelect
:key="kindSelectKey"
:items="kindSelectItems"
:value="kind"
:label="$tr('questionTypeLabel')"
data-test="kindSelect"
:menu-props="menuProps"
:attach="attach"
box
@input="onKindUpdate"
/>
</template>
</DropdownWrapper>
</VLayout>

<VLayout>
<VFlex>
<ErrorList
:errors="questionErrorMessages"
data-test="questionErrors"
/>

<div class="grey--text mb-1 text--darken-2">
{{ $tr('questionLabel') }}
</div>

<transition name="fade">
<keep-alive include="TipTapEditor">
<!--analyticsLabel="Question"-->
<TipTapEditor
v-if="isQuestionOpen"
v-model="question"
mode="edit"
:imageProcessor="EditorImageProcessor"
@update="onQuestionUpdate"
@minimize="closeQuestion"
/>

<div class="grey--text mb-1 text--darken-2">
{{ $tr('questionLabel') }}
</div>

<transition name="fade">
<keep-alive include="TipTapEditor">
<!--analyticsLabel="Question"-->
<TipTapEditor
v-if="isQuestionOpen"
v-model="question"
mode="edit"
@update="onQuestionUpdate"
@minimize="closeQuestion"
/>

<div
v-else
class="pb-3 pl-2 pr-2 pt-3 question-text"
data-test="questionText"
@click="openQuestion"
<div
v-else
class="pb-3 pl-2 pr-2 pt-3 question-text"
data-test="questionText"
@click="openQuestion"
>
<VLayout
align-start
justify-space-between
>
<VLayout
align-start
justify-space-between
>
<VFlex grow>
<TipTapEditor
v-model="question"
mode="view"
tabindex="-1"
<VFlex grow>
<TipTapEditor
v-model="question"
mode="view"
tabindex="-1"
/>
</VFlex>

<VFlex shrink>
<button
class="v-btn v-btn--flat v-btn--icon v-size--default"
data-test="editQuestionButton"
@click.stop="openQuestion"
>
<Icon
:color="$themePalette.grey.v_800"
icon="edit"
class="mr-2"
/>
</VFlex>

<VFlex shrink>
<button
class="v-btn v-btn--flat v-btn--icon v-size--default"
data-test="editQuestionButton"
@click.stop="openQuestion"
>
<Icon
:color="$themePalette.grey.v_800"
icon="edit"
class="mr-2"
/>
</button>
</VFlex>
</VLayout>
</div>
</keep-alive>
</transition>
</VFlex>
</VLayout>

<VLayout
v-if="kind !== AssessmentItemTypes.FREE_RESPONSE"
mt-4
>
<VFlex>
<ErrorList
:errors="answersErrorMessages"
data-test="answersErrors"
/>

<AnswersEditor
:questionKind="kind"
:answers="answers"
:openAnswerIdx="openAnswerIdx"
@update="onAnswersUpdate"
@open="openAnswer"
@close="closeAnswer"
/>

<HintsEditor
class="mt-4"
:hints="hints"
:openHintIdx="openHintIdx"
:handleFileUpload="handleFiles"
@update="onHintsUpdate"
@open="openHint"
@close="closeHint"
/>
</VFlex>
</VLayout>
</template>
</Uploader>
</button>
</VFlex>
</VLayout>
</div>
</keep-alive>
</transition>
</VFlex>
</VLayout>

<VLayout
v-if="kind !== AssessmentItemTypes.FREE_RESPONSE"
mt-4
>
<VFlex>
<ErrorList
:errors="answersErrorMessages"
data-test="answersErrors"
/>

<AnswersEditor
:questionKind="kind"
:answers="answers"
:openAnswerIdx="openAnswerIdx"
@update="onAnswersUpdate"
@open="openAnswer"
@close="closeAnswer"
/>

<HintsEditor
class="mt-4"
:hints="hints"
:openHintIdx="openHintIdx"
@update="onHintsUpdate"
@open="openHint"
@close="closeHint"
/>
</VFlex>
</VLayout>
</div>

</template>

Expand All @@ -139,10 +134,9 @@
FeatureFlagKeys,
} from 'shared/constants';
import ErrorList from 'shared/views/ErrorList/ErrorList';
import Uploader from 'shared/views/files/Uploader';
import { FormatPresetsNames } from 'shared/leUtils/FormatPresets';
import DropdownWrapper from 'shared/views/form/DropdownWrapper';
import TipTapEditor from 'shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue';
import EditorImageProcessor from 'shared/views/TipTapEditor/TipTapEditor/services/imageService';

export default {
name: 'AssessmentItemEditor',
Expand All @@ -151,7 +145,6 @@
ErrorList,
AnswersEditor,
HintsEditor,
Uploader,
TipTapEditor,
},
model: {
Expand Down Expand Up @@ -212,6 +205,7 @@
openAnswerIdx: null,
kindSelectKey: 0,
AssessmentItemTypes,
EditorImageProcessor,
};
},
computed: {
Expand All @@ -224,9 +218,6 @@

return this.item.question;
},
imagePreset() {
return FormatPresetsNames.EXERCISE_IMAGE;
},
modality() {
return this.getContentNode(this.nodeId)?.extra_fields?.options?.modality;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<TipTapEditor
v-model="hint.hint"
:mode="isHintOpen(hintIdx) ? 'edit' : 'view'"
:image-processor="EditorImageProcessor"
@update="updateHintText($event, hintIdx)"
@minimize="emitClose"
@open-editor="emitOpen(answerIdx)"
Expand Down Expand Up @@ -82,6 +83,7 @@
import AssessmentItemToolbar from '../AssessmentItemToolbar';
import { AssessmentItemToolbarActions } from '../../constants';
import { swapElements } from 'shared/utils/helpers';
import EditorImageProcessor from 'shared/views/TipTapEditor/TipTapEditor/services/imageService';

import TipTapEditor from 'shared/views/TipTapEditor/TipTapEditor/TipTapEditor.vue';

Expand Down Expand Up @@ -121,6 +123,7 @@
AssessmentItemToolbarActions.MOVE_ITEM_DOWN,
AssessmentItemToolbarActions.DELETE_ITEM,
],
EditorImageProcessor,
};
},
methods: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
const { isMobile } = useBreakpoint();

const imageHandler = useImageHandling(editor);
provide('imageProcessor', props.imageProcessor);

const sharedEventHandlers = computed(() => ({
'insert-image': target => imageHandler.openCreateModal({ targetElement: target }),
Expand Down Expand Up @@ -294,6 +295,10 @@
type: [String, Number],
default: 0,
},
imageProcessor: {
type: Object,
default: () => ({}),
},
},
emits: ['update', 'minimize', 'open-editor'],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ const MESSAGES = {
},

// Error Messages
errorUploadingImage: {
message: 'Error uploading image',
context: 'Title for the error modal when an image upload fails.',
},
noFileProvided: {
message: 'No file provided.',
context: 'Error message when no file is provided for upload',
Expand All @@ -321,6 +325,10 @@ const MESSAGES = {
message: 'Failed to process the image file.',
context: 'Error message when image processing fails',
},
noEnoughStorageSpace: {
message: 'Not enough storage space available. File size exceeds remaining storage.',
context: 'Error message when there is insufficient storage space for the file',
},

// for MobileFormattingBar
collapseFormattingBar: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,19 @@
if (imageRef.value && imageRef.value.naturalWidth && imageRef.value.naturalHeight) {
naturalAspectRatio.value = imageRef.value.naturalWidth / imageRef.value.naturalHeight;

// If no dimensions are set, use natural dimensions
// If no dimensions are set, use natural dimensions but constrain to editor width
if (!width.value && !height.value) {
width.value = imageRef.value.naturalWidth;
height.value = imageRef.value.naturalHeight;
// Get the editor's actual container width
const editorContainer = props.editor.view.dom.closest('.editor-container');
const editorWidth = editorContainer
? editorContainer.offsetWidth
: window.innerWidth * 0.4; // fallback: 40% of viewport width

const maxWidth = Math.min(imageRef.value.naturalWidth, editorWidth);

width.value = maxWidth;
height.value = Math.round(maxWidth / naturalAspectRatio.value);

saveSize();
} else if (width.value && !height.value) {
// If we have width but no height, calculate height
Expand Down
Loading