@@ -739,7 +739,11 @@ define(function (require, exports, module) {
739739 * @return {!string } fullPath reference
740740 */
741741 function getWelcomeProjectPath ( ) {
742- return ProjectModel . _getWelcomeProjectPath ( Urls . GETTING_STARTED , Phoenix . VFS . getDefaultProjectDir ( ) ) ;
742+ return ProjectModel . _ensureTrailingSlash ( Phoenix . VFS . getDefaultProjectDir ( ) ) ;
743+ }
744+
745+ function _getPlaceholderProjectPath ( ) {
746+ return "/no_project_loaded" ;
743747 }
744748
745749 function getExploreProjectPath ( ) {
@@ -1115,52 +1119,132 @@ define(function (require, exports, module) {
11151119 } ) ;
11161120 }
11171121
1118- function _loadProjectInternal ( rootPath ) {
1122+ function _loadExistingProject ( rootEntry ) {
1123+ const rootPath = rootEntry . fullPath ;
11191124 const result = new $ . Deferred ( ) ;
1120- const rootEntry = FileSystem . getDirectoryForPath ( rootPath ) ;
1121- rootEntry . exists ( function ( err , exists ) {
1122- if ( exists ) {
1123- var projectRootChanged = ( ! model . projectRoot || ! rootEntry ) ||
1124- model . projectRoot . fullPath !== rootEntry . fullPath ;
1125+ var projectRootChanged = ( ! model . projectRoot || ! rootEntry ) ||
1126+ model . projectRoot . fullPath !== rootEntry . fullPath ;
11251127
1126- // Success!
1127- var perfTimerName = PerfUtils . markStart ( "Load Project: " + rootPath ) ;
1128+ // Success!
1129+ var perfTimerName = PerfUtils . markStart ( "Load Project: " + rootPath ) ;
11281130
1129- _projectWarnedForTooManyFiles = false ;
1131+ _projectWarnedForTooManyFiles = false ;
11301132
1131- _setProjectRoot ( rootEntry ) . always ( function ( ) {
1132- model . setBaseUrl ( PreferencesManager . getViewState ( "project.baseUrl" , PreferencesManager . STATE_PROJECT_CONTEXT ) || "" ) ;
1133+ _setProjectRoot ( rootEntry ) . always ( function ( ) {
1134+ model . setBaseUrl ( PreferencesManager . getViewState ( "project.baseUrl" , PreferencesManager . STATE_PROJECT_CONTEXT ) || "" ) ;
11331135
1134- if ( projectRootChanged ) {
1135- _reloadProjectPreferencesScope ( ) ;
1136- PreferencesManager . _setCurrentFile ( rootPath ) ;
1137- }
1138- _watchProjectRoot ( rootPath ) ;
1136+ if ( projectRootChanged ) {
1137+ _reloadProjectPreferencesScope ( ) ;
1138+ PreferencesManager . _setCurrentFile ( rootPath ) ;
1139+ }
1140+ _watchProjectRoot ( rootPath ) ;
11391141
1140- // If this is the most current welcome project, record it. In future launches, we want
1141- // to substitute the latest welcome project from the current build instead of using an
1142- // outdated one (when loading recent projects or the last opened project).
1143- if ( rootPath === getWelcomeProjectPath ( ) ) {
1144- addWelcomeProjectPath ( rootPath ) ;
1145- }
1142+ // If this is the most current welcome project, record it. In future launches, we want
1143+ // to substitute the latest welcome project from the current build instead of using an
1144+ // outdated one (when loading recent projects or the last opened project).
1145+ if ( rootPath === getWelcomeProjectPath ( ) ) {
1146+ addWelcomeProjectPath ( rootPath ) ;
1147+ }
11461148
1147- if ( projectRootChanged ) {
1148- // Allow asynchronous event handlers to finish before resolving result by collecting promises from them
1149- exports . trigger ( EVENT_PROJECT_OPEN , model . projectRoot ) ;
1150- result . resolve ( ) ;
1151- exports . trigger ( EVENT_AFTER_PROJECT_OPEN , model . projectRoot ) ;
1152- } else {
1153- exports . trigger ( EVENT_PROJECT_REFRESH , model . projectRoot ) ;
1154- result . resolve ( ) ;
1149+ if ( projectRootChanged ) {
1150+ // Allow asynchronous event handlers to finish before resolving result by collecting promises from them
1151+ exports . trigger ( EVENT_PROJECT_OPEN , model . projectRoot ) ;
1152+ result . resolve ( ) ;
1153+ exports . trigger ( EVENT_AFTER_PROJECT_OPEN , model . projectRoot ) ;
1154+ } else {
1155+ exports . trigger ( EVENT_PROJECT_REFRESH , model . projectRoot ) ;
1156+ result . resolve ( ) ;
1157+ }
1158+ let projectLoadTime = PerfUtils . addMeasurement ( perfTimerName ) ;
1159+ Metrics . valueEvent ( Metrics . EVENT_TYPE . PERFORMANCE , "projectLoad" ,
1160+ "timeMs" , Number ( projectLoadTime ) ) ;
1161+ } ) ;
1162+ return result . promise ( ) ;
1163+ }
1164+
1165+ const _SAMPLE_HTML = `<!DOCTYPE html>
1166+ <html>
1167+ <head>
1168+ <title>Phoenix Editor for the web</title>
1169+ </head>
1170+
1171+ <body>
1172+ <h1>Welcome to Phoenix</h1>
1173+ <p> Modern, Open-source, IDE For The Web.</p>
1174+ </body>
1175+ </html>` ;
1176+
1177+ function _createDefaultProject ( ) {
1178+ // Create phoenix app dirs
1179+ // Create Phoenix default project if it doesnt exist
1180+ return new Promise ( ( resolve , reject ) => {
1181+ let projectDir = getWelcomeProjectPath ( ) ;
1182+ Phoenix . VFS . exists ( projectDir , ( exists ) => {
1183+ if ( exists ) {
1184+ resolve ( ) ;
1185+ return ;
1186+ }
1187+ Phoenix . VFS . ensureExistsDir ( projectDir , ( err ) => {
1188+ if ( err ) {
1189+ window . logger . reportError ( err , "Error creating default project" ) ;
1190+ reject ( err ) ;
1191+ return ;
11551192 }
1156- let projectLoadTime = PerfUtils . addMeasurement ( perfTimerName ) ;
1157- Metrics . valueEvent ( Metrics . EVENT_TYPE . PERFORMANCE , "projectLoad" ,
1158- "timeMs" , Number ( projectLoadTime ) ) ;
1193+ let indexFile = Phoenix . VFS . path . normalize ( ` ${ projectDir } /index.html` ) ;
1194+ Phoenix . VFS . fs . writeFile ( indexFile , _SAMPLE_HTML , 'utf8' , ( ) => { } ) ;
1195+ resolve ( ) ;
11591196 } ) ;
1197+ } ) ;
1198+ } ) ;
1199+ }
1200+
1201+ function _loadWelcomeProject ( welcomeProjectPath ) {
1202+ const result = new $ . Deferred ( ) ;
1203+ const rootEntry = FileSystem . getDirectoryForPath ( welcomeProjectPath ) ;
1204+ function _loadRootEntry ( ) {
1205+ _loadExistingProject ( rootEntry )
1206+ . done ( result . resolve )
1207+ . fail ( result . reject ) ;
1208+ }
1209+ rootEntry . exists ( function ( err , exists ) {
1210+ if ( exists ) {
1211+ _loadRootEntry ( ) ;
1212+ } else {
1213+ // create the welcome project
1214+ _createDefaultProject ( )
1215+ . then ( _loadRootEntry )
1216+ . catch ( ( ) => {
1217+ // default project could not be created. As a last ditch effort to continue boot, we will
1218+ // use a vfs path `/no_project_loaded` to continue boot.
1219+ Phoenix . VFS . ensureExistsDir ( _getPlaceholderProjectPath ( ) , ( placeHolderErr ) => {
1220+ if ( placeHolderErr ) {
1221+ window . logger . reportError ( placeHolderErr , "Error creating /no_project_loaded" ) ;
1222+ alert ( "Unrecoverable error, startup project could not be created." ) ;
1223+ return ;
1224+ }
1225+ const placeholderProject = FileSystem . getDirectoryForPath ( _getPlaceholderProjectPath ( ) ) ;
1226+ _loadExistingProject ( placeholderProject )
1227+ . done ( result . resolve )
1228+ . fail ( result . reject ) ;
1229+ } ) ;
1230+ } ) ;
1231+ }
1232+ } ) ;
1233+ return result . promise ( ) ;
1234+ }
1235+
1236+ function _loadProjectInternal ( rootPath ) {
1237+ const result = new $ . Deferred ( ) ;
1238+ const rootEntry = FileSystem . getDirectoryForPath ( rootPath ) ;
1239+ rootEntry . exists ( function ( err , exists ) {
1240+ if ( exists ) {
1241+ _loadExistingProject ( rootEntry )
1242+ . done ( result . resolve )
1243+ . fail ( result . reject ) ;
11601244 } else {
11611245 console . error ( "error loading project" ) ;
11621246 exports . trigger ( EVENT_PROJECT_OPEN_FAILED , rootPath ) ;
1163- _showErrorDialog ( ERR_TYPE_LOADING_PROJECT_NATIVE , true , err || FileSystemError . NOT_FOUND , rootPath )
1247+ _showErrorDialog ( ERR_TYPE_LOADING_PROJECT_NATIVE , true , FileSystemError . NOT_FOUND , rootPath )
11641248 . done ( function ( ) {
11651249 // Reset _projectRoot to null so that the following _loadProject call won't
11661250 // run the 'beforeProjectClose' event a second time on the original project,
@@ -1182,7 +1266,6 @@ define(function (require, exports, module) {
11821266 } ) ;
11831267 }
11841268 } ) ;
1185-
11861269 return result . promise ( ) ;
11871270 }
11881271
@@ -1223,8 +1306,10 @@ define(function (require, exports, module) {
12231306 PreferencesManager . _reloadUserPrefs ( model . projectRoot ) ;
12241307 exports . trigger ( EVENT_PROJECT_CLOSE , model . projectRoot ) ;
12251308 }
1226-
1227- // Point at a real folder structure on local disk
1309+ if ( rootPath === getWelcomeProjectPath ( ) ) {
1310+ // welcome project path is always guaranteed to be present!
1311+ return _loadWelcomeProject ( rootPath ) ;
1312+ }
12281313 return _loadProjectInternal ( rootPath ) ;
12291314 }
12301315
@@ -1945,17 +2030,22 @@ define(function (require, exports, module) {
19452030 function _flagProjectNotExitedSafely ( projectRootPath ) {
19462031 // we store this in local storage as these checks happen in app exit/startup flows where
19472032 // phstore is not reliable. It's ok to lose this data.
1948- localStorage . setItem ( UNSAFE_PROJECT_EXIT_PREFIX + projectRootPath , "true" ) ;
2033+ PhStore . setItem ( UNSAFE_PROJECT_EXIT_PREFIX + projectRootPath , true ) ;
2034+ PhStore . persistDBForReboot ( ) ; // promise is ignored here.
19492035 }
19502036 function _flagProjectExitedSafely ( projectRootPath ) {
1951- localStorage . removeItem ( UNSAFE_PROJECT_EXIT_PREFIX + projectRootPath ) ;
2037+ PhStore . removeItem ( UNSAFE_PROJECT_EXIT_PREFIX + projectRootPath ) ;
19522038 }
19532039 function _isProjectSafeToStartup ( projectRootPath ) {
19542040 // In some cases, For eg: user tries to open a whole drive with phcode (or any project that makes phcode crash),
19552041 // phoenix may get stuck and never open again with the bad project as we try to open the same bad project
19562042 // on restart. So we keep a safe exit flag with each project. We only start the project on boot if it has
19572043 // been marked safe at previous exit or project switch. So on unsafe exit, the default project will be opened.
1958- const unsafeExit = ( localStorage . getItem ( UNSAFE_PROJECT_EXIT_PREFIX + projectRootPath ) === "true" ) ;
2044+ const unsafeExit = ( PhStore . getItem ( UNSAFE_PROJECT_EXIT_PREFIX + projectRootPath ) === true ) ;
2045+ if ( unsafeExit ) {
2046+ console . error ( `Project ${ projectRootPath } marked as not safe to startup during` +
2047+ `previous exit. Starting default project` ) ;
2048+ }
19592049 return ! unsafeExit ;
19602050 }
19612051
0 commit comments