Commit 4bbcd3de authored by Eugene Shen's avatar Eugene Shen

Squish state parameters into a single room_dict

parent 88e4fd79
...@@ -104,9 +104,9 @@ ...@@ -104,9 +104,9 @@
type: param_dict.type || "message", type: param_dict.type || "message",
author: param_dict.author, author: param_dict.author,
room: param_dict.room, room: param_dict.room,
date_ms: param_dict.date_ms || new Date(), date_ms: param_dict.date_ms || new Date().getTime(),
content: param_dict.content || "", content: param_dict.content || "",
color: param_dict.color || "grey" color: param_dict.color || "black"
}; };
} }
...@@ -150,11 +150,8 @@ ...@@ -150,11 +150,8 @@
is_image = false; is_image = false;
// Add a protocol to transform relative URLs into absolute URLs // Add a protocol to transform relative URLs into absolute URLs
if (link_string.indexOf(":") !== -1) { absolute_url = link_string.indexOf(":") === -1 ?
absolute_url = link_string; "http://" + link_string : link_string;
} else {
absolute_url = "http://" + link_string;
}
// Create an image if the URL ends with one of the image extensions // Create an image if the URL ends with one of the image extensions
for (j = 0; j < image_extensions.length; j += 1) { for (j = 0; j < image_extensions.length; j += 1) {
...@@ -205,22 +202,16 @@ ...@@ -205,22 +202,16 @@
// a dict of room IDs to their names, i.e. {foo_bar_com: "foo@bar.com"} // a dict of room IDs to their names, i.e. {foo_bar_com: "foo@bar.com"}
id_to_name: {}, id_to_name: {},
// a dict of room names to whether each has unread messages /* a dict of room names to the room with the following properties:
unread_room_dict: {}, * - unread: true if it unread messages, otherwise false
* - join_time: the epoch time in milliseconds when the user joined it
// a dict of room names to the list of messages in each, * - message_list: its chronologically ascending list of messages
// i.e. {quiet_room: [message1, message2], busy_room: [message3, ...]} * - message_count: its number of messages in the remote jIO storage
message_list_dict: {}, * - delay_refresh_queue: its currently active delayRefresh promise queue
* - delay_refresh_index: its current index in POLL_DELAY_LIST
// a dict of room names to the number of messages in jIO storage, * - delay_refresh_lock: true if it is currently running refreshChat
// i.e. {quiet_room: 3, busy_room: 429} */
message_count_dict: {}, room_dict: {},
// a dict of room names to an object with keys corresponding to
// their delayRefresh promise queues, i.e. queue: new RSVP.Queue()
// their POLL_DELAY_LIST indices, i.e. index: 3, and
// whether each is currently running refreshChat, i.e. lock: true
delay_refresh_dict: {},
// true to use alert_icon_url, false to use default_icon_url // true to use alert_icon_url, false to use default_icon_url
favicon_alert: false, favicon_alert: false,
...@@ -279,10 +270,10 @@ ...@@ -279,10 +270,10 @@
*/ */
.onStateChange(function (modification_dict) { .onStateChange(function (modification_dict) {
var i, contact_name, contact_class_list, chat_list, chat_list_element, var i, contact_name, contact_class_list,
message_list, chat_list, chat_list_element,
gadget = this, gadget = this,
contact_list = Object.keys(gadget.state.message_list_dict), contact_list = Object.keys(gadget.state.room_dict),
message_list = gadget.state.message_list_dict[gadget.state.room],
favicon_element = document.querySelector("link[rel*='icon']") favicon_element = document.querySelector("link[rel*='icon']")
|| document.createElement("link"); || document.createElement("link");
...@@ -290,7 +281,7 @@ ...@@ -290,7 +281,7 @@
for (i = 0; i < contact_list.length; i += 1) { for (i = 0; i < contact_list.length; i += 1) {
contact_name = contact_list[i]; contact_name = contact_list[i];
contact_class_list = []; contact_class_list = [];
if (gadget.state.unread_room_dict[contact_name]) { if (gadget.state.room_dict[contact_name].unread) {
contact_class_list.push("notify"); contact_class_list.push("notify");
} }
if (contact_name === gadget.state.room) { if (contact_name === gadget.state.room) {
...@@ -304,11 +295,8 @@ ...@@ -304,11 +295,8 @@
} }
// set favicon depending on whether there are new unread messages // set favicon depending on whether there are new unread messages
if (gadget.state.favicon_alert) { favicon_element.href = gadget.state.favicon_alert ?
favicon_element.href = gadget.state.alert_icon_url; gadget.state.alert_icon_url : gadget.state.default_icon_url;
} else {
favicon_element.href = gadget.state.default_icon_url;
}
favicon_element.type = "image/x-icon"; favicon_element.type = "image/x-icon";
favicon_element.rel = "shortcut icon"; favicon_element.rel = "shortcut icon";
document.head.appendChild(favicon_element); document.head.appendChild(favicon_element);
...@@ -336,8 +324,10 @@ ...@@ -336,8 +324,10 @@
// render the contact list and chat list using Handlebars // render the contact list and chat list using Handlebars
gadget.element.querySelector(".contact-list").innerHTML = gadget.element.querySelector(".contact-list").innerHTML =
gadget.state.contact_list_template({list: contact_list}); gadget.state.contact_list_template({list: contact_list});
if (gadget.state.is_chat) { if (gadget.state.is_chat &&
gadget.state.room_dict.hasOwnProperty(gadget.state.room)) {
chat_list = []; chat_list = [];
message_list = gadget.state.room_dict[gadget.state.room].message_list;
for (i = 0; i < message_list.length; i += 1) { for (i = 0; i < message_list.length; i += 1) {
chat_list.push(messageToChat(message_list[i])); chat_list.push(messageToChat(message_list[i]));
} }
...@@ -424,7 +414,7 @@ ...@@ -424,7 +414,7 @@
.push(function () { .push(function () {
gadget.element.querySelector(".send-form input[type='text']") gadget.element.querySelector(".send-form input[type='text']")
.onfocus = function () { .onfocus = function () {
gadget.state.unread_room_dict[gadget.state.room] = false; gadget.state.room_dict[gadget.state.room].unread = false;
return gadget.changeState({ return gadget.changeState({
refresh_chat: true, refresh_chat: true,
favicon_alert: false favicon_alert: false
...@@ -493,7 +483,7 @@ ...@@ -493,7 +483,7 @@
if (!room.trim()) { if (!room.trim()) {
throw "An invisible name is not allowed! You couldn't click on it!"; throw "An invisible name is not allowed! You couldn't click on it!";
} }
if (gadget.state.message_list_dict.hasOwnProperty(room)) { if (gadget.state.room_dict.hasOwnProperty(room)) {
throw "A contact with the same name already exists!"; throw "A contact with the same name already exists!";
} }
return gadget.declareGadget("gadget_erp5_chat_room.html", { return gadget.declareGadget("gadget_erp5_chat_room.html", {
...@@ -524,12 +514,14 @@ ...@@ -524,12 +514,14 @@
}); });
}) })
.push(function () { .push(function () {
gadget.state.message_list_dict[room] = []; gadget.state.room_dict[room] = {
gadget.state.message_count_dict[room] = 0; unread: false,
gadget.state.delay_refresh_dict[room] = { join_time: new Date().getTime(),
queue: new RSVP.Queue(), message_list: [],
index: 0, message_count: 0,
lock: false delay_refresh_queue: new RSVP.Queue(),
delay_refresh_index: 0,
delay_refresh_lock: false
}; };
gadget.state.id_to_name["chat-contact-" + nameToId(room)] = room; gadget.state.id_to_name["chat-contact-" + nameToId(room)] = room;
return room_gadget.render(); return room_gadget.render();
...@@ -576,7 +568,7 @@ ...@@ -576,7 +568,7 @@
.declareMethod("changeRoom", function (room) { .declareMethod("changeRoom", function (room) {
var gadget = this; var gadget = this;
if (gadget.state.message_count_dict[room] > 0) { if (gadget.state.room_dict[room].message_count > 0) {
return gadget.changeState({room: room, is_chat: true}); return gadget.changeState({room: room, is_chat: true});
} }
return gadget.changeState({room: room, is_chat: false, update: true}); return gadget.changeState({room: room, is_chat: false, update: true});
...@@ -599,10 +591,10 @@ ...@@ -599,10 +591,10 @@
.declareMethod("deployMessage", function (param_dict) { .declareMethod("deployMessage", function (param_dict) {
var gadget = this, var gadget = this,
message = createMessage(param_dict); message = createMessage(param_dict);
gadget.state.message_list_dict[param_dict.room].push(message); gadget.state.room_dict[param_dict.room].message_list.push(message);
// increase so that rerreshChat() does not also call changeState() // increase so that rerreshChat() does not also call changeState()
gadget.state.message_count_dict[param_dict.room] += 1; gadget.state.room_dict[param_dict.room].message_count += 1;
gadget.state.unread_room_dict[param_dict.room] = false; gadget.state.room_dict[param_dict.room].unread = false;
return gadget.storeArchive(message) return gadget.storeArchive(message)
.push(function () { .push(function () {
return gadget.changeState({ return gadget.changeState({
...@@ -621,14 +613,14 @@ ...@@ -621,14 +613,14 @@
* - createMessage(param_dict) creates a valid message * - createMessage(param_dict) creates a valid message
* Effects: * Effects:
* - create a new message * - create a new message
* - append the message to the local message_list_dict but not jIO storage * - append the message to the local message list but not jIO storage
* - refresh the chat * - refresh the chat
*/ */
.declareMethod("deployNotification", function (param_dict) { .declareMethod("deployNotification", function (param_dict) {
var gadget = this; var gadget = this;
param_dict.type = "notification"; param_dict.type = "notification";
gadget.state.message_list_dict[param_dict.room] gadget.state.room_dict[param_dict.room].message_list
.push(createMessage(param_dict)); .push(createMessage(param_dict));
return gadget.changeState({refresh_chat: true}); return gadget.changeState({refresh_chat: true});
}) })
...@@ -653,7 +645,7 @@ ...@@ -653,7 +645,7 @@
parent_relative_url: "text_post_module", parent_relative_url: "text_post_module",
author: message.author, author: message.author,
room: message.room, room: message.room,
date_ms: getTime(message), date_ms: message.date_ms,
content: message.content content: message.content
}]); }]);
}); });
...@@ -666,7 +658,7 @@ ...@@ -666,7 +658,7 @@
* - poll_delay_index: the index in POLL_DELAY_LIST of * - poll_delay_index: the index in POLL_DELAY_LIST of
* the time in milliseconds to wait before refreshing again * the time in milliseconds to wait before refreshing again
* Requirements: * Requirements:
* - gadget.state.delay_refresh_dict[room].queue has new RSVP.Queue() in it * - gadget.state.room_dict[room].delay_refresh_queue is a RSVP.Queue()
* Effects: * Effects:
* - call refreshChat and wait a while before calling it again * - call refreshChat and wait a while before calling it again
*/ */
...@@ -711,23 +703,23 @@ ...@@ -711,23 +703,23 @@
* - so, do nothing * - so, do nothing
*/ */
.push(function () { .push(function () {
if (poll_delay_index < gadget.state.delay_refresh_dict[room].index if (poll_delay_index <
&& !gadget.state.delay_refresh_dict[room].lock) { gadget.state.room_dict[room].delay_refresh_index
gadget.state.delay_refresh_dict[room].queue.cancel(); && !gadget.state.room_dict[room].delay_refresh_lock) {
gadget.state.room_dict[room].delay_refresh_queue.cancel();
} }
if (poll_delay_index <= gadget.state.delay_refresh_dict[room].index) { if (poll_delay_index <=
gadget.state.delay_refresh_dict[room] = { gadget.state.room_dict[room].delay_refresh_index) {
// delayRefresh() is immediately called after this line // delayRefresh() is immediately called after this line
// and can be cancelled to overwrite longer intervals // and can be cancelled to overwrite longer intervals
queue: new RSVP.Queue() gadget.state.room_dict[room].delay_refresh_queue = new RSVP.Queue()
.push(function () { .push(function () {
return gadget.delayRefresh(room, poll_delay_index + 1); return gadget.delayRefresh(room, poll_delay_index + 1);
}), });
// increase the polling interval over time // increase the polling interval over time
index: poll_delay_index + 1, gadget.state.room_dict[room].delay_refresh_index =
// only refreshChat() should modify the locks poll_delay_index + 1;
lock: gadget.state.delay_refresh_dict[room].lock // only refreshChat() should modify the locks; no change here
};
} }
}); });
}) })
...@@ -740,10 +732,10 @@ ...@@ -740,10 +732,10 @@
* - refreshChat() is not currently being executed * - refreshChat() is not currently being executed
* - room has an associated room gadget with a valid jIO storage * - room has an associated room gadget with a valid jIO storage
* - there are no duplicate messages in that jIO storage * - there are no duplicate messages in that jIO storage
* - gadget.state.message_count_dict[room] is the total number of messages * - gadget.state.room_dict[room].message_Count is the number of messages
* retrieved from allDocs() the last time refreshChat() was triggered * retrieved from allDocs() the last time refreshChat() was triggered
* - gadget.state.message_list_dict[room] is a chronologically ascending * - gadget.state.room_dict[room].message_list is a sorted chronologically
* list of the unique messages loaded in the current room * ascending list of the unique messages loaded in the current room
* Effects: * Effects:
* - get a sorted list of all chats in the current room from jIO storage * - get a sorted list of all chats in the current room from jIO storage
* - merge the list with the sorted list of unique current messages * - merge the list with the sorted list of unique current messages
...@@ -758,10 +750,10 @@ ...@@ -758,10 +750,10 @@
// multiple calls to repair() results in unmanageable duplication // multiple calls to repair() results in unmanageable duplication
// atomic because JavaScript is single threaded, // atomic because JavaScript is single threaded,
// so nothing else can run between the following four lines // so nothing else can run between the following four lines
if (gadget.state.delay_refresh_dict[room].lock) { if (gadget.state.room_dict[room].delay_refresh_lock) {
return; return;
} }
gadget.state.delay_refresh_dict[room].lock = true; gadget.state.room_dict[room].delay_refresh_lock = true;
return gadget.getDeclaredGadget("room-gadget-" + room) return gadget.getDeclaredGadget("room-gadget-" + room)
.push(function (sub_gadget) { .push(function (sub_gadget) {
...@@ -781,19 +773,23 @@ ...@@ -781,19 +773,23 @@
}) })
.push(function (result_list) { .push(function (result_list) {
var i, j, message, new_list = [], var i, j, message, new_list = [],
old_list = gadget.state.message_list_dict[room]; old_list = gadget.state.room_dict[room].message_list;
// only run if there are new messages, since messages are not deleted // only run if there are new messages, since messages are not deleted
// calling refreshChat() after deployMessage() does nothing // calling refreshChat() after deployMessage() does nothing
// because deployMessage() already added one new message // because deployMessage() already added one new message
if (result_list.data.total_rows > if (result_list.data.total_rows >
gadget.state.message_count_dict[room]) { gadget.state.room_dict[room].message_count) {
gadget.state.message_count_dict[room] = result_list.data.total_rows; gadget.state.room_dict[room].message_count =
result_list.data.total_rows;
// merge two sorted lists of unique messages together // merge two sorted lists of unique messages together
j = 0; j = 0;
for (i = 0; i < result_list.data.total_rows; i += 1) { for (i = 0; i < result_list.data.total_rows; i += 1) {
message = createMessage(result_list.data.rows[i].value); message = createMessage(result_list.data.rows[i].value);
if (getTime(message) < gadget.state.room_dict[room].join_time) {
message.color = "grey";
}
// add old messages sent before the current message // add old messages sent before the current message
while (j < old_list.length while (j < old_list.length
&& getTime(old_list[j]) < getTime(message)) { && getTime(old_list[j]) < getTime(message)) {
...@@ -819,8 +815,8 @@ ...@@ -819,8 +815,8 @@
} }
// override the current list of messages and notify the user // override the current list of messages and notify the user
gadget.state.message_list_dict[room] = new_list; gadget.state.room_dict[room].message_list = new_list;
gadget.state.unread_room_dict[room] = true; gadget.state.room_dict[room].unread = true;
return gadget.changeState({ return gadget.changeState({
refresh_chat: true, refresh_chat: true,
favicon_alert: true favicon_alert: true
...@@ -830,9 +826,10 @@ ...@@ -830,9 +826,10 @@
// release the lock no matter what errors occur // release the lock no matter what errors occur
.push(function () { .push(function () {
gadget.state.delay_refresh_dict[room].lock = false; gadget.state.room_dict[room].delay_refresh_lock = false;
}, function () { }, function (error) {
gadget.state.delay_refresh_dict[room].lock = false; gadget.state.room_dict[room].delay_refresh_lock = false;
throw error;
}); });
}) })
...@@ -857,11 +854,11 @@ ...@@ -857,11 +854,11 @@
"/leave: disconnects you from the current room", "/leave: disconnects you from the current room",
"/quit: disconnects from the chat and refreshes the page" "/quit: disconnects from the chat and refreshes the page"
]; ];
switch (command) {
switch (command) {
// change to the given room // change to the given room
case "join": case "join":
if (gadget.state.message_list_dict[argument]) { if (gadget.state.room_dict[argument]) {
return gadget.changeRoom(argument); return gadget.changeRoom(argument);
} }
return gadget.deployNotification({ return gadget.deployNotification({
...@@ -883,7 +880,7 @@ ...@@ -883,7 +880,7 @@
color: "red" color: "red"
}); });
} }
delete gadget.state.message_list_dict[gadget.state.room]; delete gadget.state.room_dict[gadget.state.room];
return gadget.deployMessage({ return gadget.deployMessage({
author: gadget.state.name, author: gadget.state.name,
room: gadget.state.room, room: gadget.state.room,
...@@ -929,7 +926,7 @@ ...@@ -929,7 +926,7 @@
room; room;
if (event.target.classList.contains("chat-contact")) { if (event.target.classList.contains("chat-contact")) {
room = gadget.state.id_to_name[event.target.id]; room = gadget.state.id_to_name[event.target.id];
gadget.state.unread_room_dict[room] = false; gadget.state.room_dict[room].unread = false;
return gadget.changeState({favicon_alert: false}) return gadget.changeState({favicon_alert: false})
.push(function () { .push(function () {
return gadget.changeRoom(room); return gadget.changeRoom(room);
...@@ -977,9 +974,9 @@ ...@@ -977,9 +974,9 @@
}) })
.push(function () { .push(function () {
var promise_list = [], room; var promise_list = [], room;
for (room in gadget.state.message_list_dict) { for (room in gadget.state.room_dict) {
if (gadget.state.message_list_dict.hasOwnProperty(room) if (gadget.state.room_dict.hasOwnProperty(room)
&& gadget.state.message_count_dict[room] > 0) { && gadget.state.room_dict[room].message_count > 0) {
promise_list.push(gadget.deployMessage({ promise_list.push(gadget.deployMessage({
author: gadget.state.name, author: gadget.state.name,
room: room, room: room,
......
...@@ -237,7 +237,7 @@ ...@@ -237,7 +237,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>958.43234.30120.30600</string> </value> <value> <string>958.44293.34365.30907</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -255,7 +255,7 @@ ...@@ -255,7 +255,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1492099357.94</float> <float>1492162895.42</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment