This commit is contained in:
Sam Thorogood 2020-11-12 19:05:10 +11:00
Родитель c1390194e9
Коммит bbe8bab175
2 изменённых файлов: 124 добавлений и 19 удалений

Просмотреть файл

@ -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
*/
@ -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 {
@ -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.

Просмотреть файл

@ -14,7 +14,6 @@
* the License.
*/
void function() {
/**
@ -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();
@ -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() {