From e505583f526feb5ee507b871f3b94c89ed55402c Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Thu, 30 Jan 2014 16:42:19 -0500 Subject: [PATCH] Split out new module people.js for tracking people. (imported from commit fb9b769819ade25d1d3d6e452e68c7ee8651cfdd) --- static/js/activity.js | 18 +-- static/js/compose_fade.js | 2 +- static/js/echo.js | 10 +- static/js/people.js | 163 +++++++++++++++++++++++++ static/js/server_events.js | 6 +- static/js/subs.js | 27 +--- static/js/tab_bar.js | 8 +- static/js/zulip.js | 118 +----------------- tools/jslint/check-all.js | 6 +- zerver/tests/frontend/node/activity.js | 23 ++-- zerver/tests/frontend/node/echo.js | 4 +- zproject/settings.py | 1 + 12 files changed, 215 insertions(+), 171 deletions(-) create mode 100644 static/js/people.js diff --git a/static/js/activity.js b/static/js/activity.js index 49e5e6666d..66f63f8951 100644 --- a/static/js/activity.js +++ b/static/js/activity.js @@ -67,7 +67,7 @@ exports.full_huddle_name = function (huddle) { var emails = huddle.split(','); var names = _.map(emails, function (email) { - var person = people_dict.get(email); + var person = people.get_by_email(email); return person ? person.full_name : email; }); @@ -79,7 +79,7 @@ exports.short_huddle_name = function (huddle) { var num_to_show = 3; var names = _.map(emails.slice(0, num_to_show), function (email) { - var person = people_dict.get(email); + var person = people.get_by_email(email); return person ? person.full_name : email; }); var others = emails.length - num_to_show; @@ -127,11 +127,11 @@ function sort_users(users, presence_info) { // Sort equivalent PM names alphabetically var full_name_a = a; var full_name_b = b; - if (people_dict.has(a)) { - full_name_a = people_dict.get(a).full_name; + if (people.get_by_email(a)) { + full_name_a = people.get_by_email(a).full_name; } - if (people_dict.has(b)) { - full_name_b = people_dict.get(b).full_name; + if (people.get_by_email(b)) { + full_name_b = people.get_by_email(b).full_name; } return util.strcmp(full_name_a, full_name_b); }); @@ -163,7 +163,7 @@ function filter_users_by_search(users) { }); var filtered_users = _.filter(users, function (user) { - var person = people_dict.get(user); + var person = people.get_by_email(user); if (!person || !person.full_name) { return false; } @@ -189,7 +189,7 @@ function actually_update_users() { var users = Object.keys(presence_info); users = filter_users_by_search(users); users = _.filter(users, function (email) { - return people_dict.has(email); + return people.get_by_email(email); }); users = sort_users(users, presence_info); @@ -208,7 +208,7 @@ function actually_update_users() { function info_for(email) { var presence = presence_info[email]; return { - name: people_dict.get(email).full_name, + name: people.get_by_email(email).full_name, email: email, num_unread: get_num_unread(email), type: presence, diff --git a/static/js/compose_fade.js b/static/js/compose_fade.js index b04c1aa06a..eb3f875234 100644 --- a/static/js/compose_fade.js +++ b/static/js/compose_fade.js @@ -111,7 +111,7 @@ exports.would_receive_message = function (email) { } if (focused_recipient.type === 'stream') { - var user = realm_people_dict.get(email); + var user = people.realm_get(email); var sub = stream_data.get_sub(focused_recipient.stream); if (user && sub && user.is_bot && !sub.invite_only) { // Bots may receive messages on public streams even if they are diff --git a/static/js/echo.js b/static/js/echo.js index 986fb1e923..15b4de6f49 100644 --- a/static/js/echo.js +++ b/static/js/echo.js @@ -149,7 +149,7 @@ function insert_local_message(message_request, local_id) { var emails = message_request.private_message_recipient.split(','); message.display_recipient = _.map(emails, function (email) { email = email.trim(); - var person = people_dict.get(email); + var person = people.get_by_email(email); if (person !== undefined) { return person; } @@ -239,8 +239,8 @@ exports.process_from_server = function process_from_server(messages) { if (client_message.display_reply_to !== reply_to) { client_message.display_reply_to = reply_to; _.each(message.display_recipient, function (person) { - if (people_dict.get(person.email).full_name !== person.full_name) { - reify_person(person); + if (people.get_by_email(person.email).full_name !== person.full_name) { + people.reify(person); } }); updated = true; @@ -308,8 +308,8 @@ function handleEmoji(emoji_name) { } function handleUserMentions(username) { - if (people_by_name_dict.get(username)) { - var person = people_by_name_dict.get(username); + var person = people.get_by_name(username); + if (person !== undefined) { return '' + '@' + person.full_name + ''; } else if (username === 'all' || username === 'everyone') { diff --git a/static/js/people.js b/static/js/people.js new file mode 100644 index 0000000000..c162e6dafc --- /dev/null +++ b/static/js/people.js @@ -0,0 +1,163 @@ +var people = (function () { + +var exports = {}; + +// The following three Dicts point to the same objects +// All people we've seen +var people_dict = new Dict(); +var people_by_name_dict = new Dict(); +// People in this realm +var realm_people_dict = new Dict(); + +exports.get_by_email = function get_by_email(email) { + return people_dict.get(email); +}; + +exports.realm_get = function realm_get(email) { + return realm_people_dict.get(email); +}; + +exports.get_by_name = function realm_get(name) { + return people_by_name_dict.get(name); +}; + +// TODO: Replace these with the tests setting up page_params before +// loading people.js +exports.test_set_people_dict = function (data) { + people_dict = new Dict.from(data); +}; +exports.test_set_people_name_dict = function (data) { + people_by_name_dict = new Dict.from(data); +}; + +function people_cmp(person1, person2) { + // Compares objects of the form used in people_list. + var name_cmp = util.strcmp(person1.full_name, person2.full_name); + if (name_cmp < 0) { + return -1; + } else if (name_cmp > 0) { + return 1; + } + return util.strcmp(person1.email, person2.email); +} + +exports.get_rest_of_realm = function get_rest_of_realm() { + var people_minus_you = []; + realm_people_dict.each(function (person) { + if (person.email !== page_params.email) { + people_minus_you.push({"email": person.email, + "full_name": person.full_name}); + } + }); + return people_minus_you.sort(people_cmp); +}; + +exports.add = function add(person, in_realm) { + page_params.people_list.push(person); + people_dict.set(person.email, person); + people_by_name_dict.set(person.full_name, person); + person.pm_recipient_count = 0; +}; + +exports.add_in_realm = function add_in_realm(person) { + realm_people_dict.set(person.email, person); + exports.add(person); +}; + +exports.remove = function remove(person) { + var i; + for (i = 0; i < page_params.people_list.length; i++) { + if (page_params.people_list[i].email === person.email) { + page_params.people_list.splice(i, 1); + break; + } + } + people_dict.del(person.email); + people_by_name_dict.del(person.full_name); + realm_people_dict.del(person.email); +}; + +exports.reify = function reify(person) { + // If a locally sent message is a PM to + // an out-of-realm recipient, a people_dict + // entry is created with simply an email address + // Once we've received the full person object, replace + // it + if (! people_dict.has(person.email)) { + return; + } + + var old_person = people_dict.get(person.email); + var old_idx = page_params.people_list.indexOf(old_person); + + var new_person = _.extend({}, old_person, person); + people_dict.set(person.email, person); + people_by_name_dict.set(person.full_name, person); + page_params.people_list[old_idx] = new_person; + + if (people_by_name_dict.has(person.email)) { + people_by_name_dict.del(person.email); + } +}; + +exports.update = function update(person) { + // Currently the only attribute that can change is full_name, so + // we just push out changes to that field. As we add more things + // that can change, this will need to either get complicated or be + // replaced by MVC + if (! people_dict.has(person.email)) { + blueslip.error("Got update_person event for unexpected user", + {email: person.email}); + return; + } + var person_obj = people_dict.get(person.email); + + if (_.has(person, 'full_name')) { + if (people_by_name_dict.has(person_obj.full_name)) { + people_by_name_dict.set(person.full_name, person_obj); + people_by_name_dict.del(person_obj.full_name); + } + + person_obj.full_name = person.full_name; + + if (person.email === page_params.email) { + page_params.fullname = person.full_name; + } + } + + if (_.has(person, 'is_admin')) { + person_obj.is_admin = person.is_admin; + + if (person.email === page_params.email) { + page_params.is_admin = person.is_admin; + admin.show_or_hide_menu_item(); + } + } + + activity.set_user_statuses([]); + + // TODO: update sender names on messages +}; + +$(function () { + _.each(page_params.people_list, function (person) { + people_dict.set(person.email, person); + people_by_name_dict.set(person.full_name, person); + realm_people_dict.set(person.email, person); + person.pm_recipient_count = 0; + }); + + // The special account feedback@zulip.com is used for in-app + // feedback and should always show up as an autocomplete option. + if (! people.get_by_email('feedback@zulip.com')) { + exports.add({"email": "feedback@zulip.com", + "full_name": "Zulip Feedback Bot"}); + } +}); + +return exports; + +}()); +if (typeof module !== 'undefined') { + module.exports = people; +} diff --git a/static/js/server_events.js b/static/js/server_events.js index a1ec023c5c..a02e6354eb 100644 --- a/static/js/server_events.js +++ b/static/js/server_events.js @@ -63,11 +63,11 @@ function get_events_success(events) { break; case 'realm_user': if (event.op === 'add') { - add_person_in_realm(event.person); + people.add_in_realm(event.person); } else if (event.op === 'remove') { - remove_person(event.person); + people.remove(event.person); } else if (event.op === 'update') { - update_person(event.person); + people.update(event.person); } break; case 'stream': diff --git a/static/js/subs.js b/static/js/subs.js index 4814e987d9..d35b295e2e 100644 --- a/static/js/subs.js +++ b/static/js/subs.js @@ -548,17 +548,6 @@ function ajaxSubscribeForCreation(stream, principals, invite_only, announce) { }); } -function people_cmp(person1, person2) { - // Compares objects of the form used in people_list. - var name_cmp = util.strcmp(person1.full_name, person2.full_name); - if (name_cmp < 0) { - return -1; - } else if (name_cmp > 0) { - return 1; - } - return util.strcmp(person1.email, person2.email); -} - // Within the new stream modal... function update_announce_stream_state() { // If the stream is invite only, or everyone's added, disable @@ -579,16 +568,8 @@ function update_announce_stream_state() { } function show_new_stream_modal() { - var people_minus_you_and_internal_users = []; - realm_people_dict.each(function (person) { - if (person.email !== page_params.email) { - people_minus_you_and_internal_users.push({"email": person.email, - "full_name": person.full_name}); - } - }); - $('#people_to_add').html(templates.render('new_stream_users', { - users: people_minus_you_and_internal_users.sort(people_cmp) + users: people.get_rest_of_realm() })); // Make the options default to the same each time: @@ -797,7 +778,7 @@ $(function () { // mark_subscribed adds the user to the member list mark_subscribed(stream); } else { - add_to_member_list(list, people_dict.get(principal).full_name, principal); + add_to_member_list(list, people.get_by_email(principal).full_name, principal); } } else { error_elem.addClass("hide"); @@ -961,11 +942,11 @@ $(function () { success: function (data) { util.destroy_loading_indicator(indicator_elem); var subscribers = _.map(data.subscribers, function (elem) { - var person = people_dict.get(elem); + var person = people.get_by_email(elem); if (person === undefined) { return elem; } - return format_member_list_elem(people_dict.get(elem).full_name, elem); + return format_member_list_elem(people.get_by_email(elem).full_name, elem); }); _.each(subscribers.sort().reverse(), function (elem) { // add_element_to_member_list *prepends* the element, diff --git a/static/js/tab_bar.js b/static/js/tab_bar.js index 0e25e874ff..3c279a2fb1 100644 --- a/static/js/tab_bar.js +++ b/static/js/tab_bar.js @@ -50,10 +50,10 @@ function make_tab_data() { if (filter.has_operator("pm-with")) { var emails = filter.operands("pm-with")[0].split(','); var names = _.map(emails, function (email) { - if (! people_dict.has(email)) { + if (! people.get_by_email(email)) { return email; } - return people_dict.get(email).full_name; + return people.get_by_email(email).full_name; }); tabs.push(make_tab(names.join(', '), hashed)); @@ -69,8 +69,8 @@ function make_tab_data() { tabs.push(make_tab("Mentions", hashed)); } else if (filter.has_operator("sender")) { var sender = filter.operands("sender")[0]; - if (people_dict.has(sender)) { - sender = people_dict.get(sender).full_name; + if (people.get_by_email(sender)) { + sender = people.get_by_email(sender).full_name; } tabs.push(make_tab("Sent by " + sender, hashed)); } else if (filter.has_operator("search")) { diff --git a/static/js/zulip.js b/static/js/zulip.js index 9ac273ca83..30f1023402 100644 --- a/static/js/zulip.js +++ b/static/js/zulip.js @@ -12,13 +12,6 @@ var home_msg_list = new MessageList('zhome', var narrowed_msg_list; var current_msg_list = home_msg_list; -// The following three Dicts point to the same objects -// All people we've seen -var people_dict = new Dict(); -var people_by_name_dict = new Dict(); -// People in this realm -var realm_people_dict = new Dict(); - var recent_subjects = new Dict({fold_case: true}); var queued_mark_as_read = []; @@ -46,93 +39,6 @@ var suppress_unread_counts = true; var waiting_on_browser_scroll = true; -function add_person(person, in_realm) { - page_params.people_list.push(person); - people_dict.set(person.email, person); - people_by_name_dict.set(person.full_name, person); - person.pm_recipient_count = 0; -} - -function add_person_in_realm(person) { - realm_people_dict.set(person.email, person); - add_person(person); -} - -function remove_person(person) { - var i; - for (i = 0; i < page_params.people_list.length; i++) { - if (page_params.people_list[i].email === person.email) { - page_params.people_list.splice(i, 1); - break; - } - } - people_dict.del(person.email); - people_by_name_dict.del(person.full_name); - realm_people_dict.del(person.email); -} - -function reify_person(person) { - // If a locally sent message is a PM to - // an out-of-realm recipient, a people_dict - // entry is created with simply an email address - // Once we've received the full person object, replace - // it - if (! people_dict.has(person.email)) { - return; - } - - var old_person = people_dict.get(person.email); - var old_idx = page_params.people_list.indexOf(old_person); - - var new_person = _.extend({}, old_person, person); - people_dict.set(person.email, person); - people_by_name_dict.set(person.full_name, person); - page_params.people_list[old_idx] = new_person; - - if (people_by_name_dict.has(person.email)) { - people_by_name_dict.del(person.email); - } -} - -function update_person(person) { - // Currently the only attribute that can change is full_name, so - // we just push out changes to that field. As we add more things - // that can change, this will need to either get complicated or be - // replaced by MVC - if (! people_dict.has(person.email)) { - blueslip.error("Got update_person event for unexpected user", - {email: person.email}); - return; - } - var person_obj = people_dict.get(person.email); - - if (_.has(person, 'full_name')) { - if (people_by_name_dict.has(person_obj.full_name)) { - people_by_name_dict.set(person.full_name, person_obj); - people_by_name_dict.del(person_obj.full_name); - } - - person_obj.full_name = person.full_name; - - if (person.email === page_params.email) { - page_params.fullname = person.full_name; - } - } - - if (_.has(person, 'is_admin')) { - person_obj.is_admin = person.is_admin; - - if (person.email === page_params.email) { - page_params.is_admin = person.is_admin; - admin.show_or_hide_menu_item(); - } - } - - activity.set_user_statuses([]); - - // TODO: update sender names on messages -} - function within_viewport(row_offset, row_height) { // Returns true if a message is fully within the effectively visible // part of the viewport. @@ -683,17 +589,17 @@ function add_message_metadata(message) { _.each(involved_people, function (person) { // Do the hasOwnProperty() call via the prototype to avoid problems // with keys like "hasOwnProperty" - if (! people_dict.has(person.email)) { - add_person(person); + if (! people.get_by_email(person.email)) { + people.add(person); } - if (people_dict.get(person.email).full_name !== person.full_name) { - reify_person(person); + if (people.get_by_email(person.email).full_name !== person.full_name) { + people.reify(person); } if (message.type === 'private' && message.sent_by_me) { // Track the number of PMs we've sent to this person to improve autocomplete - people_dict.get(person.email).pm_recipient_count += 1; + people.get_by_email(person.email).pm_recipient_count += 1; } }); @@ -1090,20 +996,6 @@ function consider_bankruptcy() { } } -_.each(page_params.people_list, function (person) { - people_dict.set(person.email, person); - people_by_name_dict.set(person.full_name, person); - realm_people_dict.set(person.email, person); - person.pm_recipient_count = 0; -}); - -// The special account feedback@zulip.com is used for in-app -// feedback and should always show up as an autocomplete option. -if (! people_dict.has('feedback@zulip.com')){ - add_person({"email": "feedback@zulip.com", - "full_name": "Zulip Feedback Bot"}); -} - function main() { activity.set_user_statuses(page_params.initial_presences, page_params.initial_servertime); diff --git a/tools/jslint/check-all.js b/tools/jslint/check-all.js index dcf8418abc..f8efc7b839 100644 --- a/tools/jslint/check-all.js +++ b/tools/jslint/check-all.js @@ -25,7 +25,7 @@ var globals = + ' compose compose_fade rows hotkeys narrow reload notifications_bar search subs' + ' composebox_typeahead server_events typeahead_helper notifications hashchange' + ' invite ui util activity timerender MessageList MessageListView blueslip unread stream_list' - + ' message_edit tab_bar emoji popovers navigate settings' + + ' message_edit tab_bar emoji popovers navigate people settings' + ' avatar feature_flags search_suggestion referral stream_color Dict' + ' Filter summary admin stream_data muting WinChan muting_ui Socket channel' @@ -53,7 +53,6 @@ var globals = // zulip.js + ' all_msg_list home_msg_list narrowed_msg_list current_msg_list get_updates_params' + ' add_messages' - + ' people_dict people_by_name_dict realm_people_dict' + ' keep_pointer_in_view unread_messages_read_in_narrow' + ' respond_to_message recenter_view last_viewport_movement_direction' + ' scroll_to_selected get_private_message_recipient' @@ -65,7 +64,6 @@ var globals = + ' mark_current_list_as_read message_range message_in_table process_loaded_for_unread' + ' mark_all_as_read message_unread process_read_messages unread_in_current_view' + ' fast_forward_pointer recent_subjects unread_subjects' - + ' add_person_in_realm remove_person update_person' + ' furthest_read server_furthest_read update_messages' + ' add_message_metadata' + ' mark_message_as_read batched_flag_updater' @@ -74,7 +72,7 @@ var globals = + ' suppress_unread_counts' + ' msg_metadata_cache' + ' report_as_received' - + ' insert_new_messages process_message_for_recent_subjects reify_person' + + ' insert_new_messages process_message_for_recent_subjects' ; diff --git a/zerver/tests/frontend/node/activity.js b/zerver/tests/frontend/node/activity.js index 648fa0094a..dbab3c81c3 100644 --- a/zerver/tests/frontend/node/activity.js +++ b/zerver/tests/frontend/node/activity.js @@ -1,11 +1,5 @@ var assert = require('assert'); -add_dependencies({ - _: 'third/underscore/underscore.js', - util: 'js/util.js', - Dict: 'js/dict.js' -}); - set_global('$', function () { return { on: function () { @@ -13,6 +7,18 @@ set_global('$', function () { } }; }); +$.fn = {}; +$.fn.expectOne = function () { + assert(this.length === 1); + return this; +}; + +add_dependencies({ + _: 'third/underscore/underscore.js', + util: 'js/util.js', + Dict: 'js/dict.js', + people: 'js/people.js' +}); set_global('document', { hasFocus: function () { @@ -20,7 +26,8 @@ set_global('document', { } }); -set_global('people_dict', new global.Dict.from({ +var people = require("js/people.js"); +people.test_set_people_dict({ 'alice@zulip.com': { full_name: 'Alice Smith' }, @@ -36,7 +43,7 @@ set_global('people_dict', new global.Dict.from({ 'norbert@zulip.com': { full_name: 'Norbert Oswald' } -})); +}); var activity = require('js/activity.js'); diff --git a/zerver/tests/frontend/node/echo.js b/zerver/tests/frontend/node/echo.js index e974f73c66..f2ab8d4e09 100644 --- a/zerver/tests/frontend/node/echo.js +++ b/zerver/tests/frontend/node/echo.js @@ -10,6 +10,7 @@ add_dependencies({ marked: 'third/marked/lib/marked.js', Dict: 'js/dict.js', emoji: 'js/emoji.js', + people: 'js/people.js', fenced_code: 'js/fenced_code.js' }); @@ -35,7 +36,8 @@ set_global('page_params', { set_global('feature_flags', {local_echo: true}); -set_global('people_by_name_dict', Dict.from({'Cordelia Lear': {full_name: 'Cordelia Lear', email: 'cordelia@zulip.com'}})); +var people = require("js/people.js"); +people.test_set_people_name_dict({'Cordelia Lear': {full_name: 'Cordelia Lear', email: 'cordelia@zulip.com'}}); var echo = require('js/echo.js'); diff --git a/zproject/settings.py b/zproject/settings.py index 4bc86b6a8d..e7c342673a 100644 --- a/zproject/settings.py +++ b/zproject/settings.py @@ -553,6 +553,7 @@ JS_SPECS = { 'js/message_list.js', 'js/alert_words.js', 'js/alert_words_ui.js', + 'js/people.js', 'js/server_events.js', 'js/zulip.js', 'js/activity.js',