From 5b0ec7e09937bdcc71dff171ead4567206767884 Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Sat, 10 Mar 2018 23:33:41 -0500 Subject: [PATCH 1/8] Add Typescript definitions --- pjax.d.ts | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 pjax.d.ts diff --git a/pjax.d.ts b/pjax.d.ts new file mode 100644 index 0000000..ac73f3b --- /dev/null +++ b/pjax.d.ts @@ -0,0 +1,67 @@ +export = class Pjax { + constructor(options?: Partial); + + static switches: { + [key: string]: Switch + }; + + static isSupported: () => boolean; + + log: VoidFunction; + + getElements(el: Element | Document): NodeListOf; + + parseDOM(el: Element | Document): void; + + refresh: ElementFunction; + + reload: VoidFunction; + + attachLink(el: HTMLAnchorElement): void; + + attachForm(el: HTMLFormElement): void; + + forEachSelectors(cb: ElementFunction, context: Pjax, DOMcontext?: Element | Document): void; + + switchesSelectors(selectors: string[], fromEl: Element | Document, toEl: Element | Document, options: IOptions): void; + + latestChance(href: string): void; + + onSwitch: VoidFunction; + + loadContent(html: string, options: IOptions): void; + + abortRequest(request: XMLHttpRequest): void; + + doRequest(location: string, options: IOptions | null, + callback: (requestText: string, request: XMLHttpRequest, href: string) => void): XMLHttpRequest; + + handleResponse(requestText: string, request: XMLHttpRequest, href: string): void; + + loadUrl(href: string, options?: IOptions): void; + + afterAllSwitches: VoidFunction; +} + +export interface StringKeyedObject { + [key: string]: T +} + +export interface IOptions { + elements: string; + selectors: string[]; + switches: StringKeyedObject; + switchesOptions: StringKeyedObject; + history: boolean; + analytics: Function | false; + scrollTo: number | number[] | false; + scrollRestoration: boolean; + cacheBust: boolean; + debug: boolean; + timeout: number + currentUrlFullReload: boolean; +} + +export type Switch = (oldEl: Element, newEl: Element, options?: IOptions, switchesOptions?: StringKeyedObject) => void; + +export type ElementFunction = (el: Element) => void; -- 2.49.1 From 7a07a435bc41040977b6c05227d7eed16cabca87 Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Wed, 14 Mar 2018 16:40:07 -0400 Subject: [PATCH 2/8] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38efdb5..3fd4645 100644 --- a/README.md +++ b/README.md @@ -578,7 +578,7 @@ Clone this repository and run `npm run example`, which will open the example app * ⇄ Pull requests and ★ Stars are always welcome. * For bugs and feature requests, please create an issue. -* Pull requests must be accompanied by passing automated tests (`npm test`). +* Pull requests must be accompanied by passing automated tests (`npm test`). If the API is changed, please update the Typescript definitions as well (`pjax.d.ts`). ## [CHANGELOG](CHANGELOG.md) -- 2.49.1 From 8dabf6b9a03eac56e6a3bb899baa9db56992c862 Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Thu, 15 Mar 2018 16:02:45 -0400 Subject: [PATCH 3/8] Fix structure of TS definition file --- pjax.d.ts | 61 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/pjax.d.ts b/pjax.d.ts index ac73f3b..513ea39 100644 --- a/pjax.d.ts +++ b/pjax.d.ts @@ -1,8 +1,8 @@ -export = class Pjax { - constructor(options?: Partial); +declare class Pjax { + constructor(options?: Partial); static switches: { - [key: string]: Switch + [key in DefaultSwitches]: Pjax.Switch }; static isSupported: () => boolean; @@ -23,45 +23,58 @@ export = class Pjax { forEachSelectors(cb: ElementFunction, context: Pjax, DOMcontext?: Element | Document): void; - switchesSelectors(selectors: string[], fromEl: Element | Document, toEl: Element | Document, options: IOptions): void; + switchesSelectors(selectors: string[], fromEl: Element | Document, toEl: Element | Document, options: Pjax.IOptions): void; latestChance(href: string): void; onSwitch: VoidFunction; - loadContent(html: string, options: IOptions): void; + loadContent(html: string, options: Pjax.IOptions): void; abortRequest(request: XMLHttpRequest): void; - doRequest(location: string, options: IOptions | null, + doRequest(location: string, options: Pjax.IOptions | null, callback: (requestText: string, request: XMLHttpRequest, href: string) => void): XMLHttpRequest; handleResponse(requestText: string, request: XMLHttpRequest, href: string): void; - loadUrl(href: string, options?: IOptions): void; + loadUrl(href: string, options?: Pjax.IOptions): void; afterAllSwitches: VoidFunction; + + // Allows reassignment of existing prototype functions to be able to do something before calling the original function + [key: string]: Function; } -export interface StringKeyedObject { +declare namespace Pjax { + export interface IOptions { + elements: string; + selectors: string[]; + switches: StringKeyedObject; + switchesOptions: StringKeyedObject; + history: boolean; + analytics: Function | false; + scrollTo: number | [number, number] | false; + scrollRestoration: boolean; + cacheBust: boolean; + debug: boolean; + timeout: number; + currentUrlFullReload: boolean; + } + + export type Switch = (oldEl: Element, newEl: Element, options?: IOptions, switchesOptions?: StringKeyedObject) => void; +} + +interface StringKeyedObject { [key: string]: T } -export interface IOptions { - elements: string; - selectors: string[]; - switches: StringKeyedObject; - switchesOptions: StringKeyedObject; - history: boolean; - analytics: Function | false; - scrollTo: number | number[] | false; - scrollRestoration: boolean; - cacheBust: boolean; - debug: boolean; - timeout: number - currentUrlFullReload: boolean; +type ElementFunction = (el: Element) => void; + +declare enum DefaultSwitches { + innerHTML = "innerHTML", + ouetrHTML = "outerHTML", + sideBySide = "sideBySide" } -export type Switch = (oldEl: Element, newEl: Element, options?: IOptions, switchesOptions?: StringKeyedObject) => void; - -export type ElementFunction = (el: Element) => void; +export = Pjax; -- 2.49.1 From 8cc616369d83aeed7c7863f5728b51457b3cf564 Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Thu, 15 Mar 2018 16:03:18 -0400 Subject: [PATCH 4/8] Add TS definition file to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a925c5d..1bb67e5 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "pjax.js", "pjax.min.js" ], + "types": "pjax.d.ts", "devDependencies": { "browserify": "^15.0.0", "jscs": "^3.0.7", -- 2.49.1 From d9e5cd779bee6b59d3f071f2c728b65231a9a0bb Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Thu, 15 Mar 2018 16:03:45 -0400 Subject: [PATCH 5/8] Fix documentation in README --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3fd4645..42ff54e 100644 --- a/README.md +++ b/README.md @@ -385,7 +385,7 @@ However, there is almost no use case where you would want to do that. Internally, this option is used when a `popstate` event triggers Pjax (to not `pushState()` again). -##### `analytics` (Function|Boolean, default: a function that pushes `_gaq` `_trackPageview` or sends `ga` `pageview` +##### `analytics` (Function | Boolean, default: a function that pushes `_gaq` `_trackPageview` or sends `ga` `pageview` Function that allows you to add behavior for analytics. By default it tries to track a pageview with Google Analytics (if it exists on the page). @@ -393,9 +393,13 @@ It's called every time a page is switched, even for history navigation. Set to `false` to disable this behavior. -##### `scrollTo` (Integer, default: `0`) +##### `scrollTo` (Integer | \[Integer, Integer\] | False, default: `0`) -Value (in px from the top of the page) to scroll to when a page is switched. +When set to an integer, this is the value (in px from the top of the page) to scroll to when a page is switched. + +When set to an array of 2 integers (\[x, y\]), this is the value to scroll both horizontally and vertically. + +Set this to `false` to disable scrolling, which will mean the page will stay in that same position it was before loading the new elements. ##### `scrollRestoration` (Boolean, default: `true`) -- 2.49.1 From 8985b107bd45211f5cbc9e6c44f1599c2168f07c Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Thu, 15 Mar 2018 16:04:34 -0400 Subject: [PATCH 6/8] Rename pjax.d.ts to index.d.ts --- pjax.d.ts => index.d.ts | 0 package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename pjax.d.ts => index.d.ts (100%) diff --git a/pjax.d.ts b/index.d.ts similarity index 100% rename from pjax.d.ts rename to index.d.ts diff --git a/package.json b/package.json index 1bb67e5..a00fe1e 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "pjax.js", "pjax.min.js" ], - "types": "pjax.d.ts", + "types": "index.d.ts", "devDependencies": { "browserify": "^15.0.0", "jscs": "^3.0.7", -- 2.49.1 From ac42ba5fcfb7014a0b24751831eeb179440aa094 Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Thu, 15 Mar 2018 16:09:36 -0400 Subject: [PATCH 7/8] Add test file for TS I haven't added any tooling for this test. To check it, Typescript needs to be installed. Then run: tsc --noEmit ./tests/test.ts --- tests/test.ts | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/test.ts diff --git a/tests/test.ts b/tests/test.ts new file mode 100644 index 0000000..4d76ad4 --- /dev/null +++ b/tests/test.ts @@ -0,0 +1,41 @@ +import Pjax = require("../index"); + +let options: Pjax.IOptions = { + elements: "a.pjax, form.pjax", + selectors: ["div.pjax"], + switches: { + "a.pjax": (oldEl, newEl) => { + oldEl.parentNode.replaceChild(newEl, oldEl); + this.onSwitch(); + }, + "form.pjax": Pjax.switches.innerHTML + }, + switchesOptions: {}, + history: true, + analytics: false, + scrollTo: 1, + scrollRestoration: false, + cacheBust: false, + debug: true, + timeout: 60000, + currentUrlFullReload: true +}; + +options.analytics = () => {}; +options.scrollTo = [1, 1]; +options.scrollTo = false; + +if (Pjax.isSupported()) { + delete options.switchesOptions; + const pjax = new Pjax(options); + + pjax.reload(); + pjax.loadUrl("https://example.org", options); + + pjax._handleResponse = pjax.handleResponse; + pjax.handleResponse = (requestText: string, request: XMLHttpRequest, href: string) => { + pjax.abortRequest(request); + + return pjax._handleResponse(requestText, request, href); + } +} -- 2.49.1 From 316f1160b48bcb2fe7958e28e9b0371328946833 Mon Sep 17 00:00:00 2001 From: Behind The Math Date: Thu, 15 Mar 2018 20:59:40 -0400 Subject: [PATCH 8/8] Add JSDoc comments to the TS definitions --- index.d.ts | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 513ea39..f7e8ccc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -5,6 +5,9 @@ declare class Pjax { [key in DefaultSwitches]: Pjax.Switch }; + /** + * Checks if Pjax is supported by the environment. + */ static isSupported: () => boolean; log: VoidFunction; @@ -29,36 +32,139 @@ declare class Pjax { onSwitch: VoidFunction; + /** + * Loads the HTML from the response into the DOM. + * + * @param {string} html + * @param {Pjax.IOptions} options + */ loadContent(html: string, options: Pjax.IOptions): void; + /** + * Aborts an ongoing XHR request. + * + * @param {XMLHttpRequest} request + */ abortRequest(request: XMLHttpRequest): void; + /** + * Makes the XHR request. + * + * @param {string} location The URI for the request. + * @param {Pjax.IOptions | null} options + * @param {(requestText: string, request: XMLHttpRequest, href: string) => void} callback The callback to call when + * the response is received. The signature should match that of handleResponse. + * @returns {XMLHttpRequest} + */ doRequest(location: string, options: Pjax.IOptions | null, callback: (requestText: string, request: XMLHttpRequest, href: string) => void): XMLHttpRequest; + /** + * Saves the state, updates the URL if there were any redirects, then calls loadContent(). + * + * @param {string} requestText The raw text of the response. Same as request.responseText. + * @param {XMLHttpRequest} request The XHR object. + * @param {string} href The original URI used to initiate the request. + */ handleResponse(requestText: string, request: XMLHttpRequest, href: string): void; + /** + * Initiates the request by calling doRequest(). + * @param {string} href + * @param {Pjax.IOptions} options + */ loadUrl(href: string, options?: Pjax.IOptions): void; + /** + * Called after all switches complete (even async). + */ afterAllSwitches: VoidFunction; - // Allows reassignment of existing prototype functions to be able to do something before calling the original function + /** + * Allows reassignment of existing prototype functions to be able to do something before calling the original function. + * For example: + * + *
+   *   pjax._handleResponse = pjax.handleResponse;
+   *   pjax.handleResponse = (requestText: string, request: XMLHttpRequest, href: string) => {
+   *     return pjax._handleResponse(requestText, request, href);
+   *   }
+   * 
+ */ [key: string]: Function; } declare namespace Pjax { export interface IOptions { + /** + * CSS selector to use to retrieve links to apply Pjax to. + */ elements: string; + + /** + * CSS selectors for the elements to replace. + */ selectors: string[]; + + /** + * Objects containing callbacks that can be used to switch old elements with new elements. + * Keys should be one of the defined selectors. + */ switches: StringKeyedObject; + + /** + * These are options that can be used during switches. + * Keys should be one of the defined selectors. + */ switchesOptions: StringKeyedObject; + + /** + * Enable the use of pushState(). Disabling this will prevent Pjax from updating browser history. + * Internally, this option is used when a popstate event triggers Pjax (to not pushState() again). + */ history: boolean; + + /** + * Function that allows you to add behavior for analytics. + * By default it tries to track a pageview with Google Analytics (if it exists on the page). + * It's called every time a page is switched, even for history navigation. + * Set to false to disable this behavior. + */ analytics: Function | false; + + /** + * When set to an integer, this is the value (in px from the top of the page) to scroll to when a page is switched. + * When set to an array of 2 integers ([x, y]), this is the value to scroll both horizontally and vertically. + * Set this to false to disable scrolling, which will mean the page will stay in that same position it was before + * loading the new elements. + */ scrollTo: number | [number, number] | false; + + /** + * When set to true, attempt to restore the scroll position when navigating backwards or forwards. + */ scrollRestoration: boolean; + + /** + * When set to true, append a timestamp query string segment to the requested URLs in order to skip browser cache. + */ cacheBust: boolean; + + /** + * Enables verbose mode. + */ debug: boolean; + + /** + * The timeout in milliseconds for the XHR requests. Set to 0 to disable the timeout. + */ timeout: number; + + /** + * When set to true, clicking on a link that points to the current URL will trigger a full page reload. + * (Note that if cacheBust is set to true, the code that checks if the href is the same as the current page's URL + * will not work, due to the query string appended to force a cache bust). + */ currentUrlFullReload: boolean; } -- 2.49.1