Factor out compose typeahead into individual functions

(imported from commit 293c61d5793ced7792c57713210a34736d851ae8)
This commit is contained in:
Leo Franchi 2013-09-20 13:13:39 -04:00
parent 03fe84aa6a
commit 4f0f469a8e
1 changed files with 122 additions and 112 deletions

View File

@ -183,6 +183,127 @@ exports.split_at_cursor = function (query) {
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 () {
select_on_focus("stream");
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
});
$( "#new_message_content" ).typeahead({
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
});
exports.initialize_compose_typeahead("#new_message_content");
$( "#private_message_recipient" ).blur(function (event) {
var val = $(this).val();