diff --git a/examples/form/index.html b/examples/form/index.html new file mode 100644 index 00000000..3c72b6f3 --- /dev/null +++ b/examples/form/index.html @@ -0,0 +1,87 @@ + + + + Basic + + + + +

GET form

+

+
+

+ + +

+

+ + +

+

+ + 1 + 2 +

+

+ + checkbox1 + checkbox2 +

+

+ + +

+

+ + +

+

+ + + +

+

+ + +

+

+ + + +

+

+ + + +

+

+ + +

+ +
+ + + + diff --git a/index.js b/index.js index 197f9b87..8d7c31db 100755 --- a/index.js +++ b/index.js @@ -183,6 +183,7 @@ * - `click` bind to click events [true] * - `popstate` bind to popstate [true] * - `dispatch` perform initial dispatch [true] + * - `submit` bind to submit events (GET-forms only) [true] * * @param {Object} options * @api public @@ -199,6 +200,9 @@ if (false !== options.click && hasDocument) { pageWindow.document.addEventListener(clickEvent, onclick, false); } + if (false !== options.submit && hasDocument) { + pageWindow.document.addEventListener('submit', onsubmit, false); + } hashbang = !!options.hashbang; if(hashbang && hasWindow && !hasHistory) { pageWindow.addEventListener('hashchange', onpopstate, false); @@ -233,6 +237,7 @@ page.len = 0; running = false; hasDocument && pageWindow.document.removeEventListener(clickEvent, onclick, false); + hasDocument && pageWindow.document.removeEventListener('submit', onsubmit, false); hasWindow && pageWindow.removeEventListener('popstate', onpopstate, false); hasWindow && pageWindow.removeEventListener('hashchange', onpopstate, false); }; @@ -683,6 +688,77 @@ page.show(orig); } + /** + * Handle "submit" events. + */ + + function onsubmit(e) { + if (e.defaultPrevented) return; + + var form = e.target, + btnSubmit = checkButtonElement(document.activeElement) && document.activeElement; + + var action = form.hasAttribute('action') && form.getAttribute('action'), + method = form.hasAttribute('method') && form.getAttribute('method'), + target = form.hasAttribute('target') && form.getAttribute('target'); + + if (btnSubmit) { + if (btnSubmit.hasAttribute('formaction')) action = btnSubmit.getAttribute('formaction'); + if (btnSubmit.hasAttribute('formmethod')) method = btnSubmit.getAttribute('formmethod'); + if (btnSubmit.hasAttribute('formtarget')) target = btnSubmit.getAttribute('formtarget'); + } + + // Ignore if tag has + // 1. method and not method="get" + // 2. target and not target="_self" + if (method && method.toLowerCase() !== 'get') return; + if (target && target.toLowerCase() !== '_self') return; + + var a = document.createElement('a'); + a.href = action; + + var pathname = a.pathname, + hash = a.hash || '', + search = []; + + var elements = form.elements, + len = elements.length; + + for (var i = 0; i < len; i++) { + if ( ! elements[i].name || elements[i].disabled) continue; + if (['checkbox', 'radio'].indexOf(elements[i].type) >= 0 && !elements[i].checked) { + continue; + } + if (checkButtonElement(elements[i]) && elements[i] !== btnSubmit) { + continue; + } + search.push(elements[i].name + '=' + elements[i].value); + } + + var path = (pathname + '?' + search.join('&') + hash); + path = path[0] !== '/' ? '/' + path : path; + + // strip leading "/[drive letter]:" on NW.js on Windows + if (hasProcess && path.match(/^\/[a-zA-Z]:\//)) { + path = path.replace(/^\/[a-zA-Z]:\//, '/'); + } + + var pageBase = getBase(); + + if (path.indexOf(pageBase) === 0) { + path = path.substr(base.length); + } + + if (hashbang) path = path.replace('#!', ''); + + e.preventDefault(); + page.show(path); + } + + function checkButtonElement(el) { + return (el.type && ['button', 'submit', 'image'].indexOf(el.type) >= 0) || el.tagName === 'button'; + } + /** * Event button. */ diff --git a/page.js b/page.js index 4f2eef17..4ae3f4f6 100644 --- a/page.js +++ b/page.js @@ -583,6 +583,7 @@ pathToRegexp_1.tokensToRegExp = tokensToRegExp_1; * - `click` bind to click events [true] * - `popstate` bind to popstate [true] * - `dispatch` perform initial dispatch [true] + * - `submit` bind to submit events (GET-forms only) [true] * * @param {Object} options * @api public @@ -599,6 +600,9 @@ pathToRegexp_1.tokensToRegExp = tokensToRegExp_1; if (false !== options.click && hasDocument) { pageWindow.document.addEventListener(clickEvent, onclick, false); } + if (false !== options.submit && hasDocument) { + pageWindow.document.addEventListener('submit', onsubmit, false); + } hashbang = !!options.hashbang; if(hashbang && hasWindow && !hasHistory) { pageWindow.addEventListener('hashchange', onpopstate, false); @@ -633,6 +637,7 @@ pathToRegexp_1.tokensToRegExp = tokensToRegExp_1; page.len = 0; running = false; hasDocument && pageWindow.document.removeEventListener(clickEvent, onclick, false); + hasDocument && pageWindow.document.removeEventListener('submit', onsubmit, false); hasWindow && pageWindow.removeEventListener('popstate', onpopstate, false); hasWindow && pageWindow.removeEventListener('hashchange', onpopstate, false); }; @@ -1083,6 +1088,77 @@ pathToRegexp_1.tokensToRegExp = tokensToRegExp_1; page.show(orig); } + /** + * Handle "submit" events. + */ + + function onsubmit(e) { + if (e.defaultPrevented) return; + + var form = e.target, + btnSubmit = checkButtonElement(document.activeElement) && document.activeElement; + + var action = form.hasAttribute('action') && form.getAttribute('action'), + method = form.hasAttribute('method') && form.getAttribute('method'), + target = form.hasAttribute('target') && form.getAttribute('target'); + + if (btnSubmit) { + if (btnSubmit.hasAttribute('formaction')) action = btnSubmit.getAttribute('formaction'); + if (btnSubmit.hasAttribute('formmethod')) method = btnSubmit.getAttribute('formmethod'); + if (btnSubmit.hasAttribute('formtarget')) target = btnSubmit.getAttribute('formtarget'); + } + + // Ignore if tag has + // 1. method and not method="get" + // 2. target and not target="_self" + if (method && method.toLowerCase() !== 'get') return; + if (target && target.toLowerCase() !== '_self') return; + + var a = document.createElement('a'); + a.href = action; + + var pathname = a.pathname, + hash = a.hash || '', + search = []; + + var elements = form.elements, + len = elements.length; + + for (var i = 0; i < len; i++) { + if ( ! elements[i].name || elements[i].disabled) continue; + if (['checkbox', 'radio'].indexOf(elements[i].type) >= 0 && !elements[i].checked) { + continue; + } + if (checkButtonElement(elements[i]) && elements[i] !== btnSubmit) { + continue; + } + search.push(elements[i].name + '=' + elements[i].value); + } + + var path = (pathname + '?' + search.join('&') + hash); + path = path[0] !== '/' ? '/' + path : path; + + // strip leading "/[drive letter]:" on NW.js on Windows + if (hasProcess && path.match(/^\/[a-zA-Z]:\//)) { + path = path.replace(/^\/[a-zA-Z]:\//, '/'); + } + + var pageBase = getBase(); + + if (path.indexOf(pageBase) === 0) { + path = path.substr(base.length); + } + + if (hashbang) path = path.replace('#!', ''); + + e.preventDefault(); + page.show(path); + } + + function checkButtonElement(el) { + return (el.type && ['button', 'submit', 'image'].indexOf(el.type) >= 0) || el.tagName === 'button'; + } + /** * Event button. */