@@ -28,6 +28,18 @@ export const nonQuestionKeys = [
28
28
'textline' ,
29
29
] ;
30
30
31
+ export const richTextFormats = [
32
+ 'h1' ,
33
+ 'h2' ,
34
+ 'h3' ,
35
+ 'h4' ,
36
+ 'h5' ,
37
+ 'h6' ,
38
+ 'div' ,
39
+ 'p' ,
40
+ 'pre' ,
41
+ ] ;
42
+
31
43
export const responseKeys = [
32
44
'multiplechoiceresponse' ,
33
45
'numericalresponse' ,
@@ -62,57 +74,52 @@ export const stripNonTextTags = ({ input, tag }) => {
62
74
63
75
export class OLXParser {
64
76
constructor ( olxString ) {
65
- this . problem = { } ;
66
- this . questionData = { } ;
67
- this . richTextProblem = { } ;
68
- const richTextOptions = {
77
+ // There are two versions of the parsed XLM because the fields using tinymce require the order
78
+ // of the parsed data and spacing values to be preserved. However, all the other widgets need
79
+ // the data grouped by the wrapping tag. Examples of the parsed format can be found here:
80
+ // https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/docs/v4/2.XMLparseOptions.md
81
+ const baseParserOptions = {
69
82
ignoreAttributes : false ,
70
- alwaysCreateTextNode : true ,
71
83
numberParseOptions : {
72
84
leadingZeros : false ,
73
85
hex : false ,
74
86
} ,
75
- preserveOrder : true ,
76
87
processEntities : false ,
77
88
} ;
89
+
90
+ // Base Parser
91
+ this . problem = { } ;
78
92
const parserOptions = {
79
- ignoreAttributes : false ,
93
+ ... baseParserOptions ,
80
94
alwaysCreateTextNode : true ,
81
- numberParseOptions : {
82
- leadingZeros : false ,
83
- hex : false ,
84
- } ,
85
- processEntities : false ,
86
95
} ;
87
96
const builderOptions = {
88
- ignoreAttributes : false ,
89
- numberParseOptions : {
90
- leadingZeros : false ,
91
- hex : false ,
92
- } ,
93
- processEntities : false ,
97
+ ...baseParserOptions ,
98
+ } ;
99
+ const parser = new XMLParser ( parserOptions ) ;
100
+ this . builder = new XMLBuilder ( builderOptions ) ;
101
+ this . parsedOLX = parser . parse ( olxString ) ;
102
+ if ( _ . has ( this . parsedOLX , 'problem' ) ) {
103
+ this . problem = this . parsedOLX . problem ;
104
+ }
105
+
106
+ // Parser with `preservedOrder: true` and `trimValues: false`
107
+ this . richTextProblem = [ ] ;
108
+ const richTextOptions = {
109
+ ...baseParserOptions ,
110
+ alwaysCreateTextNode : true ,
111
+ preserveOrder : true ,
112
+ trimValues : false ,
94
113
} ;
95
114
const richTextBuilderOptions = {
96
- ignoreAttributes : false ,
97
- numberParseOptions : {
98
- leadingZeros : false ,
99
- hex : false ,
100
- } ,
115
+ ...baseParserOptions ,
101
116
preserveOrder : true ,
102
- processEntities : false ,
117
+ trimValues : false ,
103
118
} ;
104
- // There are two versions of the parsed XLM because the fields using tinymce require the order
105
- // of the parsed data to be preserved. However, all the other widgets need the data grouped by
106
- // the wrapping tag.
107
119
const richTextParser = new XMLParser ( richTextOptions ) ;
108
- const parser = new XMLParser ( parserOptions ) ;
109
- this . builder = new XMLBuilder ( builderOptions ) ;
110
120
this . richTextBuilder = new XMLBuilder ( richTextBuilderOptions ) ;
111
- this . parsedOLX = parser . parse ( olxString ) ;
112
121
this . richTextOLX = richTextParser . parse ( olxString ) ;
113
122
if ( _ . has ( this . parsedOLX , 'problem' ) ) {
114
- this . problem = this . parsedOLX . problem ;
115
- this . questionData = this . richTextOLX [ 0 ] . problem ;
116
123
this . richTextProblem = this . richTextOLX [ 0 ] . problem ;
117
124
}
118
125
}
@@ -462,7 +469,7 @@ export class OLXParser {
462
469
* @return {string } string of OLX
463
470
*/
464
471
parseQuestions ( problemType ) {
465
- const problemArray = _ . get ( this . questionData [ 0 ] , problemType ) || this . questionData ;
472
+ const problemArray = _ . get ( this . richTextProblem [ 0 ] , problemType ) || this . richTextProblem ;
466
473
467
474
const questionArray = [ ] ;
468
475
problemArray . forEach ( tag => {
@@ -478,7 +485,7 @@ export class OLXParser {
478
485
*/
479
486
tag [ tagName ] . forEach ( subTag => {
480
487
const subTagName = Object . keys ( subTag ) [ 0 ] ;
481
- if ( subTagName === 'label' || subTagName === 'description' ) {
488
+ if ( subTagName === 'label' || subTagName === 'description' || richTextFormats . includes ( subTagName ) ) {
482
489
questionArray . push ( subTag ) ;
483
490
}
484
491
} ) ;
@@ -503,11 +510,13 @@ export class OLXParser {
503
510
if ( objKeys . includes ( 'demandhint' ) ) {
504
511
const currentDemandHint = obj . demandhint ;
505
512
currentDemandHint . forEach ( hint => {
506
- const hintValue = this . richTextBuilder . build ( hint . hint ) ;
507
- hintsObject . push ( {
508
- id : hintsObject . length ,
509
- value : hintValue ,
510
- } ) ;
513
+ if ( Object . keys ( hint ) . includes ( 'hint' ) ) {
514
+ const hintValue = this . richTextBuilder . build ( hint . hint ) ;
515
+ hintsObject . push ( {
516
+ id : hintsObject . length ,
517
+ value : hintValue ,
518
+ } ) ;
519
+ }
511
520
} ) ;
512
521
}
513
522
} ) ;
@@ -526,21 +535,17 @@ export class OLXParser {
526
535
getSolutionExplanation ( problemType ) {
527
536
if ( ! _ . has ( this . problem , `${ problemType } .solution` ) && ! _ . has ( this . problem , 'solution' ) ) { return null ; }
528
537
const [ problemBody ] = this . richTextProblem . filter ( section => Object . keys ( section ) . includes ( problemType ) ) ;
529
- let { solution } = problemBody [ problemType ] . pop ( ) ;
530
- const { div } = solution [ 0 ] ;
531
- if ( solution . length === 1 && div ) {
532
- div . forEach ( ( block ) => {
533
- const [ key ] = Object . keys ( block ) ;
534
- const [ value ] = block [ key ] ;
535
- if ( ( key === 'p' || key === 'h2' )
536
- && ( _ . get ( value , '#text' , null ) === 'Explanation' )
537
- ) {
538
- div . shift ( ) ;
538
+ const [ solutionBody ] = problemBody [ problemType ] . filter ( section => Object . keys ( section ) . includes ( 'solution' ) ) ;
539
+ const [ divBody ] = solutionBody . solution . filter ( section => Object . keys ( section ) . includes ( 'div' ) ) ;
540
+ const solutionArray = [ ] ;
541
+ if ( divBody && divBody . div ) {
542
+ divBody . div . forEach ( tag => {
543
+ if ( _ . get ( Object . values ( tag ) [ 0 ] [ 0 ] , '#text' , null ) !== 'Explanation' ) {
544
+ solutionArray . push ( tag ) ;
539
545
}
540
546
} ) ;
541
- solution = div ;
542
547
}
543
- const solutionString = this . richTextBuilder . build ( solution ) ;
548
+ const solutionString = this . richTextBuilder . build ( solutionArray ) ;
544
549
return solutionString ;
545
550
}
546
551
0 commit comments