Update 0.2.2: Fix issue #19

This commit is contained in:
Joxit 2017-08-06 11:39:01 +02:00
parent 36cbda1263
commit d34d793b73
9 changed files with 135 additions and 46 deletions

147
dist/scripts/vendor.js vendored
View file

@ -6,7 +6,7 @@
// nb. This is for IE10 and lower _only_.
var supportCustomEvent = window.CustomEvent;
if (!supportCustomEvent || typeof supportCustomEvent == 'object') {
if (!supportCustomEvent || typeof supportCustomEvent === 'object') {
supportCustomEvent = function CustomEvent(event, x) {
x = x || {};
var ev = document.createEvent('CustomEvent');
@ -66,7 +66,7 @@
* @param {Element} el to blur
*/
function safeBlur(el) {
if (el && el.blur && el != document.body) {
if (el && el.blur && el !== document.body) {
el.blur();
}
}
@ -78,13 +78,24 @@
*/
function inNodeList(nodeList, node) {
for (var i = 0; i < nodeList.length; ++i) {
if (nodeList[i] == node) {
if (nodeList[i] === node) {
return true;
}
}
return false;
}
/**
* @param {HTMLFormElement} el to check
* @return {boolean} whether this form has method="dialog"
*/
function isFormMethodDialog(el) {
if (!el || !el.hasAttribute('method')) {
return false;
}
return el.getAttribute('method').toLowerCase() === 'dialog';
}
/**
* @param {!HTMLDialogElement} dialog to upgrade
* @constructor
@ -121,6 +132,7 @@
}.bind(this);
var timeout;
var delayModel = function(ev) {
if (ev.target !== dialog) { return; } // not for a child element
var cand = 'DOMNodeRemoved';
removed |= (ev.type.substr(0, cand.length) === cand);
window.clearTimeout(timeout);
@ -363,7 +375,7 @@
}
var cssTop = rule.style.getPropertyValue('top');
var cssBottom = rule.style.getPropertyValue('bottom');
if ((cssTop && cssTop != 'auto') || (cssBottom && cssBottom != 'auto')) {
if ((cssTop && cssTop !== 'auto') || (cssBottom && cssBottom !== 'auto')) {
return true;
}
}
@ -373,7 +385,7 @@
dialogPolyfill.needsCentering = function(dialog) {
var computedStyle = window.getComputedStyle(dialog);
if (computedStyle.position != 'absolute') {
if (computedStyle.position !== 'absolute') {
return false;
}
@ -381,9 +393,10 @@
// WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but
// Firefox returns the used value. So we do this crazy thing instead: check
// the inline style and then go through CSS rules.
if ((dialog.style.top != 'auto' && dialog.style.top != '') ||
(dialog.style.bottom != 'auto' && dialog.style.bottom != ''))
if ((dialog.style.top !== 'auto' && dialog.style.top !== '') ||
(dialog.style.bottom !== 'auto' && dialog.style.bottom !== '')) {
return false;
}
return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog);
};
@ -391,7 +404,7 @@
* @param {!Element} element to force upgrade
*/
dialogPolyfill.forceRegisterDialog = function(element) {
if (element.showModal) {
if (window.HTMLDialogElement || element.showModal) {
console.warn('This browser already supports <dialog>, the polyfill ' +
'may not work correctly', element);
}
@ -449,10 +462,8 @@
continue;
} else if (c.localName === 'dialog') {
removed.push(c);
} else {
var q = c.querySelector('dialog');
q && removed.push(q);
}
removed = removed.concat(c.querySelectorAll('dialog'));
}
});
removed.length && checkDOM(removed);
@ -603,7 +614,7 @@
*/
dialogPolyfill.DialogManager.prototype.removeDialog = function(dpi) {
var index = this.pendingDialogStack.indexOf(dpi);
if (index == -1) { return; }
if (index === -1) { return; }
this.pendingDialogStack.splice(index, 1);
if (this.pendingDialogStack.length === 0) {
@ -613,33 +624,103 @@
};
dialogPolyfill.dm = new dialogPolyfill.DialogManager();
dialogPolyfill.formSubmitter = null;
dialogPolyfill.useValue = null;
/**
* Global form 'dialog' method handler. Closes a dialog correctly on submit
* and possibly sets its return value.
* Installs global handlers, such as click listers and native method overrides. These are needed
* even if a no dialog is registered, as they deal with <form method="dialog">.
*/
document.addEventListener('submit', function(ev) {
var target = ev.target;
if (!target || !target.hasAttribute('method')) { return; }
if (target.getAttribute('method').toLowerCase() !== 'dialog') { return; }
ev.preventDefault();
if (window.HTMLDialogElement === undefined) {
var dialog = findNearestDialog(/** @type {Element} */ (ev.target));
if (!dialog) { return; }
/**
* If HTMLFormElement translates method="DIALOG" into 'get', then replace the descriptor with
* one that returns the correct value.
*/
var testForm = document.createElement('form');
testForm.setAttribute('method', 'dialog');
if (testForm.method !== 'dialog') {
var methodDescriptor = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'method');
var realGet = methodDescriptor.get;
methodDescriptor.get = function() {
if (isFormMethodDialog(this)) {
return 'dialog';
}
return realGet.call(this);
};
var realSet = methodDescriptor.set;
methodDescriptor.set = function(v) {
if (typeof v === 'string' && v.toLowerCase() === 'dialog') {
return this.setAttribute('method', v);
}
return realSet.call(this, v);
};
Object.defineProperty(HTMLFormElement.prototype, 'method', methodDescriptor);
}
// FIXME: The original event doesn't contain the element used to submit the
// form (if any). Look in some possible places.
var returnValue;
var cands = [document.activeElement, ev.explicitOriginalTarget];
var els = ['BUTTON', 'INPUT'];
cands.some(function(cand) {
if (cand && cand.form == ev.target && els.indexOf(cand.nodeName.toUpperCase()) != -1) {
returnValue = cand.value;
return true;
/**
* Global 'click' handler, to capture the <input type="submit"> or <button> element which has
* submitted a <form method="dialog">. Needed as Safari and others don't report this inside
* document.activeElement.
*/
document.addEventListener('click', function(ev) {
dialogPolyfill.formSubmitter = null;
dialogPolyfill.useValue = null;
if (ev.defaultPrevented) { return; } // e.g. a submit which prevents default submission
var target = /** @type {Element} */ (ev.target);
if (!target || !isFormMethodDialog(target.form)) { return; }
var valid = (target.type === 'submit' && ['button', 'input'].indexOf(target.localName) > -1);
if (!valid) {
if (!(target.localName === 'input' && target.type === 'image')) { return; }
// this is a <input type="image">, which can submit forms
dialogPolyfill.useValue = ev.offsetX + ',' + ev.offsetY;
}
});
dialog.close(returnValue);
}, true);
var dialog = findNearestDialog(target);
if (!dialog) { return; }
dialogPolyfill.formSubmitter = target;
}, false);
/**
* Replace the native HTMLFormElement.submit() method, as it won't fire the
* submit event and give us a chance to respond.
*/
var nativeFormSubmit = HTMLFormElement.prototype.submit;
function replacementFormSubmit() {
if (!isFormMethodDialog(this)) {
return nativeFormSubmit.call(this);
}
var dialog = findNearestDialog(this);
dialog && dialog.close();
}
HTMLFormElement.prototype.submit = replacementFormSubmit;
/**
* Global form 'dialog' method handler. Closes a dialog correctly on submit
* and possibly sets its return value.
*/
document.addEventListener('submit', function(ev) {
var form = /** @type {HTMLFormElement} */ (ev.target);
if (!isFormMethodDialog(form)) { return; }
ev.preventDefault();
var dialog = findNearestDialog(form);
if (!dialog) { return; }
// Forms can only be submitted via .submit() or a click (?), but anyway: sanity-check that
// the submitter is correct before using its value as .returnValue.
var s = dialogPolyfill.formSubmitter;
if (s && s.form === form) {
dialog.close(dialogPolyfill.useValue || s.value);
} else {
dialog.close();
}
dialogPolyfill.formSubmitter = null;
}, true);
}
dialogPolyfill['forceRegisterDialog'] = dialogPolyfill.forceRegisterDialog;
dialogPolyfill['registerDialog'] = dialogPolyfill.registerDialog;