mirror of https://github.com/zulip/zulip.git
Factor out compose typeahead into individual functions
(imported from commit 293c61d5793ced7792c57713210a34736d851ae8)
This commit is contained in:
parent
03fe84aa6a
commit
4f0f469a8e
|
@ -183,6 +183,127 @@ exports.split_at_cursor = function (query) {
|
||||||
return [query.slice(0, cursor), query.slice(cursor)];
|
return [query.slice(0, cursor), query.slice(cursor)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.compose_content_begins_typeahead = function (query) {
|
||||||
|
var q = exports.split_at_cursor(query)[0];
|
||||||
|
|
||||||
|
var strings = q.split(/[\s*(){}\[\]]/);
|
||||||
|
if (strings.length < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var current_token = strings[strings.length-1];
|
||||||
|
|
||||||
|
// Only start the emoji autocompleter if : is directly after one
|
||||||
|
// of the whitespace or punctuation chars we split on.
|
||||||
|
if (current_token[0] === ':') {
|
||||||
|
// We don't want to match non-emoji emoticons such
|
||||||
|
// as :P or :-p
|
||||||
|
// Also, if the user has only typed a colon and nothing after,
|
||||||
|
// no need to match yet.
|
||||||
|
if (/^:-?.?$/.test(current_token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.completing = 'emoji';
|
||||||
|
this.token = current_token.substring(1);
|
||||||
|
return emoji.emojis;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't autocomplete more than this many characters.
|
||||||
|
var max_chars = 30;
|
||||||
|
var last_at = q.lastIndexOf('@');
|
||||||
|
if (last_at === -1 || last_at < q.length-1 - max_chars) {
|
||||||
|
return false; // No '@', or too far back
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only match if the @ follows a space, various punctuation,
|
||||||
|
// or is at the beginning of the string.
|
||||||
|
if (last_at > 0 && "\n\t \"'(){}[]".indexOf(q[last_at-1]) === -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_token = q.substring(last_at + 1);
|
||||||
|
if (current_token.length < 1 || current_token.lastIndexOf('*') !== -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.completing = 'mention';
|
||||||
|
this.token = current_token.substring(current_token.indexOf("@")+1);
|
||||||
|
var all_item = {
|
||||||
|
special_item_text: "all (Notify everyone)",
|
||||||
|
email: "all",
|
||||||
|
// Always sort above, under the assumption that names will
|
||||||
|
// be longer and only contain "all" as a substring.
|
||||||
|
pm_recipient_count: Infinity,
|
||||||
|
full_name: "all"
|
||||||
|
};
|
||||||
|
return page_params.people_list.concat([all_item]);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.content_highlighter = function (item) {
|
||||||
|
if (this.completing === 'emoji') {
|
||||||
|
return "<img class='emoji' src='" + item.emoji_url + "' /> " + item.emoji_name;
|
||||||
|
} else if (this.completing === 'mention') {
|
||||||
|
var item_formatted = typeahead_helper.render_person(item);
|
||||||
|
return typeahead_helper.highlight_with_escaping(this.token, item_formatted);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.content_typeahead_selected = function (item) {
|
||||||
|
var pieces = exports.split_at_cursor(this.query);
|
||||||
|
var beginning = pieces[0];
|
||||||
|
var rest = pieces[1];
|
||||||
|
|
||||||
|
if (this.completing === 'emoji') {
|
||||||
|
//leading and trailing spaces are required for emoji, except if it begins a message.
|
||||||
|
if (beginning.lastIndexOf(":") === 0 || beginning.charAt(beginning.lastIndexOf(":") - 1) === " ") {
|
||||||
|
beginning = beginning.replace(/:\S+$/, "") + ":" + item.emoji_name + ": ";
|
||||||
|
} else {
|
||||||
|
beginning = beginning.replace(/:\S+$/, "") + " :" + item.emoji_name + ": ";
|
||||||
|
}
|
||||||
|
} else if (this.completing === 'mention') {
|
||||||
|
beginning = (beginning.substring(0, beginning.length - this.token.length-1)
|
||||||
|
+ '@**' + item.full_name + '** ');
|
||||||
|
|
||||||
|
// We insert a special `all` item to the autocompleter above
|
||||||
|
// Don't consider it a user mention
|
||||||
|
if (item.email !== 'all') {
|
||||||
|
$(document).trigger('usermention_completed.zulip', {mentioned: item});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the cursor after the newly inserted text, as Bootstrap will call textbox.change() to overwrite the text
|
||||||
|
// in the textbox.
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#new_message_content').caret(beginning.length, beginning.length);
|
||||||
|
}, 0);
|
||||||
|
return beginning + rest;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.initialize_compose_typeahead = function (selector) {
|
||||||
|
$(selector).typeahead({
|
||||||
|
items: 5,
|
||||||
|
dropup: true,
|
||||||
|
fixed: true,
|
||||||
|
source: exports.compose_content_begins_typeahead,
|
||||||
|
highlighter: exports.content_highlighter,
|
||||||
|
matcher: function (item) {
|
||||||
|
if (this.completing === 'emoji') {
|
||||||
|
return query_matches_emoji(this.token, item);
|
||||||
|
} else if (this.completing === 'mention') {
|
||||||
|
return query_matches_person(this.token, item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sorter: function (matches) {
|
||||||
|
if (this.completing === 'emoji') {
|
||||||
|
return typeahead_helper.sort_emojis(matches, this.token);
|
||||||
|
} else if (this.completing === 'mention') {
|
||||||
|
return typeahead_helper.sort_recipients(matches, this.token);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updater: exports.content_typeahead_selected,
|
||||||
|
stopAdvance: true // Do not advance to the next field on a tab or enter
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
exports.initialize = function () {
|
exports.initialize = function () {
|
||||||
select_on_focus("stream");
|
select_on_focus("stream");
|
||||||
select_on_focus("subject");
|
select_on_focus("subject");
|
||||||
|
@ -286,118 +407,7 @@ exports.initialize = function () {
|
||||||
stopAdvance: true // Do not advance to the next field on a tab or enter
|
stopAdvance: true // Do not advance to the next field on a tab or enter
|
||||||
});
|
});
|
||||||
|
|
||||||
$( "#new_message_content" ).typeahead({
|
exports.initialize_compose_typeahead("#new_message_content");
|
||||||
source: function (query, process) {
|
|
||||||
var q = exports.split_at_cursor(query)[0];
|
|
||||||
|
|
||||||
var strings = q.split(/[\s*(){}\[\]]/);
|
|
||||||
if (strings.length < 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var current_token = strings[strings.length-1];
|
|
||||||
|
|
||||||
// Only start the emoji autocompleter if : is directly after one
|
|
||||||
// of the whitespace or punctuation chars we split on.
|
|
||||||
if (current_token[0] === ':') {
|
|
||||||
// We don't want to match non-emoji emoticons such
|
|
||||||
// as :P or :-p
|
|
||||||
// Also, if the user has only typed a colon and nothing after,
|
|
||||||
// no need to match yet.
|
|
||||||
if (/^:-?.?$/.test(current_token)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.completing = 'emoji';
|
|
||||||
this.token = current_token.substring(1);
|
|
||||||
return emoji.emojis;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't autocomplete more than this many characters.
|
|
||||||
var max_chars = 30;
|
|
||||||
var last_at = q.lastIndexOf('@');
|
|
||||||
if (last_at === -1 || last_at < q.length-1 - max_chars) {
|
|
||||||
return false; // No '@', or too far back
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only match if the @ follows a space, various punctuation,
|
|
||||||
// or is at the beginning of the string.
|
|
||||||
if (last_at > 0 && "\n\t \"'(){}[]".indexOf(q[last_at-1]) === -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_token = q.substring(last_at + 1);
|
|
||||||
if (current_token.length < 1 || current_token.lastIndexOf('*') !== -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.completing = 'mention';
|
|
||||||
this.token = current_token.substring(current_token.indexOf("@")+1);
|
|
||||||
var all_item = {
|
|
||||||
special_item_text: "all (Notify everyone)",
|
|
||||||
email: "all",
|
|
||||||
// Always sort above, under the assumption that names will
|
|
||||||
// be longer and only contain "all" as a substring.
|
|
||||||
pm_recipient_count: Infinity,
|
|
||||||
full_name: "all"
|
|
||||||
};
|
|
||||||
return page_params.people_list.concat([all_item]);
|
|
||||||
},
|
|
||||||
items: 5,
|
|
||||||
highlighter: function (item) {
|
|
||||||
if (this.completing === 'emoji') {
|
|
||||||
return "<img class='emoji' src='" + item.emoji_url + "' /> " + item.emoji_name;
|
|
||||||
} else if (this.completing === 'mention') {
|
|
||||||
var item_formatted = typeahead_helper.render_person(item);
|
|
||||||
return typeahead_helper.highlight_with_escaping(this.token, item_formatted);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dropup: true,
|
|
||||||
fixed: true,
|
|
||||||
matcher: function (item) {
|
|
||||||
if (this.completing === 'emoji') {
|
|
||||||
return query_matches_emoji(this.token, item);
|
|
||||||
} else if (this.completing === 'mention') {
|
|
||||||
return query_matches_person(this.token, item);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sorter: function (matches) {
|
|
||||||
if (this.completing === 'emoji') {
|
|
||||||
return typeahead_helper.sort_emojis(matches, this.token);
|
|
||||||
} else if (this.completing === 'mention') {
|
|
||||||
return typeahead_helper.sort_recipients(matches, this.token);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updater: function (item) {
|
|
||||||
var pieces = exports.split_at_cursor(this.query);
|
|
||||||
var beginning = pieces[0];
|
|
||||||
var rest = pieces[1];
|
|
||||||
|
|
||||||
if (this.completing === 'emoji') {
|
|
||||||
//leading and trailing spaces are required for emoji, except if it begins a message.
|
|
||||||
if (beginning.lastIndexOf(":") === 0 || beginning.charAt(beginning.lastIndexOf(":") - 1) === " ") {
|
|
||||||
beginning = beginning.replace(/:\S+$/, "") + ":" + item.emoji_name + ": ";
|
|
||||||
} else {
|
|
||||||
beginning = beginning.replace(/:\S+$/, "") + " :" + item.emoji_name + ": ";
|
|
||||||
}
|
|
||||||
} else if (this.completing === 'mention') {
|
|
||||||
beginning = (beginning.substring(0, beginning.length - this.token.length-1)
|
|
||||||
+ '@**' + item.full_name + '** ');
|
|
||||||
|
|
||||||
// We insert a special `all` item to the autocompleter above
|
|
||||||
// Don't consider it a user mention
|
|
||||||
if (item.email !== 'all') {
|
|
||||||
$(document).trigger('usermention_completed.zulip', {mentioned: item});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the cursor after the newly inserted text, as Bootstrap will call textbox.change() to overwrite the text
|
|
||||||
// in the textbox.
|
|
||||||
setTimeout(function () {
|
|
||||||
$('#new_message_content').caret(beginning.length, beginning.length);
|
|
||||||
}, 0);
|
|
||||||
return beginning + rest;
|
|
||||||
},
|
|
||||||
stopAdvance: true // Do not advance to the next field on a tab or enter
|
|
||||||
});
|
|
||||||
|
|
||||||
$( "#private_message_recipient" ).blur(function (event) {
|
$( "#private_message_recipient" ).blur(function (event) {
|
||||||
var val = $(this).val();
|
var val = $(this).val();
|
||||||
|
|
Loading…
Reference in New Issue