Commit 995f2a99 authored by JC Brand's avatar JC Brand

Add arrow navigation to the emoji picker

parent 2b213d05
...@@ -75,9 +75,13 @@ ...@@ -75,9 +75,13 @@
position: relative; position: relative;
&.insert-emoji { &.insert-emoji {
margin: 0; margin: 0;
height: 32px; padding: 3px;
height: 30px;
width: 32px; width: 32px;
&.selected {
background-color: var(--highlight-color);
}
&.picked { &.picked {
background-color: var(--highlight-color); background-color: var(--highlight-color);
} }
...@@ -112,6 +116,9 @@ ...@@ -112,6 +116,9 @@
border: 1px var(--chat-head-color) solid; border: 1px var(--chat-head-color) solid;
border-bottom: none; border-bottom: none;
} }
&.selected {
background-color: var(--highlight-color);
}
padding: 0.25em; padding: 0.25em;
font-size: var(--font-size-huge); font-size: var(--font-size-huge);
&:hover { &:hover {
......
...@@ -62,7 +62,7 @@ $mobile_portrait_length: 480px !default; ...@@ -62,7 +62,7 @@ $mobile_portrait_length: 480px !default;
--chat-topic-display: block; --chat-topic-display: block;
--chat-info-display: block; --chat-info-display: block;
--highlight-color: #DCF9F6; --highlight-color: #B0E8E2;
--primary-color: var(--light-blue); --primary-color: var(--light-blue);
--primary-color-dark: #397491; --primary-color-dark: #397491;
......
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
// Check that ENTER now inserts the match // Check that ENTER now inserts the match
const enter_event = Object.assign({}, tab_event, {'keyCode': 13, 'key': 'Enter', 'target': input}); const enter_event = Object.assign({}, tab_event, {'keyCode': 13, 'key': 'Enter', 'target': input});
view.emoji_picker_view.onKeyDown(enter_event); view.emoji_picker_view._onGlobalKeyDown(enter_event);
expect(input.value).toBe(''); expect(input.value).toBe('');
expect(textarea.value).toBe(':grimacing: '); expect(textarea.value).toBe(':grimacing: ');
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
// Check that pressing enter without an unambiguous match does nothing // Check that pressing enter without an unambiguous match does nothing
const enter_event = Object.assign({}, event, {'keyCode': 13}); const enter_event = Object.assign({}, event, {'keyCode': 13});
view.emoji_picker_view.onKeyDown(enter_event); view.emoji_picker_view._onGlobalKeyDown(enter_event);
expect(input.value).toBe('smiley'); expect(input.value).toBe('smiley');
// Test that TAB autocompletes the to first match // Test that TAB autocompletes the to first match
...@@ -148,7 +148,7 @@ ...@@ -148,7 +148,7 @@
expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:'); expect(visible_emojis[0].getAttribute('data-emoji')).toBe(':smiley:');
// Check that ENTER now inserts the match // Check that ENTER now inserts the match
view.emoji_picker_view.onKeyDown(enter_event); view.emoji_picker_view._onGlobalKeyDown(enter_event);
expect(input.value).toBe(''); expect(input.value).toBe('');
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: '); expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
done(); done();
......
...@@ -282,28 +282,28 @@ converse.plugins.add("converse-autocomplete", { ...@@ -282,28 +282,28 @@ converse.plugins.add("converse-autocomplete", {
onKeyDown (ev) { onKeyDown (ev) {
if (this.opened) { if (this.opened) {
if (_.includes([_converse.keycodes.ENTER, _converse.keycodes.TAB], ev.keyCode) && this.selected) { if (_.includes([converse.keycodes.ENTER, converse.keycodes.TAB], ev.keyCode) && this.selected) {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
this.select(); this.select();
return true; return true;
} else if (ev.keyCode === _converse.keycodes.ESCAPE) { } else if (ev.keyCode === converse.keycodes.ESCAPE) {
this.close({'reason': 'esc'}); this.close({'reason': 'esc'});
return true; return true;
} else if (_.includes([_converse.keycodes.UP_ARROW, _converse.keycodes.DOWN_ARROW], ev.keyCode)) { } else if (_.includes([converse.keycodes.UP_ARROW, converse.keycodes.DOWN_ARROW], ev.keyCode)) {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
this[ev.keyCode === _converse.keycodes.UP_ARROW ? "previous" : "next"](); this[ev.keyCode === converse.keycodes.UP_ARROW ? "previous" : "next"]();
return true; return true;
} }
} }
if (_.includes([ if (_.includes([
_converse.keycodes.SHIFT, converse.keycodes.SHIFT,
_converse.keycodes.META, converse.keycodes.META,
_converse.keycodes.META_RIGHT, converse.keycodes.META_RIGHT,
_converse.keycodes.ESCAPE, converse.keycodes.ESCAPE,
_converse.keycodes.ALT] converse.keycodes.ALT]
, ev.keyCode)) { , ev.keyCode)) {
return; return;
} }
...@@ -323,8 +323,8 @@ converse.plugins.add("converse-autocomplete", { ...@@ -323,8 +323,8 @@ converse.plugins.add("converse-autocomplete", {
evaluate (ev) { evaluate (ev) {
const selecting = this.selected && ev && ( const selecting = this.selected && ev && (
ev.keyCode === _converse.keycodes.UP_ARROW || ev.keyCode === converse.keycodes.UP_ARROW ||
ev.keyCode === _converse.keycodes.DOWN_ARROW ev.keyCode === converse.keycodes.DOWN_ARROW
); );
if (!this.auto_evaluate && !this.auto_completing || selecting) { if (!this.auto_evaluate && !this.auto_completing || selecting) {
......
...@@ -869,29 +869,29 @@ converse.plugins.add('converse-chatview', { ...@@ -869,29 +869,29 @@ converse.plugins.add('converse-chatview', {
return; return;
} }
if (!ev.shiftKey && !ev.altKey && !ev.metaKey) { if (!ev.shiftKey && !ev.altKey && !ev.metaKey) {
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.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) {
return this.onEnterPressed(ev); return this.onEnterPressed(ev);
} else if (ev.keyCode === _converse.keycodes.UP_ARROW && !ev.target.selectionEnd) { } else if (ev.keyCode === converse.keycodes.UP_ARROW && !ev.target.selectionEnd) {
const textarea = this.el.querySelector('.chat-textarea'); const textarea = this.el.querySelector('.chat-textarea');
if (!textarea.value || u.hasClass('correcting', textarea)) { if (!textarea.value || u.hasClass('correcting', textarea)) {
return this.editEarlierMessage(); return this.editEarlierMessage();
} }
} else if (ev.keyCode === _converse.keycodes.DOWN_ARROW && } else if (ev.keyCode === converse.keycodes.DOWN_ARROW &&
ev.target.selectionEnd === ev.target.value.length && ev.target.selectionEnd === ev.target.value.length &&
u.hasClass('correcting', this.el.querySelector('.chat-textarea'))) { u.hasClass('correcting', this.el.querySelector('.chat-textarea'))) {
return this.editLaterMessage(); return this.editLaterMessage();
} }
} }
if ([_converse.keycodes.SHIFT, if ([converse.keycodes.SHIFT,
_converse.keycodes.META, converse.keycodes.META,
_converse.keycodes.META_RIGHT, converse.keycodes.META_RIGHT,
_converse.keycodes.ESCAPE, converse.keycodes.ESCAPE,
_converse.keycodes.ALT].includes(ev.keyCode)) { converse.keycodes.ALT].includes(ev.keyCode)) {
return; return;
} }
if (this.model.get('chat_state') !== _converse.COMPOSING) { if (this.model.get('chat_state') !== _converse.COMPOSING) {
......
This diff is collapsed.
// Converse.js
// https://conversejs.org
//
// Copyright (c) 2013-2019, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
//
/** /**
* @module converse-muc-views * @module converse-muc-views
* @description * @copyright 2013-2019, the Converse.js developers
* XEP-0045 Multi-User Chat Views * @description XEP-0045 Multi-User Chat Views
* @license Mozilla Public License (MPLv2)
*/ */
import "converse-modal"; import "converse-modal";
import "backbone.vdomview"; import "backbone.vdomview";
......
// Converse.js
// https://conversejs.org
//
// Copyright (c) 2013-2019, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
/** /**
* @module converse-singleton * @module converse-singleton
* @description * @copyright JC Brand
* A plugin which restricts Converse to only one chat. * @license Mozilla Public License (MPLv2)
* @description A plugin which restricts Converse to only one chat.
*/ */
import converse from "@converse/headless/converse-core"; import converse from "@converse/headless/converse-core";
......
This diff is collapsed.
...@@ -149,21 +149,6 @@ _converse.IllegalMessage = IllegalMessage; ...@@ -149,21 +149,6 @@ _converse.IllegalMessage = IllegalMessage;
// Make converse pluggable // Make converse pluggable
pluggable.enable(_converse, '_converse', 'pluggable'); pluggable.enable(_converse, '_converse', 'pluggable');
_converse.keycodes = {
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
ESCAPE: 27,
UP_ARROW: 38,
DOWN_ARROW: 40,
FORWARD_SLASH: 47,
AT: 50,
META: 91,
META_RIGHT: 93
};
// Module-level constants // Module-level constants
_converse.STATUS_WEIGHTS = { _converse.STATUS_WEIGHTS = {
'offline': 6, 'offline': 6,
...@@ -1732,6 +1717,23 @@ window.converse = window.converse || {}; ...@@ -1732,6 +1717,23 @@ window.converse = window.converse || {};
* @namespace converse * @namespace converse
*/ */
Object.assign(window.converse, { Object.assign(window.converse, {
keycodes: {
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
ESCAPE: 27,
LEFT_ARROW: 37,
UP_ARROW: 38,
RIGHT_ARROW: 39,
DOWN_ARROW: 40,
FORWARD_SLASH: 47,
AT: 50,
META: 91,
META_RIGHT: 93
},
/** /**
* Public API method which initializes Converse. * Public API method which initializes Converse.
* This method must always be called when using Converse. * This method must always be called when using Converse.
......
// Converse.js
// https://conversejs.org
//
// Copyright (c) 2013-2019, the Converse.js developers
// Licensed under the Mozilla Public License (MPLv2)
//
/** /**
* @module converse-muc * @module converse-muc
* @description * @copyright The Converse.js developers
* Implements the non-view logic for XEP-0045 Multi-User Chat * @license Mozilla Public License (MPLv2)
* @description Implements the non-view logic for XEP-0045 Multi-User Chat
*/ */
import "./converse-chat"; import "./converse-chat";
import "./converse-disco"; import "./converse-disco";
......
...@@ -279,11 +279,23 @@ u.hasClass = function (className, el) { ...@@ -279,11 +279,23 @@ u.hasClass = function (className, el) {
return (el instanceof Element) && el.classList.contains(className); return (el instanceof Element) && el.classList.contains(className);
}; };
/**
* Add a class to an element.
* @method u#addClass
* @param {string} className
* @param {Element} el
*/
u.addClass = function (className, el) { u.addClass = function (className, el) {
(el instanceof Element) && el.classList.add(className); (el instanceof Element) && el.classList.add(className);
return el; return el;
} }
/**
* Remove a class from an element.
* @method u#removeClass
* @param {string} className
* @param {Element} el
*/
u.removeClass = function (className, el) { u.removeClass = function (className, el) {
(el instanceof Element) && el.classList.remove(className); (el instanceof Element) && el.classList.remove(className);
return el; return el;
......
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