diff --git a/.eslintignore b/.eslintignore index 66ec1e2..8858ba6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,5 @@ /dist/ /node_modules/ -/example/ + +/example/pill.js +/example/pill.min.js diff --git a/.npmignore b/.npmignore index cac9291..2914d6b 100644 --- a/.npmignore +++ b/.npmignore @@ -2,8 +2,8 @@ .eslintignore .editorconfig -bin/ -example/ -local/ -src/ -tmp/ +/bin/ +/example/ +/local/ +/src/ +/tmp/ diff --git a/example/site.js b/example/site.js index 47a1e64..661981f 100644 --- a/example/site.js +++ b/example/site.js @@ -1,3 +1,5 @@ +/* globals pill */ +/* eslint-disable no-console */ const indicator = document.getElementById('indicator') let timeout = 0 @@ -12,22 +14,23 @@ pill('#page', { indicator.style.display = 'block' }, onUnmounting(page, url, element) { - PreserveFormPlugin(element) + preserveFormPlugin(element) }, - onReady(page, element) { + onReady(page, url, element) { // Delay to simulate long content loading timeout = setTimeout(() => { indicator.style.display = 'none' }, 1000) - PopulateFormPlugin(element) + populateFormPlugin(element) }, onMounting() { console.log('updating content') - } + }, + listenClickEventOn: '#page', }) -const PopulateFormPlugin = element =>{ - const key = location.pathname; +function populateFormPlugin(element) { + const key = location.pathname const fields = Array.from(element.querySelectorAll('input, textarea, select')) if (fields.length > 0) { const obj = JSON.parse(localStorage.getItem(key) || '[]') @@ -35,23 +38,25 @@ const PopulateFormPlugin = element =>{ const input = document.querySelector('[name=' + field.fieldName + ']') if (input.type === 'checkbox' || input.type === 'radio') { input.checked = field.value - } else if (input.nodeName === 'TEXTAREA') { + } + else if (input.nodeName === 'TEXTAREA') { input.textContent = field.value - } else { + } + else { input.value = field.value } }) } } -const PreserveFormPlugin = (element) =>{ +function preserveFormPlugin(element) { const key = location.pathname const fields = Array.from(element.querySelectorAll('input, textarea, select')) if (fields.length > 0) { const values = fields.map((val) => { return { fieldName: val.name, - value: val.type == 'checkbox' || val.type == 'radio' ? val.checked : val.value + value: val.type === 'checkbox' || val.type === 'radio' ? val.checked : val.value, } }) localStorage.setItem(key, JSON.stringify(values)) diff --git a/readme.md b/readme.md index 776dbbe..288c477 100644 --- a/readme.md +++ b/readme.md @@ -139,7 +139,7 @@ Handle page loading exception. By default is `console.error`. #### `PillOptions.onLoading()` ``` -(page:Page) -> void +(page:Page, url:URL, element:HTMLElement) -> void ``` Handle loading start. @@ -151,7 +151,7 @@ Fires everytime new content is about to be loaded to the DOM. #### `PillOptions.onReady()` ``` -(page:Page) -> void +(page:Page, url:URL, element:HTMLElement) -> void ``` Handle loading finish. @@ -163,6 +163,14 @@ Fires everytime content is about to be removed from the DOM. ### Other options + +### `PillOptions.listenClickEventOn` +``` +String +``` + +CSS selector which determine which element should Pill click handler be binded on. Default value is `"body"`. + ### `PillOptions.fromError()` ``` (error:Error) -> {title, content} @@ -182,7 +190,7 @@ new pathname and search string combination will cause new request. ### `PillOptions.shouldReload()` ``` -(page:Page) -> Boolean +(page:Page, element:HTMLElement) -> Boolean ``` Determine wether previously loaded page should be loaded from server. diff --git a/src/pill.js b/src/pill.js index 7ebf5b1..d6da7d1 100644 --- a/src/pill.js +++ b/src/pill.js @@ -87,6 +87,7 @@ export default function pill(selector, options) { var fromError = options.fromError || defaultErrorHandler var shouldServe = options.shouldServe || shouldServeDefault var shouldReload = options.shouldReload || noop + var listenClickEventOn = options.listenClickEventOn || 'body' var current = 0 var isLoading = false @@ -104,7 +105,7 @@ export default function pill(selector, options) { updateState(null, url, page.title, push) onMounting(page, url, element) setContent(element, page) - onReady(page, element) + onReady(page, url, element) if (push && url.hash.length > 1) { scrollToAnchor(url.hash.slice(1)) } @@ -117,7 +118,7 @@ export default function pill(selector, options) { if (cacheKey in cache) { var cachedPage = cache[cacheKey] - if (shouldReload(cachedPage) !== true) { + if (shouldReload(cachedPage, element) !== true) { render(url, cachedPage, push) return } @@ -154,11 +155,13 @@ export default function pill(selector, options) { if (requestId !== current) { return } + currentPage = page render(url, page, false) }) .catch(function (error) { if (requestId === current) { var page = fromError(error) + currentPage = page render(url, page, false) } @@ -168,14 +171,13 @@ export default function pill(selector, options) { .catch(onError) isLoading = true - onLoading(url) + onLoading(currentPage, url, element) } function onClick (e) { if (e.target.nodeName !== 'A') { return } - var url = new URL(e.target.href, document.location) if (! shouldServe(url, e.target)) { @@ -183,8 +185,9 @@ export default function pill(selector, options) { } e.preventDefault() - + // Restore scroll window.scrollTo(0, 0) + // `! isLoading` specify wether new page should stop the request and replace url in the address bar. goto(url, ! isLoading) } @@ -207,7 +210,8 @@ export default function pill(selector, options) { }, 100) } - document.body.addEventListener('click', onClick) + document.querySelector(listenClickEventOn) + .addEventListener('click', onClick) window.addEventListener('popstate', onPopState) window.addEventListener('scroll', onScroll) -} \ No newline at end of file +}