Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion img/emoji-smile.svg

This file was deleted.

78 changes: 78 additions & 0 deletions src/components/NewMessageForm/NewMessageForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,26 @@
</ActionButton>
</Actions>
</div>
<div
class="new-message-form__button">
<EmojiPicker @select="addEmoji">
<button
type="button"
class="new-message-form__icon new-message-form__button"
:aria-label="t('spreed', 'Add emoji')"
:aria-haspopup="true">
<EmoticonOutline
:size="20" />
</button>
</EmojiPicker>
</div>
<div class="new-message-form__input">
<Quote
v-if="messageToBeReplied"
:is-new-message-form-quote="true"
v-bind="messageToBeReplied" />
<AdvancedInput
ref="advancedInput"
v-model="text"
:token="token"
@update:contentEditable="contentEditableToParsed"
Expand All @@ -84,10 +98,12 @@ import { postNewMessage } from '../../services/messagesService'
import Quote from '../Quote'
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import EmojiPicker from '@nextcloud/vue/dist/Components/EmojiPicker'
import { shareFile } from '../../services/filesSharingServices'
import { processFiles } from '../../utils/fileUpload'
import { CONVERSATION } from '../../constants'
import createTemporaryMessage from '../../utils/temporaryMessage'
import EmoticonOutline from 'vue-material-design-icons/EmoticonOutline'

const picker = getFilePickerBuilder(t('spreed', 'File to share'))
.setMultiSelect(false)
Expand All @@ -103,6 +119,8 @@ export default {
Quote,
Actions,
ActionButton,
EmojiPicker,
EmoticonOutline,
},
data: function() {
return {
Expand Down Expand Up @@ -250,6 +268,55 @@ export default {
// Uploads and shares the files
processFiles(files, this.token, uploadId)
},

/**
* Add selected emoji to text input area
*
* The emoji will be added at the current caret position, and any text
* currently selected will be replaced by the emoji. If the input area
* does not have the focus there will be no caret or selection; in that
* case the emoji will be added at the end.
*
* @param {Emoji} emoji Emoji object
*/
addEmoji(emoji) {
const selection = document.getSelection()

const contentEditable = this.$refs.advancedInput.$refs.contentEditable

// There is no select, or current selection does not start in the
// content editable element, so just append the emoji at the end.
if (!contentEditable.isSameNode(selection.anchorNode) && !contentEditable.contains(selection.anchorNode)) {
// Browsers add a "<br>" element as soon as some rich text is
// written in a content editable div (for example, if a new line
// is added the div content will be "<br><br>"), so the emoji
// has to be added before the last "<br>" (if any).
if (this.text.endsWith('<br>')) {
this.text = this.text.substr(0, this.text.lastIndexOf('<br>')) + emoji + '<br>'
} else {
this.text += emoji
}

return
}

// Although due to legacy reasons the API allows several ranges the
// specification requires the selection to always have a single
// range.
// https://developer.mozilla.org/en-US/docs/Web/API/Selection#Multiple_ranges_in_a_selection
const range = selection.getRangeAt(0)

// Deleting the contents also collapses the range to the start.
range.deleteContents()

const emojiTextNode = document.createTextNode(emoji)
range.insertNode(emojiTextNode)

this.text = contentEditable.innerHTML

range.setStartAfter(emojiTextNode)
},

},
}
</script>
Expand Down Expand Up @@ -286,6 +353,17 @@ export default {
background-color: transparent;
border: none;
}

// put a grey round background when popover is opened
// or hover-focused
&__icon:hover,
&__icon:focus,
&__icon:active {
opacity: $opacity_full;
// good looking on dark AND white bg
background-color: $icon-focus-bg;
}

}
}
</style>