252
252
</ span >
253
253
</ div >
254
254
255
- <!-- Modal -->
256
- < div class ="modal fade " id ="saveModal " tabindex ="-1 " role ="dialog " aria-labelledby ="saveModalLabel ">
257
- < div class ="modal-dialog " role ="document ">
258
- < div class ="modal-content ">
259
- < div class ="modal-header ">
260
- < button type ="button " class ="close " data-dismiss ="modal " aria-label ="Close "> < span aria-hidden ="true "> ×</ span > </ button >
261
- < h4 class ="modal-title " id ="saveModalLabel "> Choose a name for your project:</ h4 >
262
- </ div >
263
- < div class ="modal-body ">
264
- < div id ="projectNameGroup " class ="form-group ">
265
- < input type ="text " class ="form-control " id ="projectName " placeholder ="my-project " onkeyup ="validate() " onkeydown ="validate() ">
255
+ < div class ="modal fade " id ="saveModal " tabindex ="-1 " role ="dialog " aria-labelledby ="saveModalLabel ">
256
+ < div class ="modal-dialog " role ="document ">
257
+ < div class ="modal-content ">
258
+ < div class ="modal-header ">
259
+ < h4 class ="modal-title " id ="saveModalLabel "> Choose a name for your project</ h4 >
266
260
</ div >
267
- < span id ="nameTaken " style ="display:none; " class ="text-danger "> That project name has already been taken. Try another one.</ span >
268
- < span id ="illegalCharacter " class ="text-danger "> </ span >
269
- </ div >
270
- < div class ="modal-footer ">
271
- < button type ="button " class ="btn btn-default " data-dismiss ="modal "> Close</ button >
272
- < button type ="button " id ="saveChanges " class ="btn btn-primary disabled " data-loading-text ="Loading... " onclick ="saveName() "> Save</ button >
261
+ < div class ="modal-body ">
262
+ < div id ="projectNameGroup " class ="form-group " :class ="{'has-info': projectNameInputValue == '', 'has-error': projectNameRequest == 'NAME TAKEN', 'has-success': projectNameInputValue != '' && projectNameRequest != 'NAME TAKEN', animated: projectNameRequest == 'NAME TAKEN' || projectNameLastKeyIllegal, shake: projectNameRequest == 'NAME TAKEN' || projectNameLastKeyIllegal} ">
263
+ < input type ="text " class ="form-control " id ="projectName " placeholder ="my-project " :value ="projectNameInputValue " @input ="validate($event) " @keyDown.enter ="saveName(projectNameInputValue) ">
264
+ < span id ="nameTaken " :style ="{opacity: projectNameRequest == 'NAME TAKEN' ? '1' : '0'} " class ="text-danger "> That project name has already been taken. Try another one.</ span >
265
+ </ div >
266
+ < span id ="illegalCharacter " class ="text-danger " :class ="{animated: projectNameLastKeyIllegal, shake: projectNameLastKeyIllegal} " style ="display: inline-block " :style ="{opacity: projectNameLastKeyIllegal ? '1' : '0'} "> You cannot include {{ projectNameLastKeyIllegal }} in project names.</ span >
267
+ </ div >
268
+ < div class ="modal-footer ">
269
+ < button type ="button " class ="btn btn-default " data-dismiss ="modal "> Close</ button >
270
+ < button type ="button " id ="saveChanges " class ="btn btn-primary " :class ="{disabled: projectNameRequest != 'NOT LOADING' || projectNameInputValue == ''} " @click ="saveName() "> {{ projectNameRequest == "LOADING" ? "Loading..." : "Save" }}</ button >
271
+ </ div >
272
+ </ div >
273
273
</ div >
274
274
</ div >
275
- </ div >
276
- </ div >
277
275
278
276
< div id ="container ">
279
277
@@ -345,7 +343,7 @@ <h4 class="modal-title" id="saveModalLabel">Choose a name for your project:</h4>
345
343
return window . location . hash . substring ( 1 , window . location . hash . length ) . split ( "/" ) [ 0 ] ;
346
344
}
347
345
var getIDWithRevision = function ( ) {
348
- // returns the name of a project, not inlcuding the current revision
346
+ // returns the name of a project, inlcuding the current revision
349
347
return window . location . hash . substring ( 1 , window . location . hash . length ) ;
350
348
}
351
349
var getCurrentRevisionCode = function ( revisions ) {
@@ -389,6 +387,10 @@ <h4 class="modal-title" id="saveModalLabel">Choose a name for your project:</h4>
389
387
mouseX : 0 ,
390
388
mouseY : 0 ,
391
389
seenError : true ,
390
+
391
+ projectNameRequest : "NOT LOADING" , // or "LOADING" or "NAME TAKEN"
392
+ projectNameInputValue : "" ,
393
+ projectNameLastKeyIllegal : false ,
392
394
} ,
393
395
computed : {
394
396
styles : function ( ) { return {
@@ -424,6 +426,34 @@ <h4 class="modal-title" id="saveModalLabel">Choose a name for your project:</h4>
424
426
var beautiful = js_beautify ( editor . getValue ( ) , { space_after_anon_function : true , indent_size : 2 , indent_with_tabs : false } )
425
427
editor . setValue ( beautiful )
426
428
} ,
429
+ validate : function ( $event ) {
430
+ var newName = $event . target . value
431
+
432
+ this . projectNameRequest = 'NOT LOADING' // reset state so that you can hit save after you change the name after you get a NAME TAKEN error
433
+
434
+ this . projectNameLastKeyIllegal = false // take off the animation
435
+ setTimeout ( function ( ) {
436
+ var lastKeyPressIllegal = newName . length > 0 && newName [ newName . length - 1 ] . match ( / \. | # | \$ | \/ | \[ | \] / )
437
+ if ( lastKeyPressIllegal ) {
438
+ this . projectNameLastKeyIllegal = lastKeyPressIllegal [ 0 ]
439
+ } else {
440
+ this . projectNameLastKeyIllegal = false
441
+ }
442
+ } . bind ( this ) , 10 )
443
+
444
+
445
+ this . projectNameInputValue = newName . replace ( " " , "-" )
446
+ this . projectNameInputValue = this . projectNameInputValue . replace ( / \. | # | \$ | \/ | \[ | \] / g, "" )
447
+ } ,
448
+ saveName : function ( ) {
449
+ if ( app . projectNameRequest == "NOT LOADING" ) {
450
+ app . projectNameRequest = "LOADING"
451
+ var name = app . projectNameInputValue
452
+ if ( name ) {
453
+ saveProject ( name ) ;
454
+ }
455
+ }
456
+ } ,
427
457
} ,
428
458
watch : {
429
459
error : function ( newError ) {
@@ -547,87 +577,29 @@ <h4 class="modal-title" id="saveModalLabel">Choose a name for your project:</h4>
547
577
}
548
578
} )
549
579
550
- var errorChar = "" ;
551
- var characterErrorMessages = "\n" ;
552
- document . getElementById ( "illegalCharacter" ) . innerText = characterErrorMessages ;
553
-
554
- var validate = function ( ) {
555
- document . getElementById ( "illegalCharacter" ) . style . display = "block" ;
556
- document . getElementById ( "illegalCharacter" ) . innerText = characterErrorMessages ;
557
- if ( errorChar != "#" && errorChar != "$" ) {
558
- document . getElementById ( "illegalCharacter" ) . className = 'text-danger' ;
559
- } else {
560
- errorChar = "" ;
561
- }
562
- //Using onkeyup and onkeydown checkers to achieve validation on every action
563
- var input = document . getElementById ( "projectName" ) . value ;
564
- if ( input . includes ( "." ) || input . includes ( "#" ) || input . includes ( "$" ) || input . includes ( '/' ) || input . includes ( "[" ) || input . includes ( "]" ) || input . includes ( " " ) ) {
565
- if ( input [ input . length - 1 ] != " " ) {
566
- inputError ( input [ input . length - 1 ] ) ;
567
- document . getElementById ( "projectNameGroup" ) . className = "form-group has-success" ;
568
- document . getElementById ( "nameTaken" ) . className = "text-danger" ;
569
- }
570
- var input = document . getElementById ( "projectName" ) . value ;
571
- var cleanedString = "" ;
572
- for ( i = 0 ; i < input . length ; i ++ ) {
573
- if ( input [ i ] == " " ) {
574
- cleanedString += "-" ;
575
- } else if ( input [ i ] != "." && input [ i ] != "#" && input [ i ] != "$" && input [ i ] != "/" && input [ i ] != "[" && input [ i ] != "]" ) {
576
- cleanedString += input [ i ] ;
577
- }
578
- }
579
- document . getElementById ( "projectName" ) . value = cleanedString ;
580
- if ( cleanedString == "" ) {
581
- document . getElementById ( "projectNameGroup" ) . className = "form-group has-info" ;
582
- document . getElementById ( "nameTaken" ) . className = "text-danger" ;
583
- }
584
- } else if ( input == "" ) {
585
- document . getElementById ( "projectNameGroup" ) . className = "form-group has-info" ;
586
- document . getElementById ( "nameTaken" ) . className = "text-danger" ;
587
- } else {
588
- inputSuccess ( ) ;
589
- }
590
- }
591
-
592
- var inputError = function ( character ) {
593
- characterErrorMessages = "You cannot include \"" + character + "\" in project names." ;
594
- errorChar = character ;
595
- document . getElementById ( "illegalCharacter" ) . innerText = characterErrorMessages ;
596
- document . getElementById ( "illegalCharacter" ) . className = 'text-danger animated shake' ;
597
- }
598
-
599
- var inputSuccess = function ( ) {
600
- document . getElementById ( "projectNameGroup" ) . className = "form-group has-success" ;
601
- document . getElementById ( "nameTaken" ) . className = "text-danger" ;
602
- document . getElementById ( "saveChanges" ) . className = "btn btn-primary" ;
603
- document . getElementById ( "nameTaken" ) . style . display = "none" ;
604
- }
605
-
606
580
var saveProject = function ( name ) {
607
581
firebase . database ( ) . ref ( '/code/' + name ) . limitToLast ( 1 ) . once ( 'value' ) . then ( function ( snapshot ) {
608
582
if ( snapshot . val ( ) ) {
609
583
if ( firebase . auth ( ) . currentUser && snapshot . val ( ) [ Object . keys ( snapshot . val ( ) ) [ 0 ] ] . uid == firebase . auth ( ) . currentUser . uid ) {
610
- // if the project exists and you own it, push the new code as a revision
611
- $ ( '#saveModal' ) . modal ( 'hide' ) ;
612
- firebase . database ( ) . ref ( ) . child ( "/code/" + name ) . push ( {
613
- code : editor . getValue ( ) ,
614
- time : firebase . database . ServerValue . TIMESTAMP ,
615
- uid : firebase . auth ( ) . currentUser && firebase . auth ( ) . currentUser . uid
616
- } ) . then ( function ( ) {
617
- window . location . hash = name
618
- makeClean ( )
619
- } ) . catch ( function ( error ) {
620
- alert ( "Unable to save project: " + error )
621
- } ) ;
622
- } else {
623
- document . getElementById ( "projectNameGroup" ) . className = "form-group has-error animated shake" ;
624
- document . getElementById ( "nameTaken" ) . className = "text-danger animated shake" ;
625
- document . getElementById ( "nameTaken" ) . style . display = "block" ;
626
- document . getElementById ( "saveChanges" ) . className = "btn btn-primary disabled" ;
627
- document . getElementById ( "saveChanges" ) . innerText = "Save" ;
628
- }
584
+ // if the project exists and you own it, push the new code as a revision
585
+ $ ( '#saveModal' ) . modal ( 'hide' ) ;
586
+ app . projectNameRequest = "NOT LOADING"
587
+ firebase . database ( ) . ref ( ) . child ( "/code/" + name ) . push ( {
588
+ code : editor . getValue ( ) ,
589
+ time : firebase . database . ServerValue . TIMESTAMP ,
590
+ uid : firebase . auth ( ) . currentUser && firebase . auth ( ) . currentUser . uid
591
+ } ) . then ( function ( ) {
592
+ window . location . hash = name
593
+ makeClean ( )
594
+ } ) . catch ( function ( error ) {
595
+ alert ( "Unable to save project: " + error )
596
+ } ) ;
597
+ } else {
598
+ app . projectNameRequest = "NAME TAKEN"
599
+ }
629
600
} else {
630
601
$ ( '#saveModal' ) . modal ( 'hide' ) ;
602
+ app . projectNameRequest = "NOT LOADING"
631
603
firebase . database ( ) . ref ( ) . child ( "/code/" + name + "/--uid" ) . set ( firebase . auth ( ) . currentUser && firebase . auth ( ) . currentUser . uid )
632
604
firebase . database ( ) . ref ( ) . child ( "/code/" + name ) . push ( {
633
605
code : editor . getValue ( ) ,
@@ -643,53 +615,38 @@ <h4 class="modal-title" id="saveModalLabel">Choose a name for your project:</h4>
643
615
}
644
616
} ) ;
645
617
}
646
-
647
- var saveName = function ( ) {
648
- document . getElementById ( "illegalCharacter" ) . style . display = "none" ;
649
- var input = document . getElementById ( "projectName" ) . value ;
650
- if ( ! ( document . getElementById ( "saveChanges" ) . innerText == "Loading..." || document . getElementById ( "saveChanges" ) . className == "btn btn-primary disabled" ) ) {
651
- document . getElementById ( "saveChanges" ) . className = "btn btn-primary disabled" ;
652
- document . getElementById ( "saveChanges" ) . innerText = "Loading..." ;
653
- var name = document . getElementById ( "projectName" ) . value ;
654
- if ( name ) {
655
- characterErrorMessages = "\n" ;
656
- document . getElementById ( "illegalCharacter" ) . innerText = characterErrorMessages ;
657
- saveProject ( name ) ;
658
- }
659
- }
660
- }
661
618
662
-
663
619
var save = function ( ) {
664
620
if ( app . status == "SAVED" ) { return }
665
621
666
622
if ( editor . getValue ( ) . startsWith ( "// Loading..." ) ) {
667
623
return // don't allow students to save projects that haven't loaded
668
624
}
669
625
670
- var name
671
- if ( myCode ) {
672
- name = getID ( )
626
+ if ( myCode && getID ( ) ) {
627
+ saveProject ( getID ( ) )
673
628
} else {
674
- $ ( '#saveModal' ) . modal ( 'show' )
675
- var projName = window . location . href . split ( "#" ) [ 1 ] ;
676
- if ( projName != undefined ) {
677
- if ( projName [ projName . length - 2 ] == "-" && parseInt ( projName [ projName . length - 1 ] ) != NaN ) {
678
- var versionNumber = parseInt ( projName [ projName . length - 1 ] ) ;
679
- versionNumber += 1 ;
680
- document . getElementById ( "projectName" ) . value = projName . substring ( 0 , projName . length - 2 ) + "-" + versionNumber . toString ( ) ;
681
- } else {
682
- document . getElementById ( "projectName" ) . value = window . location . href . split ( "#" ) [ 1 ] + "-1" ;
683
- }
684
- document . getElementById ( "saveChanges" ) . className = "btn btn-primary" ;
685
- document . getElementById ( "saveChanges" ) . innerText = "Save" ;
686
- document . getElementById ( "projectNameGroup" ) . className = "form-group has-success" ;
629
+ if ( getID ( ) ) {
630
+ app . projectNameInputValue = autoIncrimentedName ( )
687
631
}
632
+ $ ( '#saveModal' ) . modal ( 'show' )
688
633
}
689
- if ( name ) {
690
- saveProject ( name ) ;
634
+ }
635
+
636
+ $ ( '.modal' ) . on ( 'shown.bs.modal' , function ( ) {
637
+ $ ( '#projectName' ) . focus ( ) // focus on the project name input box when the modal loads
638
+ } )
639
+
640
+ var autoIncrimentedName = function ( ) {
641
+ var projName = getID ( ) ;
642
+ var versionNumber = parseInt ( projName [ projName . length - 1 ] )
643
+ if ( ! isNaN ( versionNumber ) && projName [ projName . length - 2 ] == "-" ) {
644
+ versionNumber += 1 ;
645
+ return projName . substring ( 0 , projName . length - 1 ) + versionNumber . toString ( ) ;
646
+ } else {
647
+ return projName + "-1" ;
691
648
}
692
- } ;
649
+ }
693
650
694
651
// keyboard shortcuts
695
652
var mac = CodeMirror . keyMap [ "default" ] == CodeMirror . keyMap . macDefault ;
0 commit comments