Add focusManager

parent deedd42d
"use strict";
function isAncestor(ancestor, descendant) {
var element = descendant;
while (element) {
if (element === ancestor) {
return true;
}
element = element.parentElement;
}
return false;
}
function isDisabled(element) {
return element.disabled === true;
}
function isFocusable(element) {
return Boolean(element) && element.tabIndex >= 0 && !isDisabled(element);
}
function makeFocusable(element) {
// A tabIndex is needed to make the element focusable
// A tabIndex of -1 means that the element is only programmatically focusable
if (isDisabled(element)) {
element.disabled = false;
}
if (!isFocusable(element)) {
element.tabIndex = -1;
}
}
// Find the first focusable element.
// The candidates are the element and it's descendants.
// The search is performed depth-first.
function findFirstFocusableElement(element) {
if (isFocusable(element)) {
return element;
}
var children = element.children;
var length = children.length;
var child;
var focusableDescendant;
for (var i = 0; i < length; i += 1) {
child = children[i];
focusableDescendant = findFirstFocusableElement(child);
if (focusableDescendant) {
return focusableDescendant;
}
}
return null;
}
// Find the first focusable element.
// The candidates are the element and it's descendants.
// The search is performed depth-first.
function findLastFocusableElement(element) {
var children = element.children;
var length = children.length;
var child;
var focusableDescendant;
for (var i = length -1; i >= 0; i -= 1) {
child = children[i];
focusableDescendant = findLastFocusableElement(child);
if (focusableDescendant) {
return focusableDescendant;
}
}
if (isFocusable(element)) {
return element;
}
return null;
}
function focus(element) {
makeFocusable(element);
element.focus();
state.lastFocus = element;
}
function resolveFocus(parent, defaultFocus) {
var focusElement;
if (defaultFocus) {
focusElement = defaultFocus;
} else {
focusElement = findFirstFocusableElement(parent) || parent;
if (focusElement === state.lastFocus) {
focusElement = findLastFocusableElement(parent) || parent;
}
}
focus(focusElement);
}
function focusFirstInElement(element) {
var focusElement = findFirstFocusableElement(element) || element;
focus(focusElement);
}
function focusLastInElement(element) {
var focusElement = findLastFocusableElement(element) || element;
focus(focusElement);
}
// State is kept is these variables.
// Since only one modal dialog can capture focus at a time the state is a singleton.
var state = {
eventListenerArguments: null,
eventListenerContext: null,
lastFocus: null
};
function releaseModalFocus(focusElement) {
var eventListenerContext = state.eventListenerContext;
var eventListenerArguments = state.eventListenerArguments;
if (eventListenerContext && eventListenerArguments) {
eventListenerContext.removeEventListener.apply(eventListenerContext, eventListenerArguments);
}
// Reset the state object
state.eventListenerContext = null;
state.eventListenerArguments = null;
state.lastFocus = null;
if (focusElement) {
focusElement.focus();
}
}
// Keep focus inside the modal
function restrictFocus(modal, focusedElement) {
if (isAncestor(modal, focusedElement)) {
state.lastFocus = focusedElement;
} else {
resolveFocus(modal);
}
}
// modal, the element in which to contain focus
// focusElement (optional), the element inside the modal to focus when opening
// backgroundElement (optional), All focus events within this element are redirected to the modal. Defaults to document
function captureModalFocus(modal, focusElement, backgroundElement) {
// without a modal there is nothing to capture
if (!modal) {
return null;
}
// If any focus is already being captured, release it now
releaseModalFocus();
// focus the modal so the user knows it was opened
resolveFocus(modal, focusElement);
// Whenever an element outside of the modal is focused, the modal is focused instead
function focusCallback(evnt) {
restrictFocus(modal, evnt.target);
}
// The focus event does not bubble
// however it can be captured on an ancestor element
// by setting useCapture to true
var eventListenerContext = backgroundElement || document;
var eventListenerArguments = ["focus", focusCallback, true];
// Save the eventListener data in the state object so it can be removed later
// by the releaseModalFocus function
state.eventListenerContext = eventListenerContext;
state.eventListenerArguments = eventListenerArguments;
eventListenerContext.addEventListener.apply(eventListenerContext, eventListenerArguments);
}
var focusManager = {
capture: captureModalFocus,
release: releaseModalFocus,
focusFirstInElement: focusFirstInElement,
focusLastInElement: focusLastInElement
};
export.default = focusManager;
// focusManager
function isAncestor(ancestor, descendant) {
var element = descendant;
while (element) {
if (element === ancestor) {
return true;
}
element = element.parentElement;
}
return false;
}
function isDisabled(element) {
return element.disabled === true;
}
function isFocusable(element) {
return Boolean(element) && element.tabIndex >= 0 && !isDisabled(element);
}
function makeFocusable(element) {
// A tabIndex is needed to make the element focusable
// A tabIndex of -1 means that the element is only programmatically focusable
if (isDisabled(element)) {
element.disabled = false;
}
if (!isFocusable(element)) {
element.tabIndex = -1;
}
}
// Find the first focusable element.
// The candidates are the element and it's descendants.
// The search is performed depth-first.
function findFirstFocusableElement(element) {
if (isFocusable(element)) {
return element;
}
var children = element.children;
var length = children.length;
var child;
var focusableDescendant;
for (var i = 0; i < length; i += 1) {
child = children[i];
focusableDescendant = findFirstFocusableElement(child);
if (focusableDescendant) {
return focusableDescendant;
}
}
return null;
}
// Find the first focusable element.
// The candidates are the element and it's descendants.
// The search is performed depth-first.
function findLastFocusableElement(element) {
var children = element.children;
var length = children.length;
var child;
var focusableDescendant;
for (var i = length -1; i >= 0; i -= 1) {
child = children[i];
focusableDescendant = findLastFocusableElement(child);
if (focusableDescendant) {
return focusableDescendant;
}
}
if (isFocusable(element)) {
return element;
}
return null;
}
function focus(element) {
makeFocusable(element);
element.focus();
state.lastFocus = element;
}
function resolveFocus(parent, defaultFocus) {
var focusElement;
if (defaultFocus) {
focusElement = defaultFocus;
} else {
focusElement = findFirstFocusableElement(parent) || parent;
if (focusElement === state.lastFocus) {
focusElement = findLastFocusableElement(parent) || parent;
}
}
focus(focusElement);
}
function focusFirstInElement(element) {
var focusElement = findFirstFocusableElement(element) || element;
focus(focusElement);
}
function focusLastInElement(element) {
var focusElement = findLastFocusableElement(element) || element;
focus(focusElement);
}
// State is kept is these variables.
// Since only one modal dialog can capture focus at a time the state is a singleton.
var state = {
eventListenerArguments: null,
eventListenerContext: null,
lastFocus: null
};
function releaseModalFocus(focusElement) {
var eventListenerContext = state.eventListenerContext;
var eventListenerArguments = state.eventListenerArguments;
if (eventListenerContext && eventListenerArguments) {
eventListenerContext.removeEventListener.apply(eventListenerContext, eventListenerArguments);
}
// Reset the state object
state.eventListenerContext = null;
state.eventListenerArguments = null;
state.lastFocus = null;
if (focusElement) {
focusElement.focus();
}
}
// Keep focus inside the modal
function restrictFocus(modal, focusedElement) {
if (isAncestor(modal, focusedElement)) {
state.lastFocus = focusedElement;
} else {
resolveFocus(modal);
}
}
// modal, the element in which to contain focus
// focusElement (optional), the element inside the modal to focus when opening
// backgroundElement (optional), All focus events within this element are redirected to the modal. Defaults to document
function captureModalFocus(modal, focusElement, backgroundElement) {
// without a modal there is nothing to capture
if (!modal) {
return null;
}
// If any focus is already being captured, release it now
releaseModalFocus();
// focus the modal so the user knows it was opened
resolveFocus(modal, focusElement);
// Whenever an element outside of the modal is focused, the modal is focused instead
function focusCallback(evnt) {
restrictFocus(modal, evnt.target);
}
// The focus event does not bubble
// however it can be captured on an ancestor element
// by setting useCapture to true
var eventListenerContext = backgroundElement || document;
var eventListenerArguments = ["focus", focusCallback, true];
// Save the eventListener data in the state object so it can be removed later
// by the releaseModalFocus function
state.eventListenerContext = eventListenerContext;
state.eventListenerArguments = eventListenerArguments;
eventListenerContext.addEventListener.apply(eventListenerContext, eventListenerArguments);
}
var focusManager = {
capture: captureModalFocus,
release: releaseModalFocus,
focusFirstInElement: focusFirstInElement,
focusLastInElement: focusLastInElement
};
///////////////////////////////////////////////
//Номер баги
var bugId = getIdFromUrl() || getBugIdFromField();
......@@ -61,6 +257,7 @@ function showDiv() {
document.querySelector("#timeQuestionDiv").style.display = "block";
document.querySelector("#realworktime").focus();
}
function closeDiv() {
document.querySelector("#timeQuestionDiv").style.display = "none";
}
......@@ -112,15 +309,19 @@ function getTimespentValue() {
}
// add listener for comment commit
let commitBtn = document.querySelector("#commit");
//let commitBtn = document.querySelector("#commit");
let openButton = document.querySelector("#commit");
let closeButton = document.querySelectorAll("#timeQuestionDiv .close");
let dialog = document.querySelector("#timeQuestionDiv");
commitBtn.addEventListener("click", function(event) {
openButton.addEventListener("click", function(event) {
// cancel form submiting
event.preventDefault();
let timespentValue = getTimespentValue();
document.querySelector("#timeQuestionDiv").style.display = "block";
dialog.style.display = "block";
focusManager.capture(dialog);
// write work time in input value
document.querySelector("#realworktime").value = timespentValue;
......@@ -224,4 +425,4 @@ if (typeof window.addEventListener != "undefined") {
} else if (typeof window.attachEvent != "undefined") {
//win/ie
window.attachEvent("onload", initTimer);
}
}
\ No newline at end of file
......@@ -15,12 +15,14 @@
text-align: center;
width:108px;
}
#timerblock #timer_pause {
position:absolute;
top:8px;
left:102px;
cursor:pointer;
}
#timerblock #timer_play {
position:absolute;
top:8px;
......@@ -28,12 +30,14 @@
cursor:pointer;
visibility:hidden;
}
#timerblock #timer_stop {
position:absolute;
top:8px;
left:7px;
cursor:pointer;
}
#timerblock #timespent {
border: none;
text-align: center;
......@@ -42,33 +46,24 @@
margin-left:6px;
}
/* Блок сохранения времени */
/*#timeQuestionDiv {
position: fixed;
top: 100px;
left: 25%;
width: 50%;
display: none;
padding: 10px;
border: 1px solid;
background: #DDDDDD;
text-align: center;
font-size: 12px;
z-index: 10;
}
#timeQuestionDiv a {
cursor: pointer;
}
#timeQuestionDiv .div_show {
display: block;
/* Затемнение всей остальной страницы и создание focus-lock */
.timer-shadow {
z-index: 10;
background: #000;
opacity: 0.6;
filter: blur(2px);
width: 100%;
max-height: 100%;
position: absolute;
top: 0;
left: 0;
}
#timeQuestionDiv .div_hide {
display: none;
}*/
/* Блок сохранения времени */
#timeQuestionDiv {
display: none;
z-index: 10;
z-index: 15;
position: fixed;
top: 100px;
width: 50%;
......@@ -179,10 +174,10 @@ fieldset {
text-align: center;
}
.workTime input:focus,
.workTime textarea:focus {
outline: 0;
border: 1px solid #aaa;
.workTime__input:focus,
.workTime__button:focus,
.close:focus {
outline: 2px solid rgba(82, 157, 236, 0.8);
}
.workTimeInner{
......@@ -195,11 +190,14 @@ fieldset {
top: 10px;
width: 25px;
height: 25px;
opacity: 0.4; */
opacity: 0.4;
cursor: pointer;
}
.close:hover {
opacity: 1;
}
.close:before, .close:after {
position: absolute;
left: 15px;
......@@ -208,9 +206,11 @@ fieldset {
width: 2px;
background-color: #000;
}
.close:before {
transform: rotate(45deg);
}
.close:after {
transform: rotate(-45deg);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment