Skip to content

Commit

Permalink
support formmethod
Browse files Browse the repository at this point in the history
  • Loading branch information
samthor committed Nov 12, 2020
1 parent c139019 commit bbe8bab
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 19 deletions.
74 changes: 57 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,32 @@ function isConnected(element) {
return element.isConnected || document.body.contains(element);
}

/**
* @param {!Event} event
*/
function findFormSubmitter(event) {
if (event.submitter) {
return event.submitter;
}

var form = event.target;
if (!(form instanceof HTMLFormElement)) {
return null;
}

var submitter = dialogPolyfill.formSubmitter;
if (!submitter) {
var target = event.target;
var root = ('getRootNode' in target && target.getRootNode() || document);
submitter = root.activeElement;
}

if (submitter.form !== form) {
return null;
}
return submitter;
}

/**
* @param {!Event} event
*/
Expand All @@ -162,32 +188,28 @@ function maybeHandleSubmit(event) {
return;
}
var form = /** @type {!HTMLFormElement} */ (event.target);
if (!isFormMethodDialog(form)) {
return;
}
event.preventDefault();

// We'd have a value if we clicked on an imagemap.
var value = dialogPolyfill.useValue;
var submitter = dialogPolyfill.formSubmitter || event.submitter;
if (!value) {
if (!submitter) {
var root = ('getRootNode' in form && form.getRootNode() || document);
var activeElement = root.activeElement;
if (activeElement) {
submitter = event.submitter = activeElement;
}
}
if (submitter) {
value = submitter.value;
}
var submitter = findFormSubmitter(event);
if (value === null && submitter) {
value = submitter.value;
}

const dialog = findNearestDialog(form);
// There should always be a dialog as this handler is added specifically on them, but check just
// in case.
var dialog = findNearestDialog(form);
if (!dialog) {
return;
}

// Prefer formmethod on the button.
var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method');
if (formmethod !== 'dialog') {
return;
}
event.preventDefault();

if (submitter) {
dialog.close(value);
} else {
Expand Down Expand Up @@ -795,6 +817,24 @@ if (window.HTMLDialogElement === undefined) {

}, false);

/**
* Global 'submit' handler. This handles submits of `method="dialog"` which are invalid, i.e.,
* outside a dialog. They get prevented.
*/
document.addEventListener('submit', function(ev) {
var form = ev.target;
var dialog = findNearestDialog(form);
if (dialog) {
return; // ignore, handle there
}

var submitter = findFormSubmitter(ev);
var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method');
if (formmethod === 'dialog') {
ev.preventDefault();
}
});

/**
* Replace the native HTMLFormElement.submit() method, as it won't fire the
* submit event and give us a chance to respond.
Expand Down
69 changes: 67 additions & 2 deletions suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* the License.
*/


void function() {

/**
Expand Down Expand Up @@ -789,7 +788,10 @@ void function() {
dialog.showModal();

iframe.addEventListener('load', function() {
assert.fail('should not load a new page');
var href = iframe.contentWindow.location.href;
if (href !== 'about:blank') {
assert.fail('should not load a new page: ' + href);
}
});
button.click();

Expand All @@ -801,6 +803,69 @@ void function() {
done();
}, 50);
});
test('form submit with formmethod', function(done) {
const iframeName = 'formmethod_test_frame';

var iframe = document.createElement('iframe');
iframe.setAttribute('name', iframeName);
document.body.append(iframe);
cleanup(iframe);

var form = document.createElement('form');
form.setAttribute('method', 'dialog');
form.setAttribute('target', iframeName);
form.setAttribute('action', '/test-invalid.html');
dialog.append(form);
dialog.show();

var button = document.createElement('button');
button.setAttribute('formmethod', 'get');
form.append(button);
button.value = '123';
button.textContent = 'Long button';

var timeout = window.setTimeout(function() {
assert.fail('page should load (form submit with formmethod)');
}, 500);
iframe.addEventListener('load', function() {
window.clearTimeout(timeout);
assert.isTrue(dialog.open);
done();
});
button.click();
});
test('form method="dialog" prevented outside dialog', function(done) {
const iframeName = 'outside_dialog_test';

var iframe = document.createElement('iframe');
iframe.setAttribute('name', iframeName);
document.body.append(iframe);
cleanup(iframe);

var form = document.createElement('form');
form.setAttribute('method', 'dialog');
form.setAttribute('target', iframeName);
form.setAttribute('action', '/test-invalid.html');
document.body.append(form);
cleanup(form);

iframe.addEventListener('load', function() {
if (iframe.contentWindow.location.href !== 'about:blank') {
assert.fail('should not load a new page: ' + iframe.contentWindow.location.href);
}
});

form.submit();

// Try with an actual button, too.
var button = document.createElement('button');
form.append(button);
button.click();

var timeout = window.setTimeout(function() {
done();
}, 1000);
});
});

suite('order', function() {
Expand Down

0 comments on commit bbe8bab

Please sign in to comment.