CLASSROOMIO-T-128: TinyMCE Editor Test

CLASSROOMIO-T-128: TinyMCE Integration

Merge branch 'main' into CLASSROOMIO-T-128

CLASSROOMIO-T-128: Resolved Fixes

CLASSROOMIO-T-128: Ts Errors

CLASSROOMIO-T-128: Resolved Feedbacks

CLASSROOMIO-T-128: Replace Quill with tinyMCE

CLASSROOMIO-T-128: Compare Editors

CLASSROOMIO-T-128: TinyMCE Editor Test


Co-authored-by: Rotimi Best <[email protected]>
Co-authored-by: Tunji Adeyemi <[email protected]>


Merge-request: CLASSROOMIO-MR-62
Merged-by: Best Admin <[email protected]>
This commit is contained in:
tunny17
2023-09-05 13:21:44 +00:00
committed by Space Cloud
co-authored by Rotimi Best
parent 0200bc46ac
commit 75479e9719
14 changed files with 168 additions and 1206 deletions
@@ -1,4 +1,5 @@
<script lang="ts">
import isEmpty from 'lodash/isEmpty';
import { useCompletion } from 'ai/svelte';
import MODES from '$lib/utils/constants/mode.js';
import TrashCanIcon from 'carbon-icons-svelte/lib/TrashCan.svelte';
@@ -16,8 +17,6 @@
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import TextField from '$lib/components/Form/TextField.svelte';
import TextEditor from '$lib/components/TextEditor/index.svelte';
// import ClEditor from '$lib/components/ClEditor/index.svelte';
import {
lesson,
lessons,
@@ -28,8 +27,8 @@
} from '$lib/components/Course/components/Lesson/store/lessons';
import VideoUploader from '$lib/components/Course/components/Lesson/Materials/Video/Index.svelte';
import { course } from '$lib/components/Course/store';
import TextEditor from '$lib/components/TextEditor/index.svelte';
import * as CONSTANTS from './constants';
import isEmpty from 'lodash/isEmpty';
export let mode = MODES.view;
export let prevMode = '';
@@ -41,7 +40,7 @@
let tabs = CONSTANTS.tabs;
let currentTab = tabs[0].value;
let errors = {};
let textareaRef = {};
let editorWindowRef;
let aiButtonRef = {};
let openPopover = false;
let player = null;
@@ -108,9 +107,10 @@
function updateNoteByCompletion(completion) {
$lesson.materials.note = completion;
if (textareaRef && textareaRef?.children?.[0]) {
let qlEditor = textareaRef?.children?.[0];
qlEditor.scrollTop = qlEditor.scrollHeight;
if (editorWindowRef) {
const tmceBody = editorWindowRef?.document?.querySelector('body');
editorWindowRef?.scrollTo(0, tmceBody?.scrollHeight);
}
}
@@ -230,13 +230,13 @@
</PrimaryButton>
</div>
<div class="h-[60vh]">
<div class="h-[60vh] mt-5">
<TextEditor
bind:container={textareaRef}
bind:content={$lesson.materials.note}
onChange={(c) => ($lesson.materials.note = c)}
bind:editorWindowRef
value={$lesson.materials.note}
onChange={(html) => ($lesson.materials.note = html)}
placeholder="Write your lesson note here"
/>
<!-- <ClEditor bind:html={$lesson.materials.note} /> -->
</div>
{:else if !isNoteEmpty($lesson.materials?.note)}
<article class="preview prose prose-sm sm:prose p-2">
+6 -5
View File
@@ -1,14 +1,13 @@
<script>
import TextEditor from '$lib/components/TextEditor/index.svelte';
import { marked } from 'marked';
import RoleBasedSecurity from '../RoleBasedSecurity/index.svelte';
import PageNav from '../PageNav/index.svelte';
import MODES from '$lib/utils/constants/mode';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import PageBody from '../PageBody/index.svelte';
import EditContent from '../EditContent/index.svelte';
import { course } from './store';
import { updateCourse } from '$lib/utils/services/courses';
import TextEditor from '$lib/components/TextEditor/index.svelte';
let mode = MODES.view;
let isDirty = false;
@@ -43,11 +42,13 @@
<PageBody width="max-w-3xl px-3">
{#if mode === MODES.edit}
<TextEditor
bind:content={$course.overview}
onChange={(c) => {
$course.overview = c;
value={$course.overview}
onChange={(html) => {
isDirty = true;
$course.overview = html;
}}
placeholder="Write your overview here"
height="700"
/>
{:else}
<article class="preview prose prose-sm sm:prose p-2">
@@ -5,15 +5,14 @@
import TextEditor from '$lib/components/TextEditor/index.svelte';
export let course;
function handleChange(html) {
const _course = cloneDeep(course);
set(_course, 'metadata.description', html);
course = _course;
}
</script>
<div class="h-2/5">
<TextEditor
content={get(course, 'metadata.description')}
onChange={(html) => {
const _course = cloneDeep(course);
set(_course, 'metadata.description', html);
course = _course;
}}
/>
<TextEditor value={get(course, 'metadata.description')} onChange={handleChange} />
</div>
@@ -5,15 +5,14 @@
import TextEditor from '$lib/components/TextEditor/index.svelte';
export let course;
function handleChange(html) {
const _course = cloneDeep(course);
set(_course, 'metadata.goals', html);
course = _course;
}
</script>
<div class="h-2/5">
<TextEditor
content={get(course, 'metadata.goals')}
onChange={(html) => {
const _course = cloneDeep(course);
set(_course, 'metadata.goals', html);
course = _course;
}}
/>
<TextEditor value={get(course, 'metadata.goals')} onChange={handleChange} />
</div>
@@ -4,8 +4,8 @@
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import { Toggle } from 'carbon-components-svelte';
import TextEditor from '$lib/components/TextEditor/index.svelte';
import TextField from '$lib/components/Form/TextField.svelte';
import TextEditor from '$lib/components/TextEditor/index.svelte';
export let course = {};
@@ -34,6 +34,12 @@
course = _course;
}
function handleChange(html) {
const _course = cloneDeep(course);
set(_course, 'metadata.reward.description', html);
course = _course;
}
$: setter(showDiscount, 'metadata.showDiscount');
$: setter(discount, 'metadata.discount');
$: setter(giftToggled, 'metadata.reward.show');
@@ -88,13 +94,6 @@
<p class="dark:text-white font-bold mt-5">About Gift</p>
<div class="h-2/5">
<TextEditor
content={get(course, 'metadata.reward.description')}
onChange={(html) => {
const _course = cloneDeep(course);
set(_course, 'metadata.reward.description', html);
course = _course;
}}
/>
<TextEditor value={get(course, 'metadata.reward.description')} onChange={handleChange} />
</div>
{/if}
@@ -5,15 +5,14 @@
import TextEditor from '$lib/components/TextEditor/index.svelte';
export let course;
function handleChange(html) {
const _course = cloneDeep(course);
set(_course, 'metadata.requirements', html);
course = _course;
}
</script>
<div class="h-2/5">
<TextEditor
content={get(course, 'metadata.requirements')}
onChange={(html) => {
const _course = cloneDeep(course);
set(_course, 'metadata.requirements', html);
course = _course;
}}
/>
<TextEditor value={get(course, 'metadata.requirements')} onChange={handleChange} />
</div>
+34 -123
View File
@@ -1,130 +1,41 @@
<script>
import { onMount } from 'svelte';
import { PUBLIC_TINYMCE_API_KEY } from '$env/static/public';
import Editor from '@tinymce/tinymce-svelte';
export let onChange;
export let content;
export let disable;
export let docId;
export let placeholder = 'Type something...';
export let errorMessage;
export let container;
export let value;
export let onChange = (html = '') => {};
export let height = 300;
export let placeholder = '';
export let editorWindowRef;
const settings = {
modules: {
toolbar: {
modules: {
syntax: true,
toolbar: [
[{ header: [1, 2, 3, false] }],
['bold', 'italic', 'underline', 'strike'],
['link', 'code-block']
]
},
placeholder: 'Type something...',
theme: 'snow'
}
},
theme: 'snow',
placeholder
const apiKey = PUBLIC_TINYMCE_API_KEY;
// editor configuration
let conf = {
plugins: 'lists',
toolbar: [
{ name: 'history', items: ['undo', 'redo'] },
{ name: 'styles', items: ['styles'] },
{ name: 'formatting', items: ['bold', 'italic'] },
{ name: 'alignment', items: ['alignleft', 'aligncenter', 'alignright', 'alignjustify'] },
{ name: 'indentation', items: ['outdent', 'indent'] },
{ name: 'list', items: ['numlist', 'bullist'] }
],
lists_indent_on_tab: false,
min_height: height,
placeholder: placeholder,
init_instance_callback: function (editor) {
editorWindowRef = editor.iframeElement?.contentWindow;
editor.on('Input', function (e) {
const html = editor.getContent();
if (onChange) {
onChange(html);
}
});
}
};
let quill = null;
let isUserTyping = false;
function resetContent(docId) {
if (quill && quill.setText) {
if (content) {
quill.setContents(JSON.parse(content));
} else {
quill.setText('');
}
}
}
function setQuillHTML(html) {
if (quill) {
quill.setHTML(html);
}
}
onMount(async () => {
const { default: Quill } = await import('quill');
Quill.prototype.getHTML = function () {
return this.container.querySelector('.ql-editor').innerHTML;
};
Quill.prototype.setHTML = function (html) {
this.container.querySelector('.ql-editor').innerHTML = html;
};
quill = new Quill(container, settings);
quill.setHTML(content || '');
quill.on('text-change', function () {
onChange(quill.getHTML());
});
quill.getModule('toolbar').container.addEventListener('mousedown', (e) => {
e.preventDefault();
isUserTyping = true;
});
quill.root.addEventListener('focus', () => {
isUserTyping = true;
});
quill.root.addEventListener('blur', () => {
isUserTyping = false;
});
});
$: {
if (quill && quill.setText) {
if (disable) {
quill.disable(disable);
} else {
quill.enable(true);
}
}
}
$: if (!isUserTyping) {
setQuillHTML(content);
}
$: resetContent(docId);
</script>
<div class="p-2 w-full h-full">
<div bind:this={container} />
{#if errorMessage}
<p class="dark:text-white text-red-500 text-sm">
{errorMessage}
</p>
{/if}
<div>
<Editor onIni {value} {apiKey} {conf} />
</div>
<style>
:global(.dark .ql-stroke) {
stroke: #fff;
}
:global(.dark .ql-snow .ql-picker) {
color: #fff;
}
:global(.dark .ql-editor.ql-blank::before) {
color: #fff;
}
:global(.ql-editor) {
white-space: normal !important;
}
:global(.ql-editor p),
:global(.ql-editor h1),
:global(.ql-editor h2),
:global(.ql-editor h3),
:global(.ql-editor h4) {
line-height: 2.2;
}
</style>