diff --git a/src/static/js/getHomeUrl.ts b/src/static/js/getHomeUrl.ts new file mode 100644 index 00000000000..44a407408a5 --- /dev/null +++ b/src/static/js/getHomeUrl.ts @@ -0,0 +1,12 @@ +'use strict'; + +/** + * Resolve the Etherpad home URL from a pad URL. + * + * Pad pages live at `{prefix}/p/{padId}`. One `..` segment removes the pad id + * and lands on `{prefix}/`, which is correct both for root deployments + * (`/p/testpad` -> `/`) and reverse-proxy prefixes (`/etherpad/p/testpad` + * -> `/etherpad/`). See issue #8111. + */ +export const getHomeUrl = (fromHref: string): string => + new URL('..', fromHref).href; diff --git a/src/static/js/pad_editbar.ts b/src/static/js/pad_editbar.ts index 30fd55fa34e..6e9e8f1ba50 100644 --- a/src/static/js/pad_editbar.ts +++ b/src/static/js/pad_editbar.ts @@ -24,6 +24,7 @@ */ const hooks = require('./pluginfw/hooks'); +import {getHomeUrl} from './getHomeUrl'; import padutils from "./pad_utils"; const padeditor = require('./pad_editor').padeditor; const padsavedrevs = require('./pad_savedrevs'); @@ -481,9 +482,9 @@ exports.padeditbar = new class { this.registerDropdownCommand('connectivity'); this.registerDropdownCommand('import_export'); this.registerDropdownCommand('embed'); - this.registerCommand('home', ()=>{ - window.location.href = new URL('../..', window.location.href).href - }) + this.registerCommand('home', () => { + window.location.href = getHomeUrl(window.location.href); + }); this.registerCommand('settings', () => { this.toggleDropDown('settings'); diff --git a/src/static/js/pad_editor.ts b/src/static/js/pad_editor.ts index bd721e62cd8..2293da674bc 100644 --- a/src/static/js/pad_editor.ts +++ b/src/static/js/pad_editor.ts @@ -22,6 +22,7 @@ * limitations under the License. */ +import {getHomeUrl} from './getHomeUrl'; import padutils from "./pad_utils"; const Ace2Editor = require('./ace').Ace2Editor; import html10n from '../js/vendors/html10n' @@ -176,7 +177,7 @@ const padeditor = (() => { pad.socket.on('message', (data: any) => { if (data && data.disconnect === 'deleted') { handled = true; - window.location.href = '/'; + window.location.href = getHomeUrl(window.location.href); } }); pad.socket.on('shout', (data: any) => { @@ -192,7 +193,7 @@ const padeditor = (() => { data: {padId: pad.getPadId(), deletionToken: token}, }); setTimeout(() => { - if (!handled) window.location.href = '/'; + if (!handled) window.location.href = getHomeUrl(window.location.href); }, 5000); }); @@ -207,7 +208,7 @@ const padeditor = (() => { pad.socket.on('message', (data: any) => { if (data && data.disconnect === 'deleted') { handled = true; - window.location.href = '/'; + window.location.href = getHomeUrl(window.location.href); } }); // If the user is not the pad creator, the server sends a shout @@ -224,7 +225,7 @@ const padeditor = (() => { // Fallback: if the server doesn't respond within 5 seconds // (e.g. socket dropped), navigate away anyway. setTimeout(() => { - if (!handled) window.location.href = '/'; + if (!handled) window.location.href = getHomeUrl(window.location.href); }, 5000); } }) diff --git a/src/tests/backend-new/specs/getHomeUrl.test.ts b/src/tests/backend-new/specs/getHomeUrl.test.ts new file mode 100644 index 00000000000..1933e4148bb --- /dev/null +++ b/src/tests/backend-new/specs/getHomeUrl.test.ts @@ -0,0 +1,20 @@ +'use strict'; + +import {describe, it, expect} from 'vitest'; +import {getHomeUrl} from '../../../static/js/getHomeUrl'; + +describe('getHomeUrl', () => { + it('returns / for a root-deployed pad', () => { + expect(getHomeUrl('https://example.com/p/testpad')).toBe('https://example.com/'); + }); + + it('returns the proxy prefix home for a prefixed pad URL', () => { + expect(getHomeUrl('https://example.com/etherpad/p/testpad')) + .toBe('https://example.com/etherpad/'); + }); + + it('preserves a deep proxy prefix', () => { + expect(getHomeUrl('https://example.com/api/hassio_ingress/abc/p/testpad')) + .toBe('https://example.com/api/hassio_ingress/abc/'); + }); +}); diff --git a/src/tests/frontend-new/specs/editbar.spec.ts b/src/tests/frontend-new/specs/editbar.spec.ts index 154d79180e4..eb60ac6f388 100644 --- a/src/tests/frontend-new/specs/editbar.spec.ts +++ b/src/tests/frontend-new/specs/editbar.spec.ts @@ -15,4 +15,5 @@ test('should go to home on pad', async ({page}) => { await page.waitForURL((url) => !url.pathname.includes('/p/')); const url = page.url(); expect(url).not.toContain('/p/'); -}) + expect(new URL(url).pathname).toBe('/'); +});