@@ -443,6 +443,7 @@ cwc.ui.Tutorial.prototype.startTutorial = function() {
443
443
youtube_videos : ( step . videos || [ ] ) . map ( ( video ) =>
444
444
video [ 'youtube_id' ]
445
445
) ,
446
+ hasCode : step . code && step . code . trim ( ) . length > 0 ,
446
447
} ) ) ,
447
448
}
448
449
) ;
@@ -501,8 +502,8 @@ cwc.ui.Tutorial.prototype.initMediaOverlay_ = function() {
501
502
*/
502
503
cwc . ui . Tutorial . prototype . initMedia_ = function ( ) {
503
504
this . initMediaOverlay_ ( ) ;
504
- let nodeListImages = this . rootNode_ . querySelectorAll (
505
- '.js-project- step-image' ) ;
505
+ let nodeListImages = this . rootNode_ . querySelectorAll ( '.' + this . prefix +
506
+ 'step-image' ) ;
506
507
if ( this . imagesDb_ ) {
507
508
[ ] . forEach . call ( nodeListImages , ( image ) => {
508
509
let imageSrc = image . getAttribute ( 'data-src' ) ;
@@ -526,16 +527,16 @@ cwc.ui.Tutorial.prototype.initMedia_ = function() {
526
527
*/
527
528
cwc . ui . Tutorial . prototype . initSteps_ = function ( ) {
528
529
let prefix = this . prefix + 'step-' ;
530
+ let classPrefix = '.' + prefix ;
529
531
this . steps_ . forEach ( ( step ) => {
530
532
let stepNode = goog . dom . getElement ( prefix + step . id ) ;
531
533
step . node = stepNode ;
532
- step . nodeContinue = stepNode . querySelector (
533
- '.js-project-step-continue' ) ;
534
- step . nodeHeader = stepNode . querySelector (
535
- '.js-project-step-header' ) ,
536
- step . nodeListMediaExpand = stepNode . querySelectorAll (
537
- '.js-project-step-media-expand' ) ;
538
- step . nodeMessage = stepNode . querySelector ( '.' + prefix + 'message' ) ;
534
+ step . nodeContinue = stepNode . querySelector ( classPrefix + 'continue' ) ;
535
+ step . nodeLoadCode = stepNode . querySelector ( classPrefix + 'load-code' ) ;
536
+ step . nodeHeader = stepNode . querySelector ( classPrefix + 'header' ) ;
537
+ step . nodeListMediaExpand = stepNode . querySelectorAll ( classPrefix +
538
+ 'media-expand' ) ;
539
+ step . nodeMessage = stepNode . querySelector ( classPrefix + 'message' ) ;
539
540
goog . style . setElementShown ( step . nodeMessage , false ) ;
540
541
} ) ;
541
542
this . initStepButtons_ ( ) ;
@@ -552,6 +553,10 @@ cwc.ui.Tutorial.prototype.initStepButtons_ = function() {
552
553
goog . events . listen ( step . nodeContinue , goog . events . EventType . CLICK ,
553
554
this . completeCurrentStep_ . bind ( this ) ) ;
554
555
}
556
+ if ( step . nodeLoadCode ) {
557
+ goog . events . listen ( step . nodeLoadCode , goog . events . EventType . CLICK ,
558
+ this . loadCodeWithPrompt_ . bind ( this ) ) ;
559
+ }
555
560
goog . events . listen ( step . nodeHeader , goog . events . EventType . CLICK ,
556
561
this . jumpToStep_ . bind ( this , step . id ) ) ;
557
562
@@ -744,24 +749,83 @@ cwc.ui.Tutorial.prototype.showMedia_ = function(media) {
744
749
* @private
745
750
*/
746
751
cwc . ui . Tutorial . prototype . setState_ = function ( change ) {
747
- let prevStepID = this . state_ . activeStepID ;
752
+ let isEditorDirty = this . isEditorDirty_ ( ) ;
748
753
Object . keys ( change ) . forEach ( ( key ) => {
749
754
this . state_ [ key ] = change [ key ] ;
750
755
} ) ;
751
- if ( prevStepID !== this . state_ . activeStepID ) {
752
- let editorInstance = this . helper . getInstance ( 'editor' ) ;
753
- let activeStep = this . getActiveStep_ ( ) ;
754
- if ( editorInstance && activeStep . code ) {
755
- this . solved ( false ) ;
756
- // TODO: support multiple editor views
757
- editorInstance . setEditorContent ( activeStep . code ,
758
- editorInstance . getCurrentView ( ) ) ;
759
- }
760
- this . restartValidate_ ( ) ;
761
- }
762
756
this . updateView_ ( ) ;
757
+ if ( ! isEditorDirty ) {
758
+ this . loadCode_ ( ) ;
759
+ }
763
760
} ;
764
761
762
+ /**
763
+ * Tests if the editor has been modified from the example code
764
+ * @return {!boolean }
765
+ * @private
766
+ */
767
+ cwc . ui . Tutorial . prototype . isEditorDirty_ = function ( ) {
768
+ let editorInstance = this . helper . getInstance ( 'editor' ) ;
769
+ let activeStep = this . getActiveStep_ ( ) ;
770
+ let code = editorInstance . getEditorContent ( editorInstance . getCurrentView ( ) ) ;
771
+ code = code ? code . trim ( ) : '' ;
772
+
773
+ // It's always ok to load code into an empty editor
774
+ if ( code . length === 0 ) {
775
+ return false ;
776
+ }
777
+ if ( activeStep && activeStep . code && activeStep . code . trim ( ) === code ) {
778
+ return false ;
779
+ }
780
+ return true ;
781
+ } ;
782
+
783
+ /**
784
+ * Prompts to overwrite dirty editor and loads code if user confirms
785
+ * @private
786
+ */
787
+ cwc . ui . Tutorial . prototype . loadCodeWithPrompt_ = function ( ) {
788
+ if ( ! this . getActiveStep_ ( ) . code ) {
789
+ return ;
790
+ }
791
+ if ( ! this . isEditorDirty_ ( ) ) {
792
+ this . loadCode_ ( ) ;
793
+ return ;
794
+ }
795
+
796
+ let dialogInstance = this . helper . getInstance ( 'dialog' ) ;
797
+ let title = {
798
+ icon : 'warning' ,
799
+ title : 'Overwrite editor content?' ,
800
+ } ;
801
+ let content = 'Loading the example code will overwrite your changes in the ' +
802
+ 'editor. Are you sure you want to load the example code?' ;
803
+ let action = i18t ( 'Load example code into editor' ) ;
804
+ dialogInstance . showActionCancel ( title , content , action ) . then ( ( answer ) => {
805
+ if ( ! answer ) {
806
+ return ;
807
+ }
808
+ this . loadCode_ ( ) ;
809
+ } ) ;
810
+ } ;
811
+
812
+ /**
813
+ * Loads example code into editor
814
+ * @private
815
+ */
816
+ cwc . ui . Tutorial . prototype . loadCode_ = function ( ) {
817
+ let activeStep = this . getActiveStep_ ( ) ;
818
+ if ( ! ( activeStep && activeStep . code ) ) {
819
+ return ;
820
+ }
821
+ let editorInstance = this . helper . getInstance ( 'editor' ) ;
822
+ // TODO: support multiple editor views
823
+ editorInstance . setEditorContent ( activeStep . code ,
824
+ editorInstance . getCurrentView ( ) ) ;
825
+ this . log_ . info ( 'Loaded example code into editor' , activeStep . code ) ;
826
+ this . solved ( false ) ;
827
+ this . restartValidate_ ( ) ;
828
+ } ;
765
829
766
830
/**
767
831
* Updates the view to reflect the current state
0 commit comments