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

Squish state parameters into a single room_dict

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