From f09f97c9a20d165403415cfaec44c89277c475cf Mon Sep 17 00:00:00 2001 From: Ger Hean Date: Sun, 24 Mar 2019 12:15:06 +0800 Subject: [PATCH 1/2] fix import for firefox --- .../TextareaContent.tsx | 20 +++++++++---------- src/utils/xmlParser.ts | 19 +++++++++++++----- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx b/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx index 27a0f9a4ea..613b477cb8 100644 --- a/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx +++ b/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx @@ -35,20 +35,20 @@ export class TextareaContent extends React.Component { } public render() { - const filler = 'Please enter value (if applicable)'; let display; if (this.state.isEditing) { - display =
{this.makeEditingTextarea()}
; + display = this.makeEditingTextarea(); } else { - let value = getValueFromPath(this.props.path, this.props.assessment) || filler; - value = value.match('^(\n| )*$') ? filler : value; - display = ( -
- {this.state.useRawValue ? value : } -
- ); + if (this.state.useRawValue) { + display = getValueFromPath(this.props.path, this.props.assessment); + } else { + const filler = 'Please enter value (if applicable)'; + let value = getValueFromPath(this.props.path, this.props.assessment) || ''; + value = value.match('^(\n| )*$') ? filler : value; + display = ; + } } - return display; + return
{display}
; } private saveEditAssessment = (e: any) => { diff --git a/src/utils/xmlParser.ts b/src/utils/xmlParser.ts index cbe827acee..54765a77ce 100644 --- a/src/utils/xmlParser.ts +++ b/src/utils/xmlParser.ts @@ -237,14 +237,23 @@ export const exportXml = () => { }; let xmlStr = builder.buildObject(xml); xmlStr = xmlStr.replace(/( )+/g, ''); - const element = document.createElement('a'); - const file = new Blob([xmlStr], { endings: 'native', type: 'text/xml;charset=UTF-8' }); - element.href = URL.createObjectURL(file); - element.download = title + '.xml'; - element.click(); + download(title + '.xml', xmlStr); } }; +const download = (filename: string, text: string) => { + const element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); +}; + const exportLibrary = (library: Library) => { const deployment = { $: { From 0cf76f4f96bca1389dc736099b57d1b22e113325 Mon Sep 17 00:00:00 2001 From: Ger Hean Date: Sun, 24 Mar 2019 15:44:31 +0800 Subject: [PATCH 2/2] increase abstraction removed numberRange from textArea Reduced save frequency of solutionTemplate --- .../GradingTab.tsx | 10 +- .../QuestionTemplateTab.tsx | 105 +++++++++++++----- .../TextareaContent.tsx | 8 +- .../editingWorkspaceSideContent/index.tsx | 14 +++ 4 files changed, 99 insertions(+), 38 deletions(-) diff --git a/src/components/incubator/editingWorkspaceSideContent/GradingTab.tsx b/src/components/incubator/editingWorkspaceSideContent/GradingTab.tsx index 04d1ad0140..9f445ef945 100644 --- a/src/components/incubator/editingWorkspaceSideContent/GradingTab.tsx +++ b/src/components/incubator/editingWorkspaceSideContent/GradingTab.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { IAssessment } from '../../assessment/assessmentShape'; +import { limitNumberRange } from './'; import TextareaContent from './TextareaContent'; interface IProps { @@ -18,12 +19,13 @@ export class GradingTab extends React.Component { return this.gradingTab(); } - private textareaContent = (path: Array, isNumber: boolean = false) => { + private textareaContent = (path: Array) => { return ( ); @@ -32,10 +34,10 @@ export class GradingTab extends React.Component { private gradingTab = () => (
Max Grade: - {this.textareaContent(this.props.path.concat(['maxGrade']), true)} + {this.textareaContent(this.props.path.concat(['maxGrade']))}
Max Xp: - {this.textareaContent(this.props.path.concat(['maxXp']), true)} + {this.textareaContent(this.props.path.concat(['maxXp']))}
); } diff --git a/src/components/incubator/editingWorkspaceSideContent/QuestionTemplateTab.tsx b/src/components/incubator/editingWorkspaceSideContent/QuestionTemplateTab.tsx index cfe5a3b9d8..cb3bae3f11 100644 --- a/src/components/incubator/editingWorkspaceSideContent/QuestionTemplateTab.tsx +++ b/src/components/incubator/editingWorkspaceSideContent/QuestionTemplateTab.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import AceEditor from 'react-ace'; import { IAssessment, IMCQQuestion } from '../../assessment/assessmentShape'; -import { assignToPath, getValueFromPath } from './'; +import { assignToPath, getValueFromPath, limitNumberRange } from './'; import TextareaContent from './TextareaContent'; interface IProps { @@ -12,9 +12,18 @@ interface IProps { updateAssessment: (assessment: IAssessment) => void; } -export class QuestionTemplateTab extends React.Component { +interface IState { + templateValue: string; + templateFocused: boolean; +} + +export class QuestionTemplateTab extends React.Component { public constructor(props: IProps) { super(props); + this.state = { + templateValue: '', + templateFocused: false + }; } public render() { @@ -34,30 +43,60 @@ export class QuestionTemplateTab extends React.Component { const path = ['questions', this.props.questionId, 'answer']; const handleTemplateChange = (newCode: string) => { - const assessmentVal = this.props.assessment; - assignToPath(path, newCode, assessmentVal); - this.props.updateAssessment(assessmentVal); + this.setState({ + templateValue: newCode + }); }; + const value = this.state.templateFocused + ? this.state.templateValue + : getValueFromPath(path, this.props.assessment); + const display = ( - +
+ +
); return display; }; + private focusEditor = (path: Array) => (e: any): void => { + if (!this.state.templateFocused) { + this.setState({ + templateValue: getValueFromPath(path, this.props.assessment), + templateFocused: true + }); + } + }; + + private unFocusEditor = (path: Array) => (e: any): void => { + if (this.state.templateFocused) { + const value = getValueFromPath(path, this.props.assessment); + if (value !== this.state.templateValue) { + const assessmentVal = this.props.assessment; + assignToPath(path, this.state.templateValue, assessmentVal); + this.props.updateAssessment(assessmentVal); + } + this.setState({ + templateValue: '', + templateFocused: false + }); + } + }; + private mcqTab = () => { const questionId = this.props.questionId; const question = this.props.assessment!.questions[questionId] as IMCQQuestion; @@ -87,17 +126,27 @@ export class QuestionTemplateTab extends React.Component { private textareaContent = ( path: Array, isNumber: boolean = false, - numberRange: number[] = [0] + range: number[] = [0] ) => { - return ( - - ); + if (isNumber) { + return ( + + ); + } else { + return ( + + ); + } }; } diff --git a/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx b/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx index 613b477cb8..14086f182e 100644 --- a/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx +++ b/src/components/incubator/editingWorkspaceSideContent/TextareaContent.tsx @@ -8,7 +8,6 @@ import { assignToPath, getValueFromPath } from './'; interface IProps { assessment: IAssessment; isNumber?: boolean; - numberRange?: number[]; path: Array; useRawValue?: boolean; processResults?: (newVal: string | number) => string | number; @@ -54,12 +53,9 @@ export class TextareaContent extends React.Component { private saveEditAssessment = (e: any) => { let fieldValue: number | string; if (this.state.isNumber) { - const range = this.props.numberRange || [0]; fieldValue = parseInt(this.state.fieldValue, 10); - if (isNaN(fieldValue) || fieldValue < range[0]) { - fieldValue = range[0]; - } else if (range.length > 1 && fieldValue > range[1]) { - fieldValue = range[1]; + if (isNaN(fieldValue)) { + fieldValue = getValueFromPath(this.props.path, this.props.assessment); } } else { fieldValue = this.state.fieldValue; diff --git a/src/components/incubator/editingWorkspaceSideContent/index.tsx b/src/components/incubator/editingWorkspaceSideContent/index.tsx index d89c4bbc5f..6d73029c78 100644 --- a/src/components/incubator/editingWorkspaceSideContent/index.tsx +++ b/src/components/incubator/editingWorkspaceSideContent/index.tsx @@ -20,3 +20,17 @@ export const assignToPath = (path: Array, value: any, obj: any) } obj[path[i]] = value; }; + +export const limitNumberRange = (min: number | null = 0, max: number | null = null) => ( + value: number +): number => { + let result; + if (min !== null && value < min) { + result = min; + } else if (max !== null && value > max) { + result = max; + } else { + result = value; + } + return result; +};