Skip to content

Commit

Permalink
Merge branch 'Simon-Initiative:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
dtiwarATS authored Sep 30, 2024
2 parents a98163d + a038083 commit 45faee0
Show file tree
Hide file tree
Showing 57 changed files with 5,752 additions and 422 deletions.
2 changes: 2 additions & 0 deletions assets/src/apps/Components.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Evaluation } from 'components/activities/common/delivery/evaluation/Evaluation';
import { LikertReportRenderer } from 'components/activities/likert/reports/LikerReportRenderer';
import { DeliveryElementRenderer } from 'components/common/DeliveryElementRenderer';
import { ECLRepl } from 'components/common/ECLRepl';
Expand Down Expand Up @@ -45,3 +46,4 @@ registerApplication('RichTextEditor', RichTextEditor, globalStore);
registerApplication('VegaLiteRenderer', VegaLiteRenderer, globalStore);
registerApplication('LikertReportRenderer', LikertReportRenderer, globalStore);
registerApplication('ActivityBank', ActivityBank, globalStore);
registerApplication('Evaluation', Evaluation, globalStore);
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ import { isDefined } from 'utils/common';

interface Props {
shouldShow?: boolean;
showExplanation?: boolean;
attemptState: ActivityState;
context: WriterContext;
partOrder?: string[];
}

export function renderPartFeedback(partState: PartState, context: WriterContext) {
export function renderPartFeedback(
partState: PartState,
context: WriterContext,
showExplanation: boolean,
) {
if (!partState.score && !partState.outOf) {
return null;
}
Expand All @@ -38,7 +43,7 @@ export function renderPartFeedback(partState: PartState, context: WriterContext)
direction={feedbackDirection}
/>
</Component>
{explanation && resultCl !== 'correct' && (
{showExplanation && explanation && resultCl !== 'correct' && (
<Component
key={`${partState.partId}-explanation`}
resultClass="explanation"
Expand All @@ -64,6 +69,7 @@ export function renderPartFeedback(partState: PartState, context: WriterContext)

export const Evaluation: React.FC<Props> = ({
shouldShow = true,
showExplanation = true,
attemptState,
context,
partOrder,
Expand All @@ -74,7 +80,7 @@ export const Evaluation: React.FC<Props> = ({
}

if (parts.length === 1) {
return renderPartFeedback(parts[0], context);
return renderPartFeedback(parts[0], context, showExplanation);
}

// part order for migrated multi-inputs may be random, so allow caller to specify appropriate one
Expand All @@ -84,7 +90,9 @@ export const Evaluation: React.FC<Props> = ({
if (newOrder.length === parts.length) orderedParts = newOrder;
}

return <>{orderedParts.map((partState) => renderPartFeedback(partState, context))}</>;
return (
<>{orderedParts.map((partState) => renderPartFeedback(partState, context, showExplanation))}</>
);
};

interface ComponentProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ export const FocusedFeedback: React.FC<FocusedFeedbackProps> = (props: FocusedFe
<React.Fragment>
{uiState.attemptState.parts.map((part) => (
<React.Fragment key={part.partId}>
{renderPartFeedback(part, writerContext)}
{renderPartFeedback(part, writerContext, true)}
</React.Fragment>
))}
</React.Fragment>
);
} else {
// otherwise, only render the currently focused part feedback
const part = uiState.attemptState.parts.find((ps) => ps.partId === focusedPart);
return part !== undefined ? renderPartFeedback(part, writerContext) : null;
return part !== undefined ? renderPartFeedback(part, writerContext, true) : null;
}
};
10 changes: 10 additions & 0 deletions assets/src/components/hooks/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,13 @@ export function useGlobalState(userId: number, active: boolean) {

return data;
}

declare global {
interface Window {
ReactToLiveView?: LiveViewHook;
}
}

interface LiveViewHook {
pushEvent: (event: string, payload: any) => void;
}
11 changes: 10 additions & 1 deletion assets/src/components/parts/janus-text-flow/Markup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,16 @@ const Markup: React.FC<any> = ({
if (renderStyles?.height === 'auto') {
renderStyles.height = '';
}
return <img src={src} ref={el} key={key} className={customCssClass} style={renderStyles} />;
return (
<img
src={src}
alt={`${text || ''}`}
ref={el}
key={key}
className={customCssClass}
style={renderStyles}
/>
);
case 'text':
// this is a special case similar to xml text nodes
// not expected to have children
Expand Down
210 changes: 117 additions & 93 deletions assets/src/components/parts/janus-text-flow/QuillEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useEffect } from 'react';
import React, { useEffect, useMemo, useRef } from 'react';
import ReactQuill, { Quill } from 'react-quill';
import Delta from 'quill-delta';
import register from '../customElementWrapper';
import { QuillImageUploader } from './QuillImageUploader';
import { convertJanusToQuill, convertQuillToJanus } from './quill-utils';

interface QuillEditorProps {
Expand Down Expand Up @@ -75,32 +76,6 @@ const fontStyles = `${getCssForFonts(supportedFonts)}
font-size: 18px !important;
}
`;

const customHandlers = {
adaptivity: function (value: string) {
const range = this.quill.getSelection();
let selectionValue = '';
if (range && range.length > 0) {
selectionValue = this.quill.getText(range.index, range.length);
if (selectionValue.charAt(0) === '{') {
selectionValue = selectionValue.substring(1, selectionValue.length - 1);
}
}
const expression = prompt('Enter the Expression', selectionValue);
if (expression) {
this.quill.insertText(range.index, `{${expression}}`);
this.quill.deleteText(range.index + expression.length + 2, expression.length + 2);
}
},
image: function (value: string) {
const range = this.quill.getSelection();
const expression = prompt('Enter the image URL', '');
if (expression) {
this.quill.insertEmbed(range.index, 'image', expression);
}
},
};

export const QuillEditor: React.FC<QuillEditorProps> = ({
tree,
html,
Expand All @@ -110,9 +85,49 @@ export const QuillEditor: React.FC<QuillEditorProps> = ({
onCancel,
showimagecontrol = false,
}) => {
const quill: any = useRef();
const [contents, setContents] = React.useState<any>(tree);
const [delta, setDelta] = React.useState<any>(convertJanusToQuill(tree));
const [currentQuillRange, setCurrentQuillRange] = React.useState<number>(0);
const [showImageSelectorDailog, setShowImageSelectorDailog] = React.useState<boolean>(false);
const customHandlers = {
adaptivity: function (value: string) {
const range = this.quill.getSelection();
let selectionValue = '';
if (range && range.length > 0) {
selectionValue = this.quill.getText(range.index, range.length);
if (selectionValue.charAt(0) === '{') {
selectionValue = selectionValue.substring(1, selectionValue.length - 1);
}
}
const expression = prompt('Enter the Expression', selectionValue);
if (expression) {
this.quill.insertText(range.index, `{${expression}}`);
this.quill.deleteText(range.index + expression.length + 2, expression.length + 2);
}
},
image: function (value: string) {
setShowImageSelectorDailog(true);
setCurrentQuillRange(this.quill.getSelection()?.index || 0);
},
};
const handleImageDetailsSave = (imageURL: string, imageAltText: string) => {
setShowImageSelectorDailog(false);
if (quill?.current) {
if (imageURL) {
const img = document.createElement('img');
img.src = imageURL;
img.alt = imageAltText;
// quill.insertEmbed does not allow inserting any additional attributes hence using dangerouslyPasteHTML function to set the Alt text
// This code only gets executed when user tries to add a Image in MCQ Options.
quill.current.editor.clipboard.dangerouslyPasteHTML(currentQuillRange, img.outerHTML);
}
}
};

const handleImageUploaderDailogClose = () => {
setShowImageSelectorDailog(false);
};
/* console.log('[QuillEditor]', { tree, html }); */

useEffect(() => {
Expand All @@ -138,6 +153,72 @@ export const QuillEditor: React.FC<QuillEditorProps> = ({
},
[onChange],
);
const modules = useMemo(
() => ({
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote' /* , 'code-block' */],

[{ list: 'ordered' }, { list: 'bullet' }],
[{ script: 'sub' }, { script: 'super' }], // superscript/subscript
[{ indent: '-1' }, { indent: '+1' }], // outdent/indent

[{ header: [1, 2, 3, 4, 5, 6, false] }],

[
{
color: [
'#000000',
'#e60000',
'#ff9900',
'#ffff00',
'#008a00',
'#0066cc',
'#9933ff',
'#ffffff',
'#facccc',
'#ffebcc',
'#ffffcc',
'#cce8cc',
'#cce0f5',
'#ebd6ff',
'#bbbbbb',
'#f06666',
'#ffc266',
'#ffff66',
'#66b966',
'#66a3e0',
'#c285ff',
'#888888',
'#a10000',
'#b26b00',
'#b2b200',
'#006100',
'#0047b2',
'#6b24b2',
'#444444',
'#5c0000',
'#663d00',
'#666600',
'#003700',
'#002966',
'#3d1466',
],
},
{ background: [] },
], // dropdown with defaults from theme
[{ font: FontAttributor.whitelist }, { size: ['10px', '12px', '14px', '16px', '18px'] }],
[{ align: [] }],
['link', 'adaptivity'],
['clean'], // remove formatting button
showimagecontrol ? ['image'] : [],
],
handlers: customHandlers,
},
}),
[],
);

return (
<React.Fragment>
Expand All @@ -154,73 +235,9 @@ export const QuillEditor: React.FC<QuillEditorProps> = ({
}}
>
<ReactQuill
ref={quill}
style={{ maxHeight: '100%' }}
modules={{
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote' /* , 'code-block' */],

[{ list: 'ordered' }, { list: 'bullet' }],
[{ script: 'sub' }, { script: 'super' }], // superscript/subscript
[{ indent: '-1' }, { indent: '+1' }], // outdent/indent

[{ header: [1, 2, 3, 4, 5, 6, false] }],

[
{
color: [
'#000000',
'#e60000',
'#ff9900',
'#ffff00',
'#008a00',
'#0066cc',
'#9933ff',
'#ffffff',
'#facccc',
'#ffebcc',
'#ffffcc',
'#cce8cc',
'#cce0f5',
'#ebd6ff',
'#bbbbbb',
'#f06666',
'#ffc266',
'#ffff66',
'#66b966',
'#66a3e0',
'#c285ff',
'#888888',
'#a10000',
'#b26b00',
'#b2b200',
'#006100',
'#0047b2',
'#6b24b2',
'#444444',
'#5c0000',
'#663d00',
'#666600',
'#003700',
'#002966',
'#3d1466',
],
},
{ background: [] },
], // dropdown with defaults from theme
[
{ font: FontAttributor.whitelist },
{ size: ['10px', '12px', '14px', '16px', '18px'] },
],
[{ align: [] }],
['link', 'adaptivity'],
['clean'], // remove formatting button
showimagecontrol ? ['image'] : [],
],
handlers: customHandlers,
},
}}
modules={modules}
defaultValue={delta}
onChange={handleQuillChange}
/>
Expand All @@ -231,6 +248,13 @@ export const QuillEditor: React.FC<QuillEditorProps> = ({
</>
)}
</div>
{
<QuillImageUploader
showImageSelectorDailog={showImageSelectorDailog}
handleImageDetailsSave={handleImageDetailsSave}
handleImageDailogClose={handleImageUploaderDailogClose}
></QuillImageUploader>
}
</React.Fragment>
);
};
Expand Down
Loading

0 comments on commit 45faee0

Please sign in to comment.