diff --git a/addons/mail/static/src/js/composer.js b/addons/mail/static/src/js/composer.js index 6ffd2bc63c3b9fed93adf0d67be3b37e1b0cca8a..4fafe8427eb9ed0b2082998a1cb7b4af56fa8693 100644 --- a/addons/mail/static/src/js/composer.js +++ b/addons/mail/static/src/js/composer.js @@ -27,6 +27,8 @@ var accented_letters_mapping = { ' ': '[()\\[\\]]', }; +var NON_BREAKING_SPACE = '\u00a0'; + var MENTION_PARTNER_DELIMITER = '@'; var MENTION_CHANNEL_DELIMITER = '#'; @@ -71,6 +73,8 @@ var MentionManager = Widget.extend({ var selected_suggestion = _.find(_.flatten(this.get('mention_suggestions')), function (s) { return s.id === id; }); + // replace white spaces with non-breaking spaces to facilitate mentions detection in text + selected_suggestion.name = selected_suggestion.name.replace(/ /g, NON_BREAKING_SPACE); var get_mention_index = function (matches, cursor_position) { for (var i=0; i<matches.length; i++) { if (cursor_position <= matches[i].index) { @@ -121,9 +125,16 @@ var MentionManager = Widget.extend({ return this.open; }, + /** + * Returns the mentions of the given listener that haven't been erased from the composer's input + */ get_listener_selection: function (delimiter) { var listener = _.findWhere(this.listeners, {delimiter: delimiter}); - return listener ? listener.selection : []; + if (listener) { + var input_mentions = this.composer.$input.val().match(new RegExp(delimiter+'[^ ]+', 'g')); + return this._validate_selection(listener.selection, input_mentions); + } + return []; }, get_listener_selections: function () { @@ -199,33 +210,6 @@ var MentionManager = Widget.extend({ }, this.options.typing_speed); }, - /** - * Checks if a listener's selection should be updated after DELETE or BACKSPACE keypress - */ - check_remove: function () { - var self = this; - var to_remove = []; - var selection = this._get_selection_positions(); - var deleted_binf = selection.start; - var deleted_bsup = selection.end; - - _.each(this.listeners, function (listener) { - var mention_selection = listener.selection; - var matches = self._get_match(self.composer.$input.val(), listener); - for (var i=0; i<matches.length; i++) { - var m = matches[i]; - var m1 = m.index; - var m2 = m.index + m[0].length; - if (deleted_binf <= m2 && m1 < deleted_bsup) { - to_remove.push(mention_selection[i]); - } - } - if (to_remove.length) { - listener.selection = _.difference(mention_selection, to_remove); - } - }); - }, - /** * Replaces mentions appearing in the string 's' by html links with proper redirection */ @@ -242,7 +226,8 @@ var MentionManager = Widget.extend({ for (var i=0; i<matches.length; i++) { var match = matches[i]; var end_index = match.index + match[0].length; - var match_name = match[0].substring(1); + // put back white spaces instead of non-breaking spaces in mention's name + var match_name = match[0].substring(1).replace(new RegExp(NON_BREAKING_SPACE, 'g'), ' '); var href = base_href + _.str.sprintf("#model=%s&id=%s", listener.model, selection[i].id); var processed_text = _.str.sprintf(mention_link, href, listener.redirect_classname, selection[i].id, listener.model, listener.delimiter, match_name); var subtext = s.substring(start_index, end_index).replace(match[0], processed_text); @@ -303,6 +288,16 @@ var MentionManager = Widget.extend({ this.open = false; } }, + _validate_selection: function (selection, input_mentions) { + var validated_selection = []; + _.each(input_mentions, function (mention) { + var validated_mention = _.findWhere(selection, {name: mention.slice(1)}); + if (validated_mention) { + validated_selection.push(validated_mention); + } + }); + return validated_selection; + }, // Cursor position and selection utils _get_selection_positions: function () { @@ -477,11 +472,6 @@ var BasicComposer = Widget.extend({ event.preventDefault(); } break; - // BACKSPACE, DELETE: check if need to remove a mention - case $.ui.keyCode.BACKSPACE: - case $.ui.keyCode.DELETE: - this.mention_manager.check_remove(); - break; // ENTER: submit the message only if the dropdown mention proposition is not displayed case $.ui.keyCode.ENTER: if (this.mention_manager.is_open()) {