Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
0b9a114f
Commit
0b9a114f
authored
Sep 02, 2020
by
Lyza Danger Gardner
Committed by
Lyza Gardner
Sep 03, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adjust keyboard interaction with TagEditor
parent
b32cbefb
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
111 additions
and
51 deletions
+111
-51
tag-editor.js
src/sidebar/components/tag-editor.js
+29
-11
tag-editor-test.js
src/sidebar/components/test/tag-editor-test.js
+82
-40
No files found.
src/sidebar/components/tag-editor.js
View file @
0b9a114f
...
@@ -84,7 +84,6 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
...
@@ -84,7 +84,6 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
setSuggestions
(
removeDuplicates
(
suggestions
,
tagList
));
setSuggestions
(
removeDuplicates
(
suggestions
,
tagList
));
setSuggestionsListOpen
(
suggestions
.
length
>
0
);
setSuggestionsListOpen
(
suggestions
.
length
>
0
);
}
}
setActiveItem
(
-
1
);
setActiveItem
(
-
1
);
};
};
...
@@ -194,44 +193,63 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
...
@@ -194,44 +193,63 @@ function TagEditor({ onEditTags, tags: tagsService, tagList }) {
};
};
/**
/**
* Keydown handler for keyboard navigation of the suggestions list
* Keydown handler for keyboard navigation of the tag editor field and the
* and when the user presses "Enter" or ","" to add a new typed item not
* suggested-tags list.
* found in the suggestions list
*
*
* @param {KeyboardEvent} e
* @param {KeyboardEvent} e
*/
*/
const
handleKeyDown
=
e
=>
{
const
handleKeyDown
=
e
=>
{
switch
(
normalizeKeyName
(
e
.
key
))
{
switch
(
normalizeKeyName
(
e
.
key
))
{
case
'ArrowUp'
:
case
'ArrowUp'
:
// Select the previous item in the suggestion list
changeSelectedItem
(
-
1
);
changeSelectedItem
(
-
1
);
e
.
preventDefault
();
e
.
preventDefault
();
break
;
break
;
case
'ArrowDown'
:
case
'ArrowDown'
:
// Select the next item in the suggestion list
changeSelectedItem
(
1
);
changeSelectedItem
(
1
);
e
.
preventDefault
();
e
.
preventDefault
();
break
;
break
;
case
'Escape'
:
// Clear any entered text, but retain focus
inputEl
.
current
.
value
=
''
;
e
.
preventDefault
();
break
;
case
'Enter'
:
case
'Enter'
:
case
','
:
case
','
:
// Commit a tag
if
(
activeItem
===
-
1
)
{
if
(
activeItem
===
-
1
)
{
// nothing selected, just add the typed text
// nothing selected, just add the typed text
addTag
(
/** @type {HTMLInputElement} */
(
inputEl
.
current
).
value
);
addTag
(
/** @type {HTMLInputElement} */
(
inputEl
.
current
).
value
);
}
else
{
}
else
{
// Add the selected tag
addTag
(
suggestions
[
activeItem
]);
addTag
(
suggestions
[
activeItem
]);
}
}
e
.
preventDefault
();
e
.
preventDefault
();
break
;
break
;
case
'Tab'
:
case
'Tab'
:
// Commit a tag, or tab out of the field if it is empty (default browser
// behavior)
if
(
inputEl
.
current
.
value
.
trim
()
===
''
)
{
// If the tag field is empty, allow `Tab` to have its default
// behavior: continue to the next element in tab order
break
;
}
if
(
activeItem
!==
-
1
)
{
if
(
activeItem
!==
-
1
)
{
// If there is a selected item
, then allow `Tab` to behave exactly
// If there is a selected item
in the suggested tag list,
//
like `Enter` or `,`.
//
commit that tag (just like `Enter` and `,` in this case)
addTag
(
suggestions
[
activeItem
]);
addTag
(
suggestions
[
activeItem
]);
e
.
preventDefault
();
}
else
if
(
suggestions
.
length
===
1
)
{
}
else
if
(
suggestionsListOpen
)
{
// If there is exactly one suggested tag match, commit that tag
// If there is no selected item, then allow `Tab` to add the first
// This emulates a "tab-complete" behavior
// item in the list if the list is open.
addTag
(
suggestions
[
0
]);
addTag
(
suggestions
[
0
]);
e
.
preventDefault
();
}
else
{
// Commit the tag as typed in the field
addTag
(
/** @type {HTMLInputElement} */
(
inputEl
.
current
).
value
);
}
}
// Retain focus
e
.
preventDefault
();
break
;
}
}
};
};
...
...
src/sidebar/components/test/tag-editor-test.js
View file @
0b9a114f
...
@@ -207,8 +207,9 @@ describe('TagEditor', function () {
...
@@ -207,8 +207,9 @@ describe('TagEditor', function () {
*/
*/
const
assertAddTagsSuccess
=
(
wrapper
,
tagList
)
=>
{
const
assertAddTagsSuccess
=
(
wrapper
,
tagList
)
=>
{
// saves the suggested tags to the service
// saves the suggested tags to the service
assert
.
isTrue
(
assert
.
calledWith
(
fakeTagsService
.
store
.
calledWith
(
tagList
.
map
(
tag
=>
({
text
:
tag
})))
fakeTagsService
.
store
,
tagList
.
map
(
tag
=>
({
text
:
tag
}))
);
);
// called the onEditTags callback prop
// called the onEditTags callback prop
assert
.
isTrue
(
fakeOnEditTags
.
calledWith
({
tags
:
tagList
}));
assert
.
isTrue
(
fakeOnEditTags
.
calledWith
({
tags
:
tagList
}));
...
@@ -242,10 +243,10 @@ describe('TagEditor', function () {
...
@@ -242,10 +243,10 @@ describe('TagEditor', function () {
].
forEach
(
keyAction
=>
{
].
forEach
(
keyAction
=>
{
it
(
`adds a tag from the <input> field when typing "
${
keyAction
[
1
]}
"`
,
()
=>
{
it
(
`adds a tag from the <input> field when typing "
${
keyAction
[
1
]}
"`
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'input'
).
instance
().
value
=
'
tag3
'
;
wrapper
.
find
(
'input'
).
instance
().
value
=
'
umbrella
'
;
typeInput
(
wrapper
);
// opens suggestion list
typeInput
(
wrapper
);
// opens suggestion list
keyAction
[
0
](
wrapper
);
keyAction
[
0
](
wrapper
);
assertAddTagsSuccess
(
wrapper
,
[
'tag1'
,
'tag2'
,
'
tag3
'
]);
assertAddTagsSuccess
(
wrapper
,
[
'tag1'
,
'tag2'
,
'
umbrella
'
]);
// ensure focus is still on the input field
// ensure focus is still on the input field
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
});
});
...
@@ -268,49 +269,90 @@ describe('TagEditor', function () {
...
@@ -268,49 +269,90 @@ describe('TagEditor', function () {
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
});
});
});
});
it
(
'should not add a tag if the <input> is empty'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'input'
).
instance
().
value
=
''
;
selectOptionViaEnter
(
wrapper
);
assertAddTagsFail
();
});
it
(
'should not add a tag if the input is empty'
,
()
=>
{
context
(
'When using the "Escape" key'
,
()
=>
{
const
wrapper
=
createComponent
();
it
(
'should clear tag text in <input> but retain focus'
,
()
=>
{
wrapper
.
find
(
'input'
).
instance
().
value
=
''
;
const
wrapper
=
createComponent
();
selectOptionViaEnter
(
wrapper
);
// Add and commit a tag
assertAddTagsFail
();
wrapper
.
find
(
'input'
).
instance
().
value
=
'thankyou'
;
typeInput
(
wrapper
);
wrapper
.
find
(
'input'
).
simulate
(
'keydown'
,
{
key
:
'Tab'
});
// Type more text
wrapper
.
find
(
'input'
).
instance
().
value
=
'food'
;
typeInput
(
wrapper
);
// // Now press escape
wrapper
.
find
(
'input'
).
simulate
(
'keydown'
,
{
key
:
'Escape'
});
assert
.
equal
(
wrapper
.
find
(
'input'
).
instance
().
value
,
''
);
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
});
});
});
it
(
'should not add a tag if the <input> value is only white space'
,
()
=>
{
context
(
'When using the "Enter" key'
,
()
=>
{
const
wrapper
=
createComponent
();
it
(
'should not add a tag if the <input> is empty'
,
()
=>
{
wrapper
.
find
(
'input'
).
instance
().
value
=
' '
;
const
wrapper
=
createComponent
();
selectOptionViaEnter
(
wrapper
);
wrapper
.
find
(
'input'
).
instance
().
value
=
''
;
assertAddTagsFail
();
selectOptionViaEnter
(
wrapper
);
});
assertAddTagsFail
();
});
it
(
'should not add a tag if its a duplicate of one already in the list
'
,
()
=>
{
it
(
'should not add a tag if the <input> value is only white space
'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
wrapper
.
find
(
'input'
).
instance
().
value
=
'tag1
'
;
wrapper
.
find
(
'input'
).
instance
().
value
=
'
'
;
selectOptionViaEnter
(
wrapper
);
selectOptionViaEnter
(
wrapper
);
assertAddTagsFail
();
assertAddTagsFail
();
});
});
it
(
'should not add a tag when pressing "Tab" and there are no suggestions'
,
()
=>
{
it
(
'should not add a tag if its a duplicate of one already in the list'
,
()
=>
{
const
wrapper
=
createComponent
();
const
wrapper
=
createComponent
();
fakeTagsService
.
filter
.
returns
([]);
wrapper
.
find
(
'input'
).
instance
().
value
=
'tag1'
;
wrapper
.
find
(
'input'
).
instance
().
value
=
'tag33'
;
selectOptionViaEnter
(
wrapper
);
typeInput
(
wrapper
);
assertAddTagsFail
();
selectOptionViaTab
(
wrapper
);
});
assertAddTagsFail
();
});
});
it
(
'should not a tag when pressing "Tab" and no suggestions are found'
,
()
=>
{
context
(
'Using the "Tab" key'
,
()
=>
{
const
wrapper
=
createComponent
();
it
(
'should add the tag as typed when there are no suggestions'
,
()
=>
{
wrapper
.
find
(
'input'
).
instance
().
value
=
'tag3'
;
const
wrapper
=
createComponent
();
// note: typeInput() opens the suggestions list
fakeTagsService
.
filter
.
returns
([]);
selectOptionViaTab
(
wrapper
);
wrapper
.
find
(
'input'
).
instance
().
value
=
'tag33'
;
assertAddTagsFail
();
typeInput
(
wrapper
);
selectOptionViaTab
(
wrapper
);
assertAddTagsSuccess
(
wrapper
,
[
'tag1'
,
'tag2'
,
'tag33'
]);
// ensure focus is still on the input field
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
});
it
(
'should add the tag as typed when there are multiple suggestions'
,
()
=>
{
const
wrapper
=
createComponent
();
fakeTagsService
.
filter
.
returns
([]);
wrapper
.
find
(
'input'
).
instance
().
value
=
't'
;
typeInput
(
wrapper
);
selectOptionViaTab
(
wrapper
);
assertAddTagsSuccess
(
wrapper
,
[
'tag1'
,
'tag2'
,
't'
]);
// ensure focus is still on the input field
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
});
it
(
'should add the suggested tag when there is exactly one suggestion'
,
()
=>
{
const
wrapper
=
createComponent
();
fakeTagsService
.
filter
.
returns
([
'tag3'
]);
wrapper
.
find
(
'input'
).
instance
().
value
=
'tag'
;
typeInput
(
wrapper
);
// suggestions: [tag3]
selectOptionViaTab
(
wrapper
);
assertAddTagsSuccess
(
wrapper
,
[
'tag1'
,
'tag2'
,
'tag3'
]);
// ensure focus is still on the input field
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'INPUT'
);
});
it
(
'should allow navigation out of field when there is no <input> value'
,
()
=>
{
const
wrapper
=
createComponent
();
wrapper
.
find
(
'input'
).
instance
().
value
=
''
;
typeInput
(
wrapper
);
selectOptionViaTab
(
wrapper
);
// Focus has moved
assert
.
equal
(
document
.
activeElement
.
nodeName
,
'BODY'
);
});
});
});
});
});
...
...
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