Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
converse.js
Commits
e4dc9fa8
Commit
e4dc9fa8
authored
Aug 19, 2019
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Open emojis popup when TAB is pressed on a word starting with :
parent
9099ef89
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
101 additions
and
29 deletions
+101
-29
src/converse-chatview.js
src/converse-chatview.js
+28
-3
src/converse-emoji-views.js
src/converse-emoji-views.js
+53
-22
src/headless/utils/core.js
src/headless/utils/core.js
+20
-4
No files found.
src/converse-chatview.js
View file @
e4dc9fa8
...
@@ -883,6 +883,8 @@ converse.plugins.add('converse-chatview', {
...
@@ -883,6 +883,8 @@ converse.plugins.add('converse-chatview', {
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
FORWARD_SLASH
)
{
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
FORWARD_SLASH
)
{
// Forward slash is used to run commands. Nothing to do here.
// Forward slash is used to run commands. Nothing to do here.
return
;
return
;
}
else
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
TAB
)
{
return
this
.
onTabPressed
(
ev
);
}
else
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
ESCAPE
)
{
}
else
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
ESCAPE
)
{
return
this
.
onEscapePressed
(
ev
);
return
this
.
onEscapePressed
(
ev
);
}
else
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
ENTER
)
{
}
else
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
ENTER
)
{
...
@@ -922,6 +924,8 @@ converse.plugins.add('converse-chatview', {
...
@@ -922,6 +924,8 @@ converse.plugins.add('converse-chatview', {
return
this
.
onFormSubmitted
(
ev
);
return
this
.
onFormSubmitted
(
ev
);
},
},
onTabPressed
(
ev
)
{},
// noop, overridden in other plugins
onEscapePressed
(
ev
)
{
onEscapePressed
(
ev
)
{
ev
.
preventDefault
();
ev
.
preventDefault
();
const
idx
=
this
.
model
.
messages
.
findLastIndex
(
'
correcting
'
),
const
idx
=
this
.
model
.
messages
.
findLastIndex
(
'
correcting
'
),
...
@@ -1021,7 +1025,19 @@ converse.plugins.add('converse-chatview', {
...
@@ -1021,7 +1025,19 @@ converse.plugins.add('converse-chatview', {
return
this
;
return
this
;
},
},
insertIntoTextArea
(
value
,
replace
=
false
,
correcting
=
false
)
{
/**
* Insert a particular string value into the textarea of this chat box.
* @private
* @method _converse.ChatBoxView#insertIntoTextArea
* @param {string} value - The value to be inserted.
* @param {(boolean|string)} [replace] - Whether an existing value
* should be replaced. If set to `true`, the entire textarea will
* be replaced with the new value. If set to a string, then only
* that string will be replaced *if* a position is also specified.
* @param {integer} [position] - The end index of the string to be
* replaced with the new value.
*/
insertIntoTextArea
(
value
,
replace
=
false
,
correcting
=
false
,
position
)
{
const
textarea
=
this
.
el
.
querySelector
(
'
.chat-textarea
'
);
const
textarea
=
this
.
el
.
querySelector
(
'
.chat-textarea
'
);
if
(
correcting
)
{
if
(
correcting
)
{
u
.
addClass
(
'
correcting
'
,
textarea
);
u
.
addClass
(
'
correcting
'
,
textarea
);
...
@@ -1029,8 +1045,17 @@ converse.plugins.add('converse-chatview', {
...
@@ -1029,8 +1045,17 @@ converse.plugins.add('converse-chatview', {
u
.
removeClass
(
'
correcting
'
,
textarea
);
u
.
removeClass
(
'
correcting
'
,
textarea
);
}
}
if
(
replace
)
{
if
(
replace
)
{
textarea
.
value
=
''
;
if
(
position
&&
typeof
replace
==
'
string
'
)
{
textarea
.
value
=
value
;
textarea
.
value
=
textarea
.
value
.
replace
(
new
RegExp
(
replace
,
'
g
'
),
(
match
,
offset
)
=>
{
return
offset
==
position
-
replace
.
length
?
value
:
match
}
);
}
else
{
textarea
.
value
=
''
;
textarea
.
value
=
value
;
}
}
else
{
}
else
{
let
existing
=
textarea
.
value
;
let
existing
=
textarea
.
value
;
if
(
existing
&&
(
existing
[
existing
.
length
-
1
]
!==
'
'
))
{
if
(
existing
&&
(
existing
[
existing
.
length
-
1
]
!==
'
'
))
{
...
...
src/converse-emoji-views.js
View file @
e4dc9fa8
...
@@ -42,6 +42,29 @@ converse.plugins.add('converse-emoji-views', {
...
@@ -42,6 +42,29 @@ converse.plugins.add('converse-emoji-views', {
this
.
emoji_dropdown
.
toggle
();
this
.
emoji_dropdown
.
toggle
();
}
}
this
.
__super__
.
onEnterPressed
.
apply
(
this
,
arguments
);
this
.
__super__
.
onEnterPressed
.
apply
(
this
,
arguments
);
},
async
onTabPressed
(
ev
)
{
const
{
_converse
}
=
this
.
__super__
;
const
input
=
ev
.
target
;
const
value
=
u
.
getCurrentWord
(
input
,
null
,
/
(
:.*
?
:
)
/g
);
if
(
value
.
startsWith
(
'
:
'
))
{
ev
.
preventDefault
();
ev
.
stopPropagation
();
if
(
this
.
emoji_dropdown
===
undefined
)
{
this
.
createEmojiDropdown
();
}
this
.
emoji_dropdown
.
toggle
();
await
_converse
.
api
.
waitUntil
(
'
emojisInitialized
'
);
this
.
emoji_picker_view
.
model
.
set
({
'
autocompleting
'
:
value
,
'
position
'
:
ev
.
target
.
selectionStart
});
this
.
emoji_picker_view
.
filter
(
value
,
true
);
this
.
emoji_picker_view
.
render
();
}
else
{
this
.
__super__
.
onTabPressed
.
apply
(
this
,
arguments
);
}
}
}
},
},
...
@@ -82,12 +105,16 @@ converse.plugins.add('converse-emoji-views', {
...
@@ -82,12 +105,16 @@ converse.plugins.add('converse-emoji-views', {
this
.
emoji_picker_view
.
chatview
=
this
;
this
.
emoji_picker_view
.
chatview
=
this
;
},
},
createEmojiDropdown
(
ev
)
{
const
dropdown_el
=
this
.
el
.
querySelector
(
'
.toggle-smiley.dropup
'
);
this
.
emoji_dropdown
=
new
bootstrap
.
Dropdown
(
dropdown_el
,
true
);
this
.
emoji_dropdown
.
el
=
dropdown_el
;
},
async
toggleEmojiMenu
(
ev
)
{
async
toggleEmojiMenu
(
ev
)
{
if
(
this
.
emoji_dropdown
===
undefined
)
{
if
(
this
.
emoji_dropdown
===
undefined
)
{
ev
.
stopPropagation
();
ev
.
stopPropagation
();
const
dropdown_el
=
this
.
el
.
querySelector
(
'
.toggle-smiley.dropup
'
);
this
.
createEmojiDropdown
();
this
.
emoji_dropdown
=
new
bootstrap
.
Dropdown
(
dropdown_el
,
true
);
this
.
emoji_dropdown
.
el
=
dropdown_el
;
this
.
emoji_dropdown
.
toggle
();
this
.
emoji_dropdown
.
toggle
();
await
_converse
.
api
.
waitUntil
(
'
emojisInitialized
'
);
await
_converse
.
api
.
waitUntil
(
'
emojisInitialized
'
);
this
.
emoji_picker_view
.
render
();
this
.
emoji_picker_view
.
render
();
...
@@ -116,7 +143,7 @@ converse.plugins.add('converse-emoji-views', {
...
@@ -116,7 +143,7 @@ converse.plugins.add('converse-emoji-views', {
},
},
initialize
()
{
initialize
()
{
this
.
debouncedFilter
=
_
.
debounce
(
input
=>
this
.
filter
(
input
),
50
);
this
.
debouncedFilter
=
_
.
debounce
(
input
=>
this
.
filter
(
input
.
value
),
50
);
this
.
model
.
on
(
'
change:query
'
,
this
.
render
,
this
);
this
.
model
.
on
(
'
change:query
'
,
this
.
render
,
this
);
this
.
model
.
on
(
'
change:current_skintone
'
,
this
.
render
,
this
);
this
.
model
.
on
(
'
change:current_skintone
'
,
this
.
render
,
this
);
this
.
model
.
on
(
'
change:current_category
'
,
()
=>
{
this
.
model
.
on
(
'
change:current_category
'
,
()
=>
{
...
@@ -145,8 +172,16 @@ converse.plugins.add('converse-emoji-views', {
...
@@ -145,8 +172,16 @@ converse.plugins.add('converse-emoji-views', {
return
html
;
return
html
;
},
},
filter
(
input
)
{
filter
(
value
,
set_property
)
{
this
.
model
.
set
({
'
query
'
:
input
.
value
});
this
.
model
.
set
({
'
query
'
:
value
});
if
(
set_property
)
{
// XXX: Ideally we would set `query` on the model and
// then let the view re-render, instead of doing it
// manually here. Snabbdom supports setting properties,
// Backbone.VDOMView doesn't.
const
input
=
this
.
el
.
querySelector
(
'
.emoji-search
'
);
input
.
value
=
value
;
}
},
},
onKeyDown
(
ev
)
{
onKeyDown
(
ev
)
{
...
@@ -154,25 +189,21 @@ converse.plugins.add('converse-emoji-views', {
...
@@ -154,25 +189,21 @@ converse.plugins.add('converse-emoji-views', {
ev
.
preventDefault
();
ev
.
preventDefault
();
const
match
=
_
.
find
(
_converse
.
emoji_shortnames
,
sn
=>
_converse
.
FILTER_CONTAINS
(
sn
,
ev
.
target
.
value
));
const
match
=
_
.
find
(
_converse
.
emoji_shortnames
,
sn
=>
_converse
.
FILTER_CONTAINS
(
sn
,
ev
.
target
.
value
));
if
(
match
)
{
if
(
match
)
{
// XXX: Ideally we would set `query` on the model and
this
.
filter
(
match
,
true
);
// then let the view re-render, instead of doing it
// manually here. Snabbdom supports setting properties,
// Backbone.VDOMView doesn't.
ev
.
target
.
value
=
match
;
this
.
filter
(
ev
.
target
);
}
}
}
else
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
ENTER
)
{
}
else
if
(
ev
.
keyCode
===
_converse
.
keycodes
.
ENTER
)
{
ev
.
preventDefault
();
ev
.
preventDefault
();
ev
.
stopPropagation
();
ev
.
stopPropagation
();
if
(
_converse
.
emoji_shortnames
.
includes
(
ev
.
target
.
value
))
{
if
(
_converse
.
emoji_shortnames
.
includes
(
ev
.
target
.
value
))
{
this
.
chatview
.
insertIntoTextArea
(
ev
.
target
.
value
);
const
replace
=
this
.
model
.
get
(
'
autocompleting
'
);
const
position
=
this
.
model
.
get
(
'
position
'
);
this
.
model
.
set
({
'
autocompleting
'
:
null
,
'
position
'
:
null
});
this
.
chatview
.
insertIntoTextArea
(
ev
.
target
.
value
,
replace
,
false
,
position
);
this
.
chatview
.
emoji_dropdown
.
toggle
();
this
.
chatview
.
emoji_dropdown
.
toggle
();
// XXX: See above
this
.
filter
(
''
,
true
);
ev
.
target
.
value
=
''
;
this
.
filter
(
ev
.
target
);
}
}
}
else
{
}
else
{
this
.
debouncedFilter
(
ev
.
target
);
this
.
debouncedFilter
(
ev
.
target
.
value
);
}
}
},
},
...
@@ -239,12 +270,12 @@ converse.plugins.add('converse-emoji-views', {
...
@@ -239,12 +270,12 @@ converse.plugins.add('converse-emoji-views', {
ev
.
preventDefault
();
ev
.
preventDefault
();
ev
.
stopPropagation
();
ev
.
stopPropagation
();
const
target
=
ev
.
target
.
nodeName
===
'
IMG
'
?
ev
.
target
.
parentElement
:
ev
.
target
;
const
target
=
ev
.
target
.
nodeName
===
'
IMG
'
?
ev
.
target
.
parentElement
:
ev
.
target
;
this
.
chatview
.
insertIntoTextArea
(
target
.
getAttribute
(
'
data-emoji
'
));
const
replace
=
this
.
model
.
get
(
'
autocompleting
'
);
const
position
=
this
.
model
.
get
(
'
position
'
);
this
.
model
.
set
({
'
autocompleting
'
:
null
,
'
position
'
:
null
});
this
.
chatview
.
insertIntoTextArea
(
target
.
getAttribute
(
'
data-emoji
'
),
replace
,
false
,
position
);
this
.
chatview
.
emoji_dropdown
.
toggle
();
this
.
chatview
.
emoji_dropdown
.
toggle
();
// XXX: See above
this
.
filter
(
''
,
true
);
const
input
=
this
.
el
.
querySelector
(
'
.emoji-search
'
);
input
.
value
=
''
;
this
.
filter
(
input
);
}
}
});
});
...
...
src/headless/utils/core.js
View file @
e4dc9fa8
...
@@ -418,11 +418,25 @@ u.siblingIndex = function (el) {
...
@@ -418,11 +418,25 @@ u.siblingIndex = function (el) {
return
i
;
return
i
;
};
};
u
.
getCurrentWord
=
function
(
input
,
index
)
{
/**
* Returns the current word being written in the input element
* @method u#getCurrentWord
* @param {HTMLElement} input - The HTMLElement in which text is being entered
* @param {integer} [index] - An optional rightmost boundary index. If given, the text
* value of the input element will only be considered up until this index.
* @param {string} [delineator] - An optional string delineator to
* differentiate between words.
* @private
*/
u
.
getCurrentWord
=
function
(
input
,
index
,
delineator
)
{
if
(
!
index
)
{
if
(
!
index
)
{
index
=
input
.
selectionEnd
||
undefined
;
index
=
input
.
selectionEnd
||
undefined
;
}
}
return
_
.
last
(
input
.
value
.
slice
(
0
,
index
).
split
(
'
'
));
let
[
word
]
=
input
.
value
.
slice
(
0
,
index
).
split
(
'
'
).
slice
(
-
1
);
if
(
delineator
)
{
[
word
]
=
word
.
split
(
delineator
).
slice
(
-
1
);
}
return
word
;
};
};
u
.
replaceCurrentWord
=
function
(
input
,
new_value
)
{
u
.
replaceCurrentWord
=
function
(
input
,
new_value
)
{
...
@@ -535,6 +549,7 @@ u.getUniqueId = function () {
...
@@ -535,6 +549,7 @@ u.getUniqueId = function () {
/**
/**
* Clears the specified timeout and interval.
* Clears the specified timeout and interval.
* @method u#clearTimers
* @param {number} timeout - Id if the timeout to clear.
* @param {number} timeout - Id if the timeout to clear.
* @param {number} interval - Id of the interval to clear.
* @param {number} interval - Id of the interval to clear.
* @private
* @private
...
@@ -550,12 +565,13 @@ function clearTimers(timeout, interval) {
...
@@ -550,12 +565,13 @@ function clearTimers(timeout, interval) {
/**
/**
* Creates a {@link Promise} that resolves if the passed in function returns a truthy value.
* Creates a {@link Promise} that resolves if the passed in function returns a truthy value.
* Rejects if it throws or does not return truthy within the given max_wait.
* Rejects if it throws or does not return truthy within the given max_wait.
* @method u#waitUntil
* @param {Function} func - The function called every check_delay,
* @param {Function} func - The function called every check_delay,
* and the result of which is the resolved value of the promise.
*
and the result of which is the resolved value of the promise.
* @param {number} [max_wait=300] - The time to wait before rejecting the promise.
* @param {number} [max_wait=300] - The time to wait before rejecting the promise.
* @param {number} [check_delay=3] - The time to wait before each invocation of {func}.
* @param {number} [check_delay=3] - The time to wait before each invocation of {func}.
* @returns {Promise} A promise resolved with the value of func,
* @returns {Promise} A promise resolved with the value of func,
* or rejected with the exception thrown by it or it times out.
*
or rejected with the exception thrown by it or it times out.
* @copyright Simen Bekkhus 2016
* @copyright Simen Bekkhus 2016
* @license MIT
* @license MIT
*/
*/
...
...
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