@@ -3,6 +3,7 @@ import { saveAs } from 'file-saver';
33import UserCodeMirror from './UserCodeMirror.jsx' ;
44import Toolbox from './Toolbox.jsx' ;
55import Tabs from './Tabs.jsx' ;
6+ import PageTabs from './PageTabs.jsx' ;
67import { computeCss , computeHtml , computeJs } from '../computes' ;
78import { CssModes , HtmlModes , JsModes , modes } from '../codeModes' ;
89import { getCompleteHtml , loadJS , log } from '../utils' ;
@@ -41,7 +42,15 @@ export default class ContentWrap extends Component {
4142 this . jsMode = JsModes . JS ;
4243 this . prefs = { } ;
4344 this . codeInPreview = { html : null , css : null , js : null } ;
44- this . cmCodes = { html : props . currentItem . html , css : '' , js : '' } ;
45+
46+ // Initialize with the current page's content if available
47+ const currentPage = this . getCurrentPage ( ) ;
48+ this . cmCodes = {
49+ html : props . currentItem . html ,
50+ css : currentPage ? currentPage . css : props . currentItem . css || '' ,
51+ js : currentPage ? currentPage . js : props . currentItem . js || ''
52+ } ;
53+
4554 this . cm = { } ;
4655 this . logCount = 0 ;
4756
@@ -94,31 +103,90 @@ export default class ContentWrap extends Component {
94103 this . onCodeChange ( editor , change ) ;
95104 }
96105
97- onCssCodeChange ( editor , change ) {
98- this . cmCodes . css = editor . getValue ( ) ;
99- this . props . onCodeChange (
100- 'css' ,
101- this . cmCodes . css ,
102- change . origin !== 'setValue' ,
103- ) ;
104- this . onCodeChange ( editor , change ) ;
105- }
106-
107106 async onJsCodeChange ( editor , change ) {
108107 await this . setState ( { lineOfCode : editor . doc . size } ) ;
109108 this . cmCodes . js = editor . getValue ( ) ;
110- this . props . onCodeChange (
111- 'js' ,
112- this . cmCodes . js ,
113- change . origin !== 'setValue' ,
114- ) ;
109+
110+ // Update the current page's JS content
111+ const currentPage = this . getCurrentPage ( ) ;
112+ if ( currentPage ) {
113+ const updatedPage = {
114+ ...currentPage ,
115+ js : editor . getValue ( )
116+ } ;
117+
118+ // Find the index of the current page
119+ const pageIndex = this . props . currentItem . pages . findIndex (
120+ page => page . id === currentPage . id
121+ ) ;
122+
123+ if ( pageIndex !== - 1 ) {
124+ // Create updated pages array
125+ const updatedPages = [ ...this . props . currentItem . pages ] ;
126+ updatedPages [ pageIndex ] = updatedPage ;
127+
128+ // Update the current item with the new pages array
129+ const updatedItem = {
130+ ...this . props . currentItem ,
131+ pages : updatedPages ,
132+ // Also update the js field for backward compatibility
133+ js : editor . getValue ( )
134+ } ;
135+
136+ // Only call onCodeChange once with the updated item
137+ this . props . onCodeChange ( 'js' , editor . getValue ( ) , change . origin !== 'setValue' , updatedItem ) ;
138+ } else {
139+ this . props . onCodeChange ( 'js' , editor . getValue ( ) , change . origin !== 'setValue' ) ;
140+ }
141+ } else {
142+ this . props . onCodeChange ( 'js' , editor . getValue ( ) , change . origin !== 'setValue' ) ;
143+ }
115144
116145 const targetWindow =
117146 this . detachedWindow ||
118147 document . getElementById ( 'demo-frame' ) . contentWindow ;
119148 targetWindow . postMessage ( { code : this . cmCodes . js } , '*' ) ;
120149 }
121150
151+ async onCssCodeChange ( editor , change ) {
152+ this . cmCodes . css = editor . getValue ( ) ;
153+
154+ // Update the current page's CSS content
155+ const currentPage = this . getCurrentPage ( ) ;
156+ if ( currentPage ) {
157+ const updatedPage = {
158+ ...currentPage ,
159+ css : editor . getValue ( )
160+ } ;
161+
162+ // Find the index of the current page
163+ const pageIndex = this . props . currentItem . pages . findIndex (
164+ page => page . id === currentPage . id
165+ ) ;
166+
167+ if ( pageIndex !== - 1 ) {
168+ // Create updated pages array
169+ const updatedPages = [ ...this . props . currentItem . pages ] ;
170+ updatedPages [ pageIndex ] = updatedPage ;
171+
172+ // Update the current item with the new pages array
173+ const updatedItem = {
174+ ...this . props . currentItem ,
175+ pages : updatedPages ,
176+ // Also update the css field for backward compatibility
177+ css : editor . getValue ( )
178+ } ;
179+
180+ // Only call onCodeChange once with the updated item
181+ this . props . onCodeChange ( 'css' , editor . getValue ( ) , change . origin !== 'setValue' , updatedItem ) ;
182+ } else {
183+ this . props . onCodeChange ( 'css' , editor . getValue ( ) , change . origin !== 'setValue' ) ;
184+ }
185+ } else {
186+ this . props . onCodeChange ( 'css' , editor . getValue ( ) , change . origin !== 'setValue' ) ;
187+ }
188+ }
189+
122190 onCursorMove ( editor ) {
123191 const cursor = editor . getCursor ( ) ;
124192 const line = cursor . line ;
@@ -159,6 +227,19 @@ export default class ContentWrap extends Component {
159227 } , this . updateDelay ) ;
160228 }
161229
230+ /**
231+ * Gets the current active page from the current item
232+ * @returns {Object|null } The current page or null if not found
233+ */
234+ getCurrentPage ( ) {
235+ const { currentItem } = this . props ;
236+ if ( ! currentItem || ! currentItem . pages || ! currentItem . currentPageId ) {
237+ return null ;
238+ }
239+
240+ return currentItem . pages . find ( page => page . id === currentItem . currentPageId ) || null ;
241+ }
242+
162243 // Called for both detached window and non-detached window
163244 async createPreviewFile ( html , css , js ) {
164245 // isNotChrome
@@ -303,10 +384,18 @@ export default class ContentWrap extends Component {
303384 }
304385
305386 refreshEditor ( ) {
306- this . cmCodes . css = this . props . currentItem . css ;
307- this . cmCodes . js = this . props . currentItem . js ;
308- this . cm . css . setValue ( this . cmCodes . css || '' ) ;
309- this . cm . js . setValue ( this . cmCodes . js || '' ) ;
387+ const currentPage = this . getCurrentPage ( ) ;
388+
389+ if ( currentPage ) {
390+ this . cmCodes . css = currentPage . css || '' ;
391+ this . cmCodes . js = currentPage . js || '' ;
392+ } else {
393+ this . cmCodes . css = this . props . currentItem . css || '' ;
394+ this . cmCodes . js = this . props . currentItem . js || '' ;
395+ }
396+
397+ this . cm . css . setValue ( this . cmCodes . css ) ;
398+ this . cm . js . setValue ( this . cmCodes . js ) ;
310399 this . cm . css . refresh ( ) ;
311400 this . cm . js . refresh ( ) ;
312401
@@ -558,6 +647,13 @@ export default class ContentWrap extends Component {
558647 const baseTranspilerPath = 'lib/transpilers' ;
559648 // Exit if already loaded
560649 var d = deferred ( ) ;
650+
651+ // Add null check for modes[mode]
652+ if ( ! mode || ! modes [ mode ] ) {
653+ d . resolve ( ) ;
654+ return d . promise ;
655+ }
656+
561657 if ( modes [ mode ] . hasLoaded ) {
562658 d . resolve ( ) ;
563659 return d . promise ;
@@ -599,36 +695,57 @@ export default class ContentWrap extends Component {
599695 updateHtmlMode ( value ) {
600696 this . props . onCodeModeChange ( 'html' , value ) ;
601697 this . props . currentItem . htmlMode = value ;
602- CodeMirror . autoLoadMode (
603- this . cm . html ,
604- modes [ value ] . cmPath || modes [ value ] . cmMode ,
605- ) ;
698+
699+ // Add null check to prevent "Cannot read properties of undefined (reading 'cmPath')" error
700+ if ( this . cm && this . cm . html && modes [ value ] ) {
701+ CodeMirror . autoLoadMode (
702+ this . cm . html ,
703+ modes [ value ] . cmPath || modes [ value ] . cmMode ,
704+ ) ;
705+ }
706+
606707 return this . handleModeRequirements ( value ) ;
607708 }
608709
609710 updateCssMode ( value ) {
610711 this . props . onCodeModeChange ( 'css' , value ) ;
611712 this . props . currentItem . cssMode = value ;
612- this . cm . css . setOption ( 'mode' , modes [ value ] . cmMode ) ;
613- this . cm . css . setOption ( 'readOnly' , modes [ value ] . cmDisable ) ;
614- window . cssSettingsBtn . classList [
615- modes [ value ] . hasSettings ? 'remove' : 'add'
616- ] ( 'hide' ) ;
617- CodeMirror . autoLoadMode (
618- this . cm . css ,
619- modes [ value ] . cmPath || modes [ value ] . cmMode ,
620- ) ;
713+
714+ // Add null check to prevent "Cannot read properties of undefined" error
715+ if ( this . cm && this . cm . css && modes [ value ] ) {
716+ this . cm . css . setOption ( 'mode' , modes [ value ] . cmMode ) ;
717+ this . cm . css . setOption ( 'readOnly' , modes [ value ] . cmDisable ) ;
718+
719+ CodeMirror . autoLoadMode (
720+ this . cm . css ,
721+ modes [ value ] . cmPath || modes [ value ] . cmMode ,
722+ ) ;
723+ }
724+
725+ // Only modify DOM if the element exists
726+ if ( window . cssSettingsBtn && modes [ value ] ) {
727+ window . cssSettingsBtn . classList [
728+ modes [ value ] . hasSettings ? 'remove' : 'add'
729+ ] ( 'hide' ) ;
730+ }
731+
621732 return this . handleModeRequirements ( value ) ;
622733 }
623734
624735 updateJsMode ( value ) {
625736 this . props . onCodeModeChange ( 'js' , value ) ;
626737 this . props . currentItem . jsMode = value ;
627- this . cm . js . setOption ( 'mode' , modes [ value ] . cmMode ) ;
628- CodeMirror . autoLoadMode (
629- this . cm . js ,
630- modes [ value ] . cmPath || modes [ value ] . cmMode ,
631- ) ;
738+
739+ // Add null check to prevent "Cannot read properties of undefined" error
740+ if ( this . cm && this . cm . js && modes [ value ] ) {
741+ this . cm . js . setOption ( 'mode' , modes [ value ] . cmMode ) ;
742+
743+ CodeMirror . autoLoadMode (
744+ this . cm . js ,
745+ modes [ value ] . cmPath || modes [ value ] . cmMode ,
746+ ) ;
747+ }
748+
632749 return this . handleModeRequirements ( value ) ;
633750 }
634751
@@ -899,17 +1016,15 @@ export default class ContentWrap extends Component {
8991016 < UserCodeMirror
9001017 ref = { ( dslEditor ) => ( this . dslEditor = dslEditor ) }
9011018 options = { {
902- mode : 'htmlmixed' ,
903- profile : 'xhtml' ,
1019+ mode : 'javascript' ,
9041020 gutters : [
9051021 'CodeMirror-linenumbers' ,
9061022 'CodeMirror-foldgutter' ,
9071023 ] ,
9081024 noAutocomplete : true ,
909- matchTags : { bothTags : true } ,
9101025 prettier : true ,
911- prettierParser : 'html ' ,
912- emmet : true ,
1026+ prettierParser : 'babel ' ,
1027+ emmet : false ,
9131028 } }
9141029 prefs = { this . props . prefs }
9151030 autoComplete = { this . props . prefs . autoComplete }
@@ -995,6 +1110,14 @@ export default class ContentWrap extends Component {
9951110 </ div >
9961111 < div class = "demo-side" id = "js-demo-side" >
9971112 < div className = "h-full flex flex-col" >
1113+ { this . props . currentItem && this . props . currentItem . pages && this . props . currentItem . pages . length > 0 && (
1114+ < PageTabs
1115+ pages = { this . props . currentItem . pages }
1116+ currentPageId = { this . props . currentItem . currentPageId }
1117+ onTabClick = { this . props . onPageSwitch }
1118+ onAddPage = { this . props . onAddPage }
1119+ />
1120+ ) }
9981121 < div
9991122 className = "flex-grow"
10001123 style = "overflow-y: auto; -webkit-overflow-scrolling: touch; "
0 commit comments