Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ivan Ivlev
bugzilla
Commits
3777f2c8
Commit
3777f2c8
authored
5 years ago
by
Давид Добряков
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add focusManager
parent
deedd42d
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
427 additions
and
30 deletions
+427
-30
focusManager.js
js/etersoft/focusManager.js
+196
-0
timer.js
js/etersoft/timer.js
+204
-3
timersplash.css
js/etersoft/timersplash.css
+27
-27
No files found.
js/etersoft/focusManager.js
0 → 100644
View file @
3777f2c8
"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
;
This diff is collapsed.
Click to expand it.
js/etersoft/timer.js
View file @
3777f2c8
// 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
();
var
bugId
=
getIdFromUrl
()
||
getBugIdFromField
();
...
@@ -61,6 +257,7 @@ function showDiv() {
...
@@ -61,6 +257,7 @@ function showDiv() {
document
.
querySelector
(
"#timeQuestionDiv"
).
style
.
display
=
"block"
;
document
.
querySelector
(
"#timeQuestionDiv"
).
style
.
display
=
"block"
;
document
.
querySelector
(
"#realworktime"
).
focus
();
document
.
querySelector
(
"#realworktime"
).
focus
();
}
}
function
closeDiv
()
{
function
closeDiv
()
{
document
.
querySelector
(
"#timeQuestionDiv"
).
style
.
display
=
"none"
;
document
.
querySelector
(
"#timeQuestionDiv"
).
style
.
display
=
"none"
;
}
}
...
@@ -112,15 +309,19 @@ function getTimespentValue() {
...
@@ -112,15 +309,19 @@ function getTimespentValue() {
}
}
// add listener for comment commit
// 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"
);
commitBt
n
.
addEventListener
(
"click"
,
function
(
event
)
{
openButto
n
.
addEventListener
(
"click"
,
function
(
event
)
{
// cancel form submiting
// cancel form submiting
event
.
preventDefault
();
event
.
preventDefault
();
let
timespentValue
=
getTimespentValue
();
let
timespentValue
=
getTimespentValue
();
document
.
querySelector
(
"#timeQuestionDiv"
).
style
.
display
=
"block"
;
dialog
.
style
.
display
=
"block"
;
focusManager
.
capture
(
dialog
);
// write work time in input value
// write work time in input value
document
.
querySelector
(
"#realworktime"
).
value
=
timespentValue
;
document
.
querySelector
(
"#realworktime"
).
value
=
timespentValue
;
...
...
This diff is collapsed.
Click to expand it.
js/etersoft/timersplash.css
View file @
3777f2c8
...
@@ -15,12 +15,14 @@
...
@@ -15,12 +15,14 @@
text-align
:
center
;
text-align
:
center
;
width
:
108px
;
width
:
108px
;
}
}
#timerblock
#timer_pause
{
#timerblock
#timer_pause
{
position
:
absolute
;
position
:
absolute
;
top
:
8px
;
top
:
8px
;
left
:
102px
;
left
:
102px
;
cursor
:
pointer
;
cursor
:
pointer
;
}
}
#timerblock
#timer_play
{
#timerblock
#timer_play
{
position
:
absolute
;
position
:
absolute
;
top
:
8px
;
top
:
8px
;
...
@@ -28,12 +30,14 @@
...
@@ -28,12 +30,14 @@
cursor
:
pointer
;
cursor
:
pointer
;
visibility
:
hidden
;
visibility
:
hidden
;
}
}
#timerblock
#timer_stop
{
#timerblock
#timer_stop
{
position
:
absolute
;
position
:
absolute
;
top
:
8px
;
top
:
8px
;
left
:
7px
;
left
:
7px
;
cursor
:
pointer
;
cursor
:
pointer
;
}
}
#timerblock
#timespent
{
#timerblock
#timespent
{
border
:
none
;
border
:
none
;
text-align
:
center
;
text-align
:
center
;
...
@@ -42,33 +46,24 @@
...
@@ -42,33 +46,24 @@
margin-left
:
6px
;
margin-left
:
6px
;
}
}
/* Блок сохранения времени */
/* Затемнение всей остальной страницы и создание focus-lock */
/*#timeQuestionDiv {
.timer-shadow
{
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
;
z-index
:
10
;
background
:
#000
;
opacity
:
0.6
;
filter
:
blur
(
2px
);
width
:
100%
;
max-height
:
100%
;
position
:
absolute
;
top
:
0
;
left
:
0
;
}
}
#timeQuestionDiv a {
cursor: pointer;
}
#timeQuestionDiv .div_show {
display: block;
}
#timeQuestionDiv .div_hide {
display: none;
}*/
/* Блок сохранения времени */
#timeQuestionDiv
{
#timeQuestionDiv
{
display
:
none
;
display
:
none
;
z-index
:
1
0
;
z-index
:
1
5
;
position
:
fixed
;
position
:
fixed
;
top
:
100px
;
top
:
100px
;
width
:
50%
;
width
:
50%
;
...
@@ -179,10 +174,10 @@ fieldset {
...
@@ -179,10 +174,10 @@ fieldset {
text-align
:
center
;
text-align
:
center
;
}
}
.workTime
input
:focus
,
.workTime
__
input
:focus
,
.workTime
textarea
:focus
{
.workTime
__button
:focus
,
outline
:
0
;
.close
:focus
{
border
:
1px
solid
#aaa
;
outline
:
2px
solid
rgba
(
82
,
157
,
236
,
0.8
)
;
}
}
.workTimeInner
{
.workTimeInner
{
...
@@ -195,11 +190,14 @@ fieldset {
...
@@ -195,11 +190,14 @@ fieldset {
top
:
10px
;
top
:
10px
;
width
:
25px
;
width
:
25px
;
height
:
25px
;
height
:
25px
;
opacity
:
0.4
;
*/
opacity
:
0.4
;
cursor
:
pointer
;
}
}
.close
:hover
{
.close
:hover
{
opacity
:
1
;
opacity
:
1
;
}
}
.close
:before
,
.close
:after
{
.close
:before
,
.close
:after
{
position
:
absolute
;
position
:
absolute
;
left
:
15px
;
left
:
15px
;
...
@@ -208,9 +206,11 @@ fieldset {
...
@@ -208,9 +206,11 @@ fieldset {
width
:
2px
;
width
:
2px
;
background-color
:
#000
;
background-color
:
#000
;
}
}
.close
:before
{
.close
:before
{
transform
:
rotate
(
45deg
);
transform
:
rotate
(
45deg
);
}
}
.close
:after
{
.close
:after
{
transform
:
rotate
(
-45deg
);
transform
:
rotate
(
-45deg
);
}
}
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment