Merge branch 'release' into improved-file-handling
commit
5e87aee63c
|
@ -2898,7 +2898,12 @@ class H5PContentValidator {
|
||||||
|
|
||||||
// Check if string is within allowed length
|
// Check if string is within allowed length
|
||||||
if (isset($semantics->maxLength)) {
|
if (isset($semantics->maxLength)) {
|
||||||
$text = mb_substr($text, 0, $semantics->maxLength);
|
if (!extension_loaded('mbstring')) {
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'error');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$text = mb_substr($text, 0, $semantics->maxLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if string is according to optional regexp in semantics
|
// Check if string is according to optional regexp in semantics
|
||||||
|
@ -2948,7 +2953,11 @@ class H5PContentValidator {
|
||||||
// file name, 2. testing against a returned error array that could
|
// file name, 2. testing against a returned error array that could
|
||||||
// never be more than 1 element long anyway, 3. recreating the regex
|
// never be more than 1 element long anyway, 3. recreating the regex
|
||||||
// for every file.
|
// for every file.
|
||||||
if (!preg_match($wl_regex, mb_strtolower($file))) {
|
if (!extension_loaded('mbstring')) {
|
||||||
|
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'error');
|
||||||
|
$valid = FALSE;
|
||||||
|
}
|
||||||
|
else if (!preg_match($wl_regex, mb_strtolower($file))) {
|
||||||
$this->h5pF->setErrorMessage($this->h5pF->t('File "%filename" not allowed. Only files with the following extensions are allowed: %files-allowed.', array('%filename' => $file, '%files-allowed' => $whitelist)), 'error');
|
$this->h5pF->setErrorMessage($this->h5pF->t('File "%filename" not allowed. Only files with the following extensions are allowed: %files-allowed.', array('%filename' => $file, '%files-allowed' => $whitelist)), 'error');
|
||||||
$valid = FALSE;
|
$valid = FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
EventDispatcher.call(this);
|
EventDispatcher.call(this);
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
// Make sure confirmation dialogs have unique id
|
||||||
|
H5P.ConfirmationDialog.uniqueId += 1;
|
||||||
|
var uniqueId = H5P.ConfirmationDialog.uniqueId;
|
||||||
|
|
||||||
// Default options
|
// Default options
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.headerText = options.headerText || H5P.t('confirmDialogHeader');
|
options.headerText = options.headerText || H5P.t('confirmDialogHeader');
|
||||||
|
@ -70,13 +74,14 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
var popup = document.createElement('div');
|
var popup = document.createElement('div');
|
||||||
popup.classList.add('h5p-confirmation-dialog-popup', 'hidden');
|
popup.classList.add('h5p-confirmation-dialog-popup', 'hidden');
|
||||||
popup.setAttribute('role', 'dialog');
|
popup.setAttribute('role', 'dialog');
|
||||||
|
popup.setAttribute('aria-labelledby', 'h5p-confirmation-dialog-dialog-text-' + uniqueId);
|
||||||
popupBackground.appendChild(popup);
|
popupBackground.appendChild(popup);
|
||||||
popup.onkeydown = function (e) {
|
popup.addEventListener('keydown', function (e) {
|
||||||
if (e.which === 27) {// Esc key
|
if (e.which === 27) {// Esc key
|
||||||
// Exit dialog
|
// Exit dialog
|
||||||
dialogCanceled(e);
|
dialogCanceled(e);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// Popup header
|
// Popup header
|
||||||
var header = document.createElement('div');
|
var header = document.createElement('div');
|
||||||
|
@ -97,8 +102,8 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
// Popup text
|
// Popup text
|
||||||
var text = document.createElement('div');
|
var text = document.createElement('div');
|
||||||
text.classList.add('h5p-confirmation-dialog-text');
|
text.classList.add('h5p-confirmation-dialog-text');
|
||||||
text.setAttribute('role', 'alert');
|
|
||||||
text.innerHTML = options.dialogText;
|
text.innerHTML = options.dialogText;
|
||||||
|
text.id = 'h5p-confirmation-dialog-dialog-text-' + uniqueId;
|
||||||
body.appendChild(text);
|
body.appendChild(text);
|
||||||
|
|
||||||
// Popup buttons
|
// Popup buttons
|
||||||
|
@ -120,44 +125,56 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
// Exit button
|
// Exit button
|
||||||
var exitButton = document.createElement('button');
|
var exitButton = document.createElement('button');
|
||||||
exitButton.classList.add('h5p-confirmation-dialog-exit');
|
exitButton.classList.add('h5p-confirmation-dialog-exit');
|
||||||
|
exitButton.setAttribute('aria-hidden', 'true');
|
||||||
|
exitButton.tabIndex = -1;
|
||||||
exitButton.title = options.cancelText;
|
exitButton.title = options.cancelText;
|
||||||
|
|
||||||
// Cancel handler
|
// Cancel handler
|
||||||
cancelButton.onclick = dialogCanceled;
|
cancelButton.addEventListener('click', dialogCanceled);
|
||||||
cancelButton.onkeydown = function (e) {
|
cancelButton.addEventListener('keydown', function (e) {
|
||||||
if (e.which === 32) { // Space
|
if (e.which === 32) { // Space
|
||||||
dialogCanceled(e);
|
dialogCanceled(e);
|
||||||
}
|
}
|
||||||
else if (e.which === 9 && e.shiftKey) { // Shift-tab
|
else if (e.which === 9 && e.shiftKey) { // Shift-tab
|
||||||
flowTo(exitButton, e);
|
flowTo(confirmButton, e);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
buttons.appendChild(cancelButton);
|
buttons.appendChild(cancelButton);
|
||||||
|
|
||||||
// Confirm handler
|
// Confirm handler
|
||||||
confirmButton.onclick = dialogConfirmed;
|
confirmButton.addEventListener('click', dialogConfirmed);
|
||||||
confirmButton.onkeydown = function (e) {
|
confirmButton.addEventListener('keydown', function (e) {
|
||||||
if (e.which === 32) { // Space
|
if (e.which === 32) { // Space
|
||||||
dialogConfirmed(e);
|
dialogConfirmed(e);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
buttons.appendChild(confirmButton);
|
|
||||||
|
|
||||||
// Exit handler
|
|
||||||
exitButton.onclick = dialogCanceled;
|
|
||||||
exitButton.onkeydown = function (e) {
|
|
||||||
if (e.which === 32) { // Space
|
|
||||||
dialogCanceled(e);
|
|
||||||
}
|
|
||||||
else if (e.which === 9 && !e.shiftKey) { // Tab
|
else if (e.which === 9 && !e.shiftKey) { // Tab
|
||||||
flowTo(cancelButton, e);
|
flowTo(cancelButton, e);
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
buttons.appendChild(confirmButton);
|
||||||
|
|
||||||
|
// Exit handler
|
||||||
|
exitButton.addEventListener('click', dialogCanceled);
|
||||||
|
exitButton.addEventListener('keydown', function (e) {
|
||||||
|
if (e.which === 32) { // Space
|
||||||
|
dialogCanceled(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
popup.appendChild(exitButton);
|
popup.appendChild(exitButton);
|
||||||
|
|
||||||
// Wrapper element
|
// Wrapper element
|
||||||
var wrapperElement;
|
var wrapperElement;
|
||||||
|
|
||||||
|
// Focus capturing
|
||||||
|
var focusPredator;
|
||||||
|
|
||||||
|
// Maintains hidden state of elements
|
||||||
|
var wrapperSiblingsHidden = [];
|
||||||
|
var popupSiblingsHidden = [];
|
||||||
|
|
||||||
|
// Element with focus before dialog
|
||||||
|
var previouslyFocused;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set parent of confirmation dialog
|
* Set parent of confirmation dialog
|
||||||
* @param {HTMLElement} wrapper
|
* @param {HTMLElement} wrapper
|
||||||
|
@ -168,6 +185,87 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capture the focus element, send it to confirmation button
|
||||||
|
* @param {Event} e Original focus event
|
||||||
|
*/
|
||||||
|
var captureFocus = function (e) {
|
||||||
|
if (!popupBackground.contains(e.target)) {
|
||||||
|
e.preventDefault();
|
||||||
|
confirmButton.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide siblings of element from assistive technology
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @returns {Array} The previous hidden state of all siblings
|
||||||
|
*/
|
||||||
|
var hideSiblings = function (element) {
|
||||||
|
var hiddenSiblings = [];
|
||||||
|
var siblings = element.parentNode.children;
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < siblings.length; i += 1) {
|
||||||
|
// Preserve hidden state
|
||||||
|
hiddenSiblings[i] = siblings[i].getAttribute('aria-hidden') ?
|
||||||
|
true : false;
|
||||||
|
|
||||||
|
if (siblings[i] !== element) {
|
||||||
|
siblings[i].setAttribute('aria-hidden', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hiddenSiblings;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores assistive technology state of element's siblings
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element
|
||||||
|
* @param {Array} hiddenSiblings Hidden state of all siblings
|
||||||
|
*/
|
||||||
|
var restoreSiblings = function (element, hiddenSiblings) {
|
||||||
|
var siblings = element.parentNode.children;
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < siblings.length; i += 1) {
|
||||||
|
if (siblings[i] !== element && !hiddenSiblings[i]) {
|
||||||
|
siblings[i].removeAttribute('aria-hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start capturing focus of parent and send it to dialog
|
||||||
|
*/
|
||||||
|
var startCapturingFocus = function () {
|
||||||
|
focusPredator = wrapperElement.parentNode || wrapperElement;
|
||||||
|
focusPredator.addEventListener('focus', captureFocus, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up event listener for capturing focus
|
||||||
|
*/
|
||||||
|
var stopCapturingFocus = function () {
|
||||||
|
focusPredator.removeAttribute('aria-hidden');
|
||||||
|
focusPredator.removeEventListener('focus', captureFocus, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide siblings in underlay from assistive technologies
|
||||||
|
*/
|
||||||
|
var disableUnderlay = function () {
|
||||||
|
wrapperSiblingsHidden = hideSiblings(wrapperElement);
|
||||||
|
popupSiblingsHidden = hideSiblings(popupBackground);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore state of underlay for assistive technologies
|
||||||
|
*/
|
||||||
|
var restoreUnderlay = function () {
|
||||||
|
restoreSiblings(wrapperElement, wrapperSiblingsHidden);
|
||||||
|
restoreSiblings(popupBackground, popupSiblingsHidden);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fit popup to container. Makes sure it doesn't overflow.
|
* Fit popup to container. Makes sure it doesn't overflow.
|
||||||
* @params {number} [offsetTop] Offset of popup
|
* @params {number} [offsetTop] Offset of popup
|
||||||
|
@ -198,7 +296,11 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
* @returns {H5P.ConfirmationDialog}
|
* @returns {H5P.ConfirmationDialog}
|
||||||
*/
|
*/
|
||||||
this.show = function (offsetTop) {
|
this.show = function (offsetTop) {
|
||||||
|
// Capture focused item
|
||||||
|
previouslyFocused = document.activeElement;
|
||||||
wrapperElement.appendChild(popupBackground);
|
wrapperElement.appendChild(popupBackground);
|
||||||
|
startCapturingFocus();
|
||||||
|
disableUnderlay();
|
||||||
popupBackground.classList.remove('hidden');
|
popupBackground.classList.remove('hidden');
|
||||||
fitToContainer(offsetTop);
|
fitToContainer(offsetTop);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
|
@ -230,6 +332,11 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
this.hide = function () {
|
this.hide = function () {
|
||||||
popupBackground.classList.add('hiding');
|
popupBackground.classList.add('hiding');
|
||||||
popup.classList.add('hidden');
|
popup.classList.add('hidden');
|
||||||
|
|
||||||
|
// Restore focus
|
||||||
|
stopCapturingFocus();
|
||||||
|
previouslyFocused.focus();
|
||||||
|
restoreUnderlay();
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
popupBackground.classList.add('hidden');
|
popupBackground.classList.add('hidden');
|
||||||
wrapperElement.removeChild(popupBackground);
|
wrapperElement.removeChild(popupBackground);
|
||||||
|
@ -245,3 +352,5 @@ H5P.ConfirmationDialog = (function (EventDispatcher) {
|
||||||
return ConfirmationDialog;
|
return ConfirmationDialog;
|
||||||
|
|
||||||
}(H5P.EventDispatcher));
|
}(H5P.EventDispatcher));
|
||||||
|
|
||||||
|
H5P.ConfirmationDialog.uniqueId = -1;
|
||||||
|
|
Loading…
Reference in New Issue