diff --git a/src/create-form-poster.ts b/src/create-form-poster.ts index 1c08bf3..0aff2de 100644 --- a/src/create-form-poster.ts +++ b/src/create-form-poster.ts @@ -1,9 +1,10 @@ import FormBuilder from './form-builder'; import FormPoster from './form-poster'; +import FormPosterOptions from './form-poster-options'; -export default function createFormPoster(): FormPoster { +export default function createFormPoster(options?: FormPosterOptions): FormPoster { const formBuilder = new FormBuilder(); - const formPoster = new FormPoster(formBuilder); + const formPoster = new FormPoster(formBuilder, options); return formPoster; } diff --git a/src/form-poster-options.ts b/src/form-poster-options.ts new file mode 100644 index 0000000..dae9b4c --- /dev/null +++ b/src/form-poster-options.ts @@ -0,0 +1,3 @@ +export default interface FormPosterOptions { + host?: string; +} diff --git a/src/form-poster.ts b/src/form-poster.ts index 618bb04..aef36a6 100644 --- a/src/form-poster.ts +++ b/src/form-poster.ts @@ -1,15 +1,18 @@ import FormBuilder from './form-builder'; +import FormPosterOptions from './form-poster-options'; +import { isAbsoluteUrl, joinPaths } from './url-utils'; export default class FormPoster { /** * @internal */ constructor( - private _formBuilder: FormBuilder + private _formBuilder: FormBuilder, + private _options?: FormPosterOptions ) {} postForm(url: string, data: { [key: string]: any }, callback?: () => void): void { - const form = this._formBuilder.build(url, data); + const form = this._formBuilder.build(this._prependHost(url), data); window.addEventListener('unload', function handleUnload() { window.removeEventListener('unload', handleUnload); @@ -24,4 +27,12 @@ export default class FormPoster { form.submit(); document.body.removeChild(form); } + + private _prependHost(url: string): string { + if (!this._options || !this._options.host || isAbsoluteUrl(url)) { + return url; + } + + return joinPaths(this._options.host, url); + } } diff --git a/src/url-utils.ts b/src/url-utils.ts new file mode 100644 index 0000000..ca4edde --- /dev/null +++ b/src/url-utils.ts @@ -0,0 +1,15 @@ +export function isAbsoluteUrl(url: string): boolean { + return /^https?:\/\//.test(url); +} + +export function joinPaths(pathA: string, pathB: string): string { + return `${removeTrailingSlash(pathA)}/${removeLeadingSlash(pathB)}`; +} + +function removeTrailingSlash(path: string): string { + return path.replace(/\/$/, ''); +} + +function removeLeadingSlash(path: string): string { + return path.replace(/^\//, ''); +} diff --git a/test/form-poster.spec.ts b/test/form-poster.spec.ts index 58df35f..41a3379 100644 --- a/test/form-poster.spec.ts +++ b/test/form-poster.spec.ts @@ -29,12 +29,21 @@ describe('FormPoster', () => { formPoster.postForm(url, data); expect(formBuilder.build) - .toHaveBeenCalled(); + .toHaveBeenCalledWith(url, data); expect(form.submit) .toHaveBeenCalled(); }); + it('builds form with host appended to URL if provided', () => { + formPoster = new FormPoster(formBuilder, { host: 'https://foobar.com/' }); + + formPoster.postForm(url, data); + + expect(formBuilder.build) + .toHaveBeenCalledWith('https://foobar.com/url/123', data); + }); + it('triggers the callback after posting the data', () => { const callback = jasmine.createSpy(); diff --git a/test/url-utils.spec.ts b/test/url-utils.spec.ts new file mode 100644 index 0000000..28ac45f --- /dev/null +++ b/test/url-utils.spec.ts @@ -0,0 +1,31 @@ +import { isAbsoluteUrl, joinPaths } from '../src/url-utils'; + +describe('isAbsoluteUrl()', () => { + it('returns true if absolute URL', () => { + expect(isAbsoluteUrl('https://foobar.com/hello/world')) + .toBeTruthy(); + + expect(isAbsoluteUrl('http://foobar.com/hello/world')) + .toBeTruthy(); + }); + + it('returns false if relative URL', () => { + expect(isAbsoluteUrl('/hello/world')) + .toBeFalsy(); + + expect(isAbsoluteUrl('/')) + .toBeFalsy(); + }); +}); + +describe('joinPaths()', () => { + it('joins two paths together', () => { + expect(joinPaths('https://foobar.com', 'hello/world')) + .toEqual('https://foobar.com/hello/world'); + }); + + it('strips out trailing and leading slashes automatically', () => { + expect(joinPaths('https://foobar.com/', '/hello/world')) + .toEqual('https://foobar.com/hello/world'); + }); +});