execute: args => { const current = getCurrent(args); if (!current) { return; } const notebookPath = URLExt.encodeParts(current.context.path); const url = URLExt.join( services.serverSettings.baseUrl, 'nbconvert', (args['format']) as string, notebookPath ) + '?download=true'; const child = window.open('', '_blank'); const { context } = current; if (context.model.dirty && !context.model.readOnly) { return context.save().then(() => { child.location.assign(url); }); } return new Promise<void>((resolve) => { child.location.assign(url); resolve(undefined); }); },
export function makeSettings( options: Partial<ServerConnection.ISettings> = {} ): ServerConnection.ISettings { let extra: Partial<ServerConnection.ISettings> = {}; if (options.baseUrl && !options.wsUrl) { // Setting baseUrl to https://host... sets wsUrl to wss://host... let baseUrl = options.baseUrl; if (baseUrl.indexOf('http') !== 0) { if (typeof location !== 'undefined') { baseUrl = URLExt.join(location.origin, baseUrl); } else { // TODO: Why are we hardcoding localhost and 8888? That doesn't seem // good. See https://github.com/jupyterlab/jupyterlab/issues/4761 baseUrl = URLExt.join('http://localhost:8888/', baseUrl); } } extra = { wsUrl: 'ws' + baseUrl.slice(4) }; } return { ...ServerConnection.defaultSettings, ...options, ...extra }; }
execute: args => { let current = getCurrent(args); if (!current) { return; } let notebookPath = URLExt.encodeParts(current.context.path); let url = URLExt.join( services.serverSettings.baseUrl, 'nbconvert', (args['format']) as string, notebookPath ) + '?download=true'; let w = window.open('', '_blank'); if (current.context.model.dirty && !current.context.model.readOnly) { return current.context.save().then(() => { w.location.assign(url); }); } else { return new Promise((resolve, reject) => { w.location.assign(url); }); } },
execute: (args: IRouter.ILocation) => { const { hash, path, search } = args; const query = URLExt.queryStringToObject(search || ''); const reset = 'reset' in query; if (!reset) { return; } // If the state database has already been resolved, resetting is // impossible without reloading. if (resolved) { return document.location.reload(); } // Empty the state database. resolved = true; transform.resolve({ type: 'clear', contents: null }); // Maintain the query string parameters but remove `reset`. delete query['reset']; const url = path + URLExt.objectToQueryString(query) + hash; const cleared = commands.execute(CommandIDs.recoverState) .then(() => router.stop); // Stop routing before new route navigation. // After the state has been reset, navigate to the URL. cleared.then(() => { router.navigate(url, { silent: true }); }); return cleared; }
it('should test whether the url is a local url', () => { expect(URLExt.isLocal('https://foo/bar.txt')).to.equal(false); expect(URLExt.isLocal('http://foo/bar.txt')).to.equal(false); expect(URLExt.isLocal('//foo/bar.txt')).to.equal(false); expect(URLExt.isLocal('../foo/bar.txt')).to.equal(true); expect(URLExt.isLocal('./foo/bar.txt')).to.equal(true); expect(URLExt.isLocal('/foo/bar.txt')).to.equal(true); expect(URLExt.isLocal('foo/bar.txt')).to.equal(true); expect(URLExt.isLocal('bar.txt')).to.equal(true); expect(URLExt.isLocal('file://foo/bar.txt')).to.equal(false); expect(URLExt.isLocal('data:text/plain,123ABC')).to.equal(false); });
activate: async ( _: JupyterFrontEnd, paths: JupyterFrontEnd.IPaths, router: IRouter ) => { const { hash, path, search } = router.current; const query = URLExt.queryStringToObject(search || ''); const solver = new WindowResolver(); const match = path.match(new RegExp(`^${paths.urls.workspaces}([^?\/]+)`)); const workspace = (match && decodeURIComponent(match[1])) || ''; const candidate = Private.candidate(paths, workspace); try { await solver.resolve(candidate); } catch (error) { // Window resolution has failed so the URL must change. Return a promise // that never resolves to prevent the application from loading plugins // that rely on `IWindowResolver`. return new Promise<IWindowResolver>(() => { // If the user has requested workspace resolution create a new one. if (WORKSPACE_RESOLVE in query) { const { base, workspaces } = paths.urls; const pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const random = pool[Math.floor(Math.random() * pool.length)]; const path = URLExt.join(base, workspaces, `auto-${random}`); // Clone the originally requested workspace after redirecting. query['clone'] = workspace; // Change the URL and trigger a hard reload to re-route. const url = path + URLExt.objectToQueryString(query) + (hash || ''); router.navigate(url, { hard: true, silent: true }); return; } // Launch a dialog to ask the user for a new workspace name. console.warn('Window resolution failed:', error); return Private.redirect(router, paths, workspace); }); } // If the user has requested workspace resolution remove the query param. if (WORKSPACE_RESOLVE in query) { delete query[WORKSPACE_RESOLVE]; // Silently scrub the URL. const url = path + URLExt.objectToQueryString(query) + (hash || ''); router.navigate(url, { silent: true }); } return solver; }
return new Promise<IWindowResolver>(() => { const { base, workspaces } = paths.urls; const pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const random = pool[Math.floor(Math.random() * pool.length)]; const path = URLExt.join(base, workspaces, `auto-${random}`) + rest; // Clone the originally requested workspace after redirecting. query['clone'] = workspace; // Change the URL and trigger a hard reload to re-route. const url = path + URLExt.objectToQueryString(query) + (hash || ''); router.navigate(url, { hard: true, silent: true }); });
execute: (args: IRouter.ILocation) => { const { hash, path, search } = args; const query = URLExt.queryStringToObject(search || ''); const reset = 'reset' in query; const clone = 'clone' in query; if (!reset) { return; } // If a splash provider exists, launch the splash screen. const loading = splash ? splash.show() : new DisposableDelegate(() => undefined); // If the state database has already been resolved, resetting is // impossible without reloading. if (resolved) { return router.reload(); } // Empty the state database. resolved = true; transform.resolve({ type: 'clear', contents: null }); // Maintain the query string parameters but remove `reset`. delete query['reset']; const silent = true; const hard = true; const url = path + URLExt.objectToQueryString(query) + hash; const cleared = commands .execute(CommandIDs.recoverState) .then(() => router.stop); // Stop routing before new route navigation. // After the state has been reset, navigate to the URL. if (clone) { void cleared.then(() => { router.navigate(url, { silent, hard }); }); } else { void cleared.then(() => { router.navigate(url, { silent }); loading.dispose(); }); } return cleared; }
export async function redirect( router: IRouter, paths: JupyterFrontEnd.IPaths, workspace: string, warn = false ): Promise<void> { const form = createRedirectForm(warn); const dialog = new Dialog({ title: 'Please use a different workspace.', body: form, focusNodeSelector: 'input', buttons: [Dialog.okButton({ label: 'Switch Workspace' })] }); const result = await dialog.launch(); dialog.dispose(); if (!result.value) { return redirect(router, paths, workspace, true); } // Navigate to a new workspace URL and abandon this session altogether. const page = paths.urls.page; const workspaces = paths.urls.workspaces; const prefix = (workspace ? workspaces : page).length + workspace.length; const rest = router.current.request.substring(prefix); const url = URLExt.join(workspaces, result.value, rest); router.navigate(url, { hard: true, silent: true }); // This promise will never resolve because the application navigates // away to a new location. It only exists to satisfy the return type // of the `redirect` function. return new Promise<void>(() => undefined); }
it('should return a serialized object string suitable for a query', () => { const obj = { name: 'foo', id: 'baz' }; expect(URLExt.objectToQueryString(obj)).to.equal('?name=foo&id=baz'); });