|
78 | 78 | "\n\nYou will now be redirected to phcode.dev."); |
79 | 79 | window.location = "https://phcode.dev"; |
80 | 80 | } |
| 81 | + if(window.electronAPI) { |
| 82 | + window.__ELECTRON__ = true; |
| 83 | + } |
81 | 84 | if(location.href.startsWith("tauri://") || location.href.startsWith('https://tauri.localhost')){ |
82 | 85 | const errorMessage = `You should use custom protocol phtauri:// instead of tauri protocol ${location.href} .`; |
83 | 86 | alert(errorMessage); |
|
94 | 97 | const isSpecRunnerWindow = window.location.pathname.endsWith("/SpecRunner.html"); |
95 | 98 | return isTestPhoenixWindow || isSpecRunnerWindow; |
96 | 99 | } |
97 | | - let canAccessTauri = false; |
| 100 | + let canAccessNativeShell = false; |
98 | 101 | try { |
99 | 102 | // This is to allow phoenix live previews in phoenix desktop editor so that we can |
100 | 103 | // develop phoenix inside phoenix. |
101 | 104 | // This will throw an error if the live preview iframe and parent are cross-origin which is case in phcode |
102 | | - canAccessTauri = window.top.window.__TAURI__; |
103 | | - canAccessTauri = true; |
| 105 | + canAccessNativeShell = window.top.window.__TAURI__; |
| 106 | + canAccessNativeShell = window.top.window.electronAPI; |
| 107 | + canAccessNativeShell = true; |
104 | 108 | } catch (e) { |
105 | 109 | // Cross-origin, exception caught, isSameOrigin remains false |
106 | 110 | } |
107 | 111 |
|
108 | 112 | // In Mac !! the window.__TAURI__ object is present in iframes, even if it doesnt works. so we are forced |
109 | 113 | // to use if(window.parent.window !== window) instead of if(!window.__TAURI__) here. |
110 | | - if(canAccessTauri && window.parent.window !== window && window.top.window.__TAURI__) { |
| 114 | + if(canAccessNativeShell && window.parent.window !== window && window.top.window.__TAURI__) { |
111 | 115 | // This is only intended to be used for in tests where phoenix is loaded inside iframes. |
112 | 116 | // this means that we are loaded in an iframe in the specrunner. Tauri doesnt expose tauri APIs |
113 | 117 | // in its iframes, so we directly use the top most windows tauri api object for tests to run properly. |
|
163 | 167 | } |
164 | 168 | // fs special handling end |
165 | 169 | } |
| 170 | + // linux electron api iframe injection for tests |
| 171 | + if(canAccessNativeShell && window.parent.window !== window && window.top.window.__ELECTRON__) { |
| 172 | + // This is only intended to be used for in tests where phoenix is loaded inside iframes. |
| 173 | + // this means that we are loaded in an iframe in the specrunner. Tauri doesnt expose tauri APIs |
| 174 | + // in its iframes, so we directly use the top most windows tauri api object for tests to run properly. |
| 175 | + console.warn("Phoenix is loaded in iframe, attempting to use electron APIs from window.top.electronAPI"); |
| 176 | + window.electronAPI = window.top.window.electronAPI; |
| 177 | + } |
| 178 | + if(window.__TAURI__ || window.__ELECTRON__) { |
| 179 | + window.__IS_NATIVE_SHELL__ = true; |
| 180 | + } |
| 181 | + // Common function to process boot vars results for both Tauri and Electron |
| 182 | + function _processBootVarsResults(results, pathSep, LOCALSTORAGE_KEY, bootStartTime) { |
| 183 | + // results array: [appName, documentDir, appLocalDir, tempDir, homeDir] |
| 184 | + const idx = {appName: 0, docDir: 1, appLocal: 2, temp: 3, home: 4}; |
| 185 | + |
| 186 | + window._tauriBootVars.appname = results[idx.appName].value; |
| 187 | + |
| 188 | + if(results[idx.docDir].status === "fulfilled"){ |
| 189 | + window._tauriBootVars.documentDir = results[idx.docDir].value; |
| 190 | + } else if(results[idx.home] && results[idx.home].status === "fulfilled"){ |
| 191 | + // some linux distros may not have Documents folder. so we use the home folder |
| 192 | + // https://github.com/phcode-dev/phoenix/issues/1729 |
| 193 | + window._tauriBootVars.documentDir = results[idx.home].value; |
| 194 | + } else if(results[idx.appLocal].status === "fulfilled"){ |
| 195 | + console.error("Unable to determine user documents dir, defaulting to app data dir as document dir:", |
| 196 | + results[idx.docDir].reason, "home folder error: ", results[idx.home]?.reason); |
| 197 | + window._tauriBootVars.documentDir = results[idx.appLocal].value; |
| 198 | + } else { |
| 199 | + alert("Could not resolve user documents directory. \nPhoenix Code cannot start."); |
| 200 | + } |
| 201 | + |
| 202 | + if(results[idx.appLocal].status === "fulfilled") { |
| 203 | + window._tauriBootVars.appLocalDir = results[idx.appLocal].value; |
| 204 | + } else { |
| 205 | + alert("Could not resolve Application Data directory. \nPhoenix Code cannot start."); |
| 206 | + } |
| 207 | + |
| 208 | + // For tests, documents dir is localAppDataDir/testDocuments to keep user documents garbage free for tests |
| 209 | + // Also In github actions, the tauri get doc dir call gets stuck indefinitely |
| 210 | + if(_isTestWindow()){ |
| 211 | + if(!window._tauriBootVars.documentDir.endsWith(pathSep)){ |
| 212 | + window._tauriBootVars.documentDir = window._tauriBootVars.documentDir + pathSep; |
| 213 | + } |
| 214 | + window._tauriBootVars.documentDir = `${window._tauriBootVars.documentDir}testDocuments${pathSep}`; |
| 215 | + } |
| 216 | + |
| 217 | + window._tauriBootVars.appLocalDir = results[idx.appLocal].value; |
| 218 | + window._tauriBootVars.tempDir = results[idx.temp].value; |
| 219 | + window._tauriBootVars.bootstrapTime = Date.now() - bootStartTime; |
| 220 | + localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(window._tauriBootVars)); |
| 221 | + } |
166 | 222 | if(window.__TAURI__) { |
167 | 223 | function setupTauriBootVars() { |
168 | 224 | // this is used by storage.js (window.PhStore) to restore our persistent storage layer in tauri. |
|
201 | 257 | window._tauriBootVarsPromise = Promise.allSettled([appNamePromise, documentDirPromise, |
202 | 258 | appLocalDirPromise, tempDirPromise, homeDirPromise]) |
203 | 259 | .then((results) => { |
204 | | - window._tauriBootVars.appname = results[0].value; |
205 | | - |
206 | | - if(results[1].status === "fulfilled"){ |
207 | | - window._tauriBootVars.documentDir = results[1].value; |
208 | | - } else if(results[4].status === "fulfilled"){ |
209 | | - // some linux distros may not have Documents folder. so we use the home folder |
210 | | - // https://github.com/phcode-dev/phoenix/issues/1729 |
211 | | - window._tauriBootVars.documentDir = results[4].value; |
212 | | - } else if(results[2].status === "fulfilled"){ |
213 | | - console.error("Unable to determine user documents dir, defaulting to app data dir as document dir:", |
214 | | - results[1].reason, "home folder error: ", results[4].reason); |
215 | | - window._tauriBootVars.documentDir = results[2].value; |
216 | | - } else { |
217 | | - alert("Could not resolve user documents directory. \nPhoenix Code cannot start."); |
218 | | - } |
219 | | - |
220 | | - if(results[2].status === "fulfilled") { |
221 | | - window._tauriBootVars.appLocalDir = results[2].value; |
222 | | - } else { |
223 | | - alert("Could not resolve Application Data directory. \nPhoenix Code cannot start."); |
224 | | - } |
225 | | - |
226 | | - // For tests, documents dir is localAppDataDir/testDocuments to keep user documents garbage free for tests |
227 | | - // Also In github actions, the tauri get doc dir call gets stuck indefinitely |
228 | | - if(_isTestWindow()){ |
229 | | - if(!window._tauriBootVars.documentDir.endsWith(window.__TAURI__.path.sep)){ |
230 | | - window._tauriBootVars.documentDir = window._tauriBootVars.documentDir + window.__TAURI__.path.sep; |
231 | | - } |
232 | | - window._tauriBootVars.documentDir = `${window._tauriBootVars.documentDir}testDocuments${window.__TAURI__.path.sep}`; |
| 260 | + _processBootVarsResults(results, window.__TAURI__.path.sep, TAURI_BOOT_VARS_LOCALSTORAGE_KEY, tauriBootStartTime); |
| 261 | + }); |
| 262 | + } |
| 263 | + setupTauriBootVars(); |
| 264 | + } |
| 265 | + if(window.__ELECTRON__) { |
| 266 | + function setupElectronBootVars() { |
| 267 | + // this is used by storage.js (window.PhStore) to restore our persistent storage layer in electron. |
| 268 | + window._tauriStorageRestorePromise = window.electronFSAPI.appLocalDataDir() |
| 269 | + .then(appDataDir => { |
| 270 | + const sep = window.electronFSAPI.path.sep; |
| 271 | + const storagePath = `${appDataDir}${appDataDir.endsWith(sep) ? "" : sep}storageDB${sep}storageDBDump.json`; |
| 272 | + return window.electronFSAPI.fsReadFile(storagePath); |
| 273 | + }) |
| 274 | + .then(data => { |
| 275 | + if(data && data.__fsError) { |
| 276 | + throw new Error(data.message); |
233 | 277 | } |
234 | | - //Documents dir special case for tests |
| 278 | + return data; |
| 279 | + }) |
| 280 | + .catch(err => { |
| 281 | + console.error("First boot detected or Failed to init storage from cache." + |
| 282 | + " If first boot, ignore this error", err); |
| 283 | + }); |
| 284 | + // increase this version number if you are modifying any boot vars |
| 285 | + const TAURI_BOOT_VARS_LOCALSTORAGE_KEY = "tauriBootVarsV1"; |
| 286 | + const tauriBootVarsStr = localStorage.getItem(TAURI_BOOT_VARS_LOCALSTORAGE_KEY); |
| 287 | + if(tauriBootVarsStr) { |
| 288 | + try{ |
| 289 | + window._tauriBootVars = JSON.parse(tauriBootVarsStr); |
| 290 | + window._tauriBootVarsPromise = Promise.resolve("Resolved from localstorage."); |
| 291 | + } catch (e) { |
| 292 | + console.error("Error getting boot vars from localstorage. Falling back to make electron bootstrap calls.", e); |
| 293 | + } |
| 294 | + } |
| 295 | + const appNamePromise = window.electronAppAPI.getAppName(); |
| 296 | + // for running tests, the user document dir is set to app data dir as we dont want to |
| 297 | + // corrupt user documents dir for tests |
| 298 | + let documentDirPromise, homeDirPromise; |
| 299 | + if(_isTestWindow()){ |
| 300 | + documentDirPromise = window.electronFSAPI.appLocalDataDir(); // appdata/testDocuments will be appended below |
| 301 | + } else { |
| 302 | + documentDirPromise = window.electronFSAPI.documentDir(); |
| 303 | + homeDirPromise = window.electronFSAPI.homeDir(); |
| 304 | + } |
235 | 305 |
|
236 | | - window._tauriBootVars.appLocalDir = results[2].value; |
237 | | - window._tauriBootVars.tempDir = results[3].value; |
238 | | - window._tauriBootVars.bootstrapTime = Date.now() - tauriBootStartTime; |
239 | | - localStorage.setItem(TAURI_BOOT_VARS_LOCALSTORAGE_KEY, JSON.stringify(window._tauriBootVars)); |
| 306 | + const appLocalDirPromise = window.electronFSAPI.appLocalDataDir(); |
| 307 | + const tempDirPromise = window.electronFSAPI.tempDir(); |
| 308 | + window._tauriBootVars = {}; |
| 309 | + const tauriBootStartTime = Date.now(); |
| 310 | + window._tauriBootVarsPromise = Promise.allSettled([appNamePromise, documentDirPromise, |
| 311 | + appLocalDirPromise, tempDirPromise, homeDirPromise]) |
| 312 | + .then((results) => { |
| 313 | + _processBootVarsResults(results, window.electronFSAPI.path.sep, TAURI_BOOT_VARS_LOCALSTORAGE_KEY, tauriBootStartTime); |
240 | 314 | }); |
241 | 315 | } |
242 | | - setupTauriBootVars(); |
| 316 | + setupElectronBootVars(); |
243 | 317 | } |
244 | 318 |
|
245 | 319 | // environment setup for boot. do not move out of index html!! |
|
290 | 364 | isDeskTop: !_mobileAndTabletCheck() && !_mobileCheck(), |
291 | 365 | isChromeOS: /CrOS/.test(navigator.userAgent), |
292 | 366 | isTauri: !!window.__TAURI__, |
| 367 | + isElectron: !!window.__ELECTRON__, |
293 | 368 | mobile: { |
294 | 369 | isAndroid: (navigator.userAgent.match(/Android/i) !== null), |
295 | 370 | isIos: (navigator.userAgent.match(/iPhone|iPad|iPod/i) !== null), |
|
370 | 445 | 'https://create.phcode.dev': true |
371 | 446 | } |
372 | 447 | }; |
373 | | - window.Phoenix.isNativeApp = window.Phoenix.browser.isTauri; |
| 448 | + window.Phoenix.isNativeApp = window.__IS_NATIVE_SHELL__; |
374 | 449 | window.Phoenix.TRUSTED_ORIGINS[location.origin] = true; |
375 | 450 | Phoenix.isSupportedBrowser = Phoenix.isNativeApp || |
376 | 451 | (Phoenix.browser.isDeskTop && ("serviceWorker" in navigator)); |
|
667 | 742 | _resetCacheIfNeeded(); |
668 | 743 |
|
669 | 744 | function _addOrRemoveSplashScreenIfNeeded() { |
670 | | - if(!window.__TAURI__) { |
| 745 | + if(!window.__IS_NATIVE_SHELL__) { |
671 | 746 | document.getElementById('phoenix-loading-splash-screen-overlay').classList.remove('forced-hidden') |
672 | 747 | } |
673 | | - if(window.testEnvironment || window.__TAURI__){ |
674 | | - // tauri means local builds and, it loads up pretty fast, so splash screen |
| 748 | + if(window.testEnvironment || window.__IS_NATIVE_SHELL__){ |
| 749 | + // tauri means local builds and, it loads up pretty fast, so no splash screen |
675 | 750 | document.getElementById('phoenix-loading-splash-screen-overlay').remove(); |
676 | 751 | window.splashScreenPresent = false; |
677 | 752 | } |
|
0 commit comments