url,
{
"abort": function (msg) {
- messages_manager.add_msg(null, "xhr_abort", msg, null);
+ console.log(msg);
+ new Message({"text": msg, "user": "xhr_abort"}, null);
},
"error": function (msg) {
- messages_manager.add_msg(null, "xhr_error", msg, null);
+ console.log(msg);
+ new Message({"text": msg, "user": "xhr_error"}, null);
},
"load": function () {
var response_data;
clear_channel();
if (this === window) {
current_channel = null;
- messages_manager.add_msg(null, null, "No channel selected!", null);
+ new Message({"text": "No channel selected!"}, null);
return;
}
current_channel = this;
this.items_reload();
}
- function Message(id, user, text) {
- this.id = id;
- this.p = make_tag_with_data_id("p", id);
- this.update = function (user, text) {
- this.user = user || this.user;
- this.text = text || this.text;
+ function Message(init_msg, next) {
+ if (typeof init_msg.id === "number") {
+ this.id = init_msg.id;
+ messages_manager.msgs_by_id[this.id.toString(36)] = this;
+ } else {
+ this.id = null;
+ }
+ this.msg = init_msg;
+ this.p = make_tag_with_data_id("p", init_msg.id);
+ _.dgEBCN0("messages").insertBefore(this.p, next || null);
+ this.remove = function () {
+ this.p.parentElement.removeChild(this.p);
+ if (this.id !== null) {
+ delete messages_manager.msgs_by_id[this.id.toString(36)];
+ }
+ };
+ function get_date_span(ts) {
+ var d = new Date(ts);
+ var date_span = document.createElement("span");
+ date_span.appendChild(_.dcTN(_.strftime(d, "%H:%m")));
+ date_span.setAttribute(
+ "title",
+ _.strftime(d, "%Y-%m-%d %H:%M:%S.%f")
+ );
+ date_span.setAttribute("class", "date_span");
+ return date_span;
+ }
+ this.update = function (msg) {
+ msg = msg || this.msg;
+ if (
+ !msg.hasOwnProperty("user")
+ && current_channel !== null
+ && current_channel.hasOwnProperty("msg_user_field")
+ && msg.hasOwnProperty(current_channel.msg_user_field)
+ ) {
+ msg.user = msg[current_channel.msg_user_field];
+ delete msg[current_channel.msg_user_field];
+ }
_.clear_children(this.p);
- if (this.user) {
- if (typeof this.user === "number") {
- user = private_manager.items_per_id[this.user].username;
+ if (msg.ts) {
+ this.p.appendChild(get_date_span(msg.ts));
+ this.p.appendChild(_.dcTN(" "));
+ }
+ if (msg.user) {
+ if (typeof msg.user === "number") {
+ this.p.appendChild(
+ _.dcTN(
+ private_manager.items_per_id[
+ msg.user
+ ].username
+ )
+ );
} else {
- user = this.user;
+ this.p.appendChild(_.dcTN(msg.user));
}
- this.p.appendChild(_.dcTN(user));
this.p.appendChild(_.dcTN(": "));
}
- this.p.appendChild(_.dcTN(this.text));
+ this.p.appendChild(_.dcTN(msg.text));
+ this.msg = msg;
};
- this.update(user, text);
+ this.update();
}
function MessagesManager() {
var messages = _.dgEBCN0("messages");
this.msgs_by_id = {};
- this.add_msg = function (id, user, text, next) {
- var msg = new Message(id, user, text);
- messages.insertBefore(msg.p, next || null);
- if (id) {
- this.msgs_by_id[id.toString(36)] = msg;
- }
- };
this.by_id = function (msg_id) {
return this.msgs_by_id[msg_id.toString(36)] || null;
};
_.clear_attributes(this.msgs_by_id);
_.clear_children(messages);
};
- this.remove = function (id) {
- var msg = this.by_id(id);
- if (msg) {
- msg.p.parentElement.removeChild(msg.p);
- delete this.msgs_by_id[msg.id.toString(36)];
- }
- };
this.previous_button = function (url) {
var p;
var button;
};
this.load_msgs_callback = function (msgs, next) {
this.previous_button(msgs.previous);
- _.foreach_arr(msgs.result, function (item) {
- messages_manager.add_msg(
- item.id,
- item[current_channel.msg_user_field],
- item.text,
- next
- );
+ _.foreach_arr(msgs.result, function (msg) {
+ new Message(msg, next);
});
};
function no_bottom_callback() {
var ws_schemas = {"http:": "ws:", "https:": "wss:"};
var ws_receive_msg = {
DELETE: function (data) {
- messages_manager.remove(data.obj.id);
+ var msg = messages_manager.get_by(data.obj.id);
+ if (msg) {
+ msg.remove();
+ }
},
INSERT: function (data) {
messages_manager.stick_to_bottom();
xhr(
"get",
current_channel.msg_url + data.obj.id + "/",
- function (item) {
- messages_manager.add_msg(
- item.id,
- item[current_channel.msg_user_field],
- item.text,
- null
- );
- messages_manager.bottom_callback();
- }
+ ws_receive_msg.insert_callback
);
},
TRUNCATE: function () {
messages_manager.clear();
},
UPDATE: function (data) {
- var msg = messages_manager.by_id(data.obj.id);
- if (!msg) {
+ if (!messages_manager.by_id(data.obj.id)) {
return;
}
messages_manager.stick_to_bottom();
"get",
(
current_channel.msg_url
- + msg.id.toString()
+ + data.obj.id.toString()
+ "/"
),
- function (data) {
- msg.update(
- data[current_channel.msg_user_field],
- data.text
- );
- messages_manager.bottom_callback();
- }
+ ws_receive_msg.update_callback
);
+ },
+ insert_callback: function (item) {
+ new Message(item, null);
+ messages_manager.bottom_callback();
+ },
+ update_callback: function (data) {
+ console.log(messages_manager.by_id(data.id));
+ messages_manager.by_id(data.id).update(data);
+ messages_manager.bottom_callback();
}
};
var ws = new WebSocket(
ws.addEventListener("message", ws_receive);
ws.addEventListener("close", function (event) {
event = event || window.event;
- messages_manager.add_msg(null, "ws_close", "Closed", null);
+ new Message({"text": "Closed", "user": "ws_close"}, null);
// display reconnect button here
});
ws.addEventListener("error", function (event) {
event = event || window.event;
- messages_manager.add_msg(null, "ws_error", event, null);
+ console.log(event);
+ new Message({"text": event, "user": "ws_error"}, null);
// display reconnect button here
});
}
function () {
ta.value = "";
ta.disabled = false;
+ ta.focus();
},
JSON.stringify(data)
);
);
}
+ function left_pad(s, length, fill) {
+ var i;
+ if (typeof s === "number") {
+ s = s.toString();
+ }
+ for (i = 0; s.length < length; i += 1) {
+ s = fill[i % fill.length] + s;
+ }
+ return s;
+ }
+
+ function intl_dateformat(date, locale, obj) {
+ return new Intl.DateTimeFormat(locale || "en-US", obj).format(date);
+ }
+
+ function get_timezone_offset(date) {
+ var tzo = date.getTimezoneOffset();
+ var sign;
+ if (tzo < 0) {
+ sign = "-";
+ tzo *= -1;
+ } else {
+ sign = "+";
+ }
+ return [
+ sign,
+ left_pad(Math.floor(tzo / 60), 2, "0"),
+ left_pad(Math.floor(tzo % 60), 2, "0")
+ ].join("");
+ }
+
+ function get_timezone(date, locale) {
+ var s = intl_dateformat(date, locale, {"timeZoneName": "short"});
+ var pos = s.indexOf(",");
+ if (pos !== -1) {
+ s = s.substring(pos + 1).trim();
+ }
+ return s;
+ }
+
+ function strftime(date, s, locale) {
+ var pos = s.indexOf("%");
+ var out = [];
+ while (true) {
+ pos = s.indexOf("%");
+ if (pos === -1) {
+ break;
+ }
+ out.push(s.substring(0, pos));
+ switch (s[pos + 1]) {
+ case "a":
+ out.push(intl_dateformat(date, locale, {"weekday": "short"}));
+ break;
+ case "A":
+ out.push(intl_dateformat(date, locale, {"weekday": "long"}));
+ break;
+ case "b":
+ out.push(intl_dateformat(date, locale, {"month": "short"}));
+ break;
+ case "B":
+ out.push(intl_dateformat(date, locale, {"month": "long"}));
+ break;
+ case "c":
+ out.push(date.toLocaleString(date));
+ break;
+ case "d":
+ out.push(left_pad(date.getDate(), 2, "0"));
+ break;
+ case "f":
+ out.push(left_pad(date.getMilliseconds(), 3, "0"));
+ break;
+ case "H":
+ out.push(left_pad(date.getHours(), 2, "0"));
+ break;
+ case "I":
+ if (date.getHours() % 12 === 0) {
+ out.push("12");
+ } else {
+ out.push(left_pad(date.getHours() % 12, 2, "0"));
+ }
+ break;
+ // missing: "j"
+ case "m":
+ out.push(left_pad(date.getMonth() + 1, 2, "0"));
+ break;
+ case "M":
+ out.push(left_pad(date.getMinutes(), 2, "0"));
+ break;
+ case "p":
+ if (date.getHours() < 12) {
+ out.push("AM");
+ } else {
+ out.push("PM");
+ }
+ break;
+ case "S":
+ out.push(left_pad(date.getSeconds(), 2, "0"));
+ break;
+ // missing: "U"
+ case "w":
+ out.push(date.getDay().toString());
+ break;
+ // missing: "W"
+ case "x":
+ out.push(date.toLocaleDateString());
+ break;
+ case "X":
+ out.push(date.toLocaleTimeString());
+ break;
+ case "y":
+ out.push(left_pad(date.getFullYear() % 100, 2, "0"));
+ break;
+ case "Y":
+ out.push(left_pad(date.getFullYear(), 4, "0"));
+ break;
+ case "z":
+ out.push(get_timezone_offset(date));
+ break;
+ case "Z":
+ out.push(get_timezone(date, locale));
+ break;
+ case "%":
+ out.push(s[pos + 1]);
+ break;
+ default:
+ out.push(s.substring(pos, pos + 2));
+ }
+ s = s.substring(pos + 2);
+ }
+ out.push(s);
+ return out.join("");
+ }
+
function xhr(method, url, callbacks, data) {
var request = new XMLHttpRequest();
if (!callbacks.hasOwnProperty("error")) {
},
"foreach_arr": foreach_arr,
"foreach_obj": foreach_obj,
+ "strftime": strftime,
"xhr": xhr
};
}());